Compare commits
138 Commits
Author | SHA1 | Date |
---|---|---|
![]() |
27acc9a80e | |
![]() |
43ad5dec90 | |
![]() |
aa8802679f | |
![]() |
aa211fd789 | |
![]() |
61d39be86f | |
![]() |
b80bd37f6e | |
![]() |
3db5e191b8 | |
![]() |
45c7109212 | |
![]() |
b58d0fb723 | |
![]() |
a21a1ca533 | |
![]() |
4a37016f4e | |
![]() |
5d6ebb30ac | |
![]() |
888457238d | |
![]() |
b0d9309471 | |
![]() |
f64d0718ae | |
![]() |
968317ca9f | |
![]() |
22dad3ba6d | |
![]() |
4f7bd6f28d | |
![]() |
12fcfa15b1 | |
![]() |
e46d537d45 | |
![]() |
ac9d1b0a7f | |
![]() |
2c7008d786 | |
![]() |
49d4b3166e | |
![]() |
339fb4a230 | |
![]() |
bb443a05e2 | |
![]() |
3a79f72816 | |
![]() |
89eec07145 | |
![]() |
c69a6d29b2 | |
![]() |
2666cb79ab | |
![]() |
35d5185634 | |
![]() |
4492086aac | |
![]() |
4b7c6ac02c | |
![]() |
208b8d3085 | |
![]() |
f41fec26ba | |
![]() |
9118d6cd42 | |
![]() |
5c7aaf0dd6 | |
![]() |
b82d8dd2ad | |
![]() |
1d0fa8533a | |
![]() |
4318147fc6 | |
![]() |
312bcc5127 | |
![]() |
6594fe3964 | |
![]() |
82f28ce3d0 | |
![]() |
6e2c5a6a83 | |
![]() |
307148e2df | |
![]() |
afebeb9ffa | |
![]() |
aeda2637f6 | |
![]() |
f42d8ad1ce | |
![]() |
33a0708eb4 | |
![]() |
085eb398a4 | |
![]() |
9c27414cd0 | |
![]() |
014e86bd27 | |
![]() |
40ad45bc05 | |
![]() |
1c82940160 | |
![]() |
7ce0f115d5 | |
![]() |
54434b0931 | |
![]() |
e01f26c541 | |
![]() |
9a45b35511 | |
![]() |
8e8073d17e | |
![]() |
d6cc262c3a | |
![]() |
9d7c171940 | |
![]() |
48a3ceb921 | |
![]() |
23c620ea3a | |
![]() |
752686e334 | |
![]() |
9b0f0e71e7 | |
![]() |
42d33e963c | |
![]() |
ed27700ef4 | |
![]() |
eedd7f3302 | |
![]() |
c28c38d02e | |
![]() |
162d1fcf95 | |
![]() |
4815ee6f20 | |
![]() |
2b41e56520 | |
![]() |
ab874ffd4b | |
![]() |
61ade6b8ec | |
![]() |
4d35b8caa3 | |
![]() |
040af82eb9 | |
![]() |
a8c72fc5e7 | |
![]() |
c25736d57d | |
![]() |
4a48bfc66b | |
![]() |
4138d3c822 | |
![]() |
dec67a6d65 | |
![]() |
85c48c0566 | |
![]() |
966bc1004c | |
![]() |
457d0fde0b | |
![]() |
ff184b3969 | |
![]() |
75886a8cbf | |
![]() |
2b0c2da232 | |
![]() |
ffd4d8fe92 | |
![]() |
49e1323baa | |
![]() |
35d1de9ea6 | |
![]() |
fa46999963 | |
![]() |
01300d01da | |
![]() |
9a5f83ed06 | |
![]() |
ce6b7f3b4e | |
![]() |
4a2f95fe88 | |
![]() |
7c73beb309 | |
![]() |
0cbf3ca354 | |
![]() |
7afb7ce465 | |
![]() |
9cc73011c5 | |
![]() |
4b21210700 | |
![]() |
a80ca17461 | |
![]() |
ad8d32ab09 | |
![]() |
d870f3f8e0 | |
![]() |
c717473568 | |
![]() |
1e07544e74 | |
![]() |
8ab008d255 | |
![]() |
f034a7759e | |
![]() |
3f33cefa81 | |
![]() |
81e43c56ef | |
![]() |
f400c803e1 | |
![]() |
502c11cc4c | |
![]() |
2cdb69f706 | |
![]() |
2eed8e62ec | |
![]() |
61c0d0cc9d | |
![]() |
d7f9bd27dc | |
![]() |
4ed2868137 | |
![]() |
8696e01039 | |
![]() |
a3fd390619 | |
![]() |
a9198e44df | |
![]() |
509ec682f2 | |
![]() |
73f0a29acf | |
![]() |
f93dd9170d | |
![]() |
cfa0a68568 | |
![]() |
afcff32fcc | |
![]() |
b989cf2d97 | |
![]() |
0e6fd652b8 | |
![]() |
6625d39118 | |
![]() |
67efafca4a | |
![]() |
a8a774a5ff | |
![]() |
1fc109704b | |
![]() |
d140523c89 | |
![]() |
91fe1b0d71 | |
![]() |
c1b4941def | |
![]() |
af383a34bc | |
![]() |
1dccce4e16 | |
![]() |
8aa8e5a778 | |
![]() |
42952b713a | |
![]() |
07c36192b8 | |
![]() |
562623c091 |
|
@ -27,6 +27,7 @@ module.exports = {
|
||||||
// ],
|
// ],
|
||||||
plugins: ['markdown', 'jest', '@typescript-eslint', 'import'],
|
plugins: ['markdown', 'jest', '@typescript-eslint', 'import'],
|
||||||
globals: {
|
globals: {
|
||||||
|
h: true,
|
||||||
defineProps: 'readonly',
|
defineProps: 'readonly',
|
||||||
},
|
},
|
||||||
overrides: [
|
overrides: [
|
||||||
|
@ -108,7 +109,4 @@ module.exports = {
|
||||||
],
|
],
|
||||||
'vue/multi-word-component-names': 'off',
|
'vue/multi-word-component-names': 'off',
|
||||||
},
|
},
|
||||||
globals: {
|
|
||||||
h: true,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
blank_issues_enabled: false
|
blank_issues_enabled: true
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Create new issue
|
- name: Create new issue
|
||||||
url: https://vuecomponent.github.io/issue-helper/
|
url: https://vuecomponent.github.io/issue-helper/
|
||||||
|
|
|
@ -10,6 +10,88 @@
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 4.2.6
|
||||||
|
|
||||||
|
- 🐞 Fix Modal component aria-hidden error problem under chrome [#7823](https://github.com/vueComponent/ant-design-vue/issues/7823)
|
||||||
|
- 🐞 Fix the problem that the built-in input method of Safari automatically fills in the decimal point when inputting Chinese [#7918](https://github.com/vueComponent/ant-design-vue/issues/7918)
|
||||||
|
- 🐞 Fix InputNumber component disabled style problem [#7776](https://github.com/vueComponent/ant-design-vue/issues/7776)
|
||||||
|
- 🐞 Fix Select cannot lose focus problem [#7819](https://github.com/vueComponent/ant-design-vue/issues/7819)
|
||||||
|
|
||||||
|
## 4.2.5
|
||||||
|
|
||||||
|
- 🐞 Fix Empty component memory leak problem
|
||||||
|
- 🐞 Fix Image width & height property not working problem
|
||||||
|
|
||||||
|
## 4.2.4
|
||||||
|
|
||||||
|
- 🐞 Fix Wave memory leak problem
|
||||||
|
|
||||||
|
## 4.2.3
|
||||||
|
|
||||||
|
- 🌟 TourStep custom Button, support function children [#7628](https://github.com/vueComponent/ant-design-vue/pull/7628)
|
||||||
|
- 🐞 Fix the problem that the input value is hidden in Select and Cascader search multi-select mode [#7640](https://github.com/vueComponent/ant-design-vue/issues/7640)
|
||||||
|
|
||||||
|
## 4.2.2
|
||||||
|
|
||||||
|
- 🐞 Fix TreeSelect placeholder slot invalid [#7545](https://github.com/vueComponent/ant-design-vue/issues/7545)
|
||||||
|
- 🐞 Fix Tree slot responsive invalid issue [40ad45](https://github.com/vueComponent/ant-design-vue/commit/40ad45bc05b2bf9d0a2445d9f6ff365468ba90b7)
|
||||||
|
- 🐞 Fix FloatButton target type error issue [#7576](https://github.com/vueComponent/ant-design-vue/issues/7576)
|
||||||
|
- 🐞 Fix FormItem className error issue [#7582](https://github.com/vueComponent/ant-design-vue/issues/7582)
|
||||||
|
- 🐞 Fix Input Cannot input problem under lazy [#7543](https://github.com/vueComponent/ant-design-vue/issues/7543)
|
||||||
|
- 🐞 Fix the problem that placeholder is not hidden when inputting Chinese in Select [#7611](https://github.com/vueComponent/ant-design-vue/issues/7611)
|
||||||
|
- 🐞 Fix the problem that the pop-up window flashes when clicking the preset option in DatePicker [#7550](https://github.com/vueComponent/ant-design-vue/issues/7550)
|
||||||
|
|
||||||
|
## 4.2.1
|
||||||
|
|
||||||
|
- 🐞 fix Input clear action error [#7523](https://github.com/vueComponent/ant-design-vue/issues/7523)
|
||||||
|
|
||||||
|
## 4.2.0
|
||||||
|
|
||||||
|
- 🌟 Optimize the textColor change when the layout component switches to dark mode [#7498](https://github.com/vueComponent/ant-design-vue/issues/7498)
|
||||||
|
- 🌟 Tooltip added arrow hidden configuration [#7459](https://github.com/vueComponent/ant-design-vue/issues/7459)
|
||||||
|
- 🌟 Optimize Table hover performance [#7451](https://github.com/vueComponent/ant-design-vue/issues/7451)
|
||||||
|
- 🐞 Fixed the problem of changing the model during useForm verification, resulting in verification errors [#ffd4d8](https://github.com/vueComponent/ant-design-vue/commit/ffd4d8fe927f9ea40cbb6358ad997c447bd9a74e)
|
||||||
|
- 🐞 Fix Tabs folding calculation error issue [#7491](https://github.com/vueComponent/ant-design-vue/issues/7491)
|
||||||
|
- 🐞 Fix Qrcode missing type hint issue [#7502](https://github.com/vueComponent/ant-design-vue/issues/7502)
|
||||||
|
- 🐞 Fix Menu rendering error under SSR [#7349](https://github.com/vueComponent/ant-design-vue/issues/7349)
|
||||||
|
- 🐞 Fix Select and Cascader rendering errors under SSR [#7377](https://github.com/vueComponent/ant-design-vue/issues/7377)
|
||||||
|
- 🐞 Fix AutoComplete missing option slot declaration issue [#7396](https://github.com/vueComponent/ant-design-vue/issues/7396)
|
||||||
|
- 🐞 Fix Textarea autoSize not taking effect [#7478](https://github.com/vueComponent/ant-design-vue/issues/7478)
|
||||||
|
- 🐞 Fix Pagination’s Enter key triggering two page turns [#7368](https://github.com/vueComponent/ant-design-vue/issues/7368)
|
||||||
|
- 🐞 Fix the problem of Chinese input in the input box [#7391](https://github.com/vueComponent/ant-design-vue/issues/7391)[#7516](https://github.com/vueComponent/ant- design-vue/issues/7516)
|
||||||
|
- 🐞 Fix Carousel beforeChange current parameter error issue [#7419](https://github.com/vueComponent/ant-design-vue/issues/7419)
|
||||||
|
|
||||||
|
## 4.1.2
|
||||||
|
|
||||||
|
- 🐞 Fix table resize error reporting under vue 3.4 [#7291](https://github.com/vueComponent/ant-design-vue/issues/7291)
|
||||||
|
- 🐞 Fix the problem that the Segmented title attribute is not displayed [#7302](https://github.com/vueComponent/ant-design-vue/issues/7302)
|
||||||
|
|
||||||
|
## 4.1.1
|
||||||
|
|
||||||
|
- 🌟 QRcode adds scanned status [#7242](https://github.com/vueComponent/ant-design-vue/issues/7242)
|
||||||
|
- 🐞 Fix css prefix issue in nuxt [#7256](https://github.com/vueComponent/ant-design-vue/issues/7256)
|
||||||
|
- 🐞 Fix dropdown closing issue [#7246](https://github.com/vueComponent/ant-design-vue/issues/7246)
|
||||||
|
- 🐞 Fix divider vertical dashed not display issue [#7218](https://github.com/vueComponent/ant-design-vue/issues/7218)
|
||||||
|
- 🐞 Fix hook mode message console warning issue [#7281](https://github.com/vueComponent/ant-design-vue/issues/7281)
|
||||||
|
- 🐞 Fix table expansion error reporting under vue 3.4 [#7265](https://github.com/vueComponent/ant-design-vue/issues/7265)
|
||||||
|
- 🐞 Fix table group filter status error issue [#7233](https://github.com/vueComponent/ant-design-vue/issues/7233)
|
||||||
|
|
||||||
|
## 4.1.0
|
||||||
|
|
||||||
|
- 🐞 support vue 3.4 [#7239](https://github.com/vueComponent/ant-design-vue/issues/7239)
|
||||||
|
|
||||||
|
## 4.0.8
|
||||||
|
|
||||||
|
- 🐞 Fix theme responsiveness failure issue under Nuxt [#7180](https://github.com/vueComponent/ant-design-vue/issues/7180)
|
||||||
|
- 🐞 Fix error reporting caused by Wave [#7108](https://github.com/vueComponent/ant-design-vue/issues/7108)
|
||||||
|
- 🐞 Fix Upload disabled inheritance issue [#7110](https://github.com/vueComponent/ant-design-vue/issues/7110)
|
||||||
|
- 🐞 Fix Tooltip popupAlign not taking effect [#7112](https://github.com/vueComponent/ant-design-vue/issues/7112)
|
||||||
|
- 🐞 Fix Typography flashing problem [#7146](https://github.com/vueComponent/ant-design-vue/issues/7146)
|
||||||
|
- 🐞 Fix the issue that RangePicker prevIcon nextIcon does not take effect [#7127](https://github.com/vueComponent/ant-design-vue/issues/7127)
|
||||||
|
- 🐞 Fixed the issue of watermark not monitoring child element changes [#7149](https://github.com/vueComponent/ant-design-vue/issues/7149)
|
||||||
|
- 🐞 Fix Menu animation missing issue [#7130](https://github.com/vueComponent/ant-design-vue/issues/7130)
|
||||||
|
- 🐞 Fix the cursor change issue when TextArea autosize [#7121](https://github.com/vueComponent/ant-design-vue/issues/7121)
|
||||||
|
|
||||||
## 4.0.7
|
## 4.0.7
|
||||||
|
|
||||||
- 🌟 Added Flex component [#7052](https://github.com/vueComponent/ant-design-vue/issues/7052)
|
- 🌟 Added Flex component [#7052](https://github.com/vueComponent/ant-design-vue/issues/7052)
|
||||||
|
|
|
@ -10,6 +10,88 @@
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 4.2.6
|
||||||
|
|
||||||
|
- 🐞 修复 Modal 组件在 chrome 下,aria-hidden 报错问题 [#7823](https://github.com/vueComponent/ant-design-vue/issues/7823)
|
||||||
|
- 🐞 修复 Safari 下自带输入法 input 组件输入中文时,自动填写小数点问题 [#7918](https://github.com/vueComponent/ant-design-vue/issues/7918)
|
||||||
|
- 🐞 修复 InputNumber 组件 disabled 样式问题 [#7776](https://github.com/vueComponent/ant-design-vue/issues/7776)
|
||||||
|
- 🐞 修复 Select 无法失焦问题 [#7819](https://github.com/vueComponent/ant-design-vue/issues/7819)
|
||||||
|
|
||||||
|
## 4.2.5
|
||||||
|
|
||||||
|
- 🐞 修复 Empty 组件内存泄漏问题
|
||||||
|
- 🐞 修复 Image width & height 属性不生效问题
|
||||||
|
|
||||||
|
## 4.2.4
|
||||||
|
|
||||||
|
- 🐞 修复 Wave 内存泄漏问题
|
||||||
|
|
||||||
|
## 4.2.3
|
||||||
|
|
||||||
|
- 🌟 TourStep 自定义 Button,支持函数 children [#7628](https://github.com/vueComponent/ant-design-vue/pull/7628)
|
||||||
|
- 🐞 修复 Select 和 Cascader 搜索多选模式下,输入值被隐藏问题 [#7640](https://github.com/vueComponent/ant-design-vue/issues/7640)
|
||||||
|
|
||||||
|
## 4.2.2
|
||||||
|
|
||||||
|
- 🐞 修复 TreeSelect placeholder 插槽无效 [#7545](https://github.com/vueComponent/ant-design-vue/issues/7545)
|
||||||
|
- 🐞 修复 Tree 插槽响应式无效问题 [40ad45](https://github.com/vueComponent/ant-design-vue/commit/40ad45bc05b2bf9d0a2445d9f6ff365468ba90b7)
|
||||||
|
- 🐞 修复 FloatButton target 类型错误问题 [#7576](https://github.com/vueComponent/ant-design-vue/issues/7576)
|
||||||
|
- 🐞 修复 FormItem className 错误问题 [#7582](https://github.com/vueComponent/ant-design-vue/issues/7582)
|
||||||
|
- 🐞 修复 Input lazy 下无法输入问题 [#7543](https://github.com/vueComponent/ant-design-vue/issues/7543)
|
||||||
|
- 🐞 修复 Select 输入中文时,placeholder 未隐藏问题 [#7611](https://github.com/vueComponent/ant-design-vue/issues/7611)
|
||||||
|
- 🐞 修复 DatePicker 点击预设选项时,弹窗闪动问题 [#7550](https://github.com/vueComponent/ant-design-vue/issues/7550)
|
||||||
|
|
||||||
|
## 4.2.1
|
||||||
|
|
||||||
|
- 🐞 修复 Input 清空操作才报错问题 [#7523](https://github.com/vueComponent/ant-design-vue/issues/7523)
|
||||||
|
|
||||||
|
## 4.2.0
|
||||||
|
|
||||||
|
- 🌟 优化 layout 组件切换 dark 模式时 textColor 变化 [#7498](https://github.com/vueComponent/ant-design-vue/issues/7498)
|
||||||
|
- 🌟 Tooltip 新增 arrow 隐藏配置 [#7459](https://github.com/vueComponent/ant-design-vue/issues/7459)
|
||||||
|
- 🌟 优化 Table hover 性能 [#7451](https://github.com/vueComponent/ant-design-vue/issues/7451)
|
||||||
|
- 🐞 修复 useForm 校验时更改 model,导致校验错误问题 [#ffd4d8](https://github.com/vueComponent/ant-design-vue/commit/ffd4d8fe927f9ea40cbb6358ad997c447bd9a74e)
|
||||||
|
- 🐞 修复 Tabs 折叠计算错误问题 [#7491](https://github.com/vueComponent/ant-design-vue/issues/7491)
|
||||||
|
- 🐞 修复 Qrcode 缺少类型提示问题 [#7502](https://github.com/vueComponent/ant-design-vue/issues/7502)
|
||||||
|
- 🐞 修复 Menu 在 SSR 下渲染错误问题 [#7349](https://github.com/vueComponent/ant-design-vue/issues/7349)
|
||||||
|
- 🐞 修复 Select、Cascader 在 SSR 下渲染错误问题 [#7377](https://github.com/vueComponent/ant-design-vue/issues/7377)
|
||||||
|
- 🐞 修复 AutoComplete 缺少 option slot 声明问题 [#7396](https://github.com/vueComponent/ant-design-vue/issues/7396)
|
||||||
|
- 🐞 修复 Textarea autoSize 不生效问题 [#7478](https://github.com/vueComponent/ant-design-vue/issues/7478)
|
||||||
|
- 🐞 修复 Pagination 回车键触发两次翻页问题 [#7368](https://github.com/vueComponent/ant-design-vue/issues/7368)
|
||||||
|
- 🐞 修复输入框输入中文问题 [#7391](https://github.com/vueComponent/ant-design-vue/issues/7391)[#7516](https://github.com/vueComponent/ant-design-vue/issues/7516)
|
||||||
|
- 🐞 修复 Carousel beforeChange current 参数错误问题 [#7419](https://github.com/vueComponent/ant-design-vue/issues/7419)
|
||||||
|
|
||||||
|
## 4.1.2
|
||||||
|
|
||||||
|
- 🐞 修复 table resize 在 vue 3.4 下报错问题 [#7291](https://github.com/vueComponent/ant-design-vue/issues/7291)
|
||||||
|
- 🐞 修复 Segmented title 属性不显示问题 [#7302](https://github.com/vueComponent/ant-design-vue/issues/7302)
|
||||||
|
|
||||||
|
## 4.1.1
|
||||||
|
|
||||||
|
- 🌟 QRcode 新增 scanned 状态 [#7242](https://github.com/vueComponent/ant-design-vue/issues/7242)
|
||||||
|
- 🐞 修复 css prefix 在 nuxt 问题 [#7256](https://github.com/vueComponent/ant-design-vue/issues/7256)
|
||||||
|
- 🐞 修复 dropdown 关闭问题 [#7246](https://github.com/vueComponent/ant-design-vue/issues/7246)
|
||||||
|
- 🐞 修复 divider vertical dashed 不显示问题 [#7218](https://github.com/vueComponent/ant-design-vue/issues/7218)
|
||||||
|
- 🐞 修复 hook 模式 message 控制台 warning 问题 [#7281](https://github.com/vueComponent/ant-design-vue/issues/7281)
|
||||||
|
- 🐞 修复 table 展开在 vue 3.4 下报错问题 [#7265](https://github.com/vueComponent/ant-design-vue/issues/7265)
|
||||||
|
- 🐞 修复 table group 过滤状态错误问题 [#7233](https://github.com/vueComponent/ant-design-vue/issues/7233)
|
||||||
|
|
||||||
|
## 4.1.0
|
||||||
|
|
||||||
|
- 🐞 适配 vue 3.4 [#7239](https://github.com/vueComponent/ant-design-vue/issues/7239)
|
||||||
|
|
||||||
|
## 4.0.8
|
||||||
|
|
||||||
|
- 🐞 修复在 Nuxt 下 theme 响应式失效问题 [#7180](https://github.com/vueComponent/ant-design-vue/issues/7180)
|
||||||
|
- 🐞 修复 Wave 引起的报错问题 [#7108](https://github.com/vueComponent/ant-design-vue/issues/7108)
|
||||||
|
- 🐞 修复 Upload disabled 继承问题 [#7110](https://github.com/vueComponent/ant-design-vue/issues/7110)
|
||||||
|
- 🐞 修复 Tooltip popupAlign 未生效问题 [#7112](https://github.com/vueComponent/ant-design-vue/issues/7112)
|
||||||
|
- 🐞 修复 Typography 闪动问题 [#7146](https://github.com/vueComponent/ant-design-vue/issues/7146)
|
||||||
|
- 🐞 修复 RangePicker prevIcon nextIcon 未生效问题 [#7127](https://github.com/vueComponent/ant-design-vue/issues/7127)
|
||||||
|
- 🐞 修复 watermark 未监听子元素变动问题 [#7149](https://github.com/vueComponent/ant-design-vue/issues/7149)
|
||||||
|
- 🐞 修复 Menu 动画丢失问题 [#7130](https://github.com/vueComponent/ant-design-vue/issues/7130)
|
||||||
|
- 🐞 修复 TextArea autosize 时光标变化问题 [#7121](https://github.com/vueComponent/ant-design-vue/issues/7121)
|
||||||
|
|
||||||
## 4.0.7
|
## 4.0.7
|
||||||
|
|
||||||
- 🌟 新增 Flex 组件 [#7052](https://github.com/vueComponent/ant-design-vue/issues/7052)
|
- 🌟 新增 Flex 组件 [#7052](https://github.com/vueComponent/ant-design-vue/issues/7052)
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
|
|
||||||
An enterprise-class UI components based on Ant Design and Vue 3.
|
基于 Ant Design 和 Vue 3 的企业级 UI 组件库。
|
||||||
|
|
||||||
 [](https://codecov.io/gh/vueComponent/ant-design-vue) [](https://www.npmjs.org/package/ant-design-vue) [](http://www.npmtrends.com/ant-design-vue) [](#backers) [](#sponsors) [](https://marketplace.visualstudio.com/items?itemName=ant-design-vue.vscode-ant-design-vue-helper) [](https://github.com/actions-cool/issues-helper)
|
 [](https://codecov.io/gh/vueComponent/ant-design-vue) [](https://www.npmjs.org/package/ant-design-vue) [](http://www.npmtrends.com/ant-design-vue) [](#backers) [](#sponsors) [](https://marketplace.visualstudio.com/items?itemName=ant-design-vue.vscode-ant-design-vue-helper) [](https://github.com/actions-cool/issues-helper)
|
||||||
|
|
||||||
|
@ -73,6 +73,7 @@ $ yarn add ant-design-vue
|
||||||
| [vue-dash-event](https://github.com/vueComponent/vue-dash-event) | 在 DOM 模板中,您可以使用 ant-design-vue 组件的自定义事件(camelCase) |
|
| [vue-dash-event](https://github.com/vueComponent/vue-dash-event) | 在 DOM 模板中,您可以使用 ant-design-vue 组件的自定义事件(camelCase) |
|
||||||
| [@formily/antdv](https://github.com/formilyjs/antdv) | 这是一个结合了 Formily 和 ant-design-vue 的组件库 |
|
| [@formily/antdv](https://github.com/formilyjs/antdv) | 这是一个结合了 Formily 和 ant-design-vue 的组件库 |
|
||||||
| [@ant-design-vue/nuxt](https://github.com/vueComponent/ant-design-vue-nuxt) | ant-design-vue 的 nuxt 模块扩展 |
|
| [@ant-design-vue/nuxt](https://github.com/vueComponent/ant-design-vue-nuxt) | ant-design-vue 的 nuxt 模块扩展 |
|
||||||
|
| [ant-design-x-vue](https://github.com/wzc520pyfm/ant-design-x-vue) | 基于 Ant Design X 设计规范的 Vue AI 界面解决方案 |
|
||||||
|
|
||||||
## 问答
|
## 问答
|
||||||
|
|
||||||
|
@ -88,22 +89,23 @@ ant-design-vue 是 MIT 协议的开源项目。为了项目能够更好的持续
|
||||||
- [opencollective](https://opencollective.com/ant-design-vue)
|
- [opencollective](https://opencollective.com/ant-design-vue)
|
||||||
- [paypal](https://www.paypal.me/tangjinzhou)
|
- [paypal](https://www.paypal.me/tangjinzhou)
|
||||||
- [支付宝或微信](https://aliyuncdn.antdv.com/alipay-and-wechat.png)
|
- [支付宝或微信](https://aliyuncdn.antdv.com/alipay-and-wechat.png)
|
||||||
|
- ETH: 0x30cc48515d8ae9fefa20ab87226ad7e8ab9c3bc2
|
||||||
|
|
||||||
## Sponsors
|
## 赞助商
|
||||||
|
|
||||||
Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/ant-design-vue#sponsor)]
|
成为赞助商,并在 Github 上的自述文件上获得您的徽标,并链接到您的网站。 [[成为赞助商](https://opencollective.com/ant-design-vue#sponsor)]
|
||||||
|
|
||||||
<a href="http://www.jeecg.com/" target="_blank"><img src="https://aliyuncdn.antdv.com/jeecg-logo.png" height="64"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/0/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/1/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/2/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/3/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/4/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/5/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/6/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/7/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/8/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/9/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/10/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/10/avatar.svg"></a>
|
<a href="http://www.jeecg.com/" target="_blank"><img src="https://aliyuncdn.antdv.com/jeecg-logo.png" height="64"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/0/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/0/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/1/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/1/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/2/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/2/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/3/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/3/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/4/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/4/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/5/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/5/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/6/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/6/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/7/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/7/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/8/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/8/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/9/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/9/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/sponsor/10/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/sponsor/10/avatar.svg"></a>
|
||||||
|
|
||||||
## Backers
|
## 支持者
|
||||||
|
|
||||||
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/ant-design-vue#backer)]
|
每月捐款支持我们,帮助我们继续我们的活动。 [[成为支持者](https://opencollective.com/ant-design-vue#backer)]
|
||||||
|
|
||||||
<a href="https://github.com/chuzhixin/vue-admin-beautiful" target="_blank"><img width="64" style="border-radius: 50%;" src="https://gitee.com/chu1204505056/image/raw/master/vue-admin-beautiful.png" title="vue-admin-beautiful"></a> <a href="https://opencollective.com/ant-design-vue/backer/0/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/0/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/1/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/1/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/2/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/2/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/3/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/3/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/4/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/4/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/5/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/5/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/6/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/6/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/7/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/7/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/8/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/8/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/9/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/9/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/10/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/10/avatar.svg"></a>
|
<a href="https://github.com/chuzhixin/vue-admin-beautiful" target="_blank"><img width="64" style="border-radius: 50%;" src="https://gitee.com/chu1204505056/image/raw/master/vue-admin-beautiful.png" title="vue-admin-beautiful"></a> <a href="https://opencollective.com/ant-design-vue/backer/0/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/0/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/1/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/1/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/2/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/2/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/3/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/3/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/4/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/4/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/5/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/5/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/6/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/6/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/7/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/7/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/8/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/8/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/9/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/9/avatar.svg"></a> <a href="https://opencollective.com/ant-design-vue/backer/10/website" target="_blank"><img src="https://opencollective.com/ant-design-vue/backer/10/avatar.svg"></a>
|
||||||
|
|
||||||
## Patreon
|
## Patreon
|
||||||
|
|
||||||
Support us with a monthly donation and help us continue our activities. [[Become a backer](https://www.patreon.com/tangjinzhou)]
|
每月捐款支持我们,帮助我们继续我们的活动。 [[成为支持者](https://www.patreon.com/tangjinzhou)]
|
||||||
|
|
||||||
<a href="https://www.mokeyjay.com" target="_blank"><img width="64" style="border-radius: 50%;" src="https://www.mokeyjay.com/headimg.png" title="donation by Patreon"></a>
|
<a href="https://www.mokeyjay.com" target="_blank"><img width="64" style="border-radius: 50%;" src="https://www.mokeyjay.com/headimg.png" title="donation by Patreon"></a>
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,7 @@ If you are in a bad network environment, you can try other registries and tools
|
||||||
| [vue-dash-event](https://github.com/vueComponent/vue-dash-event) | The library function, implemented in the DOM template, can use the custom event of the ant-design-vue component (camelCase) |
|
| [vue-dash-event](https://github.com/vueComponent/vue-dash-event) | The library function, implemented in the DOM template, can use the custom event of the ant-design-vue component (camelCase) |
|
||||||
| [@formily/antdv](https://github.com/formilyjs/antdv) | The Library with Formily and ant-design-vue |
|
| [@formily/antdv](https://github.com/formilyjs/antdv) | The Library with Formily and ant-design-vue |
|
||||||
| [@ant-design-vue/nuxt](https://github.com/vueComponent/ant-design-vue-nuxt) | A nuxt module for ant-design-vue |
|
| [@ant-design-vue/nuxt](https://github.com/vueComponent/ant-design-vue-nuxt) | A nuxt module for ant-design-vue |
|
||||||
|
| [ant-design-x-vue](https://github.com/wzc520pyfm/ant-design-x-vue) | A Vue AI interface solutions base on the Ant Design X design specification |
|
||||||
|
|
||||||
## Donation
|
## Donation
|
||||||
|
|
||||||
|
@ -82,6 +83,7 @@ ant-design-vue is an MIT-licensed open source project. In order to achieve bette
|
||||||
- [opencollective](https://opencollective.com/ant-design-vue)
|
- [opencollective](https://opencollective.com/ant-design-vue)
|
||||||
- [paypal](https://www.paypal.me/tangjinzhou)
|
- [paypal](https://www.paypal.me/tangjinzhou)
|
||||||
- [支付宝或微信](https://aliyuncdn.antdv.com/alipay-and-wechat.png)
|
- [支付宝或微信](https://aliyuncdn.antdv.com/alipay-and-wechat.png)
|
||||||
|
- ETH: 0x30cc48515d8ae9fefa20ab87226ad7e8ab9c3bc2
|
||||||
|
|
||||||
## Sponsors
|
## Sponsors
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { genWebTypes } from './web-types';
|
||||||
import { outputFileSync, readFileSync } from 'fs-extra';
|
import { outputFileSync, readFileSync } from 'fs-extra';
|
||||||
import type { Options, VueTag } from './type';
|
import type { Options, VueTag } from './type';
|
||||||
import { getComponentName, normalizePath, toKebabCase } from './utils';
|
import { getComponentName, normalizePath, toKebabCase } from './utils';
|
||||||
import { genVeturAttributes, genVeturTags } from './vetur';
|
|
||||||
import { flatMap } from 'lodash';
|
import { flatMap } from 'lodash';
|
||||||
|
|
||||||
async function readMarkdown(options: Options): Promise<Map<String, VueTag>> {
|
async function readMarkdown(options: Options): Promise<Map<String, VueTag>> {
|
||||||
|
@ -22,13 +21,13 @@ async function readMarkdown(options: Options): Promise<Map<String, VueTag>> {
|
||||||
return formatter(mdParser(fileContent), componentName, kebabComponentName, options.tagPrefix);
|
return formatter(mdParser(fileContent), componentName, kebabComponentName, options.tagPrefix);
|
||||||
})
|
})
|
||||||
.filter(item => item) as VueTag[][];
|
.filter(item => item) as VueTag[][];
|
||||||
const tags: Map<String, VueTag> = new Map();
|
const tags = new Map<String, VueTag>();
|
||||||
flatMap(data, item => item).forEach(mergedTag => mergeTag(tags, mergedTag));
|
flatMap(data, item => item).forEach(mergedTag => mergeTag(tags, mergedTag));
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
function readTypings(options: Options): Map<String, VueTag> {
|
function readTypings(options: Options): Map<String, VueTag> {
|
||||||
const tags: Map<String, VueTag> = new Map();
|
const tags = new Map<String, VueTag>();
|
||||||
const fileContent = readFileSync(options.typingsPath, 'utf-8');
|
const fileContent = readFileSync(options.typingsPath, 'utf-8');
|
||||||
fileContent
|
fileContent
|
||||||
.split('\n')
|
.split('\n')
|
||||||
|
@ -62,7 +61,7 @@ function mergeTag(tags: Map<String, VueTag>, mergedTag: VueTag) {
|
||||||
|
|
||||||
function mergeTags(mergedTagsArr: Map<String, VueTag>[]): VueTag[] {
|
function mergeTags(mergedTagsArr: Map<String, VueTag>[]): VueTag[] {
|
||||||
if (mergedTagsArr.length === 1) return [...mergedTagsArr[0].values()];
|
if (mergedTagsArr.length === 1) return [...mergedTagsArr[0].values()];
|
||||||
const tags: Map<String, VueTag> = new Map();
|
const tags = new Map<String, VueTag>();
|
||||||
if (mergedTagsArr.length === 0) return [];
|
if (mergedTagsArr.length === 0) return [];
|
||||||
mergedTagsArr.forEach(mergedTags => {
|
mergedTagsArr.forEach(mergedTags => {
|
||||||
mergedTags.forEach(mergedTag => mergeTag(tags, mergedTag));
|
mergedTags.forEach(mergedTag => mergeTag(tags, mergedTag));
|
||||||
|
@ -78,13 +77,6 @@ export async function parseAndWrite(options: Options): Promise<Number> {
|
||||||
const tagsFromTypings = await readTypings(options);
|
const tagsFromTypings = await readTypings(options);
|
||||||
const tags = mergeTags([tagsFromMarkdown, tagsFromTypings]);
|
const tags = mergeTags([tagsFromMarkdown, tagsFromTypings]);
|
||||||
const webTypes = genWebTypes(tags, options);
|
const webTypes = genWebTypes(tags, options);
|
||||||
const veturTags = genVeturTags(tags);
|
|
||||||
const veturAttributes = genVeturAttributes(tags);
|
|
||||||
outputFileSync(join(options.outputDir, 'tags.json'), JSON.stringify(veturTags, null, 2));
|
|
||||||
outputFileSync(
|
|
||||||
join(options.outputDir, 'attributes.json'),
|
|
||||||
JSON.stringify(veturAttributes, null, 2),
|
|
||||||
);
|
|
||||||
outputFileSync(join(options.outputDir, 'web-types.json'), JSON.stringify(webTypes, null, 2));
|
outputFileSync(join(options.outputDir, 'web-types.json'), JSON.stringify(webTypes, null, 2));
|
||||||
return tags.length;
|
return tags.length;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ export type Articals = Artical[];
|
||||||
function readLine(input: string) {
|
function readLine(input: string) {
|
||||||
const end = input.indexOf('\n');
|
const end = input.indexOf('\n');
|
||||||
|
|
||||||
return input.substr(0, end !== -1 ? end : input.length);
|
return input.substring(0, end !== -1 ? end : input.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
function splitTableLine(line: string) {
|
function splitTableLine(line: string) {
|
||||||
|
@ -47,7 +47,7 @@ function tableParse(input: string) {
|
||||||
};
|
};
|
||||||
|
|
||||||
while (start < end) {
|
while (start < end) {
|
||||||
const target = input.substr(start);
|
const target = input.substring(start);
|
||||||
const line = readLine(target);
|
const line = readLine(target);
|
||||||
|
|
||||||
if (!/^\|/.test(target)) {
|
if (!/^\|/.test(target)) {
|
||||||
|
@ -79,7 +79,7 @@ export function mdParser(input: string): Articals {
|
||||||
const end = input.length;
|
const end = input.length;
|
||||||
|
|
||||||
while (start < end) {
|
while (start < end) {
|
||||||
const target = input.substr(start);
|
const target = input.substring(start);
|
||||||
|
|
||||||
let match;
|
let match;
|
||||||
if ((match = TITLE_REG.exec(target))) {
|
if ((match = TITLE_REG.exec(target))) {
|
||||||
|
@ -91,7 +91,7 @@ export function mdParser(input: string): Articals {
|
||||||
|
|
||||||
start += match.index + match[0].length;
|
start += match.index + match[0].length;
|
||||||
} else if ((match = TABLE_REG.exec(target))) {
|
} else if ((match = TABLE_REG.exec(target))) {
|
||||||
const { table, usedLength } = tableParse(target.substr(match.index));
|
const { table, usedLength } = tableParse(target.substring(match.index));
|
||||||
artical.push({
|
artical.push({
|
||||||
type: 'table',
|
type: 'table',
|
||||||
table,
|
table,
|
||||||
|
|
|
@ -34,25 +34,6 @@ export type VueTag = {
|
||||||
description?: string;
|
description?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type VeturTag = {
|
|
||||||
description?: string;
|
|
||||||
attributes: string[];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type VeturTags = Record<string, VeturTag>;
|
|
||||||
|
|
||||||
export type VeturAttribute = {
|
|
||||||
type: string;
|
|
||||||
description: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type VeturAttributes = Record<string, VeturAttribute>;
|
|
||||||
|
|
||||||
export type VeturResult = {
|
|
||||||
tags: VeturTags;
|
|
||||||
attributes: VeturAttributes;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Options = {
|
export type Options = {
|
||||||
name: string;
|
name: string;
|
||||||
path: PathLike;
|
path: PathLike;
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
import type { VueTag, VeturTags, VeturAttributes } from './type';
|
|
||||||
|
|
||||||
export function genVeturTags(tags: VueTag[]) {
|
|
||||||
const veturTags: VeturTags = {};
|
|
||||||
|
|
||||||
tags.forEach(tag => {
|
|
||||||
veturTags[tag.name] = {
|
|
||||||
attributes: tag.attributes ? tag.attributes.map(item => item.name) : [],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return veturTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function genVeturAttributes(tags: VueTag[]) {
|
|
||||||
const veturAttributes: VeturAttributes = {};
|
|
||||||
|
|
||||||
tags.forEach(tag => {
|
|
||||||
if (tag.attributes) {
|
|
||||||
tag.attributes.forEach(attr => {
|
|
||||||
veturAttributes[`${tag.name}/${attr.name}`] = {
|
|
||||||
type: attr.value.type,
|
|
||||||
description: `${attr.description}, Default: ${attr.default}`,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return veturAttributes;
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const assign = require('object-assign');
|
|
||||||
const { getProjectPath } = require('./utils/projectHelper');
|
const { getProjectPath } = require('./utils/projectHelper');
|
||||||
|
|
||||||
module.exports = function () {
|
module.exports = function () {
|
||||||
|
@ -9,7 +8,7 @@ module.exports = function () {
|
||||||
if (fs.existsSync(getProjectPath('tsconfig.json'))) {
|
if (fs.existsSync(getProjectPath('tsconfig.json'))) {
|
||||||
my = require(getProjectPath('tsconfig.json'));
|
my = require(getProjectPath('tsconfig.json'));
|
||||||
}
|
}
|
||||||
return assign(
|
return Object.assign(
|
||||||
{
|
{
|
||||||
noUnusedParameters: true,
|
noUnusedParameters: true,
|
||||||
noUnusedLocals: true,
|
noUnusedLocals: true,
|
||||||
|
|
|
@ -1,51 +1,167 @@
|
||||||
import { defineComponent, shallowRef, withDirectives } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
import antInput from './antInputDirective';
|
import { computed, defineComponent, shallowRef, ref, watch } from 'vue';
|
||||||
import PropTypes from './vue-types';
|
import PropTypes from './vue-types';
|
||||||
|
import type { BaseInputInnerExpose } from './BaseInputInner';
|
||||||
|
import BaseInputInner from './BaseInputInner';
|
||||||
|
import { styleObjectToString } from '../vc-util/Dom/css';
|
||||||
|
|
||||||
|
export interface BaseInputExpose {
|
||||||
|
focus: () => void;
|
||||||
|
blur: () => void;
|
||||||
|
input: HTMLInputElement | HTMLTextAreaElement | null;
|
||||||
|
setSelectionRange: (
|
||||||
|
start: number,
|
||||||
|
end: number,
|
||||||
|
direction?: 'forward' | 'backward' | 'none',
|
||||||
|
) => void;
|
||||||
|
select: () => void;
|
||||||
|
getSelectionStart: () => number | null;
|
||||||
|
getSelectionEnd: () => number | null;
|
||||||
|
getScrollTop: () => number | null;
|
||||||
|
setScrollTop: (scrollTop: number) => void;
|
||||||
|
}
|
||||||
const BaseInput = defineComponent({
|
const BaseInput = defineComponent({
|
||||||
compatConfig: { MODE: 3 },
|
compatConfig: { MODE: 3 },
|
||||||
|
inheritAttrs: false,
|
||||||
props: {
|
props: {
|
||||||
value: PropTypes.string.def(''),
|
disabled: PropTypes.looseBool,
|
||||||
|
type: PropTypes.string,
|
||||||
|
value: PropTypes.any,
|
||||||
|
lazy: PropTypes.bool.def(true),
|
||||||
|
tag: {
|
||||||
|
type: String as PropType<'input' | 'textarea'>,
|
||||||
|
default: 'input',
|
||||||
},
|
},
|
||||||
emits: ['change', 'input'],
|
size: PropTypes.string,
|
||||||
setup(_p, { emit }) {
|
style: PropTypes.oneOfType([String, Object]),
|
||||||
const inputRef = shallowRef(null);
|
class: PropTypes.string,
|
||||||
|
},
|
||||||
|
emits: [
|
||||||
|
'change',
|
||||||
|
'input',
|
||||||
|
'blur',
|
||||||
|
'keydown',
|
||||||
|
'focus',
|
||||||
|
'compositionstart',
|
||||||
|
'compositionend',
|
||||||
|
'keyup',
|
||||||
|
'paste',
|
||||||
|
'mousedown',
|
||||||
|
],
|
||||||
|
setup(props, { emit, attrs, expose }) {
|
||||||
|
const inputRef = shallowRef<BaseInputInnerExpose>(null);
|
||||||
|
const renderValue = ref();
|
||||||
|
const isComposing = ref(false);
|
||||||
|
watch(
|
||||||
|
[() => props.value, isComposing],
|
||||||
|
() => {
|
||||||
|
if (isComposing.value) return;
|
||||||
|
renderValue.value = props.value;
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
const handleChange = (e: Event) => {
|
const handleChange = (e: Event) => {
|
||||||
const { composing } = e.target as any;
|
|
||||||
if ((e as any).isComposing || composing) {
|
|
||||||
emit('input', e);
|
|
||||||
} else {
|
|
||||||
emit('input', e);
|
|
||||||
emit('change', e);
|
emit('change', e);
|
||||||
}
|
|
||||||
};
|
};
|
||||||
return {
|
const onCompositionstart = (e: CompositionEvent) => {
|
||||||
inputRef,
|
isComposing.value = true;
|
||||||
focus: () => {
|
(e.target as any).composing = true;
|
||||||
|
emit('compositionstart', e);
|
||||||
|
};
|
||||||
|
const onCompositionend = (e: CompositionEvent) => {
|
||||||
|
isComposing.value = false;
|
||||||
|
(e.target as any).composing = false;
|
||||||
|
emit('compositionend', e);
|
||||||
|
const event = document.createEvent('HTMLEvents');
|
||||||
|
event.initEvent('input', true, true);
|
||||||
|
e.target.dispatchEvent(event);
|
||||||
|
handleChange(e);
|
||||||
|
};
|
||||||
|
const handleInput = (e: Event) => {
|
||||||
|
if (isComposing.value && props.lazy) {
|
||||||
|
renderValue.value = (e.target as HTMLInputElement).value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emit('input', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleBlur = (e: Event) => {
|
||||||
|
emit('blur', e);
|
||||||
|
};
|
||||||
|
const handleFocus = (e: Event) => {
|
||||||
|
emit('focus', e);
|
||||||
|
};
|
||||||
|
|
||||||
|
const focus = () => {
|
||||||
if (inputRef.value) {
|
if (inputRef.value) {
|
||||||
inputRef.value.focus();
|
inputRef.value.focus();
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
blur: () => {
|
const blur = () => {
|
||||||
if (inputRef.value) {
|
if (inputRef.value) {
|
||||||
inputRef.value.blur();
|
inputRef.value.blur();
|
||||||
}
|
}
|
||||||
},
|
|
||||||
handleChange,
|
|
||||||
};
|
};
|
||||||
},
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
render() {
|
emit('keydown', e);
|
||||||
return withDirectives(
|
};
|
||||||
(
|
const handleKeyUp = (e: KeyboardEvent) => {
|
||||||
<input
|
emit('keyup', e);
|
||||||
{...this.$props}
|
};
|
||||||
{...this.$attrs}
|
const setSelectionRange = (
|
||||||
onInput={this.handleChange}
|
start: number,
|
||||||
onChange={this.handleChange}
|
end: number,
|
||||||
ref="inputRef"
|
direction?: 'forward' | 'backward' | 'none',
|
||||||
|
) => {
|
||||||
|
inputRef.value?.setSelectionRange(start, end, direction);
|
||||||
|
};
|
||||||
|
|
||||||
|
const select = () => {
|
||||||
|
inputRef.value?.select();
|
||||||
|
};
|
||||||
|
expose({
|
||||||
|
focus,
|
||||||
|
blur,
|
||||||
|
input: computed(() => inputRef.value?.input),
|
||||||
|
setSelectionRange,
|
||||||
|
select,
|
||||||
|
getSelectionStart: () => inputRef.value?.getSelectionStart(),
|
||||||
|
getSelectionEnd: () => inputRef.value?.getSelectionEnd(),
|
||||||
|
getScrollTop: () => inputRef.value?.getScrollTop(),
|
||||||
|
});
|
||||||
|
const handleMousedown = (e: MouseEvent) => {
|
||||||
|
emit('mousedown', e);
|
||||||
|
};
|
||||||
|
const handlePaste = (e: ClipboardEvent) => {
|
||||||
|
emit('paste', e);
|
||||||
|
};
|
||||||
|
const styleString = computed(() => {
|
||||||
|
return props.style && typeof props.style !== 'string'
|
||||||
|
? styleObjectToString(props.style)
|
||||||
|
: props.style;
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
const { style, lazy, ...restProps } = props;
|
||||||
|
return (
|
||||||
|
<BaseInputInner
|
||||||
|
{...restProps}
|
||||||
|
{...attrs}
|
||||||
|
style={styleString.value}
|
||||||
|
onInput={handleInput}
|
||||||
|
onChange={handleChange}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
onFocus={handleFocus}
|
||||||
|
ref={inputRef}
|
||||||
|
value={renderValue.value}
|
||||||
|
onCompositionstart={onCompositionstart}
|
||||||
|
onCompositionend={onCompositionend}
|
||||||
|
onKeyup={handleKeyUp}
|
||||||
|
onKeydown={handleKeyDown}
|
||||||
|
onPaste={handlePaste}
|
||||||
|
onMousedown={handleMousedown}
|
||||||
/>
|
/>
|
||||||
) as any,
|
|
||||||
[[antInput]],
|
|
||||||
);
|
);
|
||||||
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
import type { PropType } from 'vue';
|
||||||
|
import { defineComponent, shallowRef } from 'vue';
|
||||||
|
import PropTypes from './vue-types';
|
||||||
|
|
||||||
|
export interface BaseInputInnerExpose {
|
||||||
|
focus: () => void;
|
||||||
|
blur: () => void;
|
||||||
|
input: HTMLInputElement | HTMLTextAreaElement | null;
|
||||||
|
setSelectionRange: (
|
||||||
|
start: number,
|
||||||
|
end: number,
|
||||||
|
direction?: 'forward' | 'backward' | 'none',
|
||||||
|
) => void;
|
||||||
|
select: () => void;
|
||||||
|
getSelectionStart: () => number | null;
|
||||||
|
getSelectionEnd: () => number | null;
|
||||||
|
getScrollTop: () => number | null;
|
||||||
|
setScrollTop: (scrollTop: number) => void;
|
||||||
|
}
|
||||||
|
const BaseInputInner = defineComponent({
|
||||||
|
compatConfig: { MODE: 3 },
|
||||||
|
// inheritAttrs: false,
|
||||||
|
props: {
|
||||||
|
disabled: PropTypes.looseBool,
|
||||||
|
type: PropTypes.string,
|
||||||
|
value: PropTypes.any,
|
||||||
|
tag: {
|
||||||
|
type: String as PropType<'input' | 'textarea'>,
|
||||||
|
default: 'input',
|
||||||
|
},
|
||||||
|
size: PropTypes.string,
|
||||||
|
onChange: Function as PropType<(e: Event) => void>,
|
||||||
|
onInput: Function as PropType<(e: Event) => void>,
|
||||||
|
onBlur: Function as PropType<(e: Event) => void>,
|
||||||
|
onFocus: Function as PropType<(e: Event) => void>,
|
||||||
|
onKeydown: Function as PropType<(e: Event) => void>,
|
||||||
|
onCompositionstart: Function as PropType<(e: Event) => void>,
|
||||||
|
onCompositionend: Function as PropType<(e: Event) => void>,
|
||||||
|
onKeyup: Function as PropType<(e: Event) => void>,
|
||||||
|
onPaste: Function as PropType<(e: Event) => void>,
|
||||||
|
onMousedown: Function as PropType<(e: Event) => void>,
|
||||||
|
},
|
||||||
|
emits: [
|
||||||
|
'change',
|
||||||
|
'input',
|
||||||
|
'blur',
|
||||||
|
'keydown',
|
||||||
|
'focus',
|
||||||
|
'compositionstart',
|
||||||
|
'compositionend',
|
||||||
|
'keyup',
|
||||||
|
'paste',
|
||||||
|
'mousedown',
|
||||||
|
],
|
||||||
|
setup(props, { expose }) {
|
||||||
|
const inputRef = shallowRef(null);
|
||||||
|
|
||||||
|
const focus = () => {
|
||||||
|
if (inputRef.value) {
|
||||||
|
inputRef.value.focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const blur = () => {
|
||||||
|
if (inputRef.value) {
|
||||||
|
inputRef.value.blur();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const setSelectionRange = (
|
||||||
|
start: number,
|
||||||
|
end: number,
|
||||||
|
direction?: 'forward' | 'backward' | 'none',
|
||||||
|
) => {
|
||||||
|
inputRef.value?.setSelectionRange(start, end, direction);
|
||||||
|
};
|
||||||
|
|
||||||
|
const select = () => {
|
||||||
|
inputRef.value?.select();
|
||||||
|
};
|
||||||
|
expose({
|
||||||
|
focus,
|
||||||
|
blur,
|
||||||
|
input: inputRef,
|
||||||
|
setSelectionRange,
|
||||||
|
select,
|
||||||
|
getSelectionStart: () => inputRef.value?.selectionStart,
|
||||||
|
getSelectionEnd: () => inputRef.value?.selectionEnd,
|
||||||
|
getScrollTop: () => inputRef.value?.scrollTop,
|
||||||
|
});
|
||||||
|
return () => {
|
||||||
|
const { tag: Tag, value, ...restProps } = props;
|
||||||
|
return <Tag {...restProps} ref={inputRef} value={value} />;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default BaseInputInner;
|
|
@ -7,7 +7,6 @@ import {
|
||||||
onMounted,
|
onMounted,
|
||||||
onBeforeUnmount,
|
onBeforeUnmount,
|
||||||
onUpdated,
|
onUpdated,
|
||||||
getCurrentInstance,
|
|
||||||
nextTick,
|
nextTick,
|
||||||
computed,
|
computed,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
|
@ -61,6 +60,7 @@ export default defineComponent({
|
||||||
const container = shallowRef<HTMLElement>();
|
const container = shallowRef<HTMLElement>();
|
||||||
const componentRef = shallowRef();
|
const componentRef = shallowRef();
|
||||||
const rafId = shallowRef<number>();
|
const rafId = shallowRef<number>();
|
||||||
|
const triggerUpdate = shallowRef(1);
|
||||||
const defaultContainer = canUseDom() && document.createElement('div');
|
const defaultContainer = canUseDom() && document.createElement('div');
|
||||||
const removeCurrentContainer = () => {
|
const removeCurrentContainer = () => {
|
||||||
// Portal will remove from `parentNode`.
|
// Portal will remove from `parentNode`.
|
||||||
|
@ -106,8 +106,6 @@ export default defineComponent({
|
||||||
attachToParent();
|
attachToParent();
|
||||||
});
|
});
|
||||||
|
|
||||||
const instance = getCurrentInstance();
|
|
||||||
|
|
||||||
useScrollLocker(
|
useScrollLocker(
|
||||||
computed(() => {
|
computed(() => {
|
||||||
return (
|
return (
|
||||||
|
@ -155,7 +153,7 @@ export default defineComponent({
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
if (!attachToParent()) {
|
if (!attachToParent()) {
|
||||||
rafId.value = raf(() => {
|
rafId.value = raf(() => {
|
||||||
instance.update();
|
triggerUpdate.value += 1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -177,7 +175,7 @@ export default defineComponent({
|
||||||
getOpenCount: () => openCount,
|
getOpenCount: () => openCount,
|
||||||
getContainer,
|
getContainer,
|
||||||
};
|
};
|
||||||
if (forceRender || visible || componentRef.value) {
|
if (triggerUpdate.value && (forceRender || visible || componentRef.value)) {
|
||||||
portal = (
|
portal = (
|
||||||
<Portal
|
<Portal
|
||||||
getContainer={getContainer}
|
getContainer={getContainer}
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import { customRenderSlot } from '../vnode';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'RenderSlot',
|
||||||
|
setup(_props, { slots }) {
|
||||||
|
return () => {
|
||||||
|
return customRenderSlot(slots, 'default', {}, () => ['default value']);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
|
@ -0,0 +1,26 @@
|
||||||
|
import RenderSlot from '../__mocks__/RenderSlot';
|
||||||
|
import { mount } from '@vue/test-utils';
|
||||||
|
import { nextTick } from 'vue';
|
||||||
|
|
||||||
|
describe('render slot content', () => {
|
||||||
|
it('renders slot content', () => {
|
||||||
|
const wrapper = mount(RenderSlot, {
|
||||||
|
slots: {
|
||||||
|
default: () => 'This is slot content',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.html()).toContain('This is slot content');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('render default value when slot is fragment', async () => {
|
||||||
|
const wrapper = mount(RenderSlot, {
|
||||||
|
slots: {
|
||||||
|
default: () => <></>,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await nextTick();
|
||||||
|
expect(wrapper.html()).toContain('default value');
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,42 +0,0 @@
|
||||||
import type { Directive } from 'vue';
|
|
||||||
|
|
||||||
function onCompositionStart(e: any) {
|
|
||||||
e.target.composing = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function onCompositionEnd(e: any) {
|
|
||||||
// prevent triggering an input event for no reason
|
|
||||||
if (!e.target.composing) return;
|
|
||||||
e.target.composing = false;
|
|
||||||
trigger(e.target, 'input');
|
|
||||||
}
|
|
||||||
|
|
||||||
function trigger(el, type) {
|
|
||||||
const e = document.createEvent('HTMLEvents');
|
|
||||||
e.initEvent(type, true, true);
|
|
||||||
el.dispatchEvent(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addEventListener(
|
|
||||||
el: HTMLElement,
|
|
||||||
event: string,
|
|
||||||
handler: EventListenerOrEventListenerObject,
|
|
||||||
options?: boolean | AddEventListenerOptions,
|
|
||||||
) {
|
|
||||||
el.addEventListener(event, handler, options);
|
|
||||||
}
|
|
||||||
const antInput: Directive = {
|
|
||||||
created(el, binding) {
|
|
||||||
if (!binding.modifiers || !binding.modifiers.lazy) {
|
|
||||||
addEventListener(el, 'compositionstart', onCompositionStart);
|
|
||||||
addEventListener(el, 'compositionend', onCompositionEnd);
|
|
||||||
// Safari < 10.2 & UIWebView doesn't fire compositionend when
|
|
||||||
// switching focus before confirming composition choice
|
|
||||||
// this also fixes the issue where some browsers e.g. iOS Chrome
|
|
||||||
// fires "change" instead of "input" on autocomplete.
|
|
||||||
addEventListener(el, 'change', onCompositionEnd);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default antInput;
|
|
|
@ -1,130 +0,0 @@
|
||||||
const START_EVENT_NAME_MAP = {
|
|
||||||
transitionstart: {
|
|
||||||
transition: 'transitionstart',
|
|
||||||
WebkitTransition: 'webkitTransitionStart',
|
|
||||||
MozTransition: 'mozTransitionStart',
|
|
||||||
OTransition: 'oTransitionStart',
|
|
||||||
msTransition: 'MSTransitionStart',
|
|
||||||
},
|
|
||||||
|
|
||||||
animationstart: {
|
|
||||||
animation: 'animationstart',
|
|
||||||
WebkitAnimation: 'webkitAnimationStart',
|
|
||||||
MozAnimation: 'mozAnimationStart',
|
|
||||||
OAnimation: 'oAnimationStart',
|
|
||||||
msAnimation: 'MSAnimationStart',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const END_EVENT_NAME_MAP = {
|
|
||||||
transitionend: {
|
|
||||||
transition: 'transitionend',
|
|
||||||
WebkitTransition: 'webkitTransitionEnd',
|
|
||||||
MozTransition: 'mozTransitionEnd',
|
|
||||||
OTransition: 'oTransitionEnd',
|
|
||||||
msTransition: 'MSTransitionEnd',
|
|
||||||
},
|
|
||||||
|
|
||||||
animationend: {
|
|
||||||
animation: 'animationend',
|
|
||||||
WebkitAnimation: 'webkitAnimationEnd',
|
|
||||||
MozAnimation: 'mozAnimationEnd',
|
|
||||||
OAnimation: 'oAnimationEnd',
|
|
||||||
msAnimation: 'MSAnimationEnd',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const startEvents = [];
|
|
||||||
const endEvents = [];
|
|
||||||
|
|
||||||
function detectEvents() {
|
|
||||||
const testEl = document.createElement('div');
|
|
||||||
const style = testEl.style;
|
|
||||||
|
|
||||||
if (!('AnimationEvent' in window)) {
|
|
||||||
delete START_EVENT_NAME_MAP.animationstart.animation;
|
|
||||||
delete END_EVENT_NAME_MAP.animationend.animation;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!('TransitionEvent' in window)) {
|
|
||||||
delete START_EVENT_NAME_MAP.transitionstart.transition;
|
|
||||||
delete END_EVENT_NAME_MAP.transitionend.transition;
|
|
||||||
}
|
|
||||||
|
|
||||||
function process(EVENT_NAME_MAP, events) {
|
|
||||||
for (const baseEventName in EVENT_NAME_MAP) {
|
|
||||||
if (EVENT_NAME_MAP.hasOwnProperty(baseEventName)) {
|
|
||||||
const baseEvents = EVENT_NAME_MAP[baseEventName];
|
|
||||||
for (const styleName in baseEvents) {
|
|
||||||
if (styleName in style) {
|
|
||||||
events.push(baseEvents[styleName]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
process(START_EVENT_NAME_MAP, startEvents);
|
|
||||||
process(END_EVENT_NAME_MAP, endEvents);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
|
|
||||||
detectEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
function addEventListener(node, eventName, eventListener) {
|
|
||||||
node.addEventListener(eventName, eventListener, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeEventListener(node, eventName, eventListener) {
|
|
||||||
node.removeEventListener(eventName, eventListener, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
const TransitionEvents = {
|
|
||||||
// Start events
|
|
||||||
startEvents,
|
|
||||||
|
|
||||||
addStartEventListener(node, eventListener) {
|
|
||||||
if (startEvents.length === 0) {
|
|
||||||
setTimeout(eventListener, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
startEvents.forEach(startEvent => {
|
|
||||||
addEventListener(node, startEvent, eventListener);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
removeStartEventListener(node, eventListener) {
|
|
||||||
if (startEvents.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
startEvents.forEach(startEvent => {
|
|
||||||
removeEventListener(node, startEvent, eventListener);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// End events
|
|
||||||
endEvents,
|
|
||||||
|
|
||||||
addEndEventListener(node, eventListener) {
|
|
||||||
if (endEvents.length === 0) {
|
|
||||||
setTimeout(eventListener, 0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
endEvents.forEach(endEvent => {
|
|
||||||
addEventListener(node, endEvent, eventListener);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
removeEndEventListener(node, eventListener) {
|
|
||||||
if (endEvents.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
endEvents.forEach(endEvent => {
|
|
||||||
removeEventListener(node, endEvent, eventListener);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export default TransitionEvents;
|
|
|
@ -1,186 +0,0 @@
|
||||||
// https://github.com/yiminghe/css-animation 1.5.0
|
|
||||||
|
|
||||||
import Event from './Event';
|
|
||||||
import classes from '../component-classes';
|
|
||||||
import { requestAnimationTimeout, cancelAnimationTimeout } from '../requestAnimationTimeout';
|
|
||||||
import { inBrowser } from '../env';
|
|
||||||
|
|
||||||
const isCssAnimationSupported = Event.endEvents.length !== 0;
|
|
||||||
const capitalPrefixes = [
|
|
||||||
'Webkit',
|
|
||||||
'Moz',
|
|
||||||
'O',
|
|
||||||
// ms is special .... !
|
|
||||||
'ms',
|
|
||||||
];
|
|
||||||
const prefixes = ['-webkit-', '-moz-', '-o-', 'ms-', ''];
|
|
||||||
|
|
||||||
function getStyleProperty(node, name) {
|
|
||||||
if (inBrowser) return '';
|
|
||||||
// old ff need null, https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle
|
|
||||||
const style = window.getComputedStyle(node, null);
|
|
||||||
let ret = '';
|
|
||||||
for (let i = 0; i < prefixes.length; i++) {
|
|
||||||
ret = style.getPropertyValue(prefixes[i] + name);
|
|
||||||
if (ret) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
function fixBrowserByTimeout(node) {
|
|
||||||
if (isCssAnimationSupported) {
|
|
||||||
const transitionDelay = parseFloat(getStyleProperty(node, 'transition-delay')) || 0;
|
|
||||||
const transitionDuration = parseFloat(getStyleProperty(node, 'transition-duration')) || 0;
|
|
||||||
const animationDelay = parseFloat(getStyleProperty(node, 'animation-delay')) || 0;
|
|
||||||
const animationDuration = parseFloat(getStyleProperty(node, 'animation-duration')) || 0;
|
|
||||||
const time = Math.max(transitionDuration + transitionDelay, animationDuration + animationDelay);
|
|
||||||
// sometimes, browser bug
|
|
||||||
node.rcEndAnimTimeout = setTimeout(() => {
|
|
||||||
node.rcEndAnimTimeout = null;
|
|
||||||
if (node.rcEndListener) {
|
|
||||||
node.rcEndListener();
|
|
||||||
}
|
|
||||||
}, time * 1000 + 200);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearBrowserBugTimeout(node) {
|
|
||||||
if (node.rcEndAnimTimeout) {
|
|
||||||
clearTimeout(node.rcEndAnimTimeout);
|
|
||||||
node.rcEndAnimTimeout = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const cssAnimation = (node, transitionName, endCallback) => {
|
|
||||||
const nameIsObj = typeof transitionName === 'object';
|
|
||||||
const className = nameIsObj ? transitionName.name : transitionName;
|
|
||||||
const activeClassName = nameIsObj ? transitionName.active : `${transitionName}-active`;
|
|
||||||
let end = endCallback;
|
|
||||||
let start;
|
|
||||||
let active;
|
|
||||||
const nodeClasses = classes(node);
|
|
||||||
|
|
||||||
if (endCallback && Object.prototype.toString.call(endCallback) === '[object Object]') {
|
|
||||||
end = endCallback.end;
|
|
||||||
start = endCallback.start;
|
|
||||||
active = endCallback.active;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.rcEndListener) {
|
|
||||||
node.rcEndListener();
|
|
||||||
}
|
|
||||||
|
|
||||||
node.rcEndListener = e => {
|
|
||||||
if (e && e.target !== node) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.rcAnimTimeout) {
|
|
||||||
cancelAnimationTimeout(node.rcAnimTimeout);
|
|
||||||
node.rcAnimTimeout = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
clearBrowserBugTimeout(node);
|
|
||||||
|
|
||||||
nodeClasses.remove(className);
|
|
||||||
nodeClasses.remove(activeClassName);
|
|
||||||
|
|
||||||
Event.removeEndEventListener(node, node.rcEndListener);
|
|
||||||
node.rcEndListener = null;
|
|
||||||
|
|
||||||
// Usually this optional end is used for informing an owner of
|
|
||||||
// a leave animation and telling it to remove the child.
|
|
||||||
if (end) {
|
|
||||||
end();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Event.addEndEventListener(node, node.rcEndListener);
|
|
||||||
|
|
||||||
if (start) {
|
|
||||||
start();
|
|
||||||
}
|
|
||||||
nodeClasses.add(className);
|
|
||||||
|
|
||||||
node.rcAnimTimeout = requestAnimationTimeout(() => {
|
|
||||||
node.rcAnimTimeout = null;
|
|
||||||
|
|
||||||
nodeClasses.add(className);
|
|
||||||
nodeClasses.add(activeClassName);
|
|
||||||
|
|
||||||
if (active) {
|
|
||||||
requestAnimationTimeout(active, 0);
|
|
||||||
}
|
|
||||||
fixBrowserByTimeout(node);
|
|
||||||
// 30ms for firefox
|
|
||||||
}, 30);
|
|
||||||
|
|
||||||
return {
|
|
||||||
stop() {
|
|
||||||
if (node.rcEndListener) {
|
|
||||||
node.rcEndListener();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
cssAnimation.style = (node, style, callback) => {
|
|
||||||
if (node.rcEndListener) {
|
|
||||||
node.rcEndListener();
|
|
||||||
}
|
|
||||||
|
|
||||||
node.rcEndListener = e => {
|
|
||||||
if (e && e.target !== node) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.rcAnimTimeout) {
|
|
||||||
cancelAnimationTimeout(node.rcAnimTimeout);
|
|
||||||
node.rcAnimTimeout = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
clearBrowserBugTimeout(node);
|
|
||||||
|
|
||||||
Event.removeEndEventListener(node, node.rcEndListener);
|
|
||||||
node.rcEndListener = null;
|
|
||||||
|
|
||||||
// Usually this optional callback is used for informing an owner of
|
|
||||||
// a leave animation and telling it to remove the child.
|
|
||||||
if (callback) {
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Event.addEndEventListener(node, node.rcEndListener);
|
|
||||||
|
|
||||||
node.rcAnimTimeout = requestAnimationTimeout(() => {
|
|
||||||
for (const s in style) {
|
|
||||||
if (style.hasOwnProperty(s)) {
|
|
||||||
node.style[s] = style[s];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node.rcAnimTimeout = null;
|
|
||||||
fixBrowserByTimeout(node);
|
|
||||||
}, 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
cssAnimation.setTransition = (node, p, value) => {
|
|
||||||
let property = p;
|
|
||||||
let v = value;
|
|
||||||
if (value === undefined) {
|
|
||||||
v = property;
|
|
||||||
property = '';
|
|
||||||
}
|
|
||||||
property = property || '';
|
|
||||||
capitalPrefixes.forEach(prefix => {
|
|
||||||
node.style[`${prefix}Transition${property}`] = v;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
cssAnimation.isCssAnimationSupported = isCssAnimationSupported;
|
|
||||||
|
|
||||||
export { isCssAnimationSupported };
|
|
||||||
|
|
||||||
export default cssAnimation;
|
|
|
@ -8,9 +8,13 @@ import { ref, computed } from 'vue';
|
||||||
|
|
||||||
const EMPTY_OVERRIDE = {};
|
const EMPTY_OVERRIDE = {};
|
||||||
|
|
||||||
|
const isProduction = process.env.NODE_ENV === 'production';
|
||||||
|
// nuxt generate when NODE_ENV is prerender
|
||||||
|
const isPrerender = process.env.NODE_ENV === 'prerender';
|
||||||
|
|
||||||
// Generate different prefix to make user selector break in production env.
|
// Generate different prefix to make user selector break in production env.
|
||||||
// This helps developer not to do style override directly on the hash id.
|
// This helps developer not to do style override directly on the hash id.
|
||||||
const hashPrefix = process.env.NODE_ENV !== 'production' ? 'css-dev-only-do-not-override' : 'css';
|
const hashPrefix = !isProduction && !isPrerender ? 'css-dev-only-do-not-override' : 'css';
|
||||||
|
|
||||||
export interface Option<DerivativeToken, DesignToken> {
|
export interface Option<DerivativeToken, DesignToken> {
|
||||||
/**
|
/**
|
||||||
|
@ -90,7 +94,6 @@ export const getComputedToken = <DerivativeToken = object, DesignToken = Derivat
|
||||||
format?: (token: DesignToken) => DerivativeToken,
|
format?: (token: DesignToken) => DerivativeToken,
|
||||||
) => {
|
) => {
|
||||||
const derivativeToken = theme.getDerivativeToken(originToken);
|
const derivativeToken = theme.getDerivativeToken(originToken);
|
||||||
|
|
||||||
// Merge with override
|
// Merge with override
|
||||||
let mergedDerivativeToken = {
|
let mergedDerivativeToken = {
|
||||||
...derivativeToken,
|
...derivativeToken,
|
||||||
|
@ -150,7 +153,6 @@ export default function useCacheToken<DerivativeToken = object, DesignToken = De
|
||||||
|
|
||||||
const hashId = `${hashPrefix}-${hash(tokenKey)}`;
|
const hashId = `${hashPrefix}-${hash(tokenKey)}`;
|
||||||
mergedDerivativeToken._hashId = hashId; // Not used
|
mergedDerivativeToken._hashId = hashId; // Not used
|
||||||
|
|
||||||
return [mergedDerivativeToken, hashId];
|
return [mergedDerivativeToken, hashId];
|
||||||
},
|
},
|
||||||
cache => {
|
cache => {
|
||||||
|
|
|
@ -42,17 +42,17 @@ export type CSSProperties = Omit<CSS.PropertiesFallback<number | string>, 'anima
|
||||||
export type CSSPropertiesWithMultiValues = {
|
export type CSSPropertiesWithMultiValues = {
|
||||||
[K in keyof CSSProperties]:
|
[K in keyof CSSProperties]:
|
||||||
| CSSProperties[K]
|
| CSSProperties[K]
|
||||||
| Extract<CSSProperties[K], string>[]
|
| readonly Extract<CSSProperties[K], string>[]
|
||||||
| {
|
| {
|
||||||
[SKIP_CHECK]: boolean;
|
[SKIP_CHECK]?: boolean;
|
||||||
[MULTI_VALUE]?: boolean;
|
[MULTI_VALUE]?: boolean;
|
||||||
value: CSSProperties[K] | Extract<CSSProperties[K], string>[];
|
value: CSSProperties[K] | CSSProperties[K][];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CSSPseudos = { [K in CSS.Pseudos]?: CSSObject };
|
export type CSSPseudos = { [K in CSS.Pseudos]?: CSSObject };
|
||||||
|
|
||||||
type ArrayCSSInterpolation = CSSInterpolation[];
|
type ArrayCSSInterpolation = readonly CSSInterpolation[];
|
||||||
|
|
||||||
export type InterpolationPrimitive = null | undefined | boolean | number | string | CSSObject;
|
export type InterpolationPrimitive = null | undefined | boolean | number | string | CSSObject;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ export default function getScroll(
|
||||||
const method = top ? 'scrollTop' : 'scrollLeft';
|
const method = top ? 'scrollTop' : 'scrollLeft';
|
||||||
let result = 0;
|
let result = 0;
|
||||||
if (isWindow(target)) {
|
if (isWindow(target)) {
|
||||||
result = target[top ? 'pageYOffset' : 'pageXOffset'];
|
result = target[top ? 'scrollY' : 'scrollX'];
|
||||||
} else if (target instanceof Document) {
|
} else if (target instanceof Document) {
|
||||||
result = target.documentElement[method];
|
result = target.documentElement[method];
|
||||||
} else if (target instanceof HTMLElement) {
|
} else if (target instanceof HTMLElement) {
|
||||||
|
|
|
@ -28,7 +28,7 @@ export interface ConfigurableLocation {
|
||||||
location?: Location;
|
location?: Location;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultWindow = /* #__PURE__ */ isClient ? window : undefined;
|
export const defaultWindow = isClient ? window : undefined;
|
||||||
export const defaultDocument = /* #__PURE__ */ isClient ? window.document : undefined;
|
export const defaultDocument = isClient ? window.document : undefined;
|
||||||
export const defaultNavigator = /* #__PURE__ */ isClient ? window.navigator : undefined;
|
export const defaultNavigator = isClient ? window.navigator : undefined;
|
||||||
export const defaultLocation = /* #__PURE__ */ isClient ? window.location : undefined;
|
export const defaultLocation = isClient ? window.location : undefined;
|
||||||
|
|
|
@ -21,8 +21,6 @@ export const rand = (min: number, max: number) => {
|
||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
};
|
};
|
||||||
export const isIOS =
|
export const isIOS =
|
||||||
/* #__PURE__ */ isClient &&
|
isClient && window?.navigator?.userAgent && /iP(ad|hone|od)/.test(window.navigator.userAgent);
|
||||||
window?.navigator?.userAgent &&
|
|
||||||
/iP(ad|hone|od)/.test(window.navigator.userAgent);
|
|
||||||
export const hasOwn = <T extends object, K extends keyof T>(val: T, key: K): key is K =>
|
export const hasOwn = <T extends object, K extends keyof T>(val: T, key: K): key is K =>
|
||||||
Object.prototype.hasOwnProperty.call(val, key);
|
Object.prototype.hasOwnProperty.call(val, key);
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
let animation;
|
|
||||||
|
|
||||||
function isCssAnimationSupported() {
|
|
||||||
if (animation !== undefined) {
|
|
||||||
return animation;
|
|
||||||
}
|
|
||||||
const domPrefixes = 'Webkit Moz O ms Khtml'.split(' ');
|
|
||||||
const elm = document.createElement('div');
|
|
||||||
if (elm.style.animationName !== undefined) {
|
|
||||||
animation = true;
|
|
||||||
}
|
|
||||||
if (animation !== undefined) {
|
|
||||||
for (let i = 0; i < domPrefixes.length; i++) {
|
|
||||||
if (elm.style[`${domPrefixes[i]}AnimationName`] !== undefined) {
|
|
||||||
animation = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
animation = animation || false;
|
|
||||||
return animation;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default isCssAnimationSupported;
|
|
|
@ -22,8 +22,8 @@ export default function scrollTo(y: number, options: ScrollToOptions = {}) {
|
||||||
const time = timestamp - startTime;
|
const time = timestamp - startTime;
|
||||||
const nextScrollTop = easeInOutCubic(time > duration ? duration : time, scrollTop, y, duration);
|
const nextScrollTop = easeInOutCubic(time > duration ? duration : time, scrollTop, y, duration);
|
||||||
if (isWindow(container)) {
|
if (isWindow(container)) {
|
||||||
(container as Window).scrollTo(window.pageXOffset, nextScrollTop);
|
(container as Window).scrollTo(window.scrollX, nextScrollTop);
|
||||||
} else if (container instanceof Document || container.constructor.name === 'HTMLDocument') {
|
} else if (container instanceof Document) {
|
||||||
(container as Document).documentElement.scrollTop = nextScrollTop;
|
(container as Document).documentElement.scrollTop = nextScrollTop;
|
||||||
} else {
|
} else {
|
||||||
(container as HTMLElement).scrollTop = nextScrollTop;
|
(container as HTMLElement).scrollTop = nextScrollTop;
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,7 @@
|
||||||
// import { StyleProvider } from '../../cssinjs';
|
// import { StyleProvider } from '../../cssinjs';
|
||||||
import { extractStyle } from '../index';
|
import { extractStyle } from '../index';
|
||||||
import { ConfigProvider } from '../../../components';
|
import { ConfigProvider } from '../../../components';
|
||||||
|
import { theme } from '../../../index';
|
||||||
|
|
||||||
const testGreenColor = '#008000';
|
const testGreenColor = '#008000';
|
||||||
describe('Static-Style-Extract', () => {
|
describe('Static-Style-Extract', () => {
|
||||||
|
@ -26,6 +27,25 @@ describe('Static-Style-Extract', () => {
|
||||||
expect(cssText).toContain(testGreenColor);
|
expect(cssText).toContain(testGreenColor);
|
||||||
expect(cssText).toMatchSnapshot();
|
expect(cssText).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should extract static styles with customTheme and customStyle', () => {
|
||||||
|
const cssText = extractStyle(node => {
|
||||||
|
return (
|
||||||
|
<ConfigProvider
|
||||||
|
theme={{
|
||||||
|
algorithm: theme.darkAlgorithm,
|
||||||
|
token: {
|
||||||
|
colorPrimary: testGreenColor,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{node}
|
||||||
|
</ConfigProvider>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
expect(cssText).toContain('#037003');
|
||||||
|
expect(cssText).toMatchSnapshot();
|
||||||
|
});
|
||||||
// it('with custom hashPriority', () => {
|
// it('with custom hashPriority', () => {
|
||||||
// const cssText = extractStyle(
|
// const cssText = extractStyle(
|
||||||
// (node) => (
|
// (node) => (
|
||||||
|
|
|
@ -5,7 +5,7 @@ import type {
|
||||||
TransitionGroupProps,
|
TransitionGroupProps,
|
||||||
TransitionProps,
|
TransitionProps,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import { nextTick, Transition, TransitionGroup } from 'vue';
|
import { nextTick } from 'vue';
|
||||||
import { tuple } from './type';
|
import { tuple } from './type';
|
||||||
|
|
||||||
const SelectPlacements = tuple('bottomLeft', 'bottomRight', 'topLeft', 'topRight');
|
const SelectPlacements = tuple('bottomLeft', 'bottomRight', 'topLeft', 'topRight');
|
||||||
|
@ -126,6 +126,4 @@ const getTransitionName = (rootPrefixCls: string, motion: string, transitionName
|
||||||
return `${rootPrefixCls}-${motion}`;
|
return `${rootPrefixCls}-${motion}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export { Transition, TransitionGroup, collapseMotion, getTransitionName, getTransitionDirection };
|
export { collapseMotion, getTransitionName, getTransitionDirection };
|
||||||
|
|
||||||
export default Transition;
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
export default function triggerEvent(el: Element, type: string) {
|
|
||||||
if ('createEvent' in document) {
|
|
||||||
// modern browsers, IE9+
|
|
||||||
const e = document.createEvent('HTMLEvents');
|
|
||||||
e.initEvent(type, false, true);
|
|
||||||
el.dispatchEvent(e);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -33,7 +33,7 @@ export interface PropOptions<T = any, D = T> {
|
||||||
declare type VNodeChildAtom = VNode | string | number | boolean | null | undefined | void;
|
declare type VNodeChildAtom = VNode | string | number | boolean | null | undefined | void;
|
||||||
|
|
||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
export type VueNode = VNodeChildAtom | VNodeChildAtom[] | JSX.Element;
|
export type VueNode = VNodeChildAtom | VNodeChildAtom[] | VNode;
|
||||||
|
|
||||||
export const withInstall = <T>(comp: T) => {
|
export const withInstall = <T>(comp: T) => {
|
||||||
const c = comp as any;
|
const c = comp as any;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { filterEmpty } from './props-util';
|
import { filterEmpty } from './props-util';
|
||||||
import type { VNode, VNodeProps } from 'vue';
|
import type { Slots, VNode, VNodeArrayChildren, VNodeProps } from 'vue';
|
||||||
import { cloneVNode, isVNode } from 'vue';
|
import { cloneVNode, isVNode, Comment, Fragment, render as VueRender } from 'vue';
|
||||||
import warning from './warning';
|
import warning from './warning';
|
||||||
import type { RefObject } from './createRef';
|
import type { RefObject } from './createRef';
|
||||||
type NodeProps = Record<string, any> &
|
type NodeProps = Record<string, any> &
|
||||||
|
@ -51,3 +51,32 @@ export function deepCloneElement<T, U>(
|
||||||
return cloned;
|
return cloned;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function triggerVNodeUpdate(vm: VNode, attrs: Record<string, any>, dom: any) {
|
||||||
|
VueRender(cloneVNode(vm, { ...attrs }), dom);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ensureValidVNode = (slot: VNodeArrayChildren | null) => {
|
||||||
|
return (slot || []).some(child => {
|
||||||
|
if (!isVNode(child)) return true;
|
||||||
|
if (child.type === Comment) return false;
|
||||||
|
if (child.type === Fragment && !ensureValidVNode(child.children as VNodeArrayChildren))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
? slot
|
||||||
|
: null;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function customRenderSlot(
|
||||||
|
slots: Slots,
|
||||||
|
name: string,
|
||||||
|
props: Record<string, unknown>,
|
||||||
|
fallback?: () => VNodeArrayChildren,
|
||||||
|
) {
|
||||||
|
const slot = slots[name]?.(props);
|
||||||
|
if (ensureValidVNode(slot)) {
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
return fallback?.();
|
||||||
|
}
|
||||||
|
|
|
@ -159,6 +159,12 @@ function showWaveEffect(node: HTMLElement, className: string) {
|
||||||
node?.insertBefore(holder, node?.firstChild);
|
node?.insertBefore(holder, node?.firstChild);
|
||||||
|
|
||||||
render(<WaveEffect target={node} className={className} />, holder);
|
render(<WaveEffect target={node} className={className} />, holder);
|
||||||
|
return () => {
|
||||||
|
render(null, holder);
|
||||||
|
if (holder.parentElement) {
|
||||||
|
holder.parentElement.removeChild(holder);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default showWaveEffect;
|
export default showWaveEffect;
|
||||||
|
|
|
@ -33,13 +33,12 @@ export default defineComponent({
|
||||||
|
|
||||||
// =============================== Wave ===============================
|
// =============================== Wave ===============================
|
||||||
const showWave = useWave(
|
const showWave = useWave(
|
||||||
instance,
|
|
||||||
computed(() => classNames(prefixCls.value, hashId.value)),
|
computed(() => classNames(prefixCls.value, hashId.value)),
|
||||||
wave,
|
wave,
|
||||||
);
|
);
|
||||||
let onClick: (e: MouseEvent) => void;
|
let onClick: (e: MouseEvent) => void;
|
||||||
const clear = () => {
|
const clear = () => {
|
||||||
const node = findDOMNode(instance);
|
const node = findDOMNode(instance) as HTMLElement;
|
||||||
node.removeEventListener('click', onClick, true);
|
node.removeEventListener('click', onClick, true);
|
||||||
};
|
};
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
|
@ -1,21 +1,25 @@
|
||||||
import type { ComponentInternalInstance, ComputedRef, Ref } from 'vue';
|
import type { ComputedRef, Ref } from 'vue';
|
||||||
|
import { onBeforeUnmount, getCurrentInstance } from 'vue';
|
||||||
import { findDOMNode } from '../props-util';
|
import { findDOMNode } from '../props-util';
|
||||||
import showWaveEffect from './WaveEffect';
|
import showWaveEffect from './WaveEffect';
|
||||||
|
|
||||||
export default function useWave(
|
export default function useWave(
|
||||||
instance: ComponentInternalInstance | null,
|
|
||||||
className: Ref<string>,
|
className: Ref<string>,
|
||||||
wave: ComputedRef<{ disabled?: boolean }>,
|
wave?: ComputedRef<{ disabled?: boolean }>,
|
||||||
): VoidFunction {
|
): VoidFunction {
|
||||||
|
const instance = getCurrentInstance();
|
||||||
|
let stopWave: () => void;
|
||||||
function showWave() {
|
function showWave() {
|
||||||
const node = findDOMNode(instance);
|
const node = findDOMNode(instance);
|
||||||
|
stopWave?.();
|
||||||
if (wave.value?.disabled || !node) {
|
if (wave?.value?.disabled || !node) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
stopWave = showWaveEffect(node, className.value);
|
||||||
showWaveEffect(node, className.value);
|
|
||||||
}
|
}
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
stopWave?.();
|
||||||
|
});
|
||||||
|
|
||||||
return showWave;
|
return showWave;
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,7 +176,6 @@ const Affix = defineComponent({
|
||||||
affixStyle: undefined,
|
affixStyle: undefined,
|
||||||
placeholderStyle: undefined,
|
placeholderStyle: undefined,
|
||||||
});
|
});
|
||||||
currentInstance.update();
|
|
||||||
// Test if `updatePosition` called
|
// Test if `updatePosition` called
|
||||||
if (process.env.NODE_ENV === 'test') {
|
if (process.env.NODE_ENV === 'test') {
|
||||||
emit('testUpdatePosition');
|
emit('testUpdatePosition');
|
||||||
|
@ -256,7 +255,7 @@ const Affix = defineComponent({
|
||||||
const { prefixCls } = useConfigInject('affix', props);
|
const { prefixCls } = useConfigInject('affix', props);
|
||||||
const [wrapSSR, hashId] = useStyle(prefixCls);
|
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||||
return () => {
|
return () => {
|
||||||
const { affixStyle, placeholderStyle } = state;
|
const { affixStyle, placeholderStyle, status } = state;
|
||||||
const className = classNames({
|
const className = classNames({
|
||||||
[prefixCls.value]: affixStyle,
|
[prefixCls.value]: affixStyle,
|
||||||
[hashId.value]: true,
|
[hashId.value]: true,
|
||||||
|
@ -271,7 +270,7 @@ const Affix = defineComponent({
|
||||||
]);
|
]);
|
||||||
return wrapSSR(
|
return wrapSSR(
|
||||||
<ResizeObserver onResize={updatePosition}>
|
<ResizeObserver onResize={updatePosition}>
|
||||||
<div {...restProps} {...attrs} ref={placeholderNode}>
|
<div {...restProps} {...attrs} ref={placeholderNode} data-measure-status={status}>
|
||||||
{affixStyle && <div style={placeholderStyle} aria-hidden="true" />}
|
{affixStyle && <div style={placeholderStyle} aria-hidden="true" />}
|
||||||
<div class={className} ref={fixedNode} style={affixStyle}>
|
<div class={className} ref={fixedNode} style={affixStyle}>
|
||||||
{slots.default?.()}
|
{slots.default?.()}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { CSSProperties, ExtractPropTypes, PropType } from 'vue';
|
import type { CSSProperties, ExtractPropTypes, PropType } from 'vue';
|
||||||
import { computed, defineComponent, shallowRef } from 'vue';
|
import { computed, defineComponent, shallowRef, Transition } from 'vue';
|
||||||
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
|
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
|
||||||
import CheckCircleOutlined from '@ant-design/icons-vue/CheckCircleOutlined';
|
import CheckCircleOutlined from '@ant-design/icons-vue/CheckCircleOutlined';
|
||||||
import ExclamationCircleOutlined from '@ant-design/icons-vue/ExclamationCircleOutlined';
|
import ExclamationCircleOutlined from '@ant-design/icons-vue/ExclamationCircleOutlined';
|
||||||
|
@ -11,7 +11,7 @@ import InfoCircleFilled from '@ant-design/icons-vue/InfoCircleFilled';
|
||||||
import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
|
import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import { getTransitionProps, Transition } from '../_util/transition';
|
import { getTransitionProps } from '../_util/transition';
|
||||||
import { isValidElement } from '../_util/props-util';
|
import { isValidElement } from '../_util/props-util';
|
||||||
import { tuple, withInstall } from '../_util/type';
|
import { tuple, withInstall } from '../_util/type';
|
||||||
import { cloneElement } from '../_util/vnode';
|
import { cloneElement } from '../_util/vnode';
|
||||||
|
|
|
@ -97,7 +97,7 @@ import type { MessageInstance } from 'ant-design-vue/es/message/interface';
|
||||||
import type { ModalStaticFunctions } from 'ant-design-vue/es/modal/confirm';
|
import type { ModalStaticFunctions } from 'ant-design-vue/es/modal/confirm';
|
||||||
import type { NotificationInstance } from 'ant-design-vue/es/notification/interface';
|
import type { NotificationInstance } from 'ant-design-vue/es/notification/interface';
|
||||||
|
|
||||||
export const useGloablStore = defineStore('global', () => {
|
export const useGlobalStore = defineStore('global', () => {
|
||||||
const message: MessageInstance = ref();
|
const message: MessageInstance = ref();
|
||||||
const notification: NotificationInstance = ref();
|
const notification: NotificationInstance = ref();
|
||||||
const modal: Omit<ModalStaticFunctions, 'warn'> = ref();
|
const modal: Omit<ModalStaticFunctions, 'warn'> = ref();
|
||||||
|
|
|
@ -98,7 +98,7 @@ import type { MessageInstance } from 'ant-design-vue/es/message/interface';
|
||||||
import type { ModalStaticFunctions } from 'ant-design-vue/es/modal/confirm';
|
import type { ModalStaticFunctions } from 'ant-design-vue/es/modal/confirm';
|
||||||
import type { NotificationInstance } from 'ant-design-vue/es/notification/interface';
|
import type { NotificationInstance } from 'ant-design-vue/es/notification/interface';
|
||||||
|
|
||||||
export const useGloablStore = defineStore('global', () => {
|
export const useGlobalStore = defineStore('global', () => {
|
||||||
const message: MessageInstance = ref();
|
const message: MessageInstance = ref();
|
||||||
const notification: NotificationInstance = ref();
|
const notification: NotificationInstance = ref();
|
||||||
const modal: Omit<ModalStaticFunctions, 'warn'> = ref();
|
const modal: Omit<ModalStaticFunctions, 'warn'> = ref();
|
||||||
|
|
|
@ -50,6 +50,8 @@ const AutoComplete = defineComponent({
|
||||||
props: autoCompleteProps(),
|
props: autoCompleteProps(),
|
||||||
// emits: ['change', 'select', 'focus', 'blur'],
|
// emits: ['change', 'select', 'focus', 'blur'],
|
||||||
slots: Object as CustomSlotsType<{
|
slots: Object as CustomSlotsType<{
|
||||||
|
option: any;
|
||||||
|
// deprecated, should use props `options` instead, not slot
|
||||||
options: any;
|
options: any;
|
||||||
default: any;
|
default: any;
|
||||||
notFoundContent: any;
|
notFoundContent: any;
|
||||||
|
|
|
@ -3,9 +3,9 @@ import ScrollNumber from './ScrollNumber';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import { getPropsSlot, flattenChildren } from '../_util/props-util';
|
import { getPropsSlot, flattenChildren } from '../_util/props-util';
|
||||||
import { cloneElement } from '../_util/vnode';
|
import { cloneElement } from '../_util/vnode';
|
||||||
import { getTransitionProps, Transition } from '../_util/transition';
|
import { getTransitionProps } from '../_util/transition';
|
||||||
import type { ExtractPropTypes, CSSProperties, PropType } from 'vue';
|
import type { ExtractPropTypes, CSSProperties, PropType } from 'vue';
|
||||||
import { defineComponent, computed, ref, watch } from 'vue';
|
import { defineComponent, computed, ref, watch, Transition } from 'vue';
|
||||||
import Ribbon from './Ribbon';
|
import Ribbon from './Ribbon';
|
||||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||||
import isNumeric from '../_util/isNumeric';
|
import isNumeric from '../_util/isNumeric';
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { defineComponent, nextTick } from 'vue';
|
import { defineComponent, nextTick, Transition } from 'vue';
|
||||||
import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
|
import LoadingOutlined from '@ant-design/icons-vue/LoadingOutlined';
|
||||||
import Transition from '../_util/transition';
|
|
||||||
const getCollapsedWidth = (node: HTMLSpanElement) => {
|
const getCollapsedWidth = (node: HTMLSpanElement) => {
|
||||||
if (node) {
|
if (node) {
|
||||||
node.style.width = '0px';
|
node.style.width = '0px';
|
||||||
|
|
|
@ -495,7 +495,6 @@ const genBlockButtonStyle: GenerateStyle<ButtonToken> = token => {
|
||||||
// ============================== Export ==============================
|
// ============================== Export ==============================
|
||||||
export default genComponentStyleHook('Button', token => {
|
export default genComponentStyleHook('Button', token => {
|
||||||
const { controlTmpOutline, paddingContentHorizontal } = token;
|
const { controlTmpOutline, paddingContentHorizontal } = token;
|
||||||
|
|
||||||
const buttonToken = mergeToken<ButtonToken>(token, {
|
const buttonToken = mergeToken<ButtonToken>(token, {
|
||||||
colorOutlineDefault: controlTmpOutline,
|
colorOutlineDefault: controlTmpOutline,
|
||||||
buttonPaddingHorizontal: paddingContentHorizontal,
|
buttonPaddingHorizontal: paddingContentHorizontal,
|
||||||
|
|
|
@ -16,9 +16,11 @@ When data is in the form of dates, such as schedules, timetables, prices calenda
|
||||||
|
|
||||||
**Note:** Part of the Calendar's locale is read from `value`. So, please set the locale of `dayjs` correctly.
|
**Note:** Part of the Calendar's locale is read from `value`. So, please set the locale of `dayjs` correctly.
|
||||||
|
|
||||||
```html
|
```jsx
|
||||||
// The default locale is en-US, if you want to use other locale, just set locale in entry file
|
// The default locale is en-US, if you want to use other locale, just set locale in entry file globally.
|
||||||
globally. // import dayjs from 'dayjs'; // import 'dayjs/locale/zh-cn'; // dayjs.locale('zh-cn');
|
// import dayjs from 'dayjs';
|
||||||
|
// import 'dayjs/locale/zh-cn';
|
||||||
|
// dayjs.locale('zh-cn');
|
||||||
|
|
||||||
<a-calendar v-model:value @panelChange="onPanelChange" @select="onSelect"></a-calendar>
|
<a-calendar v-model:value @panelChange="onPanelChange" @select="onSelect"></a-calendar>
|
||||||
```
|
```
|
||||||
|
|
|
@ -17,25 +17,27 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*-p-wQLik200AAA
|
||||||
|
|
||||||
**注意:**Calendar 部分 locale 是从 value 中读取,所以请先正确设置 dayjs 的 locale。
|
**注意:**Calendar 部分 locale 是从 value 中读取,所以请先正确设置 dayjs 的 locale。
|
||||||
|
|
||||||
```html
|
```jsx
|
||||||
// 默认语言为 en-US,所以如果需要使用其他语言,推荐在入口文件全局设置 locale // import dayjs from
|
// 默认语言为 en-US,所以如果需要使用其他语言,推荐在入口文件全局设置 locale
|
||||||
'dayjs'; // import 'dayjs/locale/zh-cn'; // dayjs.locale('zh-cn');
|
// import dayjs from 'dayjs';
|
||||||
|
// import 'dayjs/locale/zh-cn';
|
||||||
|
// dayjs.locale('zh-cn');
|
||||||
|
|
||||||
<a-calendar v-model:value="value" @panelChange="onPanelChange" @select="onSelect"></a-calendar>
|
<a-calendar v-model:value="value" @panelChange="onPanelChange" @select="onSelect"></a-calendar>
|
||||||
```
|
```
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| dateCellRender | 作用域插槽,用来自定义渲染日期单元格,返回内容会被追加到单元格, | v-slot:dateCellRender="{current: dayjs}" | 无 | |
|
| dateCellRender | 作用域插槽,用来自定义渲染日期单元格,返回内容会被追加到单元格, | v-slot:dateCellRender="{current: dayjs}" | - | |
|
||||||
| dateFullCellRender | 作用域插槽,自定义渲染日期单元格,返回内容覆盖单元格 | v-slot:dateFullCellRender="{current: dayjs}" | 无 | |
|
| dateFullCellRender | 作用域插槽,自定义渲染日期单元格,返回内容覆盖单元格 | v-slot:dateFullCellRender="{current: dayjs}" | - | |
|
||||||
| disabledDate | 不可选择的日期 | (currentDate: dayjs) => boolean | 无 | |
|
| disabledDate | 不可选择的日期 | (currentDate: dayjs) => boolean | - | |
|
||||||
| fullscreen | 是否全屏显示 | boolean | true | |
|
| fullscreen | 是否全屏显示 | boolean | true | |
|
||||||
| headerRender | 自定义头部内容 | v-slot:headerRender="{value: dayjs, type: string, onChange: f(), onTypeChange: f()}" | - | |
|
| headerRender | 自定义头部内容 | v-slot:headerRender="{value: dayjs, type: string, onChange: f(), onTypeChange: f()}" | - | |
|
||||||
| locale | 国际化配置 | object | [默认配置](https://github.com/vueComponent/ant-design-vue/blob/main/components/date-picker/locale/example.json) | |
|
| locale | 国际化配置 | object | [默认配置](https://github.com/vueComponent/ant-design-vue/blob/main/components/date-picker/locale/example.json) | |
|
||||||
| mode | 初始模式,`month/year` | string | month | |
|
| mode | 初始模式,`month/year` | string | month | |
|
||||||
| monthCellRender | 作用域插槽,自定义渲染月单元格,返回内容会被追加到单元格 | v-slot:monthCellRender="{current: dayjs}" | 无 | |
|
| monthCellRender | 作用域插槽,自定义渲染月单元格,返回内容会被追加到单元格 | v-slot:monthCellRender="{current: dayjs}" | - | |
|
||||||
| monthFullCellRender | 作用域插槽,自定义渲染月单元格,返回内容覆盖单元格 | v-slot:monthFullCellRender="{current: dayjs}" | 无 | |
|
| monthFullCellRender | 作用域插槽,自定义渲染月单元格,返回内容覆盖单元格 | v-slot:monthFullCellRender="{current: dayjs}" | - | |
|
||||||
| validRange | 设置可以显示的日期 | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | 无 | |
|
| validRange | 设置可以显示的日期 | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | - | |
|
||||||
| value(v-model) | 展示日期 | [dayjs](https://day.js.org/) | 当前日期 | |
|
| value(v-model) | 展示日期 | [dayjs](https://day.js.org/) | 当前日期 | |
|
||||||
| valueFormat | 可选,绑定值的格式,对 value、defaultValue 起作用。不指定则绑定值为 dayjs 对象 | string,[具体格式](https://day.js.org/docs/zh-CN/display/format) | - | |
|
| valueFormat | 可选,绑定值的格式,对 value、defaultValue 起作用。不指定则绑定值为 dayjs 对象 | string,[具体格式](https://day.js.org/docs/zh-CN/display/format) | - | |
|
||||||
|
|
||||||
|
@ -43,8 +45,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*-p-wQLik200AAA
|
||||||
|
|
||||||
| 事件名称 | 说明 | 回调参数 | |
|
| 事件名称 | 说明 | 回调参数 | |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| change | 日期变化时的回调, 面板变化有可能导致日期变化 | function(date: dayjs \| string) | 无 |
|
| change | 日期变化时的回调, 面板变化有可能导致日期变化 | function(date: dayjs \| string) | - |
|
||||||
| panelChange | 日期面板变化回调 | function(date: dayjs \| string, mode: string) | 无 |
|
| panelChange | 日期面板变化回调 | function(date: dayjs \| string, mode: string) | - |
|
||||||
| select | 选择日期回调,包含来源信息 | function(date: Dayjs, info: { source: 'year' \| 'month' \| 'date' \| 'customize' }) | - | |
|
| select | 选择日期回调,包含来源信息 | function(date: Dayjs, info: { source: 'year' \| 'month' \| 'date' \| 'customize' }) | - | |
|
||||||
|
|
||||||
### 如何仅获取来自面板点击的日期?
|
### 如何仅获取来自面板点击的日期?
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { VNodeTypes, PropType, VNode, ExtractPropTypes, CSSProperties } from 'vue';
|
import type { VNodeTypes, PropType, VNode, ExtractPropTypes, CSSProperties } from 'vue';
|
||||||
import { isVNode, defineComponent, renderSlot } from 'vue';
|
import { isVNode, defineComponent } from 'vue';
|
||||||
import Tabs from '../tabs';
|
import Tabs from '../tabs';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import { flattenChildren, isEmptyElement, filterEmptyWithUndefined } from '../_util/props-util';
|
import { flattenChildren, isEmptyElement, filterEmptyWithUndefined } from '../_util/props-util';
|
||||||
|
@ -10,6 +10,8 @@ import devWarning from '../vc-util/devWarning';
|
||||||
import useStyle from './style';
|
import useStyle from './style';
|
||||||
import Skeleton from '../skeleton';
|
import Skeleton from '../skeleton';
|
||||||
import type { CustomSlotsType } from '../_util/type';
|
import type { CustomSlotsType } from '../_util/type';
|
||||||
|
import { customRenderSlot } from '../_util/vnode';
|
||||||
|
|
||||||
export interface CardTabListType {
|
export interface CardTabListType {
|
||||||
key: string;
|
key: string;
|
||||||
tab: any;
|
tab: any;
|
||||||
|
@ -152,7 +154,7 @@ const Card = defineComponent({
|
||||||
`tabList slots is deprecated, Please use \`customTab\` instead.`,
|
`tabList slots is deprecated, Please use \`customTab\` instead.`,
|
||||||
);
|
);
|
||||||
let tab = temp !== undefined ? temp : slots[name] ? slots[name](item) : null;
|
let tab = temp !== undefined ? temp : slots[name] ? slots[name](item) : null;
|
||||||
tab = renderSlot(slots, 'customTab', item as any, () => [tab]);
|
tab = customRenderSlot(slots, 'customTab', item as any, () => [tab]);
|
||||||
return <TabPane tab={tab} key={item.key} disabled={item.disabled} />;
|
return <TabPane tab={tab} key={item.key} disabled={item.disabled} />;
|
||||||
})}
|
})}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
|
@ -41,7 +41,7 @@ export default defineComponent({
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const triggerUpdate = ref(Symbol());
|
const triggerUpdate = ref(Symbol());
|
||||||
const registeredValuesMap = ref<Map<Symbol, string>>(new Map());
|
const registeredValuesMap = ref(new Map<Symbol, string>());
|
||||||
const cancelValue = (id: Symbol) => {
|
const cancelValue = (id: Symbol) => {
|
||||||
registeredValuesMap.value.delete(id);
|
registeredValuesMap.value.delete(id);
|
||||||
triggerUpdate.value = Symbol();
|
triggerUpdate.value = Symbol();
|
||||||
|
|
|
@ -2,8 +2,7 @@ import PanelContent from './PanelContent';
|
||||||
import { initDefaultProps } from '../_util/props-util';
|
import { initDefaultProps } from '../_util/props-util';
|
||||||
import { collapsePanelProps } from './commonProps';
|
import { collapsePanelProps } from './commonProps';
|
||||||
import type { ExtractPropTypes } from 'vue';
|
import type { ExtractPropTypes } from 'vue';
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent, Transition } from 'vue';
|
||||||
import Transition from '../_util/transition';
|
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import devWarning from '../vc-util/devWarning';
|
import devWarning from '../vc-util/devWarning';
|
||||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||||
|
|
|
@ -20,7 +20,7 @@ A content area which can be collapsed and expanded.
|
||||||
| Property | Description | Type | Default | Version |
|
| Property | Description | Type | Default | Version |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| accordion | If `true`, `Collapse` renders as `Accordion` | boolean | `false` | |
|
| accordion | If `true`, `Collapse` renders as `Accordion` | boolean | `false` | |
|
||||||
| activeKey(v-model) | Key of the active panel | string\[] \| string <br> number\[] \| number | No default value. In `accordion` mode, it's the key of the first panel. | |
|
| activeKey(v-model) | Key of the active panel | string\[] \| string <br> number\[] \| number | No default value. In [accordion mode](#components-collapse-demo-accordion), it's the key of the first panel. | |
|
||||||
| bordered | Toggles rendering of the border around the collapse block | boolean | `true` | |
|
| bordered | Toggles rendering of the border around the collapse block | boolean | `true` | |
|
||||||
| collapsible | Specify whether the panels of children be collapsible or the trigger area of collapsible | `header` \| `icon` \| `disabled` | - | 4.0 |
|
| collapsible | Specify whether the panels of children be collapsible or the trigger area of collapsible | `header` \| `icon` \| `disabled` | - | 4.0 |
|
||||||
| destroyInactivePanel | Destroy Inactive Panel | boolean | `false` | |
|
| destroyInactivePanel | Destroy Inactive Panel | boolean | `false` | |
|
||||||
|
|
|
@ -20,8 +20,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*sir-TK0HkWcAAA
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| accordion | 手风琴模式 | boolean | `false` | |
|
| accordion | 手风琴模式,始终只有一个面板处在激活状态 | boolean | `false` | |
|
||||||
| activeKey(v-model) | 当前激活 tab 面板的 key | string\[] \| string <br> number\[] \| number | 默认无,accordion 模式下默认第一个元素 | |
|
| activeKey(v-model) | 当前激活 tab 面板的 key | string\[] \| string <br> number\[] \| number | 默认无,[手风琴模式](#components-collapse-demo-accordion)下默认第一个元素 | |
|
||||||
| bordered | 带边框风格的折叠面板 | boolean | `true` | |
|
| bordered | 带边框风格的折叠面板 | boolean | `true` | |
|
||||||
| collapsible | 所有子面板是否可折叠或指定可折叠触发区域 | `header` \| `icon` \| `disabled` | - | 4.0 |
|
| collapsible | 所有子面板是否可折叠或指定可折叠触发区域 | `header` \| `icon` \| `disabled` | - | 4.0 |
|
||||||
| destroyInactivePanel | 销毁折叠隐藏的面板 | boolean | `false` | |
|
| destroyInactivePanel | 销毁折叠隐藏的面板 | boolean | `false` | |
|
||||||
|
@ -42,6 +42,6 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*sir-TK0HkWcAAA
|
||||||
| collapsible | 是否可折叠或指定可折叠触发区域 | `header` \| `disabled` | - | 3.0 |
|
| collapsible | 是否可折叠或指定可折叠触发区域 | `header` \| `disabled` | - | 3.0 |
|
||||||
| extra | 自定义渲染每个面板右上角的内容 | VNode \| slot | - | 1.5.0 |
|
| extra | 自定义渲染每个面板右上角的内容 | VNode \| slot | - | 1.5.0 |
|
||||||
| forceRender | 被隐藏时是否渲染 DOM 结构 | boolean | false | |
|
| forceRender | 被隐藏时是否渲染 DOM 结构 | boolean | false | |
|
||||||
| header | 面板头内容 | string\|slot | 无 | |
|
| header | 面板头内容 | string\|slot | - | |
|
||||||
| key | 对应 activeKey | string \| number | 无 | |
|
| key | 对应 activeKey | string \| number | - | |
|
||||||
| showArrow | 是否展示当前面板上的箭头 | boolean | `true` | |
|
| showArrow | 是否展示当前面板上的箭头 | boolean | `true` | |
|
||||||
|
|
|
@ -44,7 +44,7 @@ export default (name: string, props: Record<any, any>) => {
|
||||||
const csp = computed(() => props.csp ?? configProvider.csp);
|
const csp = computed(() => props.csp ?? configProvider.csp);
|
||||||
const wave = computed<{
|
const wave = computed<{
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}>(() => props.wave ?? configProvider.wave.value);
|
}>(() => props.wave ?? configProvider.wave?.value);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
configProvider,
|
configProvider,
|
||||||
|
|
|
@ -64,6 +64,7 @@ Some components use dynamic style to support wave effect. You can config `csp` p
|
||||||
| space | Set Space `size`, ref [Space](/components/space) | { size: `small` \| `middle` \| `large` \| `number` } | - | 3.0 |
|
| space | Set Space `size`, ref [Space](/components/space) | { size: `small` \| `middle` \| `large` \| `number` } | - | 3.0 |
|
||||||
| transformCellText | Table data can be changed again before rendering. The default configuration of general user empty data. | Function({ text, column, record, index }) => any | - | 1.5.4 |
|
| transformCellText | Table data can be changed again before rendering. The default configuration of general user empty data. | Function({ text, column, record, index }) => any | - | 1.5.4 |
|
||||||
| virtual | Disable virtual scroll when set to false | boolean | true | 3.0 |
|
| virtual | Disable virtual scroll when set to false | boolean | true | 3.0 |
|
||||||
|
| wave | Config wave effect | { disabled?: boolean } | - | 4.0.7 |
|
||||||
|
|
||||||
### ConfigProvider.config() `3.0.0+`
|
### ConfigProvider.config() `3.0.0+`
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { App, Plugin, WatchStopHandle } from 'vue';
|
import type { App, MaybeRef, Plugin, WatchStopHandle } from 'vue';
|
||||||
import { watch, computed, reactive, defineComponent, watchEffect } from 'vue';
|
import { watch, computed, reactive, defineComponent, watchEffect } from 'vue';
|
||||||
import defaultRenderEmpty from './renderEmpty';
|
import defaultRenderEmpty from './renderEmpty';
|
||||||
import type { RenderEmptyHandler } from './renderEmpty';
|
import type { RenderEmptyHandler } from './renderEmpty';
|
||||||
|
@ -7,7 +7,6 @@ import LocaleProvider, { ANT_MARK } from '../locale-provider';
|
||||||
|
|
||||||
import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
||||||
|
|
||||||
import type { MaybeRef } from '../_util/type';
|
|
||||||
import message from '../message';
|
import message from '../message';
|
||||||
import notification from '../notification';
|
import notification from '../notification';
|
||||||
import { registerTheme } from './cssVariables';
|
import { registerTheme } from './cssVariables';
|
||||||
|
@ -232,7 +231,6 @@ const ConfigProvider = defineComponent({
|
||||||
algorithm && (!Array.isArray(algorithm) || algorithm.length > 0)
|
algorithm && (!Array.isArray(algorithm) || algorithm.length > 0)
|
||||||
? createTheme(algorithm)
|
? createTheme(algorithm)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...rest,
|
...rest,
|
||||||
theme: themeObj,
|
theme: themeObj,
|
||||||
|
|
|
@ -65,6 +65,7 @@ ConfigProvider 使用 Vue 的 [provide / inject](https://vuejs.org/v2/api/#provi
|
||||||
| space | 设置 Space 的 `size`,参考 [Space](/components/space) | { size: `small` \| `middle` \| `large` \| `number` } | - | 3.0 |
|
| space | 设置 Space 的 `size`,参考 [Space](/components/space) | { size: `small` \| `middle` \| `large` \| `number` } | - | 3.0 |
|
||||||
| transformCellText | Table 数据渲染前可以再次改变,一般用户空数据的默认配置 | Function({ text, column, record, index }) => any | - | 1.5.4 |
|
| transformCellText | Table 数据渲染前可以再次改变,一般用户空数据的默认配置 | Function({ text, column, record, index }) => any | - | 1.5.4 |
|
||||||
| virtual | 设置 `false` 时关闭虚拟滚动 | boolean | - | 3.0 |
|
| virtual | 设置 `false` 时关闭虚拟滚动 | boolean | - | 3.0 |
|
||||||
|
| wave | 设置水波纹特效 | { disabled?: boolean } | - | 4.0.7 |
|
||||||
|
|
||||||
### ConfigProvider.config() `3.0.0+`
|
### ConfigProvider.config() `3.0.0+`
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ The following APIs are shared by DatePicker, RangePicker.
|
||||||
| disabled | Determine whether the DatePicker is disabled | boolean | false | |
|
| disabled | Determine whether the DatePicker is disabled | boolean | false | |
|
||||||
| disabledDate | Specify the date that cannot be selected | (currentDate: dayjs) => boolean | - | |
|
| disabledDate | Specify the date that cannot be selected | (currentDate: dayjs) => boolean | - | |
|
||||||
| format | To set the date format, refer to [dayjs](https://day.js.org/). When an array is provided, all values are used for parsing and first value is used for formatting, support [Custom Format](#components-date-picker-demo-format) | [formatType](#formattype) | `YYYY-MM-DD` | |
|
| format | To set the date format, refer to [dayjs](https://day.js.org/). When an array is provided, all values are used for parsing and first value is used for formatting, support [Custom Format](#components-date-picker-demo-format) | [formatType](#formattype) | `YYYY-MM-DD` | |
|
||||||
| dropdownClassName | To customize the className of the popup calendar | string | - | |
|
| popupClassName | To customize the className of the popup calendar | string | - | |
|
||||||
| getPopupContainer | To set the container of the floating layer, while the default is to create a `div` element in `body` | function(trigger) | - | |
|
| getPopupContainer | To set the container of the floating layer, while the default is to create a `div` element in `body` | function(trigger) | - | |
|
||||||
| inputReadOnly | Set the `readonly` attribute of the input tag (avoids virtual keyboard on touch devices) | boolean | false | |
|
| inputReadOnly | Set the `readonly` attribute of the input tag (avoids virtual keyboard on touch devices) | boolean | false | |
|
||||||
| locale | Localization configuration | object | [default](https://github.com/vueComponent/ant-design-vue/blob/main/components/date-picker/locale/example.json) | |
|
| locale | Localization configuration | object | [default](https://github.com/vueComponent/ant-design-vue/blob/main/components/date-picker/locale/example.json) | |
|
||||||
|
|
|
@ -86,7 +86,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*3OpRQKcygo8AAA
|
||||||
| disabled | 禁用 | boolean | false | |
|
| disabled | 禁用 | boolean | false | |
|
||||||
| disabledDate | 不可选择的日期 | (currentDate: dayjs) => boolean | - | |
|
| disabledDate | 不可选择的日期 | (currentDate: dayjs) => boolean | - | |
|
||||||
| format | 设置日期格式,为数组时支持多格式匹配,展示以第一个为准。配置参考 [dayjs](https://day.js.org/docs/zh-CN/display/format),支持[自定义格式](#components-date-picker-demo-format) | [formatType](#formattype) | `YYYY-MM-DD` | |
|
| format | 设置日期格式,为数组时支持多格式匹配,展示以第一个为准。配置参考 [dayjs](https://day.js.org/docs/zh-CN/display/format),支持[自定义格式](#components-date-picker-demo-format) | [formatType](#formattype) | `YYYY-MM-DD` | |
|
||||||
| dropdownClassName | 额外的弹出日历 className | string | - | |
|
| popupClassName | 额外的弹出日历 className | string | - | |
|
||||||
| getPopupContainer | 定义浮层的容器,默认为 body 上新建 div | function(trigger) | - | |
|
| getPopupContainer | 定义浮层的容器,默认为 body 上新建 div | function(trigger) | - | |
|
||||||
| inputReadOnly | 设置输入框为只读(避免在移动设备上打开虚拟键盘) | boolean | false | |
|
| inputReadOnly | 设置输入框为只读(避免在移动设备上打开虚拟键盘) | boolean | false | |
|
||||||
| locale | 国际化配置 | object | [默认配置](https://github.com/vueComponent/ant-design-vue/blob/main/components/date-picker/locale/example.json) | - |
|
| locale | 国际化配置 | object | [默认配置](https://github.com/vueComponent/ant-design-vue/blob/main/components/date-picker/locale/example.json) | - |
|
||||||
|
|
|
@ -6,7 +6,15 @@ import type { PickerLocale } from '../generatePicker';
|
||||||
const locale: PickerLocale = {
|
const locale: PickerLocale = {
|
||||||
lang: {
|
lang: {
|
||||||
placeholder: '日付を選択',
|
placeholder: '日付を選択',
|
||||||
|
yearPlaceholder: '年を選択',
|
||||||
|
quarterPlaceholder: '四半期を選択',
|
||||||
|
monthPlaceholder: '月を選択',
|
||||||
|
weekPlaceholder: '週を選択',
|
||||||
rangePlaceholder: ['開始日付', '終了日付'],
|
rangePlaceholder: ['開始日付', '終了日付'],
|
||||||
|
rangeYearPlaceholder: ['開始年', '終了年'],
|
||||||
|
rangeMonthPlaceholder: ['開始月', '終了月'],
|
||||||
|
rangeQuarterPlaceholder: ['開始四半期', '終了四半期'],
|
||||||
|
rangeWeekPlaceholder: ['開始週', '終了週'],
|
||||||
...CalendarLocale,
|
...CalendarLocale,
|
||||||
},
|
},
|
||||||
timePickerLocale: {
|
timePickerLocale: {
|
||||||
|
|
|
@ -105,7 +105,7 @@ const genSharedDividerStyle: GenerateStyle<DividerToken> = (token): CSSObject =>
|
||||||
},
|
},
|
||||||
|
|
||||||
[`&-vertical${componentCls}-dashed`]: {
|
[`&-vertical${componentCls}-dashed`]: {
|
||||||
borderInlineStart: lineWidth,
|
borderInlineStartWidth: lineWidth,
|
||||||
borderInlineEnd: 0,
|
borderInlineEnd: 0,
|
||||||
borderBlockStart: 0,
|
borderBlockStart: 0,
|
||||||
borderBlockEnd: 0,
|
borderBlockEnd: 0,
|
||||||
|
|
|
@ -22,7 +22,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*5qm4S4Zgh2QAAA
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | |
|
| 参数 | 说明 | 类型 | 默认值 | |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| align | 该值将合并到 placement 的配置中,设置参考 [dom-align](https://github.com/yiminghe/dom-align) | Object | 无 | |
|
| align | 该值将合并到 placement 的配置中,设置参考 [dom-align](https://github.com/yiminghe/dom-align) | Object | - | |
|
||||||
| arrow | 下拉框箭头是否显示 | boolean \| { pointAtCenter: boolean } | false | 3.3.0 |
|
| arrow | 下拉框箭头是否显示 | boolean \| { pointAtCenter: boolean } | false | 3.3.0 |
|
||||||
| destroyPopupOnHide | 关闭后是否销毁 Dropdown | boolean | false | 3.0 |
|
| destroyPopupOnHide | 关闭后是否销毁 Dropdown | boolean | false | 3.0 |
|
||||||
| disabled | 菜单是否禁用 | boolean | - | |
|
| disabled | 菜单是否禁用 | boolean | - | |
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent, h } from 'vue';
|
||||||
import type { CSSProperties, ExtractPropTypes } from 'vue';
|
import type { CSSProperties, ExtractPropTypes } from 'vue';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
import LocaleReceiver from '../locale-provider/LocaleReceiver';
|
||||||
|
@ -11,9 +11,6 @@ import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||||
|
|
||||||
import useStyle from './style';
|
import useStyle from './style';
|
||||||
|
|
||||||
const defaultEmptyImg = <DefaultEmptyImg />;
|
|
||||||
const simpleEmptyImg = <SimpleEmptyImg />;
|
|
||||||
|
|
||||||
interface Locale {
|
interface Locale {
|
||||||
description?: string;
|
description?: string;
|
||||||
}
|
}
|
||||||
|
@ -40,13 +37,16 @@ const Empty = defineComponent({
|
||||||
return () => {
|
return () => {
|
||||||
const prefixCls = prefixClsRef.value;
|
const prefixCls = prefixClsRef.value;
|
||||||
const {
|
const {
|
||||||
image = slots.image?.() || defaultEmptyImg,
|
image: mergedImage = slots.image?.() || h(DefaultEmptyImg),
|
||||||
description = slots.description?.() || undefined,
|
description = slots.description?.() || undefined,
|
||||||
imageStyle,
|
imageStyle,
|
||||||
class: className = '',
|
class: className = '',
|
||||||
...restProps
|
...restProps
|
||||||
} = { ...props, ...attrs };
|
} = { ...props, ...attrs };
|
||||||
|
const image =
|
||||||
|
typeof mergedImage === 'function' ? (mergedImage as () => VueNode)() : mergedImage;
|
||||||
|
const isNormal =
|
||||||
|
typeof image === 'object' && 'type' in image && (image.type as any).PRESENTED_IMAGE_SIMPLE;
|
||||||
return wrapSSR(
|
return wrapSSR(
|
||||||
<LocaleReceiver
|
<LocaleReceiver
|
||||||
componentName="Empty"
|
componentName="Empty"
|
||||||
|
@ -64,7 +64,7 @@ const Empty = defineComponent({
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
class={classNames(prefixCls, className, hashId.value, {
|
class={classNames(prefixCls, className, hashId.value, {
|
||||||
[`${prefixCls}-normal`]: image === simpleEmptyImg,
|
[`${prefixCls}-normal`]: isNormal,
|
||||||
[`${prefixCls}-rtl`]: direction.value === 'rtl',
|
[`${prefixCls}-rtl`]: direction.value === 'rtl',
|
||||||
})}
|
})}
|
||||||
{...restProps}
|
{...restProps}
|
||||||
|
@ -85,7 +85,7 @@ const Empty = defineComponent({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
Empty.PRESENTED_IMAGE_DEFAULT = defaultEmptyImg;
|
Empty.PRESENTED_IMAGE_DEFAULT = () => h(DefaultEmptyImg);
|
||||||
Empty.PRESENTED_IMAGE_SIMPLE = simpleEmptyImg;
|
Empty.PRESENTED_IMAGE_SIMPLE = () => h(SimpleEmptyImg);
|
||||||
|
|
||||||
export default withInstall(Empty);
|
export default withInstall(Empty);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import VerticalAlignTopOutlined from '@ant-design/icons-vue/VerticalAlignTopOutlined';
|
import VerticalAlignTopOutlined from '@ant-design/icons-vue/VerticalAlignTopOutlined';
|
||||||
import { getTransitionProps, Transition } from '../_util/transition';
|
import { getTransitionProps } from '../_util/transition';
|
||||||
import {
|
import {
|
||||||
defineComponent,
|
defineComponent,
|
||||||
nextTick,
|
nextTick,
|
||||||
|
@ -10,6 +10,7 @@ import {
|
||||||
ref,
|
ref,
|
||||||
watch,
|
watch,
|
||||||
onDeactivated,
|
onDeactivated,
|
||||||
|
Transition,
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import FloatButton, { floatButtonPrefixCls } from './FloatButton';
|
import FloatButton, { floatButtonPrefixCls } from './FloatButton';
|
||||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { defineComponent, ref, computed, watch, onBeforeUnmount } from 'vue';
|
import { defineComponent, ref, computed, watch, onBeforeUnmount, Transition } from 'vue';
|
||||||
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
|
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
|
||||||
import FileTextOutlined from '@ant-design/icons-vue/FileTextOutlined';
|
import FileTextOutlined from '@ant-design/icons-vue/FileTextOutlined';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import { getTransitionProps, Transition } from '../_util/transition';
|
import { getTransitionProps } from '../_util/transition';
|
||||||
import FloatButton, { floatButtonPrefixCls } from './FloatButton';
|
import FloatButton, { floatButtonPrefixCls } from './FloatButton';
|
||||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||||
import { useProvideFloatButtonGroupContext } from './context';
|
import { useProvideFloatButtonGroupContext } from './context';
|
||||||
|
|
|
@ -33,11 +33,11 @@ tag: New
|
||||||
| target | 相当于 a 标签的 target 属性,href 存在时生效 | string | - | |
|
| target | 相当于 a 标签的 target 属性,href 存在时生效 | string | - | |
|
||||||
| badge | 带徽标数字的悬浮按钮(不支持 status 以及相关属性) | [BadgeProps](/components/badge-cn#api) | - | |
|
| badge | 带徽标数字的悬浮按钮(不支持 status 以及相关属性) | [BadgeProps](/components/badge-cn#api) | - | |
|
||||||
|
|
||||||
### common events
|
### 共同的事件
|
||||||
|
|
||||||
| 事件名称 | 说明 | 回调参数 | 版本 |
|
| 事件名称 | 说明 | 回调参数 | 版本 |
|
||||||
| -------- | --------------------------------------- | ----------------- | ---- |
|
| -------- | ----------------------------- | ----------------- | ---- |
|
||||||
| click | Set the handler to handle `click` event | `(event) => void` | - |
|
| click | 设置处理 `click` 事件的处理器 | `(event) => void` | - |
|
||||||
|
|
||||||
### FloatButton.Group
|
### FloatButton.Group
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ tag: New
|
||||||
| trigger | 触发方式(有触发方式为菜单模式) | `click` \| `hover` | - | |
|
| trigger | 触发方式(有触发方式为菜单模式) | `click` \| `hover` | - | |
|
||||||
| open(v-model) | 受控展开 | boolean | - | |
|
| open(v-model) | 受控展开 | boolean | - | |
|
||||||
|
|
||||||
### FloatButton.Group Events
|
### FloatButton.Group 事件
|
||||||
|
|
||||||
| 事件名称 | 说明 | 回调参数 | 版本 |
|
| 事件名称 | 说明 | 回调参数 | 版本 |
|
||||||
| ---------- | ---------------- | ----------------------- | ---- |
|
| ---------- | ---------------- | ----------------------- | ---- |
|
||||||
|
|
|
@ -20,7 +20,7 @@ export const floatButtonProps = () => {
|
||||||
shape: stringType<FloatButtonShape>('circle'),
|
shape: stringType<FloatButtonShape>('circle'),
|
||||||
tooltip: PropTypes.any,
|
tooltip: PropTypes.any,
|
||||||
href: String,
|
href: String,
|
||||||
target: functionType<() => Window | HTMLElement | null>(),
|
target: String,
|
||||||
badge: objectType<FloatButtonBadgeProps>(),
|
badge: objectType<FloatButtonBadgeProps>(),
|
||||||
onClick: functionType<MouseEventHandler>(),
|
onClick: functionType<MouseEventHandler>(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -494,7 +494,7 @@ export default defineComponent({
|
||||||
>
|
>
|
||||||
<Row
|
<Row
|
||||||
{...attrs}
|
{...attrs}
|
||||||
class={`${prefixCls.value}-row`}
|
class={`${prefixCls.value}-item-row`}
|
||||||
key="row"
|
key="row"
|
||||||
v-slots={{
|
v-slots={{
|
||||||
default: () => (
|
default: () => (
|
||||||
|
|
|
@ -214,11 +214,13 @@ function useForm(
|
||||||
const errorList = results.filter(
|
const errorList = results.filter(
|
||||||
(result: { errors: string | any[] }) => result && result.errors.length,
|
(result: { errors: string | any[] }) => result && result.errors.length,
|
||||||
);
|
);
|
||||||
return Promise.reject({
|
return errorList.length
|
||||||
|
? Promise.reject({
|
||||||
values,
|
values,
|
||||||
errorFields: errorList,
|
errorFields: errorList,
|
||||||
outOfDate: lastValidatePromise !== summaryPromise,
|
outOfDate: lastValidatePromise !== summaryPromise,
|
||||||
});
|
})
|
||||||
|
: Promise.resolve(values);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Do not throw in console
|
// Do not throw in console
|
||||||
|
|
|
@ -50,6 +50,10 @@ const genGridRowStyle: GenerateStyle<GridRowToken> = (token): CSSObject => {
|
||||||
justifyContent: 'space-around',
|
justifyContent: 'space-around',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'&-space-evenly ': {
|
||||||
|
justifyContent: 'space-evenly',
|
||||||
|
},
|
||||||
|
|
||||||
// Align at the top
|
// Align at the top
|
||||||
'&-top': {
|
'&-top': {
|
||||||
alignItems: 'flex-start',
|
alignItems: 'flex-start',
|
||||||
|
|
|
@ -122,6 +122,8 @@ See [iconfont.cn documents](http://iconfont.cn/help/detail?spm=a313x.7781069.199
|
||||||
|
|
||||||
### Custom SVG Icon
|
### Custom SVG Icon
|
||||||
|
|
||||||
|
#### vue cli 3
|
||||||
|
|
||||||
You can import SVG icon as an vue component by using `vue cli 3` and [`vue-svg-loader`](https://www.npmjs.com/package/vue-svg-loader). `vue-svg-loader`'s `options` [reference](https://github.com/visualfanatic/vue-svg-loader).
|
You can import SVG icon as an vue component by using `vue cli 3` and [`vue-svg-loader`](https://www.npmjs.com/package/vue-svg-loader). `vue-svg-loader`'s `options` [reference](https://github.com/visualfanatic/vue-svg-loader).
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
@ -149,6 +151,84 @@ export default defineComponent({
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Rsbuild
|
||||||
|
|
||||||
|
Rsbuild is a new generation of build tool, official website https://rsbuild.dev/
|
||||||
|
Create your own `vue-svg-loader.js` file, which allows you to customize and beautify SVG, and then configure it in `rsbuild.config.ts`
|
||||||
|
|
||||||
|
```js
|
||||||
|
// vue-svg-loader.js
|
||||||
|
/* eslint-disable */
|
||||||
|
const { optimize } = require('svgo');
|
||||||
|
const { version } = require('vue');
|
||||||
|
const semverMajor = require('semver/functions/major');
|
||||||
|
|
||||||
|
module.exports = async function (svg) {
|
||||||
|
const callback = this.async();
|
||||||
|
|
||||||
|
try {
|
||||||
|
({ data: svg } = await optimize(svg, {
|
||||||
|
path: this.resourcePath,
|
||||||
|
js2svg: {
|
||||||
|
indent: 2,
|
||||||
|
pretty: true,
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
'convertStyleToAttrs',
|
||||||
|
'removeDoctype',
|
||||||
|
'removeXMLProcInst',
|
||||||
|
'removeComments',
|
||||||
|
'removeMetadata',
|
||||||
|
'removeTitle',
|
||||||
|
'removeDesc',
|
||||||
|
'removeStyleElement',
|
||||||
|
'removeXMLNS',
|
||||||
|
'removeXMLProcInst',
|
||||||
|
],
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
callback(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (semverMajor(version) === 2) {
|
||||||
|
svg = svg.replace('<svg', '<svg v-on="$listeners"');
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null, `<template>${svg}</template>`);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
// rsbuild.config.ts
|
||||||
|
/* eslint-disable */
|
||||||
|
import { defineConfig } from '@rsbuild/core';
|
||||||
|
import { pluginVue } from '@rsbuild/plugin-vue';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
tools: {
|
||||||
|
bundlerChain(chain, { CHAIN_ID }) {
|
||||||
|
chain.module.rule(CHAIN_ID.RULE.SVG).exclude.add(/\.svg$/);
|
||||||
|
},
|
||||||
|
rspack: {
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.svg$/,
|
||||||
|
use: ['vue-loader', 'vue-svg-loader'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
resolveLoader: {
|
||||||
|
alias: {
|
||||||
|
'vue-svg-loader': require('path').join(__dirname, './vue-svg-loader.js'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
The following properties are available for the component:
|
The following properties are available for the component:
|
||||||
|
|
||||||
| Property | Description | Type | Default |
|
| Property | Description | Type | Default |
|
||||||
|
|
|
@ -119,7 +119,9 @@ export default defineComponent({
|
||||||
|
|
||||||
### 自定义 SVG 图标
|
### 自定义 SVG 图标
|
||||||
|
|
||||||
如果使用 `vue cli 3`,可以通过配置 [vue-svg-loader](https://www.npmjs.com/package/vue-svg-loader) 来将 `svg` 图标作为 `Vue` 组件导入。更多`vue-svg-loader` 的使用方式请参阅 [文档](https://github.com/visualfanatic/vue-svg-loader)。
|
#### vue cli 3
|
||||||
|
|
||||||
|
可以通过配置 [vue-svg-loader](https://www.npmjs.com/package/vue-svg-loader) 来将 `svg` 图标作为 `Vue` 组件导入。更多`vue-svg-loader` 的使用方式请参阅 [文档](https://github.com/visualfanatic/vue-svg-loader)。
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// vue.config.js
|
// vue.config.js
|
||||||
|
@ -146,6 +148,88 @@ export default defineComponent({
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Rsbuild
|
||||||
|
|
||||||
|
Rsbuild 是新一代构建工具,官网 https://rsbuild.dev/
|
||||||
|
|
||||||
|
自己实现一个 `vue-svg-loader.js` 文件,好处是可以自定义美化 svg,然后在 `rsbuild.config.ts` 中配置:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// vue-svg-loader.js
|
||||||
|
/* eslint-disable */
|
||||||
|
const { optimize } = require('svgo');
|
||||||
|
const { version } = require('vue');
|
||||||
|
const semverMajor = require('semver/functions/major');
|
||||||
|
|
||||||
|
module.exports = async function (svg) {
|
||||||
|
const callback = this.async();
|
||||||
|
|
||||||
|
try {
|
||||||
|
({ data: svg } = await optimize(svg, {
|
||||||
|
path: this.resourcePath,
|
||||||
|
js2svg: {
|
||||||
|
indent: 2,
|
||||||
|
pretty: true,
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
'convertStyleToAttrs',
|
||||||
|
'removeDoctype',
|
||||||
|
'removeXMLProcInst',
|
||||||
|
'removeComments',
|
||||||
|
'removeMetadata',
|
||||||
|
'removeTitle',
|
||||||
|
'removeDesc',
|
||||||
|
'removeStyleElement',
|
||||||
|
'removeXMLNS',
|
||||||
|
'removeXMLProcInst',
|
||||||
|
],
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
callback(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (semverMajor(version) === 2) {
|
||||||
|
svg = svg.replace('<svg', '<svg v-on="$listeners"');
|
||||||
|
}
|
||||||
|
|
||||||
|
callback(null, `<template>${svg}</template>`);
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
// rsbuild.config.ts
|
||||||
|
/* eslint-disable */
|
||||||
|
import { defineConfig } from '@rsbuild/core';
|
||||||
|
import { pluginVue } from '@rsbuild/plugin-vue';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
tools: {
|
||||||
|
bundlerChain(chain, { CHAIN_ID }) {
|
||||||
|
chain.module
|
||||||
|
// 先给svg排除默认的规则,方便下面自定义loader
|
||||||
|
.rule(CHAIN_ID.RULE.SVG)
|
||||||
|
.exclude.add(/\.svg$/);
|
||||||
|
},
|
||||||
|
rspack: {
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.svg$/,
|
||||||
|
use: ['vue-loader', 'vue-svg-loader'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
resolveLoader: {
|
||||||
|
alias: {
|
||||||
|
'vue-svg-loader': require('path').join(__dirname, './vue-svg-loader.js'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
`Icon` 中的 `component` 组件的接受的属性如下:
|
`Icon` 中的 `component` 组件的接受的属性如下:
|
||||||
|
|
||||||
| 字段 | 说明 | 类型 | 只读值 |
|
| 字段 | 说明 | 类型 | 只读值 |
|
||||||
|
|
|
@ -13,10 +13,10 @@ export type ImageProps = Partial<
|
||||||
ExtractPropTypes<ReturnType<typeof imageProps>> &
|
ExtractPropTypes<ReturnType<typeof imageProps>> &
|
||||||
Omit<ImgHTMLAttributes, 'placeholder' | 'onClick'>
|
Omit<ImgHTMLAttributes, 'placeholder' | 'onClick'>
|
||||||
>;
|
>;
|
||||||
const Image = defineComponent<ImageProps>({
|
const Image = defineComponent({
|
||||||
name: 'AImage',
|
name: 'AImage',
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
props: imageProps() as any,
|
props: imageProps(),
|
||||||
setup(props, { slots, attrs }) {
|
setup(props, { slots, attrs }) {
|
||||||
const { prefixCls, rootPrefixCls, configProvider } = useConfigInject('image', props);
|
const { prefixCls, rootPrefixCls, configProvider } = useConfigInject('image', props);
|
||||||
// Style
|
// Style
|
||||||
|
|
|
@ -72,7 +72,7 @@ const InputNumber = defineComponent({
|
||||||
|
|
||||||
const mergedSize = computed(() => compactSize.value || size.value);
|
const mergedSize = computed(() => compactSize.value || size.value);
|
||||||
|
|
||||||
const mergedValue = shallowRef(props.value === undefined ? props.defaultValue : props.value);
|
const mergedValue = shallowRef(props.value ?? props.defaultValue);
|
||||||
const focused = shallowRef(false);
|
const focused = shallowRef(false);
|
||||||
watch(
|
watch(
|
||||||
() => props.value,
|
() => props.value,
|
||||||
|
|
|
@ -34,7 +34,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*1uH-R5kLAMIAAA
|
||||||
| parser | 指定从 formatter 里转换回数字的方式,和 formatter 搭配使用 | function( string): number | - | |
|
| parser | 指定从 formatter 里转换回数字的方式,和 formatter 搭配使用 | function( string): number | - | |
|
||||||
| precision | 数值精度 | number | - | |
|
| precision | 数值精度 | number | - | |
|
||||||
| prefix | 带有前缀图标的 input | slot | - | 3.0 |
|
| prefix | 带有前缀图标的 input | slot | - | 3.0 |
|
||||||
| size | 输入框大小 | string | 无 | |
|
| size | 输入框大小 | string | - | |
|
||||||
| status | 设置校验状态 | 'error' \| 'warning' | - | 3.3.0 |
|
| status | 设置校验状态 | 'error' \| 'warning' | - | 3.3.0 |
|
||||||
| step | 每次改变步数,可以为小数 | number\|string | 1 | |
|
| step | 每次改变步数,可以为小数 | number\|string | 1 | |
|
||||||
| stringMode | 字符值模式,开启后支持高精度小数。同时 `change` 事件将返回 string 类型 | boolean | false | 3.0 |
|
| stringMode | 字符值模式,开启后支持高精度小数。同时 `change` 事件将返回 string 类型 | boolean | false | 3.0 |
|
||||||
|
|
|
@ -395,6 +395,11 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Solve the issue of the event triggering sequence when entering numbers in chinese input (Safari)
|
||||||
|
const onBeforeInput = () => {
|
||||||
|
userTypingRef.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
const onKeyDown: KeyboardEventHandler = event => {
|
const onKeyDown: KeyboardEventHandler = event => {
|
||||||
const { which } = event;
|
const { which } = event;
|
||||||
userTypingRef.value = true;
|
userTypingRef.value = true;
|
||||||
|
@ -577,6 +582,7 @@ export default defineComponent({
|
||||||
onBlur={onBlur}
|
onBlur={onBlur}
|
||||||
onCompositionstart={onCompositionStart}
|
onCompositionstart={onCompositionStart}
|
||||||
onCompositionend={onCompositionEnd}
|
onCompositionend={onCompositionEnd}
|
||||||
|
onBeforeinput={onBeforeInput}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -263,6 +263,10 @@ const genInputNumberStyles: GenerateStyle<InputNumberToken> = (token: InputNumbe
|
||||||
[`${componentCls}-handler-wrap`]: {
|
[`${componentCls}-handler-wrap`]: {
|
||||||
display: 'none',
|
display: 'none',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[`${componentCls}-input`]: {
|
||||||
|
color: 'inherit',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
[`
|
[`
|
||||||
|
|
|
@ -59,7 +59,7 @@ export default defineComponent({
|
||||||
});
|
});
|
||||||
const getIcon = (prefixCls: string) => {
|
const getIcon = (prefixCls: string) => {
|
||||||
const { action, iconRender = slots.iconRender || defaultIconRender } = props;
|
const { action, iconRender = slots.iconRender || defaultIconRender } = props;
|
||||||
const iconTrigger = ActionMap[action!] || '';
|
const iconTrigger = ActionMap[action] || '';
|
||||||
const icon = iconRender(visible.value);
|
const icon = iconRender(visible.value);
|
||||||
const iconProps = {
|
const iconProps = {
|
||||||
[iconTrigger]: onVisibleChange,
|
[iconTrigger]: onVisibleChange,
|
||||||
|
|
|
@ -1,26 +1,26 @@
|
||||||
import type { VNode } from 'vue';
|
import type { CSSProperties } from 'vue';
|
||||||
import {
|
import {
|
||||||
onMounted,
|
computed,
|
||||||
|
watchEffect,
|
||||||
getCurrentInstance,
|
getCurrentInstance,
|
||||||
watch,
|
watch,
|
||||||
onBeforeUnmount,
|
onBeforeUnmount,
|
||||||
ref,
|
ref,
|
||||||
nextTick,
|
|
||||||
defineComponent,
|
defineComponent,
|
||||||
withDirectives,
|
|
||||||
} from 'vue';
|
} from 'vue';
|
||||||
import ResizeObserver from '../vc-resize-observer';
|
import ResizeObserver from '../vc-resize-observer';
|
||||||
import classNames from '../_util/classNames';
|
import classNames from '../_util/classNames';
|
||||||
import calculateNodeHeight from './calculateNodeHeight';
|
|
||||||
import raf from '../_util/raf';
|
import raf from '../_util/raf';
|
||||||
import warning from '../_util/warning';
|
import warning from '../_util/warning';
|
||||||
import antInput from '../_util/antInputDirective';
|
|
||||||
import omit from '../_util/omit';
|
import omit from '../_util/omit';
|
||||||
import { textAreaProps } from './inputProps';
|
import { textAreaProps } from './inputProps';
|
||||||
|
import calculateAutoSizeStyle from './calculateNodeHeight';
|
||||||
|
import type { BaseInputExpose } from '../_util/BaseInput';
|
||||||
|
import BaseInput from '../_util/BaseInput';
|
||||||
|
|
||||||
const RESIZE_STATUS_NONE = 0;
|
const RESIZE_START = 0;
|
||||||
const RESIZE_STATUS_RESIZING = 1;
|
const RESIZE_MEASURING = 1;
|
||||||
const RESIZE_STATUS_RESIZED = 2;
|
const RESIZE_STABLE = 2;
|
||||||
|
|
||||||
const ResizableTextArea = defineComponent({
|
const ResizableTextArea = defineComponent({
|
||||||
compatConfig: { MODE: 3 },
|
compatConfig: { MODE: 3 },
|
||||||
|
@ -30,9 +30,9 @@ const ResizableTextArea = defineComponent({
|
||||||
setup(props, { attrs, emit, expose }) {
|
setup(props, { attrs, emit, expose }) {
|
||||||
let nextFrameActionId: any;
|
let nextFrameActionId: any;
|
||||||
let resizeFrameId: any;
|
let resizeFrameId: any;
|
||||||
const textAreaRef = ref();
|
const textAreaRef = ref<BaseInputExpose>();
|
||||||
const textareaStyles = ref({});
|
const textareaStyles = ref({});
|
||||||
const resizeStatus = ref(RESIZE_STATUS_NONE);
|
const resizeStatus = ref(RESIZE_STABLE);
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
raf.cancel(nextFrameActionId);
|
raf.cancel(nextFrameActionId);
|
||||||
raf.cancel(resizeFrameId);
|
raf.cancel(resizeFrameId);
|
||||||
|
@ -41,10 +41,12 @@ const ResizableTextArea = defineComponent({
|
||||||
// https://github.com/ant-design/ant-design/issues/21870
|
// https://github.com/ant-design/ant-design/issues/21870
|
||||||
const fixFirefoxAutoScroll = () => {
|
const fixFirefoxAutoScroll = () => {
|
||||||
try {
|
try {
|
||||||
if (document.activeElement === textAreaRef.value) {
|
if (textAreaRef.value && document.activeElement === textAreaRef.value.input) {
|
||||||
const currentStart = textAreaRef.value.selectionStart;
|
const currentStart = textAreaRef.value.getSelectionStart();
|
||||||
const currentEnd = textAreaRef.value.selectionEnd;
|
const currentEnd = textAreaRef.value.getSelectionEnd();
|
||||||
|
const scrollTop = textAreaRef.value.getScrollTop();
|
||||||
textAreaRef.value.setSelectionRange(currentStart, currentEnd);
|
textAreaRef.value.setSelectionRange(currentStart, currentEnd);
|
||||||
|
textAreaRef.value.setScrollTop(scrollTop);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Fix error in Chrome:
|
// Fix error in Chrome:
|
||||||
|
@ -52,41 +54,82 @@ const ResizableTextArea = defineComponent({
|
||||||
// http://stackoverflow.com/q/21177489/3040605
|
// http://stackoverflow.com/q/21177489/3040605
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const minRows = ref<number>();
|
||||||
const resizeTextarea = () => {
|
const maxRows = ref<number>();
|
||||||
const autoSize = props.autoSize || props.autosize;
|
watchEffect(() => {
|
||||||
if (!autoSize || !textAreaRef.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { minRows, maxRows } = autoSize;
|
|
||||||
textareaStyles.value = calculateNodeHeight(textAreaRef.value, false, minRows, maxRows);
|
|
||||||
resizeStatus.value = RESIZE_STATUS_RESIZING;
|
|
||||||
raf.cancel(resizeFrameId);
|
|
||||||
resizeFrameId = raf(() => {
|
|
||||||
resizeStatus.value = RESIZE_STATUS_RESIZED;
|
|
||||||
resizeFrameId = raf(() => {
|
|
||||||
resizeStatus.value = RESIZE_STATUS_NONE;
|
|
||||||
fixFirefoxAutoScroll();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const resizeOnNextFrame = () => {
|
|
||||||
raf.cancel(nextFrameActionId);
|
|
||||||
nextFrameActionId = raf(resizeTextarea);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleResize = (size: { width: number; height: number }) => {
|
|
||||||
if (resizeStatus.value !== RESIZE_STATUS_NONE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
emit('resize', size);
|
|
||||||
|
|
||||||
const autoSize = props.autoSize || props.autosize;
|
const autoSize = props.autoSize || props.autosize;
|
||||||
if (autoSize) {
|
if (autoSize) {
|
||||||
resizeOnNextFrame();
|
minRows.value = autoSize.minRows;
|
||||||
|
maxRows.value = autoSize.maxRows;
|
||||||
|
} else {
|
||||||
|
minRows.value = undefined;
|
||||||
|
maxRows.value = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const needAutoSize = computed(() => !!(props.autoSize || props.autosize));
|
||||||
|
const startResize = () => {
|
||||||
|
resizeStatus.value = RESIZE_START;
|
||||||
|
};
|
||||||
|
watch(
|
||||||
|
[() => props.value, minRows, maxRows, needAutoSize],
|
||||||
|
() => {
|
||||||
|
if (needAutoSize.value) {
|
||||||
|
startResize();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
const autoSizeStyle = ref<CSSProperties>();
|
||||||
|
watch(
|
||||||
|
[resizeStatus, textAreaRef],
|
||||||
|
() => {
|
||||||
|
if (!textAreaRef.value) return;
|
||||||
|
if (resizeStatus.value === RESIZE_START) {
|
||||||
|
resizeStatus.value = RESIZE_MEASURING;
|
||||||
|
} else if (resizeStatus.value === RESIZE_MEASURING) {
|
||||||
|
const textareaStyles = calculateAutoSizeStyle(
|
||||||
|
textAreaRef.value.input as HTMLTextAreaElement,
|
||||||
|
false,
|
||||||
|
minRows.value,
|
||||||
|
maxRows.value,
|
||||||
|
);
|
||||||
|
resizeStatus.value = RESIZE_STABLE;
|
||||||
|
autoSizeStyle.value = textareaStyles;
|
||||||
|
} else {
|
||||||
|
fixFirefoxAutoScroll();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true, flush: 'post' },
|
||||||
|
);
|
||||||
|
const instance = getCurrentInstance();
|
||||||
|
const resizeRafRef = ref();
|
||||||
|
const cleanRaf = () => {
|
||||||
|
raf.cancel(resizeRafRef.value);
|
||||||
|
};
|
||||||
|
const onInternalResize = (size: { width: number; height: number }) => {
|
||||||
|
if (resizeStatus.value === RESIZE_STABLE) {
|
||||||
|
emit('resize', size);
|
||||||
|
|
||||||
|
if (needAutoSize.value) {
|
||||||
|
cleanRaf();
|
||||||
|
resizeRafRef.value = raf(() => {
|
||||||
|
startResize();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
cleanRaf();
|
||||||
|
});
|
||||||
|
const resizeTextarea = () => {
|
||||||
|
startResize();
|
||||||
|
};
|
||||||
|
|
||||||
|
expose({
|
||||||
|
resizeTextarea,
|
||||||
|
textArea: computed(() => textAreaRef.value?.input),
|
||||||
|
instance,
|
||||||
|
});
|
||||||
warning(
|
warning(
|
||||||
props.autosize === undefined,
|
props.autosize === undefined,
|
||||||
'Input.TextArea',
|
'Input.TextArea',
|
||||||
|
@ -94,7 +137,7 @@ const ResizableTextArea = defineComponent({
|
||||||
);
|
);
|
||||||
|
|
||||||
const renderTextArea = () => {
|
const renderTextArea = () => {
|
||||||
const { prefixCls, autoSize, autosize, disabled } = props;
|
const { prefixCls, disabled } = props;
|
||||||
const otherProps = omit(props, [
|
const otherProps = omit(props, [
|
||||||
'prefixCls',
|
'prefixCls',
|
||||||
'onPressEnter',
|
'onPressEnter',
|
||||||
|
@ -103,26 +146,26 @@ const ResizableTextArea = defineComponent({
|
||||||
'defaultValue',
|
'defaultValue',
|
||||||
'allowClear',
|
'allowClear',
|
||||||
'type',
|
'type',
|
||||||
'lazy',
|
|
||||||
'maxlength',
|
'maxlength',
|
||||||
'valueModifiers',
|
'valueModifiers',
|
||||||
]);
|
]);
|
||||||
const cls = classNames(prefixCls, attrs.class, {
|
const cls = classNames(prefixCls, attrs.class, {
|
||||||
[`${prefixCls}-disabled`]: disabled,
|
[`${prefixCls}-disabled`]: disabled,
|
||||||
});
|
});
|
||||||
const style = [
|
const mergedAutoSizeStyle = needAutoSize.value ? autoSizeStyle.value : null;
|
||||||
attrs.style,
|
const style = [attrs.style, textareaStyles.value, mergedAutoSizeStyle];
|
||||||
textareaStyles.value,
|
|
||||||
resizeStatus.value === RESIZE_STATUS_RESIZING
|
|
||||||
? { overflowX: 'hidden', overflowY: 'hidden' }
|
|
||||||
: null,
|
|
||||||
];
|
|
||||||
const textareaProps: any = {
|
const textareaProps: any = {
|
||||||
...otherProps,
|
...otherProps,
|
||||||
...attrs,
|
...attrs,
|
||||||
style,
|
style,
|
||||||
class: cls,
|
class: cls,
|
||||||
};
|
};
|
||||||
|
if (resizeStatus.value === RESIZE_START || resizeStatus.value === RESIZE_MEASURING) {
|
||||||
|
style.push({
|
||||||
|
overflowX: 'hidden',
|
||||||
|
overflowY: 'hidden',
|
||||||
|
});
|
||||||
|
}
|
||||||
if (!textareaProps.autofocus) {
|
if (!textareaProps.autofocus) {
|
||||||
delete textareaProps.autofocus;
|
delete textareaProps.autofocus;
|
||||||
}
|
}
|
||||||
|
@ -130,34 +173,12 @@ const ResizableTextArea = defineComponent({
|
||||||
delete textareaProps.rows;
|
delete textareaProps.rows;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ResizeObserver onResize={handleResize} disabled={!(autoSize || autosize)}>
|
<ResizeObserver onResize={onInternalResize} disabled={!needAutoSize.value}>
|
||||||
{withDirectives((<textarea {...textareaProps} ref={textAreaRef} />) as VNode, [
|
<BaseInput {...textareaProps} ref={textAreaRef} tag="textarea"></BaseInput>
|
||||||
[antInput],
|
|
||||||
])}
|
|
||||||
</ResizeObserver>
|
</ResizeObserver>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.value,
|
|
||||||
() => {
|
|
||||||
nextTick(() => {
|
|
||||||
resizeTextarea();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
onMounted(() => {
|
|
||||||
nextTick(() => {
|
|
||||||
resizeTextarea();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
const instance = getCurrentInstance();
|
|
||||||
expose({
|
|
||||||
resizeTextarea,
|
|
||||||
textArea: textAreaRef,
|
|
||||||
instance,
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
return renderTextArea();
|
return renderTextArea();
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,10 +38,10 @@ function setTriggerValue(
|
||||||
let newTriggerValue = triggerValue;
|
let newTriggerValue = triggerValue;
|
||||||
if (isCursorInEnd) {
|
if (isCursorInEnd) {
|
||||||
// 光标在尾部,直接截断
|
// 光标在尾部,直接截断
|
||||||
newTriggerValue = fixEmojiLength(triggerValue, maxLength!);
|
newTriggerValue = fixEmojiLength(triggerValue, maxLength);
|
||||||
} else if (
|
} else if (
|
||||||
[...(preValue || '')].length < triggerValue.length &&
|
[...(preValue || '')].length < triggerValue.length &&
|
||||||
[...(triggerValue || '')].length > maxLength!
|
[...(triggerValue || '')].length > maxLength
|
||||||
) {
|
) {
|
||||||
// 光标在中间,如果最后的值超过最大值,则采用原先的值
|
// 光标在中间,如果最后的值超过最大值,则采用原先的值
|
||||||
newTriggerValue = preValue;
|
newTriggerValue = preValue;
|
||||||
|
@ -58,7 +58,7 @@ export default defineComponent({
|
||||||
const formItemContext = useInjectFormItemContext();
|
const formItemContext = useInjectFormItemContext();
|
||||||
const formItemInputContext = FormItemInputContext.useInject();
|
const formItemInputContext = FormItemInputContext.useInject();
|
||||||
const mergedStatus = computed(() => getMergedStatus(formItemInputContext.status, props.status));
|
const mergedStatus = computed(() => getMergedStatus(formItemInputContext.status, props.status));
|
||||||
const stateValue = shallowRef(props.value === undefined ? props.defaultValue : props.value);
|
const stateValue = shallowRef(props.value ?? props.defaultValue);
|
||||||
const resizableTextArea = shallowRef();
|
const resizableTextArea = shallowRef();
|
||||||
const mergedValue = shallowRef('');
|
const mergedValue = shallowRef('');
|
||||||
const { prefixCls, size, direction } = useConfigInject('input', props);
|
const { prefixCls, size, direction } = useConfigInject('input', props);
|
||||||
|
@ -79,7 +79,7 @@ export default defineComponent({
|
||||||
const onInternalCompositionStart = (e: CompositionEvent) => {
|
const onInternalCompositionStart = (e: CompositionEvent) => {
|
||||||
compositing.value = true;
|
compositing.value = true;
|
||||||
// 拼音输入前保存一份旧值
|
// 拼音输入前保存一份旧值
|
||||||
oldCompositionValueRef.value = mergedValue.value as string;
|
oldCompositionValueRef.value = mergedValue.value;
|
||||||
// 保存旧的光标位置
|
// 保存旧的光标位置
|
||||||
oldSelectionStartRef.value = (e.currentTarget as any).selectionStart;
|
oldSelectionStartRef.value = (e.currentTarget as any).selectionStart;
|
||||||
emit('compositionstart', e);
|
emit('compositionstart', e);
|
||||||
|
@ -94,7 +94,7 @@ export default defineComponent({
|
||||||
oldSelectionStartRef.value === oldCompositionValueRef.value?.length;
|
oldSelectionStartRef.value === oldCompositionValueRef.value?.length;
|
||||||
triggerValue = setTriggerValue(
|
triggerValue = setTriggerValue(
|
||||||
isCursorInEnd,
|
isCursorInEnd,
|
||||||
oldCompositionValueRef.value as string,
|
oldCompositionValueRef.value,
|
||||||
triggerValue,
|
triggerValue,
|
||||||
props.maxlength,
|
props.maxlength,
|
||||||
);
|
);
|
||||||
|
@ -170,23 +170,21 @@ export default defineComponent({
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChange = (e: Event) => {
|
const handleChange = (e: Event) => {
|
||||||
const { composing } = e.target as any;
|
|
||||||
let triggerValue = (e.target as any).value;
|
let triggerValue = (e.target as any).value;
|
||||||
compositing.value = !!((e as any).isComposing || composing);
|
if (stateValue.value === triggerValue) return;
|
||||||
if ((compositing.value && props.lazy) || stateValue.value === triggerValue) return;
|
|
||||||
|
|
||||||
if (hasMaxLength.value) {
|
if (hasMaxLength.value) {
|
||||||
// 1. 复制粘贴超过maxlength的情况 2.未超过maxlength的情况
|
// 1. 复制粘贴超过maxlength的情况 2.未超过maxlength的情况
|
||||||
const target = e.target as any;
|
const target = e.target as any;
|
||||||
const isCursorInEnd =
|
const isCursorInEnd =
|
||||||
target.selectionStart >= props.maxlength! + 1 ||
|
target.selectionStart >= props.maxlength + 1 ||
|
||||||
target.selectionStart === triggerValue.length ||
|
target.selectionStart === triggerValue.length ||
|
||||||
!target.selectionStart;
|
!target.selectionStart;
|
||||||
triggerValue = setTriggerValue(
|
triggerValue = setTriggerValue(
|
||||||
isCursorInEnd,
|
isCursorInEnd,
|
||||||
mergedValue.value as string,
|
mergedValue.value,
|
||||||
triggerValue,
|
triggerValue,
|
||||||
props.maxlength!,
|
props.maxlength,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
resolveOnChange(e.currentTarget as any, e, triggerChange, triggerValue);
|
resolveOnChange(e.currentTarget as any, e, triggerChange, triggerValue);
|
||||||
|
@ -227,6 +225,7 @@ export default defineComponent({
|
||||||
id={resizeProps?.id ?? formItemContext.id.value}
|
id={resizeProps?.id ?? formItemContext.id.value}
|
||||||
ref={resizableTextArea}
|
ref={resizableTextArea}
|
||||||
maxlength={props.maxlength}
|
maxlength={props.maxlength}
|
||||||
|
lazy={props.lazy}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -238,7 +237,7 @@ export default defineComponent({
|
||||||
});
|
});
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
let val = fixControlledValue(stateValue.value) as string;
|
let val = fixControlledValue(stateValue.value);
|
||||||
if (
|
if (
|
||||||
!compositing.value &&
|
!compositing.value &&
|
||||||
hasMaxLength.value &&
|
hasMaxLength.value &&
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
// Thanks to https://github.com/andreypopp/react-textarea-autosize/
|
|
||||||
|
|
||||||
import type { CSSProperties } from 'vue';
|
import type { CSSProperties } from 'vue';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* calculateNodeHeight(uiTextNode, useCache = false)
|
* calculateNodeHeight(uiTextNode, useCache = false)
|
||||||
*/
|
*/
|
||||||
|
@ -15,7 +12,8 @@ const HIDDEN_TEXTAREA_STYLE = `
|
||||||
position:absolute !important;
|
position:absolute !important;
|
||||||
z-index:-1000 !important;
|
z-index:-1000 !important;
|
||||||
top:0 !important;
|
top:0 !important;
|
||||||
right:0 !important
|
right:0 !important;
|
||||||
|
pointer-events: none !important;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const SIZING_STYLE = [
|
const SIZING_STYLE = [
|
||||||
|
@ -36,6 +34,7 @@ const SIZING_STYLE = [
|
||||||
'border-width',
|
'border-width',
|
||||||
'box-sizing',
|
'box-sizing',
|
||||||
'word-break',
|
'word-break',
|
||||||
|
'white-space',
|
||||||
];
|
];
|
||||||
|
|
||||||
export interface NodeType {
|
export interface NodeType {
|
||||||
|
@ -45,13 +44,12 @@ export interface NodeType {
|
||||||
boxSizing: string;
|
boxSizing: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const computedStyleCache: { [key: string]: NodeType } = {};
|
const computedStyleCache: Record<string, NodeType> = {};
|
||||||
let hiddenTextarea: HTMLTextAreaElement;
|
let hiddenTextarea: HTMLTextAreaElement;
|
||||||
|
|
||||||
export function calculateNodeStyling(node: HTMLElement, useCache = false) {
|
export function calculateNodeStyling(node: HTMLElement, useCache = false) {
|
||||||
const nodeRef = (node.getAttribute('id') ||
|
const nodeRef =
|
||||||
node.getAttribute('data-reactid') ||
|
node.getAttribute('id') || node.getAttribute('data-reactid') || node.getAttribute('name');
|
||||||
node.getAttribute('name')) as string;
|
|
||||||
|
|
||||||
if (useCache && computedStyleCache[nodeRef]) {
|
if (useCache && computedStyleCache[nodeRef]) {
|
||||||
return computedStyleCache[nodeRef];
|
return computedStyleCache[nodeRef];
|
||||||
|
@ -88,7 +86,7 @@ export function calculateNodeStyling(node: HTMLElement, useCache = false) {
|
||||||
return nodeInfo;
|
return nodeInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function calculateNodeHeight(
|
export default function calculateAutoSizeStyle(
|
||||||
uiTextNode: HTMLTextAreaElement,
|
uiTextNode: HTMLTextAreaElement,
|
||||||
useCache = false,
|
useCache = false,
|
||||||
minRows: number | null = null,
|
minRows: number | null = null,
|
||||||
|
@ -104,7 +102,7 @@ export default function calculateNodeHeight(
|
||||||
// Fix wrap="off" issue
|
// Fix wrap="off" issue
|
||||||
// https://github.com/ant-design/ant-design/issues/6577
|
// https://github.com/ant-design/ant-design/issues/6577
|
||||||
if (uiTextNode.getAttribute('wrap')) {
|
if (uiTextNode.getAttribute('wrap')) {
|
||||||
hiddenTextarea.setAttribute('wrap', uiTextNode.getAttribute('wrap') as string);
|
hiddenTextarea.setAttribute('wrap', uiTextNode.getAttribute('wrap'));
|
||||||
} else {
|
} else {
|
||||||
hiddenTextarea.removeAttribute('wrap');
|
hiddenTextarea.removeAttribute('wrap');
|
||||||
}
|
}
|
||||||
|
@ -122,11 +120,12 @@ export default function calculateNodeHeight(
|
||||||
hiddenTextarea.setAttribute('style', `${sizingStyle};${HIDDEN_TEXTAREA_STYLE}`);
|
hiddenTextarea.setAttribute('style', `${sizingStyle};${HIDDEN_TEXTAREA_STYLE}`);
|
||||||
hiddenTextarea.value = uiTextNode.value || uiTextNode.placeholder || '';
|
hiddenTextarea.value = uiTextNode.value || uiTextNode.placeholder || '';
|
||||||
|
|
||||||
let minHeight = Number.MIN_SAFE_INTEGER;
|
let minHeight: number | undefined = undefined;
|
||||||
let maxHeight = Number.MAX_SAFE_INTEGER;
|
let maxHeight: number | undefined = undefined;
|
||||||
let height = hiddenTextarea.scrollHeight;
|
|
||||||
let overflowY: any;
|
let overflowY: any;
|
||||||
|
|
||||||
|
let height = hiddenTextarea.scrollHeight;
|
||||||
|
|
||||||
if (boxSizing === 'border-box') {
|
if (boxSizing === 'border-box') {
|
||||||
// border-box: add border, since height = content + padding + border
|
// border-box: add border, since height = content + padding + border
|
||||||
height += borderSize;
|
height += borderSize;
|
||||||
|
@ -155,11 +154,19 @@ export default function calculateNodeHeight(
|
||||||
height = Math.min(maxHeight, height);
|
height = Math.min(maxHeight, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
|
||||||
|
const style: CSSProperties = {
|
||||||
height: `${height}px`,
|
height: `${height}px`,
|
||||||
minHeight: `${minHeight}px`,
|
|
||||||
maxHeight: `${maxHeight}px`,
|
|
||||||
overflowY,
|
overflowY,
|
||||||
resize: 'none',
|
resize: 'none',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (minHeight) {
|
||||||
|
style.minHeight = `${minHeight}px`;
|
||||||
|
}
|
||||||
|
if (maxHeight) {
|
||||||
|
style.maxHeight = `${maxHeight}px`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return style;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ A basic widget for getting the user input is a text field. Keyboard and mouse ca
|
||||||
| id | The ID for input | string | | |
|
| id | The ID for input | string | | |
|
||||||
| maxlength | max length | number | | 1.5.0 |
|
| maxlength | max length | number | | 1.5.0 |
|
||||||
| prefix | The prefix icon for the Input. | string\|slot | | |
|
| prefix | The prefix icon for the Input. | string\|slot | | |
|
||||||
| showCount | Whether show text count | boolean | false | 3.0 |
|
| showCount | Whether show text count | boolean \| { formatter: (info: { value: string, count: number, maxLength?: number }) => string | false | 3.0 |
|
||||||
| status | Set validation status | 'error' \| 'warning' | - | 3.3.0 |
|
| status | Set validation status | 'error' \| 'warning' | - | 3.3.0 |
|
||||||
| size | The size of the input box. Note: in the context of a form, the `middle` size is used. Available: `large` `middle` `small` | string | - | |
|
| size | The size of the input box. Note: in the context of a form, the `middle` size is used. Available: `large` `middle` `small` | string | - | |
|
||||||
| suffix | The suffix icon for the Input. | string\|slot | | |
|
| suffix | The suffix icon for the Input. | string\|slot | | |
|
||||||
|
@ -52,7 +52,7 @@ A basic widget for getting the user input is a text field. Keyboard and mouse ca
|
||||||
| allowClear | allow to remove input content with clear icon | boolean | | 1.5.0 | |
|
| allowClear | allow to remove input content with clear icon | boolean | | 1.5.0 | |
|
||||||
| autosize | Height autosize feature, can be set to `true | false`or an object`{ minRows: 2, maxRows: 6 }` | boolean\|object | false | |
|
| autosize | Height autosize feature, can be set to `true | false`or an object`{ minRows: 2, maxRows: 6 }` | boolean\|object | false | |
|
||||||
| defaultValue | The initial input content | string | | | |
|
| defaultValue | The initial input content | string | | | |
|
||||||
| showCount | Whether show text count | boolean | false | | |
|
| showCount | Whether show text count | boolean \| { formatter: (info: { value: string, count: number, maxLength?: number }) => string | false | | |
|
||||||
| value(v-model) | The input content value | string | | | |
|
| value(v-model) | The input content value | string | | | |
|
||||||
|
|
||||||
### TextArea Events
|
### TextArea Events
|
||||||
|
|
|
@ -30,7 +30,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*sBqqTatJ-AkAAA
|
||||||
| id | 输入框的 id | string | | |
|
| id | 输入框的 id | string | | |
|
||||||
| maxlength | 最大长度 | number | | 1.5.0 |
|
| maxlength | 最大长度 | number | | 1.5.0 |
|
||||||
| prefix | 带有前缀图标的 input | string\|slot | | |
|
| prefix | 带有前缀图标的 input | string\|slot | | |
|
||||||
| showCount | 是否展示字数 | boolean | false | 3.0 |
|
| showCount | 是否展示字数 | boolean \| { formatter: (info: { value: string, count: number, maxLength?: number }) => string } | false | 3.0 |
|
||||||
| status | 设置校验状态 | 'error' \| 'warning' | - | 3.3.0 |
|
| status | 设置校验状态 | 'error' \| 'warning' | - | 3.3.0 |
|
||||||
| size | 控件大小。注:标准表单内的输入框大小限制为 `middle`。可选 `large` `middle` `small` | string | - | |
|
| size | 控件大小。注:标准表单内的输入框大小限制为 `middle`。可选 `large` `middle` `small` | string | - | |
|
||||||
| suffix | 带有后缀图标的 input | string\|slot | | |
|
| suffix | 带有后缀图标的 input | string\|slot | | |
|
||||||
|
@ -53,7 +53,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*sBqqTatJ-AkAAA
|
||||||
| allowClear | 可以点击清除图标删除内容 | boolean | | 1.5.0 | |
|
| allowClear | 可以点击清除图标删除内容 | boolean | | 1.5.0 | |
|
||||||
| autosize | 自适应内容高度,可设置为 `true | false` 或对象:`{ minRows: 2, maxRows: 6 }` | boolean\|object | false | |
|
| autosize | 自适应内容高度,可设置为 `true | false` 或对象:`{ minRows: 2, maxRows: 6 }` | boolean\|object | false | |
|
||||||
| defaultValue | 输入框默认内容 | string | | | |
|
| defaultValue | 输入框默认内容 | string | | | |
|
||||||
| showCount | 是否展示字数 | boolean | false | | |
|
_| showCount | 是否展示字数 | boolean \| { formatter: (info: { value: string, count: number, maxLength?: number }) => string } | false | | |_
|
||||||
| value(v-model) | 输入框内容 | string | | | |
|
| value(v-model) | 输入框内容 | string | | | |
|
||||||
|
|
||||||
### TextArea 事件
|
### TextArea 事件
|
||||||
|
|
|
@ -45,6 +45,7 @@ const genLayoutStyle: GenerateStyle<LayoutToken, CSSObject> = token => {
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flex: 'auto',
|
flex: 'auto',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
|
color: colorText,
|
||||||
|
|
||||||
/* fix firefox can't set height smaller than content on flex item */
|
/* fix firefox can't set height smaller than content on flex item */
|
||||||
minHeight: 0,
|
minHeight: 0,
|
||||||
|
|
|
@ -139,6 +139,7 @@ const localeValues: Locale = {
|
||||||
QRCode: {
|
QRCode: {
|
||||||
expired: 'QR code expired',
|
expired: 'QR code expired',
|
||||||
refresh: 'Refresh',
|
refresh: 'Refresh',
|
||||||
|
scanned: 'Scanned',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,7 @@ export interface Locale {
|
||||||
QRCode?: {
|
QRCode?: {
|
||||||
expired?: string;
|
expired?: string;
|
||||||
refresh?: string;
|
refresh?: string;
|
||||||
|
scanned?: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,11 @@ const localeValues: Locale = {
|
||||||
triggerAsc: 'Нажмите для сортировки по возрастанию',
|
triggerAsc: 'Нажмите для сортировки по возрастанию',
|
||||||
cancelSort: 'Нажмите, чтобы отменить сортировку',
|
cancelSort: 'Нажмите, чтобы отменить сортировку',
|
||||||
},
|
},
|
||||||
|
Tour: {
|
||||||
|
Next: 'Вперёд',
|
||||||
|
Previous: 'Назад',
|
||||||
|
Finish: 'Готово',
|
||||||
|
},
|
||||||
Modal: {
|
Modal: {
|
||||||
okText: 'OK',
|
okText: 'OK',
|
||||||
cancelText: 'Отмена',
|
cancelText: 'Отмена',
|
||||||
|
@ -78,6 +83,7 @@ const localeValues: Locale = {
|
||||||
back: 'Назад',
|
back: 'Назад',
|
||||||
},
|
},
|
||||||
Form: {
|
Form: {
|
||||||
|
optional: '(опционально)',
|
||||||
defaultValidateMessages: {
|
defaultValidateMessages: {
|
||||||
default: 'Ошибка проверки поля ${label}',
|
default: 'Ошибка проверки поля ${label}',
|
||||||
required: 'Пожалуйста, введите ${label}',
|
required: 'Пожалуйста, введите ${label}',
|
||||||
|
@ -128,6 +134,11 @@ const localeValues: Locale = {
|
||||||
Image: {
|
Image: {
|
||||||
preview: 'Предпросмотр',
|
preview: 'Предпросмотр',
|
||||||
},
|
},
|
||||||
|
QRCode: {
|
||||||
|
expired: 'QR код просрочен',
|
||||||
|
refresh: 'Обновить',
|
||||||
|
scanned: 'Отсканирован',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default localeValues;
|
export default localeValues;
|
||||||
|
|
|
@ -138,6 +138,7 @@ const localeValues: Locale = {
|
||||||
QRCode: {
|
QRCode: {
|
||||||
expired: '二维码已过期',
|
expired: '二维码已过期',
|
||||||
refresh: '点击刷新',
|
refresh: '点击刷新',
|
||||||
|
scanned: '已扫描',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,11 @@ const localeValues: Locale = {
|
||||||
Image: {
|
Image: {
|
||||||
preview: '預覽',
|
preview: '預覽',
|
||||||
},
|
},
|
||||||
|
QRCode: {
|
||||||
|
expired: '二維碼過期',
|
||||||
|
refresh: '點擊刷新',
|
||||||
|
scanned: '已掃描',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default localeValues;
|
export default localeValues;
|
||||||
|
|
|
@ -132,6 +132,11 @@ const localeValues: Locale = {
|
||||||
Image: {
|
Image: {
|
||||||
preview: '預覽',
|
preview: '預覽',
|
||||||
},
|
},
|
||||||
|
QRCode: {
|
||||||
|
expired: '二維碼過期',
|
||||||
|
refresh: '點擊刷新',
|
||||||
|
scanned: '已掃描',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default localeValues;
|
export default localeValues;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
order: 4
|
order: 4
|
||||||
title:
|
title:
|
||||||
zh-CN: 向上展开
|
zh-CN: 向上展开
|
||||||
en-US: Placemen
|
en-US: Placement
|
||||||
---
|
---
|
||||||
|
|
||||||
## zh-CN
|
## zh-CN
|
||||||
|
|
|
@ -30,7 +30,7 @@ More layouts with navigation: [Layout](/components/layout).
|
||||||
| forceSubMenuRender | render submenu into DOM before it shows | boolean | false |
|
| forceSubMenuRender | render submenu into DOM before it shows | boolean | false |
|
||||||
| inlineCollapsed | specifies the collapsed status when menu is inline mode | boolean | - |
|
| inlineCollapsed | specifies the collapsed status when menu is inline mode | boolean | - |
|
||||||
| inlineIndent | indent px of inline menu item on each level | number | 24 |
|
| inlineIndent | indent px of inline menu item on each level | number | 24 |
|
||||||
| items | Menu item content | [ItemType\[\]](#ItemType) | - | 4.20.0 |
|
| items | Menu item content | [ItemType\[\]](#itemtype) | - | 4.20.0 |
|
||||||
| mode | type of the menu; `vertical`, `horizontal`, and `inline` modes are supported | `vertical` \| `horizontal` \| `inline` | `vertical` |
|
| mode | type of the menu; `vertical`, `horizontal`, and `inline` modes are supported | `vertical` \| `horizontal` \| `inline` | `vertical` |
|
||||||
| multiple | Allow selection of multiple items | boolean | false |
|
| multiple | Allow selection of multiple items | boolean | false |
|
||||||
| openKeys(v-model) | array with the keys of currently opened sub menus | (string \| number)[] | |
|
| openKeys(v-model) | array with the keys of currently opened sub menus | (string \| number)[] | |
|
||||||
|
@ -55,14 +55,14 @@ More layouts with navigation: [Layout](/components/layout).
|
||||||
### Menu.Item
|
### Menu.Item
|
||||||
|
|
||||||
| Param | Description | Type | Default value |
|
| Param | Description | Type | Default value |
|
||||||
| -------- | ------------------------------------ | -------------- | ------------- |
|
| -------- | ------------------------------------ | ---------------- | ------------- |
|
||||||
| disabled | whether menu item is disabled or not | boolean | false |
|
| disabled | whether menu item is disabled or not | boolean | false |
|
||||||
| key | unique id of the menu item | string \| number | |
|
| key | unique id of the menu item | string \| number | |
|
||||||
| title | set display title for collapsed item | string \| slot | |
|
| title | set display title for collapsed item | string \| slot | |
|
||||||
|
|
||||||
### ItemType
|
### ItemType
|
||||||
|
|
||||||
> type ItemType = [MenuItemType](#MenuItemType) | [SubMenuType](#SubMenuType) | [MenuItemGroupType](#MenuItemGroupType) | [MenuDividerType](#MenuDividerType);
|
> type ItemType = [MenuItemType](#menuitemtype) | [SubMenuType](#submenutype) | [MenuItemGroupType](#menuitemgrouptype) | [MenuDividerType](#menudividertype);
|
||||||
|
|
||||||
#### MenuItemType
|
#### MenuItemType
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ More layouts with navigation: [Layout](/components/layout).
|
||||||
<!-- prettier-ignore -->
|
<!-- prettier-ignore -->
|
||||||
| Property | Description | Type | Default value | Version |
|
| Property | Description | Type | Default value | Version |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| children | Sub-menus or sub-menu items | [ItemType\[\]](#ItemType) | - | |
|
| children | Sub-menus or sub-menu items | [ItemType\[\]](#itemtype) | - | |
|
||||||
| disabled | Whether sub-menu is disabled | boolean | false | |
|
| disabled | Whether sub-menu is disabled | boolean | false | |
|
||||||
| icon | Icon of sub menu | VueNode \| (item: SubMenuType) => VueNode | - | |
|
| icon | Icon of sub menu | VueNode \| (item: SubMenuType) => VueNode | - | |
|
||||||
| key | Unique ID of the sub-menu | string \| number | - | |
|
| key | Unique ID of the sub-menu | string \| number | - | |
|
||||||
|
@ -104,7 +104,7 @@ const groupItem = {
|
||||||
|
|
||||||
| Param | Description | Type | Default value | Version |
|
| Param | Description | Type | Default value | Version |
|
||||||
| -------- | ---------------------- | --------------------------------- | ------------- | ------- |
|
| -------- | ---------------------- | --------------------------------- | ------------- | ------- |
|
||||||
| children | Sub-menu items | [MenuItemType\[\]](#MenuItemType) | - | |
|
| children | Sub-menu items | [MenuItemType\[\]](#menuitemtype) | - | |
|
||||||
| label | The title of the group | VueNode | - | |
|
| label | The title of the group | VueNode | - | |
|
||||||
|
|
||||||
#### MenuDividerType
|
#### MenuDividerType
|
||||||
|
|
|
@ -31,7 +31,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*Vn4XSqJFAxcAAA
|
||||||
| forceSubMenuRender | 在子菜单展示之前就渲染进 DOM | boolean | false |
|
| forceSubMenuRender | 在子菜单展示之前就渲染进 DOM | boolean | false |
|
||||||
| inlineCollapsed | inline 时菜单是否收起状态 | boolean | - |
|
| inlineCollapsed | inline 时菜单是否收起状态 | boolean | - |
|
||||||
| inlineIndent | inline 模式的菜单缩进宽度 | number | 24 |
|
| inlineIndent | inline 模式的菜单缩进宽度 | number | 24 |
|
||||||
| items | 菜单内容 | [ItemType\[\]](#ItemType) | - | |
|
| items | 菜单内容 | [ItemType\[\]](#itemtype) | - | |
|
||||||
| mode | 菜单类型,现在支持垂直、水平、和内嵌模式三种 | `vertical` \| `horizontal` \| `inline` | `vertical` |
|
| mode | 菜单类型,现在支持垂直、水平、和内嵌模式三种 | `vertical` \| `horizontal` \| `inline` | `vertical` |
|
||||||
| multiple | 是否允许多选 | boolean | false |
|
| multiple | 是否允许多选 | boolean | false |
|
||||||
| openKeys(v-model) | 当前展开的 SubMenu 菜单项 key 数组 | (string \| number)[] | |
|
| openKeys(v-model) | 当前展开的 SubMenu 菜单项 key 数组 | (string \| number)[] | |
|
||||||
|
@ -46,7 +46,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*Vn4XSqJFAxcAAA
|
||||||
### Menu 事件
|
### Menu 事件
|
||||||
|
|
||||||
| 事件名称 | 说明 | 回调参数 |
|
| 事件名称 | 说明 | 回调参数 |
|
||||||
| ---------- | ---------------------------------- | ------------------------------------- |
|
| ---------- | ---------------------------------- | ---------------------------------------- |
|
||||||
| click | 点击 MenuItem 调用此函数 | function({ item, key, keyPath }) |
|
| click | 点击 MenuItem 调用此函数 | function({ item, key, keyPath }) |
|
||||||
| deselect | 取消选中时调用,仅在 multiple 生效 | function({ item, key, selectedKeys }) |
|
| deselect | 取消选中时调用,仅在 multiple 生效 | function({ item, key, selectedKeys }) |
|
||||||
| openChange | SubMenu 展开/关闭的回调 | function(openKeys: (string \| number)[]) |
|
| openChange | SubMenu 展开/关闭的回调 | function(openKeys: (string \| number)[]) |
|
||||||
|
@ -55,7 +55,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*Vn4XSqJFAxcAAA
|
||||||
### Menu.Item
|
### Menu.Item
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
| -------- | ------------------------ | -------------- | ------ | ----- |
|
| -------- | ------------------------ | ---------------- | ------ | ----- |
|
||||||
| disabled | 是否禁用 | boolean | false | |
|
| disabled | 是否禁用 | boolean | false | |
|
||||||
| icon | 菜单图标 | slot | | 2.8.0 |
|
| icon | 菜单图标 | slot | | 2.8.0 |
|
||||||
| key | item 的唯一标志 | string \| number | | |
|
| key | item 的唯一标志 | string \| number | | |
|
||||||
|
@ -63,7 +63,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*Vn4XSqJFAxcAAA
|
||||||
|
|
||||||
### ItemType
|
### ItemType
|
||||||
|
|
||||||
> type ItemType = [MenuItemType](#MenuItemType) | [SubMenuType](#SubMenuType) | [MenuItemGroupType](#MenuItemGroupType) | [MenuDividerType](#MenuDividerType);
|
> type ItemType = [MenuItemType](#menuitemtype) | [SubMenuType](#submenutype) | [MenuItemGroupType](#menuitemgrouptype) | [MenuDividerType](#menudividertype);
|
||||||
|
|
||||||
### MenuItemType
|
### MenuItemType
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*Vn4XSqJFAxcAAA
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| children | 子菜单的菜单项 | [ItemType\[\]](#ItemType) | - | |
|
| children | 子菜单的菜单项 | [ItemType\[\]](#itemtype) | - | |
|
||||||
| disabled | 是否禁用 | boolean | false | |
|
| disabled | 是否禁用 | boolean | false | |
|
||||||
| icon | 菜单图标 | VueNode\|(item: SubMenuType)=>VueNode | - | |
|
| icon | 菜单图标 | VueNode\|(item: SubMenuType)=>VueNode | - | |
|
||||||
| key | 唯一标志 | string \| number | - | |
|
| key | 唯一标志 | string \| number | - | |
|
||||||
|
@ -104,7 +104,7 @@ const groupItem = {
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
| -------- | ------------ | --------------------------------- | ------ | ---- |
|
| -------- | ------------ | --------------------------------- | ------ | ---- |
|
||||||
| children | 分组的菜单项 | [MenuItemType\[\]](#MenuItemType) | - | |
|
| children | 分组的菜单项 | [MenuItemType\[\]](#menuitemtype) | - | |
|
||||||
| label | 分组标题 | VueNode | - | |
|
| label | 分组标题 | VueNode | - | |
|
||||||
|
|
||||||
#### MenuDividerType
|
#### MenuDividerType
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { computed, defineComponent, ref, watch } from 'vue';
|
import { computed, Transition, defineComponent, ref, watch } from 'vue';
|
||||||
import Transition from '../../_util/transition';
|
|
||||||
import { useInjectMenu, MenuContextProvider } from './hooks/useMenuContext';
|
import { useInjectMenu, MenuContextProvider } from './hooks/useMenuContext';
|
||||||
import type { MenuMode } from './interface';
|
import type { MenuMode } from './interface';
|
||||||
import SubMenuList from './SubMenuList';
|
import SubMenuList from './SubMenuList';
|
||||||
|
|
|
@ -112,7 +112,7 @@ export default defineComponent({
|
||||||
return !override;
|
return !override;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
const store = shallowRef<Map<string, StoreMenuInfo>>(new Map());
|
const store = shallowRef(new Map<string, StoreMenuInfo>());
|
||||||
const siderCollapsed = inject(SiderCollapsedKey, ref(undefined));
|
const siderCollapsed = inject(SiderCollapsedKey, ref(undefined));
|
||||||
const inlineCollapsed = computed(() => {
|
const inlineCollapsed = computed(() => {
|
||||||
if (siderCollapsed.value !== undefined) {
|
if (siderCollapsed.value !== undefined) {
|
||||||
|
@ -341,7 +341,7 @@ export default defineComponent({
|
||||||
const rootPrefixCls = computed(() => getPrefixCls());
|
const rootPrefixCls = computed(() => getPrefixCls());
|
||||||
const defaultMotions = computed(() => ({
|
const defaultMotions = computed(() => ({
|
||||||
horizontal: { name: `${rootPrefixCls.value}-slide-up` },
|
horizontal: { name: `${rootPrefixCls.value}-slide-up` },
|
||||||
inline: collapseMotion,
|
inline: collapseMotion(`${rootPrefixCls.value}-motion-collapse`),
|
||||||
other: { name: `${rootPrefixCls.value}-zoom-big` },
|
other: { name: `${rootPrefixCls.value}-zoom-big` },
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -439,15 +439,17 @@ export default defineComponent({
|
||||||
forceSubMenuRender: computed(() => props.forceSubMenuRender),
|
forceSubMenuRender: computed(() => props.forceSubMenuRender),
|
||||||
rootClassName: hashId,
|
rootClassName: hashId,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getChildrenList = () => itemsNodes.value || flattenChildren(slots.default?.());
|
||||||
return () => {
|
return () => {
|
||||||
const childList = itemsNodes.value || flattenChildren(slots.default?.());
|
const childList = getChildrenList();
|
||||||
const allVisible =
|
const allVisible =
|
||||||
lastVisibleIndex.value >= childList.length - 1 ||
|
lastVisibleIndex.value >= childList.length - 1 ||
|
||||||
mergedMode.value !== 'horizontal' ||
|
mergedMode.value !== 'horizontal' ||
|
||||||
props.disabledOverflow;
|
props.disabledOverflow;
|
||||||
// >>>>> Children
|
// >>>>> Children
|
||||||
const wrappedChildList =
|
const getWrapperList = childList => {
|
||||||
mergedMode.value !== 'horizontal' || props.disabledOverflow
|
return mergedMode.value !== 'horizontal' || props.disabledOverflow
|
||||||
? childList
|
? childList
|
||||||
: // Need wrap for overflow dropdown that do not response for open
|
: // Need wrap for overflow dropdown that do not response for open
|
||||||
childList.map((child, index) => (
|
childList.map((child, index) => (
|
||||||
|
@ -458,6 +460,7 @@ export default defineComponent({
|
||||||
v-slots={{ default: () => child }}
|
v-slots={{ default: () => child }}
|
||||||
></MenuContextProvider>
|
></MenuContextProvider>
|
||||||
));
|
));
|
||||||
|
};
|
||||||
const overflowedIndicator = slots.overflowedIndicator?.() || <EllipsisOutlined />;
|
const overflowedIndicator = slots.overflowedIndicator?.() || <EllipsisOutlined />;
|
||||||
|
|
||||||
return wrapSSR(
|
return wrapSSR(
|
||||||
|
@ -470,7 +473,7 @@ export default defineComponent({
|
||||||
class={[className.value, attrs.class, hashId.value]}
|
class={[className.value, attrs.class, hashId.value]}
|
||||||
role="menu"
|
role="menu"
|
||||||
id={props.id}
|
id={props.id}
|
||||||
data={wrappedChildList}
|
data={getWrapperList(childList)}
|
||||||
renderRawItem={node => node}
|
renderRawItem={node => node}
|
||||||
renderRawRest={omitItems => {
|
renderRawRest={omitItems => {
|
||||||
// We use origin list since wrapped list use context to prevent open
|
// We use origin list since wrapped list use context to prevent open
|
||||||
|
@ -514,7 +517,7 @@ export default defineComponent({
|
||||||
>
|
>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div style={{ display: 'none' }} aria-hidden>
|
<div style={{ display: 'none' }} aria-hidden>
|
||||||
<PathContext>{wrappedChildList}</PathContext>
|
<PathContext>{getWrapperList(getChildrenList())}</PathContext>
|
||||||
</div>
|
</div>
|
||||||
</Teleport>
|
</Teleport>
|
||||||
</Overflow>,
|
</Overflow>,
|
||||||
|
|
|
@ -116,7 +116,7 @@ function convertItemsToNodes(
|
||||||
export default function useItems(props: MenuProps) {
|
export default function useItems(props: MenuProps) {
|
||||||
const itemsNodes = shallowRef([]);
|
const itemsNodes = shallowRef([]);
|
||||||
const hasItmes = shallowRef(false);
|
const hasItmes = shallowRef(false);
|
||||||
const store = shallowRef<Map<string, StoreMenuInfo>>(new Map());
|
const store = shallowRef(new Map<string, StoreMenuInfo>());
|
||||||
watch(
|
watch(
|
||||||
() => props.items,
|
() => props.items,
|
||||||
() => {
|
() => {
|
||||||
|
|
|
@ -32,7 +32,7 @@ export interface MenuContextProps {
|
||||||
inlineCollapsed: Ref<boolean>;
|
inlineCollapsed: Ref<boolean>;
|
||||||
theme?: ComputedRef<MenuTheme>;
|
theme?: ComputedRef<MenuTheme>;
|
||||||
|
|
||||||
siderCollapsed?: ComputedRef<boolean>;
|
siderCollapsed?: Ref<boolean>;
|
||||||
|
|
||||||
// // Mode
|
// // Mode
|
||||||
mode: Ref<MenuMode>;
|
mode: Ref<MenuMode>;
|
||||||
|
|
|
@ -47,7 +47,9 @@ const Holder = defineComponent({
|
||||||
'rtl',
|
'rtl',
|
||||||
'transitionName',
|
'transitionName',
|
||||||
'onAllRemoved',
|
'onAllRemoved',
|
||||||
] as any,
|
'animation',
|
||||||
|
'staticGetContainer',
|
||||||
|
],
|
||||||
setup(props, { expose }) {
|
setup(props, { expose }) {
|
||||||
const { getPrefixCls, getPopupContainer } = useConfigInject('message', props);
|
const { getPrefixCls, getPopupContainer } = useConfigInject('message', props);
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import ConfirmDialog from './ConfirmDialog';
|
||||||
import type { ModalFuncProps } from './Modal';
|
import type { ModalFuncProps } from './Modal';
|
||||||
import ConfigProvider, { globalConfigForApi } from '../config-provider';
|
import ConfigProvider, { globalConfigForApi } from '../config-provider';
|
||||||
import omit from '../_util/omit';
|
import omit from '../_util/omit';
|
||||||
|
import { triggerVNodeUpdate } from '../_util/vnode';
|
||||||
|
|
||||||
import { getConfirmLocale } from './locale';
|
import { getConfirmLocale } from './locale';
|
||||||
import destroyFns from './destroyFns';
|
import destroyFns from './destroyFns';
|
||||||
|
@ -27,7 +28,6 @@ const confirm = (config: ModalFuncProps) => {
|
||||||
if (confirmDialogInstance) {
|
if (confirmDialogInstance) {
|
||||||
// destroy
|
// destroy
|
||||||
vueRender(null, container as any);
|
vueRender(null, container as any);
|
||||||
confirmDialogInstance.component.update();
|
|
||||||
confirmDialogInstance = null;
|
confirmDialogInstance = null;
|
||||||
}
|
}
|
||||||
const triggerCancel = args.some(param => param && param.triggerCancel);
|
const triggerCancel = args.some(param => param && param.triggerCancel);
|
||||||
|
@ -70,8 +70,7 @@ const confirm = (config: ModalFuncProps) => {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (confirmDialogInstance) {
|
if (confirmDialogInstance) {
|
||||||
Object.assign(confirmDialogInstance.component.props, currentConfig);
|
triggerVNodeUpdate(confirmDialogInstance, currentConfig, container);
|
||||||
confirmDialogInstance.component.update();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,8 +72,8 @@ The items listed above are all functions, expecting a settings object as paramet
|
||||||
| centered | Centered Modal | boolean | `false` | |
|
| centered | Centered Modal | boolean | `false` | |
|
||||||
| class | class of container | string | - | |
|
| class | class of container | string | - | |
|
||||||
| closable | Whether a close (x) button is visible on top right of the modal dialog or not | boolean | `false` | |
|
| closable | Whether a close (x) button is visible on top right of the modal dialog or not | boolean | `false` | |
|
||||||
| content | Content | string\|VNode \|function(h) | - | |
|
| content | Content | string\|VNode \|function() | - | |
|
||||||
| footer | Footer content, set as `footer: null` when you don't need default buttons | string\|VNode \|function(h) | - | 4.0.0 |
|
| footer | Footer content, set as `footer: null` when you don't need default buttons | string\|VNode \|function() | - | 4.0.0 |
|
||||||
| icon | custom icon (`Added in 1.14.0`) | VNode \|()=>VNode | - | |
|
| icon | custom icon (`Added in 1.14.0`) | VNode \|()=>VNode | - | |
|
||||||
| keyboard | Whether support press esc to close | boolean | true | |
|
| keyboard | Whether support press esc to close | boolean | true | |
|
||||||
| mask | Whether show mask or not. | boolean | true | |
|
| mask | Whether show mask or not. | boolean | true | |
|
||||||
|
@ -81,7 +81,7 @@ The items listed above are all functions, expecting a settings object as paramet
|
||||||
| okButtonProps | The ok button props | [ButtonProps](/components/button) | - | |
|
| okButtonProps | The ok button props | [ButtonProps](/components/button) | - | |
|
||||||
| okText | Text of the OK button | string | `OK` | |
|
| okText | Text of the OK button | string | `OK` | |
|
||||||
| okType | Button `type` of the OK button | string | `primary` | |
|
| okType | Button `type` of the OK button | string | `primary` | |
|
||||||
| title | Title | string\|VNode \|function(h) | - | |
|
| title | Title | string\|VNode \|function() | - | |
|
||||||
| width | Width of the modal dialog | string\|number | 416 | |
|
| width | Width of the modal dialog | string\|number | 416 | |
|
||||||
| wrapClassName | The class name of the container of the modal dialog | string | - | 3.2.3 |
|
| wrapClassName | The class name of the container of the modal dialog | string | - | 3.2.3 |
|
||||||
| zIndex | The `z-index` of the Modal | number | 1000 | |
|
| zIndex | The `z-index` of the Modal | number | 1000 | |
|
||||||
|
@ -155,3 +155,5 @@ When you need context information (for example, using a globally registered comp
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> [App Package Component](/components/app) can be used to simplify the problem of `useModal` and other methods that need to manually implant contextHolder.
|
||||||
|
|
|
@ -19,14 +19,14 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*fBrgSJBmavgAAA
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| afterClose | Modal 完全关闭后的回调 | function | 无 | |
|
| afterClose | Modal 完全关闭后的回调 | function | - | |
|
||||||
| bodyStyle | Modal body 样式 | object | {} | |
|
| bodyStyle | Modal body 样式 | object | {} | |
|
||||||
| cancelButtonProps | cancel 按钮 props | [ButtonProps](/components/button/#api) | - | |
|
| cancelButtonProps | cancel 按钮 props | [ButtonProps](/components/button/#api) | - | |
|
||||||
| cancelText | 取消按钮文字 | string\| slot | 取消 | |
|
| cancelText | 取消按钮文字 | string\| slot | 取消 | |
|
||||||
| centered | 垂直居中展示 Modal | boolean | `false` | |
|
| centered | 垂直居中展示 Modal | boolean | `false` | |
|
||||||
| closable | 是否显示右上角的关闭按钮 | boolean | true | |
|
| closable | 是否显示右上角的关闭按钮 | boolean | true | |
|
||||||
| closeIcon | 自定义关闭图标 | VNode \| slot | - | |
|
| closeIcon | 自定义关闭图标 | VNode \| slot | - | |
|
||||||
| confirmLoading | 确定按钮 loading | boolean | 无 | |
|
| confirmLoading | 确定按钮 loading | boolean | - | |
|
||||||
| destroyOnClose | 关闭时销毁 Modal 里的子元素 | boolean | false | |
|
| destroyOnClose | 关闭时销毁 Modal 里的子元素 | boolean | false | |
|
||||||
| footer | 底部内容,当不需要默认底部按钮时,可以设为 `:footer="null"` | string\|slot | 确定取消按钮 | |
|
| footer | 底部内容,当不需要默认底部按钮时,可以设为 `:footer="null"` | string\|slot | 确定取消按钮 | |
|
||||||
| forceRender | 强制渲染 Modal | boolean | false | |
|
| forceRender | 强制渲染 Modal | boolean | false | |
|
||||||
|
@ -38,8 +38,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*fBrgSJBmavgAAA
|
||||||
| okButtonProps | ok 按钮 props | [ButtonProps](/components/button/#api) | - | |
|
| okButtonProps | ok 按钮 props | [ButtonProps](/components/button/#api) | - | |
|
||||||
| okText | 确认按钮文字 | string\|slot | 确定 | |
|
| okText | 确认按钮文字 | string\|slot | 确定 | |
|
||||||
| okType | 确认按钮类型 | string | primary | |
|
| okType | 确认按钮类型 | string | primary | |
|
||||||
| title | 标题 | string\|slot | 无 | |
|
| title | 标题 | string\|slot | - | |
|
||||||
| open(v-model) | 对话框是否可见 | boolean | 无 | |
|
| open(v-model) | 对话框是否可见 | boolean | - | |
|
||||||
| width | 宽度 | string\|number | 520 | |
|
| width | 宽度 | string\|number | 520 | |
|
||||||
| wrapClassName | 对话框外层容器的类名 | string | - | |
|
| wrapClassName | 对话框外层容器的类名 | string | - | |
|
||||||
| zIndex | 设置 Modal 的 `z-index` | number | 1000 | |
|
| zIndex | 设置 Modal 的 `z-index` | number | 1000 | |
|
||||||
|
@ -76,8 +76,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*fBrgSJBmavgAAA
|
||||||
| centered | 垂直居中展示 Modal | boolean | `false` | |
|
| centered | 垂直居中展示 Modal | boolean | `false` | |
|
||||||
| class | 容器类名 | string | - | |
|
| class | 容器类名 | string | - | |
|
||||||
| closable | 是否显示右上角的关闭按钮 | boolean | `false` | |
|
| closable | 是否显示右上角的关闭按钮 | boolean | `false` | |
|
||||||
| content | 内容 | string \|VNode \|function(h) | 无 | |
|
| content | 内容 | string \|VNode \|function() | - | |
|
||||||
| footer | 底部内容,当不需要默认底部按钮时,可以设为 `footer: null` | string \|VNode \|function(h) | - | 4.0.0 |
|
| footer | 底部内容,当不需要默认底部按钮时,可以设为 `footer: null` | string \|VNode \|function() | - | 4.0.0 |
|
||||||
| icon | 自定义图标(1.14.0 新增) | VNode \| ()=>VNode | - | |
|
| icon | 自定义图标(1.14.0 新增) | VNode \| ()=>VNode | - | |
|
||||||
| keyboard | 是否支持键盘 esc 关闭 | boolean | true | |
|
| keyboard | 是否支持键盘 esc 关闭 | boolean | true | |
|
||||||
| mask | 是否展示遮罩 | boolean | true | |
|
| mask | 是否展示遮罩 | boolean | true | |
|
||||||
|
@ -85,12 +85,12 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*fBrgSJBmavgAAA
|
||||||
| okButtonProps | ok 按钮 props | [ButtonProps](/components/button) | - | |
|
| okButtonProps | ok 按钮 props | [ButtonProps](/components/button) | - | |
|
||||||
| okText | 确认按钮文字 | string | 确定 | |
|
| okText | 确认按钮文字 | string | 确定 | |
|
||||||
| okType | 确认按钮类型 | string | primary | |
|
| okType | 确认按钮类型 | string | primary | |
|
||||||
| title | 标题 | string\|VNode \|function(h) | 无 | |
|
| title | 标题 | string\|VNode \|function() | - | |
|
||||||
| width | 宽度 | string\|number | 416 | |
|
| width | 宽度 | string\|number | 416 | |
|
||||||
| wrapClassName | 对话框外层容器的类名 | string | - | 3.2.3 |
|
| wrapClassName | 对话框外层容器的类名 | string | - | 3.2.3 |
|
||||||
| zIndex | 设置 Modal 的 `z-index` | number | 1000 | |
|
| zIndex | 设置 Modal 的 `z-index` | number | 1000 | |
|
||||||
| onCancel | 取消回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭 | function | 无 | |
|
| onCancel | 取消回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭 | function | - | |
|
||||||
| onOk | 点击确定回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭 | function | 无 | |
|
| onOk | 点击确定回调,参数为关闭函数,返回 promise 时 resolve 后自动关闭 | function | - | |
|
||||||
|
|
||||||
以上函数调用后,会返回一个引用,可以通过该引用更新和关闭弹窗。
|
以上函数调用后,会返回一个引用,可以通过该引用更新和关闭弹窗。
|
||||||
|
|
||||||
|
@ -159,3 +159,5 @@ router.beforeEach((to, from, next) => {
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> 可通过 [App 包裹组件](/components/app-cn) 简化`useModal`等方法需要手动植入 contextHolder 的问题。
|
||||||
|
|
|
@ -8,7 +8,7 @@ title:
|
||||||
|
|
||||||
## zh-CN
|
## zh-CN
|
||||||
|
|
||||||
通过 `notification.useNotification` 创建支持读取 context 的 `contextHolder`。请注意,我们推荐通过顶层注册的方式代替 `message` 静态方法,因为静态方法无法消费上下文,因而 ConfigProvider 的数据也不会生效。
|
通过 `notification.useNotification` 创建支持读取 context 的 `contextHolder`。请注意,我们推荐通过顶层注册的方式代替 `notification` 静态方法,因为静态方法无法消费上下文,因而 ConfigProvider 的数据也不会生效。
|
||||||
|
|
||||||
## en-US
|
## en-US
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*HrFtQ6jJJFQAAA
|
||||||
| okText | 确认按钮文字 | string\|slot | 确定 | |
|
| okText | 确认按钮文字 | string\|slot | 确定 | |
|
||||||
| okType | 确认按钮类型 | string | primary | |
|
| okType | 确认按钮类型 | string | primary | |
|
||||||
| showCancel | 是否显示取消按钮 | boolean | true | 3.0 |
|
| showCancel | 是否显示取消按钮 | boolean | true | 3.0 |
|
||||||
| title | 确认框的描述 | string\|slot | 无 | |
|
| title | 确认框的描述 | string\|slot | - | |
|
||||||
| description | 确认内容的详细描述 | string\|slot | - | 4.0 |
|
| description | 确认内容的详细描述 | string\|slot | - | 4.0 |
|
||||||
| open (v-model) | 是否显示 | boolean | - | 4.0 |
|
| open (v-model) | 是否显示 | boolean | - | 4.0 |
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue