Compare commits

...

613 Commits
4.0.0 ... main

Author SHA1 Message Date
云荷YunHerry 27acc9a80e
docs(table): ajax demo (#8120)
Co-authored-by: Xian Yu <h3209851541@outlook.com>
2025-06-13 15:46:47 +08:00
selicens 43ad5dec90
docs(mentions): Spelling error in En title (#8127) 2025-06-13 15:45:49 +08:00
selicens aa8802679f
docs(Typography): fix slot name (#8184) 2025-06-13 15:35:05 +08:00
爆炒芋头 aa211fd789
docs(input): showCount type 文档 (#8041)
* fix(input): showCount type 文档

* fix(input): showCount type 文档

---------

Co-authored-by: zhiqiangchen <zhiqiang.chen@igg.com>
2025-03-06 14:37:19 +08:00
tangjinzhou 61d39be86f
Update config.yml 2025-03-06 14:34:53 +08:00
tangjinzhou b80bd37f6e fix: sm select placeholder 2025-02-17 11:28:06 +08:00
wzc520pyfm 3db5e191b8
docs: add ant-design-x-vue link at ecosystem (#8034) 2025-02-09 09:23:58 +08:00
Attacktive 45c7109212
docs: correct possible `size` size in component Select (#7991) 2025-01-05 17:04:07 +08:00
Shai b58d0fb723
docs: added centered to docs (#7967) 2025-01-05 16:55:58 +08:00
clddup a21a1ca533
docs: theme editor 2025-01-05 16:54:32 +08:00
tangjinzhou 4a37016f4e fix: ts type error 2024-11-11 14:52:27 +08:00
tangjinzhou 5d6ebb30ac release 4.2.6 2024-11-11 14:47:34 +08:00
tangjinzhou 888457238d fix: modal aria error 2024-11-11 14:40:49 +08:00
果冻橙 b0d9309471
docs: Add custom icons to support Rsbuild documentation (#7743) 2024-11-08 10:30:05 +08:00
selicens f64d0718ae
docs: Change the default values of attributes (#7744) 2024-11-08 10:28:03 +08:00
selicens 968317ca9f
fix(InputNumber): disabled text clolor (#7776) 2024-11-08 10:18:03 +08:00
Carl Chen 22dad3ba6d
fix[Select]: fix select losing focus issue (#7829) 2024-11-08 10:17:22 +08:00
iamnotblank 4f7bd6f28d
fix(Dialog): aira error (#7823)
* fix(vc-dialog): aira error

* fix(vc-dialog): aira error
2024-11-07 22:54:53 +08:00
snoweast 12fcfa15b1
fix: Safari of input IME (#7918) 2024-11-07 22:45:48 +08:00
tangjinzhou e46d537d45 release 4.2.5 2024-09-19 19:08:59 +08:00
tangjinzhou ac9d1b0a7f fix: empty memory issue 2024-09-19 19:07:08 +08:00
tangjinzhou 2c7008d786 fix: image width & height not work 2024-09-19 19:06:34 +08:00
tangjinzhou 49d4b3166e feat: update type 2024-09-13 19:33:38 +08:00
tangjinzhou 339fb4a230 release 4.2.4 2024-09-13 19:06:37 +08:00
tangjinzhou bb443a05e2 fix: button wave memory leak 2024-09-13 19:05:04 +08:00
YYP 3a79f72816
fix(doc): `positonStyle` typo (#7808) 2024-09-13 18:51:17 +08:00
5918vo 89eec07145
docs: event demo (#7699) (#7728) 2024-09-05 11:38:10 +08:00
Jason Ren c69a6d29b2
docs(zh-cn): finish translation of float-button (#7811) 2024-09-05 11:37:36 +08:00
tangjinzhou 2666cb79ab refactor: transition 2024-06-21 13:40:28 +08:00
tangjinzhou 35d5185634 docs: update changelog 2024-06-10 09:37:38 +08:00
tangjinzhou 4492086aac release 4.2.3 2024-06-10 09:20:15 +08:00
trry-hub 4b7c6ac02c
feat: TourStep support fn children (#7628)
* Fix: [修复自定义按钮无渲染]

* refactor(完善 Tour 自定义按钮代码健壮性): 🦄

---------

Co-authored-by: shizhu <shizhu@yaomaitong.cn>
2024-06-10 09:14:27 +08:00
Kylin 208b8d3085
docs: unify the default value of none to - (#7636) 2024-06-09 22:08:30 +08:00
Carl Chen f41fec26ba
fix[vc-util]: styleObjectToString filter invalid value (#7642) 2024-06-09 09:56:45 +08:00
tangjinzhou 9118d6cd42 release 4.2.2 2024-06-06 10:16:02 +08:00
Aaron-zon 5c7aaf0dd6
fix(FloatButton): type error (#7632) 2024-06-06 10:03:24 +08:00
evanlc b82d8dd2ad
fix(PresetPanel): preset panel stopPropagation (#7550) 2024-06-04 23:28:22 +08:00
Aaron-zon 1d0fa8533a
fix: add missing space-evenly alignment for grid rows (#7579) 2024-06-04 23:26:03 +08:00
Kylin 4318147fc6
refactor(input): remove unnecessary assertions and use?? instead of the ternary operator (#7571)
* refactor: remove unnecessary assertions and use?? instead of the ternary operator

* refactor: use?? instead of the ternary operator
2024-06-04 23:24:44 +08:00
Carl Chen 312bcc5127
docs(collapse): modify the `accordion` attribute text to be easier to understand (#7612) 2024-06-04 23:20:54 +08:00
tangjinzhou 6594fe3964 fix: textarea 2024-06-04 23:12:06 +08:00
tangjinzhou 82f28ce3d0 fix: select input 2024-06-04 21:20:10 +08:00
Carl Chen 6e2c5a6a83
fix[select]: fix placeholder error when inputting Chinese (#7611)
* fix[select]: fix placeholder error when inputting Chinese

fix(selector): fix placeholder error when inputting Chinese

perf: optimize types

* Update SingleSelector.tsx

* Update index.tsx

---------

Co-authored-by: tangjinzhou <415800467@qq.com>
2024-06-04 18:59:24 +08:00
lchrennew 307148e2df
fix: empty space-item are not been hidden (#7557) 2024-06-04 16:13:11 +08:00
bsuooo afebeb9ffa
docs(DatePicker): updating deprecated API (#7570) 2024-06-04 16:12:20 +08:00
selicens aeda2637f6
fix(Input): Chinese input is invalid when the modifier is lazy (#7543) 2024-06-04 16:10:46 +08:00
extclp f42d8ad1ce
chore: remove css-animation (#7613)
* chore: remove css-animate

* chore(site): remove localStorage support check
2024-06-04 16:05:21 +08:00
selicens 33a0708eb4
docs: upgrade document link direction error (#7602) 2024-06-04 16:01:26 +08:00
selicens 085eb398a4
fix(FormItem): class name error (#7582) 2024-06-04 16:00:40 +08:00
selicens 9c27414cd0
fix(FloatButton): type prompt error (#7576) 2024-06-04 15:57:40 +08:00
Kylin 014e86bd27
docs: update README-zh_CN (#7584) 2024-06-04 15:49:47 +08:00
tangjinzhou 40ad45bc05 fix: tree reative data error 2024-06-04 15:46:22 +08:00
neverland 1c82940160
docs: add Vite and Rsbuild to getting started (#7556) 2024-05-09 21:21:20 +08:00
bsuooo 7ce0f115d5
fix(cascader): remove outdated compatibility code(#7532) (#7534) 2024-04-30 19:13:48 +08:00
extclp 54434b0931
docs(Select): remove qs dependencie (#7541) 2024-04-30 19:12:05 +08:00
selicens e01f26c541
fix(TreeSelect): placehold slot invalid (#7545) 2024-04-30 19:11:08 +08:00
tangjinzhou 9a45b35511 release 4.2.1 2024-04-25 09:40:07 +08:00
hippo 8e8073d17e
fix: input clear error (#7523) 2024-04-25 09:29:38 +08:00
extclp d6cc262c3a
refactor: replement deprecated fields (#7519) 2024-04-25 09:25:29 +08:00
tangjinzhou 9d7c171940 release 4.2.0 2024-04-22 15:51:05 +08:00
extclp 48a3ceb921
chore: remove vetur type generator (#7517) 2024-04-22 15:27:58 +08:00
tangjinzhou 23c620ea3a fix: select customicon error #7377 2024-04-22 15:26:02 +08:00
tangjinzhou 752686e334 fix: input composing error, close #7516 2024-04-22 15:11:10 +08:00
tangjinzhou 9b0f0e71e7 perf: table hover cell, close #7451 2024-04-22 10:37:28 +08:00
24min 42d33e963c
fix: carousel beforeChange current value not correct (#7419) 2024-04-22 10:18:19 +08:00
tangjinzhou ed27700ef4 style: lint code 2024-04-22 10:07:02 +08:00
extclp eedd7f3302
chore: remove json file type declare (#7514) 2024-04-22 10:00:03 +08:00
Carl Chen c28c38d02e
fix[Select|Cascader]: select multiple error & cascader error in ssr mode (#7377)
* docs: updating the `dropdownRender` description and jumps in the FAQ for Select

* fix: fix  select error in multiple mode

* fix: fix cascader select error in ssr mode
2024-04-19 22:56:07 +08:00
ashu-guo 162d1fcf95
fix(AutoComplete): #7380 and #7276 (#7391) 2024-04-19 22:46:19 +08:00
selicens 4815ee6f20
fix(Pagination): block default events for the enter key (#7368)
* fix(Pagination): block default events for the enter key

* refactor: consider other keyboard events
2024-04-19 22:44:34 +08:00
bqy_fe 2b41e56520
fix(Input): autoSize not work when change value in onMounted (#7478) 2024-04-19 22:36:44 +08:00
Sean ab874ffd4b
docs: update tree-select api description (#7388) 2024-04-19 22:07:41 +08:00
tangjinzhou 61ade6b8ec fix: autoComplete option slot error, close #7396 #7405 2024-04-19 19:27:51 +08:00
selicens 4d35b8caa3
docs(Modal): add simplified descriptions (#7408)
close #7393
2024-04-19 19:19:33 +08:00
Tang 040af82eb9
docs: update table docs (#7400)
Co-authored-by: 汤显文 <tang_xianwen@gov-info.cn>
2024-04-19 19:19:01 +08:00
Carl Chen a8c72fc5e7
fix[Menu]: fix `menu-item-group` not rendering in SSR (#7349)
* docs: updating the `dropdownRender` description and jumps in the FAQ for Select

* fix: `menu-item-group` rendered in ssr
2024-04-19 19:18:30 +08:00
ashu-guo c25736d57d
chore: merge duplicate property declarations (#7417) 2024-04-19 19:16:46 +08:00
SonicKang 4a48bfc66b
fix: a-qrcord component cannot show ts prompt (#7502) 2024-04-19 19:15:12 +08:00
tangjinzhou 4138d3c822 fix: tabs size error, close #7491 #7482 2024-04-19 19:14:18 +08:00
tangjinzhou dec67a6d65 docs: update site 2024-04-19 19:13:06 +08:00
Carl Chen 85c48c0566
feat[tooltip]: add `arrow` attribute (#7459)
* docs: updating the `dropdownRender` description and jumps in the FAQ for Select

* wip: add popover-arrow

* wip: trigger add arrow attr

* fix: remove popupContextKey

* optimize

* perf: optimize

* docs: optimize docs

* docs: add `arrow` attribute in tooltip en-US docs

* fix: fix bug

* perf[demo]: `radio-group` replace with `segmented`
2024-04-19 13:17:15 +08:00
Carl Chen 966bc1004c
fix[layout]: in a dark mode layout, the text color should change. (#7498)
* docs: updating the `dropdownRender` description and jumps in the FAQ for Select

* fix[layout]: in a dark mode layout, the text color should change
2024-04-19 10:25:23 +08:00
Ordinary 457d0fde0b
fix: remove duplicate style variable (#7490)
Co-authored-by: p-hehongsheng <p-hehongsheng@xiaomi.com>
2024-04-19 10:21:07 +08:00
Saveliy ff184b3969
feat: update ru_RU localization (#7497) 2024-04-19 10:20:15 +08:00
ashu-guo 75886a8cbf
docs: match dependencies in package.json instead of simply setting 'latest' (#7381) 2024-04-19 10:19:50 +08:00
fwd01 2b0c2da232
docs: typo error (#7505)
Co-authored-by: fuwedong <fuwendong5@outlook.com>
2024-04-19 10:18:59 +08:00
tangjinzhou ffd4d8fe92 fix: useForm model change validate error 2024-04-19 10:18:04 +08:00
tangjinzhou 49e1323baa docs: update codesandbox 2024-04-19 09:52:43 +08:00
tangjinzhou 35d1de9ea6 docs: update sandbox 2024-04-19 09:29:05 +08:00
huyikai fa46999963
Update ja_JP.ts (#7438) 2024-03-23 10:40:28 +08:00
tangjinzhou 01300d01da docs: add eth sponsor 2024-03-22 16:20:10 +08:00
tangjinzhou 9a5f83ed06 chore: update pkg 2024-03-03 14:09:19 +08:00
tangjinzhou ce6b7f3b4e chore: update pkg 2024-03-03 14:04:52 +08:00
tangjinzhou 4a2f95fe88 release 4.1.2 2024-01-30 12:19:46 +08:00
Carl Chen 7c73beb309
fix: fixed an error caused by dragging under the `headerCell` slot. (#7291)
* fix: fix headerCell slots

* perf: optimize table columnTitle type
2024-01-30 12:06:45 +08:00
Carl Chen 0cbf3ca354
docs: updating the `dropdownRender` description and jumps in the FAQ for Select (#7313) 2024-01-30 12:05:20 +08:00
Weite Su 7afb7ce465
fix(segmented): title property in segmented component slot not effective (#7302)
Co-authored-by: suweite <weite.su@infinigo.cn>
2024-01-30 12:04:24 +08:00
tangjinzhou 9cc73011c5 chore: import error 2024-01-16 21:23:36 +08:00
tangjinzhou 4b21210700 release 4.1.1 2024-01-16 21:10:05 +08:00
Carl Chen a80ca17461
fix: table slot type optimization (#7288) 2024-01-16 20:57:29 +08:00
HaiWei Lian ad8d32ab09
fix: table filter does not work in header group (#7233) 2024-01-16 20:56:47 +08:00
Carl Chen d870f3f8e0
fix: fixed error with no expected value in `expandColumnTitle` slot (#7265)
* fix: fixed error report with no expected value in `expandColumnTitle` slot

* fix: optimize optional chain

* fix: use default render

* refactor: use `customRenderSlot` replace `renderSlot`

* style: code format

* perf: optimize useColumns code

* fix: fix path

* feat: add customRenderSlot unit test
2024-01-16 20:49:38 +08:00
tangjinzhou c717473568 fix: hook warning, close #7281 #7273 #7274 2024-01-16 20:34:11 +08:00
selicens 1e07544e74
feat(QRCode): support scanned status (#7242) 2024-01-12 11:44:33 +08:00
Light 8ab008d255
typo(table): Supplement FilterDropdown type (#7226)
* fix(table): Supplement FilterDropdown type

* docs(table): Type format
2024-01-12 11:42:46 +08:00
一堆菠萝 f034a7759e
fix(divider): vertical dashed divider not show (#7218) 2024-01-12 10:50:06 +08:00
Konv Suu 3f33cefa81
ci: issue-labeled format error (#7200) 2024-01-12 10:45:46 +08:00
一堆菠萝 81e43c56ef
docs(typography): trigerType api supplement Chinese translation (#7228) 2024-01-12 10:45:09 +08:00
aShu-guo f400c803e1
docs: update modal api description (#7232)
* docs: update modal api description

* docs: update modal api description
2024-01-12 10:44:48 +08:00
somethingfornothing 502c11cc4c
fix(dropdown): unexpectedly hidden(#7246) (#7254) 2024-01-12 10:42:36 +08:00
markthree 2cdb69f706
faet: fix css prefix in nuxt generate (#7256) 2024-01-12 10:30:17 +08:00
tangjinzhou 2eed8e62ec fix: type error 2024-01-05 19:28:55 +08:00
tangjinzhou 61c0d0cc9d release 4.1.0 2024-01-05 16:22:56 +08:00
tangjinzhou d7f9bd27dc fix: support vue 3.4 2024-01-05 16:20:05 +08:00
cc heart 4ed2868137
fix(vue): fixed modal component failed to trigger update in vue@3.4.x (#7244)
* fix(vue): fixed modal component failed to trigger update in vue@3.4.x version

* refactor: use cloneVNode trigger vNode update
2024-01-05 09:11:25 +08:00
tangjinzhou 8696e01039 release 4.0.8 2023-12-18 16:19:36 +08:00
tangjinzhou a3fd390619 docs: update demo 2023-12-18 16:17:43 +08:00
tangjinzhou a9198e44df fix: theme reactive not work #7180 2023-12-18 15:34:54 +08:00
yanyu 509ec682f2
fix: Fix custom theme token (#7180)
* fix: fix table column data is passed into chlidren is undefined or null errorr

* fix: fix custom theme token not take effect

* chore: reset button style

---------

Co-authored-by: undefined <undefined>
2023-12-18 15:20:24 +08:00
tangjinzhou 73f0a29acf fix: textarea cursor error, close #7121 2023-12-18 14:31:53 +08:00
somethingfornothing f93dd9170d
fix: dataRange active-bar (#7157) 2023-12-18 11:37:38 +08:00
yang cfa0a68568
fix(Menu.SubMenu): 修复ConfigProvider组件设置prefixCls属性后动画过渡失效 (#7150) 2023-12-18 11:32:38 +08:00
Konv Suu afcff32fcc
fix(menu): pass motion name to collapseMotion (#7130) 2023-12-18 11:31:57 +08:00
tangjinzhou b989cf2d97 perf: watermark 2023-12-18 11:31:04 +08:00
Jevin 0e6fd652b8
fix(watermark): modify dom properties to regenerate (#7149)
Co-authored-by: “Jevin” <jevin@mogul-tech.com>
2023-12-18 11:29:27 +08:00
selicens 6625d39118
fix(RangPicker): Incorrect display of prevIcon and nextIcon (#7127)
* fix(RangPicker): Incorrect display of prevIcon and nextIcon

* fix: superPrevIcon and superNextIcon invalid
2023-12-18 11:23:30 +08:00
Nined 67efafca4a
perf(Typography): fast and efficient syncEllipsis (#7146) 2023-12-18 11:21:55 +08:00
OliverYoung a8a774a5ff
fix: tooltip onPopupAlign never called (#7112) 2023-12-18 10:54:30 +08:00
一堆菠萝 1fc109704b
fix: Form disabled no effect on Upload (#7110)
* fix: Form disabled no effect on Upload

* docs: update Upload disabled api default value
2023-12-18 10:45:27 +08:00
puppetkkk d140523c89
fix: useWave unref (#7108)
* fix: useWave unref

* fix: wave init value

* fix: wave value

* Update useConfigInject.ts

---------

Co-authored-by: pangzebang <pangzebang@dm-ai.com>
Co-authored-by: tangjinzhou <415800467@qq.com>
2023-12-18 10:41:50 +08:00
cc heart 91fe1b0d71
docs(menu): repair Anchor Jump (#7178)
Under the menu document, some anchor clicks cannot scroll.
2023-12-18 10:27:48 +08:00
lyn c1b4941def
docs: fix typo (#7162) 2023-12-18 10:27:22 +08:00
puppetkkk af383a34bc
docs(config-provider): add wave setting (#7107)
* docs(config-provider): add wave setting

* docs(config-provider): add wave setting

---------

Co-authored-by: pangzebang <pangzebang@dm-ai.com>
2023-12-18 10:25:23 +08:00
cc heart 1dccce4e16
docs(header): restore button hover style (#7105) 2023-12-18 10:24:56 +08:00
cc heart 8aa8e5a778
docs(calendar): optimize calendar docs note layout (#7102)
docs(calendar): optimize calendar docs note layout

docs(calendar): optimize calendar docs note layout

docs(calendar): optimize calendar docs note layout

docs(calendar): optimize calendar docs note layout
2023-12-18 10:24:18 +08:00
Light 42952b713a
docs(notification): Fix hooks description in demo (#7191) 2023-12-18 10:22:49 +08:00
yang 07c36192b8
【docs】:Code example 'setup' is missing (#7153)
* flx

* flx【docs】:Modify the official website code example, switch TS to JS, the top of the example should be '<script setup>'
2023-12-18 10:22:04 +08:00
Jacky 562623c091
fix: remove /* #__PURE__*/ comments (#7156) 2023-12-18 10:21:15 +08:00
tangjinzhou e362571719 test: update flex test 2023-11-11 10:35:49 +08:00
tangjinzhou e32ae99bfd release 4.0.7 2023-11-11 10:33:04 +08:00
tangjinzhou ccbeb44264 docs: add new tag 2023-11-11 10:25:16 +08:00
tangjinzhou 3499b11a47 refactor: flex components 2023-11-11 10:24:58 +08:00
selicens dae7262f13
feat(Flex): New component (#7052)
* feat(Flex): New component

* fix: Unified type

* test: Add unit test and update snapshots

* docs: update md file

---------

Co-authored-by: undefined <undefined>
2023-11-11 10:06:02 +08:00
w-z-y 8cf6be11f7
fix: DatePicker panelChange(#7059)
onPanelChange事件缺少
2023-11-11 10:00:48 +08:00
Konv Suu 2510608665
fix(collapse): custom prefix in animation (#7074) 2023-11-11 09:59:40 +08:00
cc heart b22875db33
fix(message): message offset error (#7093) 2023-11-11 09:53:59 +08:00
lyn 2bdeed1432
typo: fix docs ant Rect is spelled as React (#7082) 2023-11-11 09:31:38 +08:00
lai9fox 49a6b588c1
docs(tree-select): fix duplicate values in demo (#7083) 2023-11-11 09:30:42 +08:00
Konv Suu bd080cde2a
chore: enable pnpm run pre scripts (#7078) 2023-11-11 09:29:29 +08:00
huiliangShen c1454bc7b5
fix(carousel): can not use jsx render children (#7077)
Co-authored-by: banruo <shl@dataqin.com>
2023-11-11 09:28:33 +08:00
cc heart 61402142f8
feat[watermark]: support dark theme (#7067)
* perf[watermark]: replace with token variable

* feat: add theme toggle watch
2023-11-11 09:14:43 +08:00
Konv Suu 242982301d
site: menu show tag when front-matter has tag prop (#7053) 2023-11-02 19:00:16 +08:00
Konv Suu 9bdf882517
docs(theme-editor): handleEditConfigChange logic (#7038) 2023-10-23 10:51:46 +08:00
Konv Suu 88ec06b717
fix(upload): disabled prop apply order (#7047) 2023-10-23 10:16:23 +08:00
Konv Suu 6c39bec277
feat(config-provider ): wave config (#7036) 2023-10-23 10:15:56 +08:00
Konv Suu 82f407d396
docs(tag): colorful demo css style (#7037) 2023-10-23 10:13:49 +08:00
bowen bfcdba251f
docs(checkbox): fix typo (#7039) 2023-10-23 10:13:18 +08:00
cc heart 0abcd25b2a
fix: fix space duplicated key (#7048) 2023-10-23 10:12:26 +08:00
tangjinzhou 72b8d09b92 release 4.0.6 2023-10-17 23:01:50 +08:00
selicens b4c29d927b
fix: dropdownVisibleChange invalid (#7033)
Co-authored-by: undefined <undefined>
2023-10-17 22:59:42 +08:00
tangjinzhou bf917f36eb release 4.0.5 2023-10-17 19:04:56 +08:00
黄小民 0f9c80b86e
fix: rangePick onOk can't close the panel (#7026) 2023-10-17 19:02:10 +08:00
Zev Zhu 61e5746b0d
fix(StyleContext): fix style cache loaded repeat (#7029)
Co-authored-by: unknown <aibayanyu20>
2023-10-17 18:55:10 +08:00
bowen 7786a81e76
docs(menu): fix typo (#7025) 2023-10-17 10:53:20 +08:00
tangjinzhou 6f89185fe1 release 4.0.4 2023-10-16 16:19:34 +08:00
Konv Suu 449adb03df
fix: setContainer in onBeforeMount for drawer (#6986)
* fix: setContainer in onBeforeMount for drawer

* fix: add judgement
2023-10-16 15:56:28 +08:00
tangjinzhou 4428423be4 fix: select dropdown custom input error #7020 2023-10-16 15:51:44 +08:00
selicens 380fcd4aa9
fix(Select): dropdownRender inside dropdown box disappears when the input box gains focus (#7020)
Co-authored-by: undefined <undefined>
2023-10-16 15:03:37 +08:00
tangjinzhou 4a1296bb3f fix: code error #7001 2023-10-16 14:35:19 +08:00
selicens b9c65656db
fix(select): list scrollbar height and timing (#6987) (#7001)
* fix: select scrollbar height

* fix: mousemove appear scrollbar

* Update List.tsx

* Update List.tsx

---------

Co-authored-by: undefined <undefined>
Co-authored-by: tangjinzhou <415800467@qq.com>
2023-10-16 14:33:37 +08:00
selicens f1bcf2093a
fix(FloatButton): BackTop attribute invalid (#7009)
* fix(FloatButton): BackTop attribute invalid

* fix: attribute props

* fix: Remove default slot

---------

Co-authored-by: undefined <undefined>
2023-10-16 14:21:39 +08:00
selicens 398710cf1b
feat(Form): FormItem add tooltip attributes (#7014)
* feat(Form): FormItem add tooltip attributes

* fix: Delete duplicate types

* fix: Remove excess slots and types

* Update FormItemLabel.tsx

---------

Co-authored-by: undefined <undefined>
Co-authored-by: tangjinzhou <415800467@qq.com>
2023-10-16 14:20:32 +08:00
黄小民 858c4ec409
fix bug:#6911 a-range-picker canot close when set popContainer (#6994)
* fix bug:#6911 a-range-picker 组件选择完之后下拉面板无法收起的问题

* update prettier to 3.0.3

* Update package.json

* Update package.json

---------

Co-authored-by: tangjinzhou <415800467@qq.com>
2023-10-16 11:42:55 +08:00
一堆菠萝 77eab3637c
docs(pagination): fix pageSizeOptions API (#7010) 2023-10-16 10:39:56 +08:00
Konv Suu 664711373c
fix(drawer): wrapper style pass to drawer content (#6983) 2023-10-16 09:57:27 +08:00
Konv Suu 21d85ea82c
fix(form-item): initialValue issue in resetField (#6979) 2023-10-16 09:54:41 +08:00
Konv Suu b3ef24963f
fix(checkbox): get disabled prop from parent (#6970) 2023-10-16 09:53:29 +08:00
Konv Suu f953482a4d
chore: remove repeat type (#6962) 2023-10-16 09:51:13 +08:00
Cherry7 a9f9899185
fix(useMessage): closeIcon (#6957)
* fix(useMessage): closeIcon

* chore: del debugger
2023-10-16 09:50:38 +08:00
果冻橙 c99e9b00bd
fix: chrome 117 onCancel event (#6991) 2023-10-16 09:48:13 +08:00
Nitin Ramnani 3084ced55f
test: Added testcases for Tour Component (#7000) 2023-10-16 09:46:04 +08:00
Konv Suu c5ea668e88
chore: provide esm output file in dist (#6966) 2023-10-16 09:44:54 +08:00
Konv Suu 3c5fb84542
fix(vc-image): remove repeat listener (#6945) 2023-09-15 14:25:48 +08:00
Konv Suu 2f7f0e6928
fix(message): getContainer prop doesn't work (#6942) 2023-09-15 14:21:22 +08:00
agoni1212 2c4d4650da
docs: typo (#6941) 2023-09-15 14:19:15 +08:00
Konv Suu 0f1ffc99cd
chore: optimize startup performance (#6952) 2023-09-15 14:18:44 +08:00
tangjinzhou 83d6c93765 release 4.0.3 2023-09-10 11:03:59 +08:00
tangjinzhou a6c945caaa fix: support shadow dom, close #6912 2023-09-10 10:36:30 +08:00
tangjinzhou d0f7c34497 chore: update cssinjs 2023-09-09 23:31:44 +08:00
tangjinzhou 2b8f2adcbf fix: icons support shadow dom, close #6914 2023-09-09 21:50:57 +08:00
Attacktive f25bf6e189
docs: correct simple copy-paste error (#6924) 2023-09-09 09:21:18 +08:00
Konv Suu 93415d0442
docs: mobile drawer menu trigger (#6927) 2023-09-09 09:20:46 +08:00
Konv Suu d185a3af21
docs: update dynamic form item demo (#6930) 2023-09-09 09:19:16 +08:00
tangjinzhou d3800b54a3 chore: update github workflow 2023-09-09 09:11:20 +08:00
tangjinzhou b7eed32484 docs: update img link 2023-09-02 21:06:07 +08:00
Konv Suu 46be19531d
docs: add hide code btn in the bottom for code box (#6917) 2023-09-01 09:35:37 +08:00
tangjinzhou 089548ed74 release 4.0.2 2023-08-31 08:05:31 +08:00
Konv Suu ce72484623
fix(transfer): checkbox click evt run repeatedly (#6902) 2023-08-31 07:47:10 +08:00
tangjinzhou 31d00bf7d1 chore: update lit & format 2023-08-30 22:48:17 +08:00
tangjinzhou deada0aeb8 chore: udpate lint, close #6896 2023-08-30 21:44:03 +08:00
Konv Suu 418d8b33dd
fix(modal): add onUpdate:open prop (#6876) 2023-08-30 16:18:54 +08:00
24min 3c05b7704b
fix(ImageGroup):fix open imagegroup without animation (#6898) 2023-08-30 16:10:03 +08:00
Konv Suu 1254677805
fix: table expandColumnTitle slot type declaration (#6908) 2023-08-30 16:08:01 +08:00
Konv Suu f7cc27b7ad
fix: onAfterClose init flip value (#6913) 2023-08-30 16:07:35 +08:00
tangjinzhou 9855e43805 fix: button wave error, close #6895 2023-08-30 16:05:54 +08:00
Konv Suu 1f01ae0728
docs: nav-phone-icon display normal (#6906) 2023-08-30 15:39:15 +08:00
Konv Suu 9464158c0c
docs(modal): remove obsolete apis (#6904) 2023-08-30 15:38:39 +08:00
24min 13a4470fd8
docs:fix full-screen modal on the presentation documentation has no effect (#6905) 2023-08-30 15:37:13 +08:00
cc hearts 84fb4b4b3d
docs: github icon support hover tips and optimized the background (#6899)
* docs: github icon support hover tips and optimized the background color under hover

* refactor: modify icon to `icon` export

* style: optimize githubIcon style
2023-08-30 15:36:18 +08:00
cc hearts 106750ed62
docs[FormItem]: update FormItem name attribute type (#6897) 2023-08-30 15:35:20 +08:00
tangjinzhou cac650737c docs: add align #6885 2023-08-30 15:26:59 +08:00
Konv Suu 95fa2547fe
docs: add judgement condition for contributor list (#6889) 2023-08-30 15:12:49 +08:00
Konv Suu 70102039c4
fix: default value for direction in configProvider (#6890)
* fix: default value for direction in configProvider

* update defaultConfigProvider
2023-08-30 15:12:10 +08:00
Konv Suu 7a0c2a384c
docs: improve footer & fix toc-affix (#6883) 2023-08-30 15:10:16 +08:00
tangjinzhou 72e148cae8 fix: portal error, close #6880 #6837 #6807 2023-08-30 15:07:27 +08:00
tangjinzhou 6c13c964c5 chore: update type 2023-08-22 14:53:50 +08:00
tangjinzhou 367ddff30e release 4.0.1 2023-08-22 14:37:57 +08:00
Konv Suu e3ad856543
fix(badge): dot with processing status (#6874)
* fix(badge): dot with processing status

* tests: update snapshot
2023-08-22 14:03:09 +08:00
Konv Suu 61df5e656f
fix(input-group): layout style (#6866)
* fix(input-group): layout style

* tests: update snapshot
2023-08-22 10:45:40 +08:00
Konv Suu 439fe840b4
docs(drawer): demo width overflow (#6872) 2023-08-22 10:05:39 +08:00
Konv Suu 197a00f6ea
docs: contributors list add last updated time (#6871) 2023-08-22 10:02:42 +08:00
tangjinzhou 3f99a7e985 docs: update readme 2023-08-21 14:31:04 +08:00
Konv Suu 9c0311546b
feat(input): add password visible feature (#6863)
* feat(input): modify visibilityToggle feature

* test: update snapshot and update test cases

* Update Password.tsx

* Update Password.tsx

* chore: update

* chore: update demo and test

---------

Co-authored-by: tangjinzhou <415800467@qq.com>
2023-08-18 17:03:16 +08:00
Kaivan Wong 7f5b630d72
docs: update the description for fieldNames fields. (#6835)
* fix: update the description for fieldNames fields.

* Update index.zh-CN.md

---------

Co-authored-by: tangjinzhou <415800467@qq.com>
2023-08-18 15:51:17 +08:00
selicens 65ccb447c9
feat(AutoComplete): add border less and customize clear button (#6829)
* feat: add border less

* feat: add customize clear button
2023-08-18 14:52:22 +08:00
tangjinzhou 18405e13b2 docs: update site style 2023-08-18 14:40:56 +08:00
Konv Suu 9e78b4a985
fix(tag): checkable tag don't pass class props (#6854), close #6850 2023-08-18 14:34:44 +08:00
Konv Suu 6cf5d79e2e
fix(tabs): animated tabs style (#6855), close #6804 2023-08-18 14:33:41 +08:00
Konv Suu 1abc33a9e7
docs: improve algolia dropdown menu shadow effect (#6845) 2023-08-18 14:24:36 +08:00
Konv Suu e39e998ecc
feat: pagination buttons transition style (#6832) 2023-08-18 14:23:50 +08:00
selicens cfd4aadc29
feat(Avatar): group add shape & synch demo (#6822) 2023-08-18 14:22:07 +08:00
Konv Suu 38dd977b4c
style: remove table's tr rounded corner (#6825) 2023-08-18 13:52:23 +08:00
selicens 72f9262d0a
feat(Tag): add border less & synch checkable (#6819) 2023-08-18 13:48:00 +08:00
cc-hearts c2d71fa7c3
docs[Form]: fix form docs code references (#6843)
* docs[Form]: fix form docs code references

* docs[Form]: fix form en docs code references

* docs[Form]: fix form en docs title
2023-08-18 11:11:54 +08:00
Cherry7 969dadb265
fix: image height (#6840), close #6836
* fix: image height

* test: update snap
2023-08-18 11:10:44 +08:00
No Two 9c3bf46108
fix: fix spelling of words in code. (#6839) 2023-08-18 11:08:47 +08:00
Konv Suu 141f0100d2
docs: improve site page (#6826) 2023-08-18 11:07:22 +08:00
Konv Suu 6ced156342
docs: add icon search input (#6828)
* docs: add icon search input

* docs: add affix for search input
2023-08-18 11:05:17 +08:00
selicens 42608a5121
docs: add contributors list (#6842) 2023-08-18 11:03:57 +08:00
Konv Suu 22b21cdac8
docs: use a-space replace br in demo (#6861) 2023-08-18 11:03:03 +08:00
Zev Zhu 80a5b531f6
feat: add px2rem in cssinjs (#6817)
* fix: fix table column data is passed into chlidren is undefined or null errorr

* feat: add px2rem in cssinjs
2023-08-18 09:48:10 +08:00
内小子 cacbde3e03
fix(InputNumber): input-number mouseup (#6772)
* fix(InputNumber): input-number mouseup

* fix: replace  with onClick

---------

Co-authored-by: nbn <nabaonan@yunlizhihui.com>
2023-08-06 12:46:26 +08:00
tangjinzhou e3f09a18a1 feat: okText add function #6748 2023-08-06 12:44:16 +08:00
selicens 7bfe30d280
docs(Modal): confirm default oktext synch (#6745) (#6748)
* docs(Modal): confim default oktext synch

* fix: okText logic
2023-08-06 12:43:09 +08:00
Zev Zhu 53dc5daaaf
feat: add static-style-extract (#6713)
* docs: add ant-design-vue nuxt module

* feat: add static-style-extract

* docs: fix import defineProps and defineEmits

* feat: add static-style extract test

* fix: add ignore component

* feat:  calendar select support info.source param (#6697)

* docs: add ant-design-vue nuxt module

* feat: calendar select support info.source param

* docs: synchronous config-provider demo (#6706)

* revert: #6706

* feat: node error

* fix: Handle the output of styles in Server Side Rendering mode

* fix: fix value required error

* chore: change tests dirname

* fix: auchor warning

* chore: add tests

* chore: generate tests snap

* docs: add ssr docs

* docs: synchronous config-provider demo (#6706)

* revert: #6706

* docs: add extract ssr doc

* fix: Removing canUseDom does not have any effect.

* fix: remove range picker in picker map

* fix: watch source can only be a getter/effect function style warning

* fix: styleContext props maybe ref

* fix: remove black list component

* feat: add compChildNameMap

---------

Co-authored-by: selicens <1244620067@qq.com>
Co-authored-by: tangjinzhou <415800467@qq.com>
2023-08-06 12:28:22 +08:00
Cherry7 531ae16553
fix: Dropdown show (#6757) 2023-08-06 11:50:43 +08:00
tangjinzhou d2b6eb9d94 docs: update site 2023-08-06 11:25:35 +08:00
tangjinzhou 27a4d8ceff
Revert "docs: banner adjust light and dark mode (#6799)" (#6816)
This reverts commit 826c183d0b.
2023-08-06 11:23:04 +08:00
tangjinzhou 12074a0dca Merge remote-tracking branch 'origin/feat-v4' 2023-08-06 11:18:07 +08:00
selicens 8f95cdd5a3
feat(App): add App component (#6735)
* feat(App): add App component

* docs: modification error

* docs: doucment update

docs: doucment update
2023-08-06 10:58:13 +08:00
Konv Suu cb0abe5fd5
docs: prev and next buttons only show cn title (#6806) 2023-08-06 10:52:49 +08:00
Konv Suu ed87500e77
docs: fix typo in en docs (#6805) 2023-08-06 10:51:50 +08:00
Konv Suu c01630113d
fix(input): prefix prop has not been passed (#6810), close #4809 2023-08-06 10:51:24 +08:00
Konv Suu 5279d1289a
fix(checkbox): change trigger form validation. (#6741) 2023-07-31 08:52:52 +08:00
Cherry7 9d406ab7ba
fix(PageHeader): ghost style (#6761)
* test(pageheader): update test snap

* fix: ghost style

* fix: ghost style

* chore(pageheader): update ghost demo

* test(pageheader): update test snap
2023-07-31 08:49:35 +08:00
Konv Suu 826c183d0b
docs: banner adjust light and dark mode (#6799) 2023-07-31 08:48:30 +08:00
tangjinzhou bc576d6255 docs: update treeselect 2023-07-29 12:21:21 +08:00
Cherry7 2c39273cc6
fix: autoplay (#6771) close #6768 2023-07-29 12:18:58 +08:00
Cherry7 b49540a339
feat: cssinjs add MULTI_VALUE key (#6770) 2023-07-29 12:17:14 +08:00
果冻橙 37059c38fd
fix dayjs is not excluded in dist (#6767) 2023-07-29 12:16:17 +08:00
黄小民 4fe57fa322
fix(table): expandedRowRender does't work(close #6782) (#6783) 2023-07-29 12:02:34 +08:00
Konv Suu a3ccdeffc2
feat(img): add img flip feature (#6785) 2023-07-29 11:18:34 +08:00
Konv Suu e8c2860c7d
fix(image): sensitivity of image scaling (#6784) 2023-07-29 11:18:22 +08:00
Fts f1f89191ee
fix: Update presetColor.tsx (#6790)
修复相互依赖的报错
2023-07-29 11:10:13 +08:00
Cherry7 0c863c1803
Update README.md (#6734) 2023-07-17 09:35:58 +08:00
selicens 7591d5c3e6
feat: float button support badge (#6738)
* docs(FloatButton): add badge demo

* fix(Badge): color attribute invalid
2023-07-17 09:35:19 +08:00
Simon He 4ea318be30
docs(drawer): fix typo (#6736) 2023-07-17 09:07:49 +08:00
tangjinzhou 5fd00c05b5 doc: update menu 2023-07-14 12:11:27 +08:00
tangjinzhou 0a738a36b6
Merge branch 'main' into feat-v4 2023-07-14 11:56:19 +08:00
tangjinzhou 10f990d534 release 4.0.0 2023-07-14 11:54:46 +08:00
PanStar 8b5d71663a
docs: export space-compact types (#6716) 2023-07-14 10:08:30 +08:00
tangjinzhou 058e8ec542 revert: #6706 2023-07-03 21:40:54 +08:00
selicens f70b04c74f
docs: synchronous config-provider demo (#6706) 2023-07-03 21:29:54 +08:00
Zev Zhu 2ce4e7da82
feat: calendar select support info.source param (#6697)
* docs: add ant-design-vue nuxt module

* feat: calendar select support info.source param
2023-07-03 21:27:18 +08:00
selicens fc5181d1d8
docs(QRCode): Synchronize QR code demonstration and add SVG (#6660)
* fix: Synchronize QR code demonstration and add SVG

* fix: responsive loss and invalid border style

* docs: synchronize antd5.6.3 QRCode color in dark mode
2023-06-28 10:11:52 +08:00
tangjinzhou 994707bd50 fix: image animation & zindex, close #6675 2023-06-25 10:55:27 +08:00
Cherry7 e9d26f2a7d
fix: portalWrapper add autoLock prop (#6687), close #6649 2023-06-25 06:51:25 +08:00
tangjinzhou 7fd0e4a225 release 4.0 2023-06-15 21:06:59 +08:00
tangjinzhou e229248053 fix: comment node error 2023-06-15 21:06:59 +08:00
selicens 10159941b9
docs(form): add form disabled demo (#6658) 2023-06-15 16:07:35 +08:00
tangjinzhou 9c26ab05d3 style: format lint 2023-06-15 13:38:17 +08:00
果冻橙 6861a77d29
fix(tour): target position (#6629) 2023-06-15 13:23:04 +08:00
Cherry7 308c30c738
fix: add disabledContext override with form components (#6618)
* fix: add disabledContext override with form components

* test: update snap

* fix: LabelWidth demo filename

* fix: fontsize spelling mistake
2023-06-15 11:17:58 +08:00
专业逮虾户aa afc1b84ed0
feat: checkbox label slot support use option label (#6642)
* docs: 📃change the default  setting of  "treeNodeFilterProp" from  "value" to "label"

* revert: ↩revert this config and create another pr to commit

* feat: checkbox label slot support use option label

* test: 🧪update checkbox *.snap file

---------

Co-authored-by: tangjinzhou <415800467@qq.com>
2023-06-15 11:11:24 +08:00
tangjinzhou 58f6d6ee28 Merge remote-tracking branch 'origin/main' into feat-v4 2023-06-15 11:05:14 +08:00
Cupid Valentine 7270855ce8
docs: fixed the style error of online demo (#6630) 2023-06-12 22:47:37 +08:00
selicens 19f0aea965
fix: layout-sider and menu transition style(#6637) (#6640) 2023-06-12 22:47:01 +08:00
Zev Zhu 6f032c9722
docs: add ant-design-vue nuxt module (#6620) 2023-06-01 14:57:23 +08:00
selicens 6be947aeb9
docs: update v4 tabs doc error(#6606) (#6607) 2023-06-01 14:55:50 +08:00
tangjinzhou 45ede0853b release 4.0.0-rc.5 2023-05-25 22:19:01 +08:00
tangjinzhou afb2619a81 fix: pagination mini size style 2023-05-25 22:18:34 +08:00
tangjinzhou 2bf85998ba fix: checxbox style 2023-05-25 21:57:35 +08:00
tangjinzhou 42cb6871ee release 4.0.0-rc.4 2023-05-23 14:38:58 +08:00
tangjinzhou 508e8e3706 fix: paginantion error, close #6590 2023-05-23 14:38:26 +08:00
tangjinzhou fe3c2bdf89 chore: remove vue private api 2023-05-20 22:09:11 +08:00
tangjinzhou 64b9347fce 4.0.0-rc.3 2023-05-20 16:58:23 +08:00
tangjinzhou 96f940d834 release 4.0.0-rc.2, close #6588 2023-05-20 15:52:46 +08:00
tangjinzhou d3d37f08a2 Merge remote-tracking branch 'origin/main' into feat-v4 2023-05-20 15:50:21 +08:00
tangjinzhou d49082008e Merge remote-tracking branch 'origin/main' into feat-v4 2023-05-19 10:15:43 +08:00
tangjinzhou 1d0a2737a4 release 4.0.0-rc.1 2023-05-19 09:12:03 +08:00
tangjinzhou c9f0841628 feat: support vue 3.3 slot type 2023-05-18 23:30:34 +08:00
tangjinzhou 03760e3e3d Merge remote-tracking branch 'origin/main' into feat-v4 2023-05-18 23:23:43 +08:00
tangjinzhou c36f7e701f fix: tour animated 2023-05-18 07:23:46 +08:00
果冻橙 83017269ab
fix: tour-mask attrs pointer-events (#6577) 2023-05-18 07:19:48 +08:00
tangjinzhou 1c7b7a35f6 test: update tour test 2023-05-17 23:05:18 +08:00
tangjinzhou 28263bbe33 test: update snap 2023-05-17 22:57:15 +08:00
tangjinzhou 5aad611d4c fix: picker support v-show 2023-05-17 22:53:02 +08:00
tangjinzhou 429172b345 fix: tour center 2023-05-17 22:12:52 +08:00
tangjinzhou e5787c2ed2 refactor: tour #6332 2023-05-17 19:02:49 +08:00
果冻橙 698c0ff3b4
feat: add tour (#6332)
* feat v4 add tour

* fix type error

* sync tour from antd5.4.6 & fix type error

* fix error
2023-05-17 11:05:47 +08:00
tangjinzhou db4148af5a feat: remove Step __legacy 2023-05-17 09:23:44 +08:00
tangjinzhou 21cf533664 fix: tooltip custom color error 2023-05-16 22:49:17 +08:00
Zev Zhu 4c8cc0129f
fix(grid): remove grid xxxl attribute (#6572)
* fix: remove grid xxxl attribute

* docs: remove xxxl in grid docs
2023-05-16 22:30:18 +08:00
selicens a694167f37
fix: segmentd disabled label is undefined (#6556)
* fix: segmentd disabled label is undefined

* fix: segmentd disabled label is undefined

* fix: segmentd disabled label is undefined
2023-05-14 17:02:07 +08:00
Zev Zhu 3ed455b3f7
docs(grid): update migrate docs && delete xxxl in grid docs (#6562) 2023-05-14 17:01:26 +08:00
果冻橙 e49e72d24a
fix: components bug & update docs (#6548)
* fix bug

* fix test case and update snapshot,fix space merge class
2023-05-14 16:59:56 +08:00
Zev Zhu 149cedd262
test(alert): update demo with space (#6541)
* docs(alert): update demo with space

* docs(alert): update alert test snap

---------

Co-authored-by: zhuzhengjian <zhuzhengjian@hoteamsoft.com>
2023-05-11 23:29:19 +08:00
Zev Zhu 8bf8515933
docs: update grid docs (#6549)
Co-authored-by: zhuzhengjian <zhuzhengjian@hoteamsoft.com>
2023-05-11 23:28:47 +08:00
tangjinzhou 0d24755ee3 release 4.0.0-beta.4 2023-05-08 16:39:33 +08:00
tangjinzhou f2f7cfd94d release 4.0.0-beta.3 2023-05-08 16:09:50 +08:00
tangjinzhou d933605b56 fix: getPopupContainer not work 2023-05-08 16:09:29 +08:00
果冻橙 266482deca
docs(customize-theme): update docs (#6540)
* fix introduce doc

* fix getting-started doc

* add migration-v4 doc

* fix docs

* Update migration-v4.zh-CN.md

* Update migration-v4.zh-CN.md

* Update migration-v4.en-US.md

* Update migration-v4.zh-CN.md

* Update getting-started.en-US.md

* Update getting-started.zh-CN.md

* Update introduce.en-US.md

* Update introduce.zh-CN.md

* update customize-theme doc & fix migration-v4 error

* update customize-theme doc

* fix migration-v4 error

* remove SSR & shadowDom

* Update customize-theme.zh-CN.md

* Update customize-theme.en-US.md

---------

Co-authored-by: tangjinzhou <415800467@qq.com>
2023-05-08 10:03:07 +08:00
Cherry7 fd8af2322c
docs(introduce): update docs (#6539)
* docs(introduce): update docs

* docs(introduce): add Dollar

* Update introduce.zh-CN.md

* Update introduce.en-US.md

---------

Co-authored-by: tangjinzhou <415800467@qq.com>
2023-05-07 20:36:58 +08:00
Cherry7 9fdc297686
docs(button): update demo with space (#6536)
* feat(button): demo space

* test(button): update demo snap

* chore(button): disabled demo Ghost space

* test(button): update disabled demo snap
2023-05-07 20:33:24 +08:00
tangjinzhou fded418b8a release 4.0.0-beta.2 2023-05-05 11:59:37 +08:00
tangjinzhou feffe70ebb refactor: useNotification #6527 2023-05-05 11:55:42 +08:00
tangjinzhou 02ed988cba refactor: useMessage #6527 2023-05-05 11:01:57 +08:00
Cherry7 6eb4d8f5c5
Feat(use): add useMessage useNotification (#6527)
* feat(Message): add useMessage hook

* feat(Notification): add useNotification hook

* feat(Message): add Hook demo

* feat(Notification): add Hook demo

* test(Message): update demo snap

* test(Notification): update demo snap

* docs(Message): update docs with FAQ

* docs(Notification): update docs with FAQ
2023-05-05 09:59:57 +08:00
Zev Zhu b61c88e5df
fix(config-provider): fix ConfigProvider.config is not function close #6528 (#6529) 2023-05-05 09:41:34 +08:00
tangjinzhou ac93c476d1 docs: fix tab demo error 2023-05-03 15:35:46 +08:00
tangjinzhou db46965761 release 4.0.0-beta.1 2023-05-03 15:10:52 +08:00
tangjinzhou 5578c14a8e perf: useModal #6517 2023-05-03 15:09:01 +08:00
Cherry7 69640c0af8
feat(modal): add useModal (#6517)
* feat(modal): add useModal hook

* feat(modal): add HookModal demo

* test(modal): update HookModal demo snap

* feat(modal): update modal docs

* chore(modal): update modal type
2023-05-03 14:15:34 +08:00
tangjinzhou 0df6abe3a7 Merge remote-tracking branch 'origin/main' into feat-v4 2023-05-03 13:50:14 +08:00
Zev Zhu b103b7570d
fix: dealing with switching topics modal, notification, message does not take effect close #6512 (#6518)
* fix: resolve dark mode not support

* fix: unified expression
2023-05-03 13:24:28 +08:00
tangjinzhou 61d6312783 fix: dropdown menu hide error 2023-05-02 23:36:12 +08:00
tangjinzhou 98be7071e5 Merge remote-tracking branch 'origin/main' into feat-v4 2023-04-28 15:51:46 +08:00
tangjinzhou 5439e0c164 fix: submenu type lose theme 2023-04-28 15:37:29 +08:00
Cherry7 9be58078d2
Refactor(demo): change options to composition api (#6499)
* feat(demo): A-B

* feat(demo): update B-checkbox

* feat(demo): update CheckBox -DatePicker

* feat(demo): update DatePicker - Form

* feat(demo): update Form - List

* feat(demo): update  List-pagination

* feat(demo): update  List - skeleton

* feat(demo): update  skeleton - switch

* feat(demo): update  skeleton - switch

* feat(demo): update   switch - upload

* feat(demo): update  watermark

* fix(demo): del hashId
2023-04-28 14:08:21 +08:00
果冻橙 063c06f9c6
fix: table resizable not work && type error (#6514) 2023-04-27 21:04:29 +08:00
tangjinzhou 43009f0c59 release 4.0.0-alpha.6 2023-04-23 19:33:19 +08:00
tangjinzhou 678ec079bc fix: antd.min error 2023-04-23 19:18:11 +08:00
tangjinzhou eba8f6b960 feat: menu items icon add arg 2023-04-23 15:52:31 +08:00
tangjinzhou 760c4c2695 doc: update menu icon 2023-04-23 15:00:34 +08:00
Cherry7 8ab50b1757
feat(menu): icon support function components with items and update demo (#6457)
* fix(menu): icon do not show problem

* fix(menu): icon do not show problem

* feat(menu): update demo

* test(menu): update demo snap

* chore(Menu): update docs

* test(Menu): update demo

* Update MenuItem.tsx

* Update SubMenu.tsx

---------

Co-authored-by: tangjinzhou <415800467@qq.com>
2023-04-23 14:23:15 +08:00
tangjinzhou b0990b7323 Merge remote-tracking branch 'origin/main' into feat-v4 2023-04-23 11:02:19 +08:00
tangjinzhou 5376014b33 docs: update doc anchor 2023-04-21 22:29:04 +08:00
tangjinzhou bccd9204e8 feat: anchor add customTitle slot #6447 2023-04-21 21:29:20 +08:00
Cherry7 8932aff13f
feat(anchor): add direction action (#6447)
* refactor(anchor): direction show

* refactor(anchor): update anchor css

* feat(anchor): update demo

* test(anchor): update demo test snap

* feat(anchor): update docs

* Update index.zh-CN.md

* Update index.en-US.md

---------

Co-authored-by: tangjinzhou <415800467@qq.com>
2023-04-21 17:33:38 +08:00
tangjinzhou de00607dc7 feat: remove backtop 2023-04-21 16:19:41 +08:00
果冻橙 118ae9a50b
docs: v4 vuedocs (#6468)
* fix introduce doc

* fix getting-started doc

* add migration-v4 doc

* fix docs

* Update migration-v4.zh-CN.md

* Update migration-v4.zh-CN.md

* Update migration-v4.en-US.md

* Update migration-v4.zh-CN.md

* Update getting-started.en-US.md

* Update getting-started.zh-CN.md

* Update introduce.en-US.md

* Update introduce.zh-CN.md

---------

Co-authored-by: tangjinzhou <415800467@qq.com>
2023-04-21 15:46:40 +08:00
tangjinzhou 0683ede0fb feat: add convertLegacyToken 2023-04-21 14:52:32 +08:00
果冻橙 838aa71b4b
fix: cssinjs compatibility (#6454) 2023-04-13 16:39:29 +08:00
Cherry7 2bf654da71
chore(docs): update docs (#6446)
* docs(space): update demo

* docs(affix): update docs
2023-04-12 21:25:23 +08:00
tangjinzhou 515ab9e38c release 4.0.0-alpha.5 2023-04-08 22:02:52 +08:00
tangjinzhou d4f2e97ca9 fix: modal api method i18n not work, close #6438 2023-04-08 21:56:32 +08:00
tangjinzhou be90b53527 docs: update site responsive 2023-04-08 21:14:27 +08:00
鱼见 0b85b84dcf
fix(badge): badge props count default value error (#6433) 2023-04-08 21:05:12 +08:00
果冻橙 4e277ea9bb
fix
* fix compile type errors

* fix menuprops type import

* fix lint errors

* fix lint errors

* fix format error

* fix node version

* fix run dist error

* fix run lint

* fix as any

* fix string type

* fix steps error & fix docs version select option & fix theme editor error
2023-04-08 20:57:46 +08:00
selicens bf97057c2c
test: add QRCode unit testing (#6441) 2023-04-08 20:56:35 +08:00
tangjinzhou 637656b0c3 fix: picker import error 2023-04-06 17:31:51 +08:00
tangjinzhou 0e1b7fd94f release 4.0.0-alpha.4 2023-04-06 17:12:50 +08:00
tangjinzhou 33d1553908 fix: qrcode size error, close #6418 2023-04-06 17:09:04 +08:00
Cherry7 2eaad16331
fix(defaultConfigProvider): add getPopupContainer (#6425), close #6419 2023-04-06 15:56:58 +08:00
tangjinzhou 58998c4978 fix: progress borderRadius reactive #6409 2023-04-06 15:40:10 +08:00
Cherry7 7db4265616
feat(Progress): enhance size prop and add variants (#6409)
* refactor(progress): Progress size and add variants

* feat(progress): add `getsize`

* refactor(progress): Progress size and add variants

* chore(progress): update props type

* chore(progress): update props type

* feat(progress): update demo

* feat(progress): update docs

* test(progress): update test snap

* fix(Circle): Merging classes

* test(progress): update test snap

* feat(progress): add size demo

* test(progress): add size snapshot

* chore(Progress): reback Circle svg class change
2023-04-06 15:11:58 +08:00
tangjinzhou 8a3ed32254 docs: update compatiple #6415 2023-04-06 14:46:47 +08:00
Cherry7 1151bdad0f
feat(StyleProvider): add StyleProvider handle cssinjs features (#6415)
* feat(StyleProvider): StyleProvider

* feat(StyleProvider): refactor to  use context

* chore(StyleProvider): update AStyleProviderProps type

* chore(App): reback

* chore(StyleProvider): export StyleProvider

* feat(StyleProvider): update StyleProvider docs

* feat(StyleProvider): update StyleProvider docs

* feat(StyleProvider): add StyleProvider docs routes

* chore(StyleProvider): with useStyleProvider
2023-04-06 11:07:55 +08:00
luoawai 84037f8eef
fix(Modal): fix modal locale (#6423) 2023-04-06 10:56:10 +08:00
tangjinzhou 3e46f27b59 perf: shallowRef instead ref 2023-04-05 22:03:02 +08:00
tangjinzhou 719847901e test: update steps 2023-04-05 17:04:02 +08:00
tangjinzhou fbfec0a062 refactor: steps #6406 2023-04-05 16:28:49 +08:00
tangjinzhou 9a5cbeee50 docs: update site 2023-04-05 13:50:08 +08:00
Cherry7 b0125de963
feat(Steps): add items prop and variants (#6406)
* refactor(steps): add items prop and variants

* feat(steps): add Label Placement and Inline Steps demo

* feat(steps): Label Placement and Inline Steps snap

* test(steps): Steps demo snap

* feat(Steps): update docs

* fix(Step): progressDot

* chore(useLegacyItems): change from warning to devWarning

* refactor(Steps): Remove useLegacyItems

* refactor(Steps): renderStep

* test(Steps): update test snapshot

* chore(Steps): filterEmpty

* feat(Steps): update docs
2023-04-05 13:39:40 +08:00
tangjinzhou bf1e6fec95 docs: update datepicker doc #6387 2023-04-05 13:30:31 +08:00
tangjinzhou 5f1cb0d240 fix: datepicker presets error #6387 2023-04-05 13:29:08 +08:00
Cherry7 f6daa8d28f
Feat(DatePicker): increase presets prop (#6387)
* feat(date-picker): add PresetDate type

* feat(date-picker): add usePresets hook

* feat(date-picker): add PresetPanel Component

* feat(date-picker): add PresetPanel Component

* feat(demo): update Preset Ranges Examples

* feat(docs): add new prop presets

* feat(docs): add new prop presets with english

* fix(RangePicker): footer is not managed by panels

* chore(Picker): prefixCls default rc-picker

* chore(date-picker): update presetted-ranges demo

* chore(date-picker): update rangePickerProps'presets

* feat(date-picker): presets reactively processing

* chore(date-picker): update type

* refactor(RangePicker): deprecated ranges prop

* chore(date-picker): update type

* chore(PickerPanel): del notuse panelRef

---------

Co-authored-by: tangjinzhou <415800467@qq.com>
2023-04-05 10:56:07 +08:00
tangjinzhou 48ab5a2f99 Merge remote-tracking branch 'origin/main' into feat-v4 2023-04-05 10:05:59 +08:00
Cherry7 ae27d430e5
docs: version menu (#6390) 2023-03-27 08:16:03 +08:00
Konv Suu 9dbe035efe
style: add dark style for `pre` and `code` (#6382) 2023-03-27 08:11:29 +08:00
tangjinzhou 6d60eba281 release 4.0.0-alpha.4 2023-03-21 15:09:00 +08:00
tangjinzhou bfcbd5bdef fix: ConfigProvider error for style, close #6368 2023-03-21 15:08:16 +08:00
Cherry7 4d2a37fcd3
fix: ant-piker-cell-range-hover-end style error (#6373)
* fix: ant-piker-cell-range-hover-end style error

* feat: be consistent with antd

* feat: be consistent with antd
2023-03-21 14:08:37 +08:00
tangjinzhou dcc3bb10cb fix: button wave not work 2023-03-20 16:45:26 +08:00
tangjinzhou 7d1418d9f4 doc: update baner 2023-03-20 13:36:49 +08:00
zkwolf 3653f37d6b
fix: dropdown divider disappear, close #6365 (#6369) 2023-03-20 13:32:23 +08:00
果冻橙 f265a7bb02
fix docs dark theme & add docs coverDark (#6367)
* fix docs dark theme & add docs coverDark

* fix theme Editor edit
2023-03-20 11:15:02 +08:00
tangjinzhou 89314fb4d0 fix: qrcode ; error, close #6362 2023-03-17 10:27:17 +08:00
tangjinzhou b1f38eb2ec release 4.0.0-alpha.2 2023-03-16 14:42:15 +08:00
tangjinzhou d95861aa90 fix: motion not work 2023-03-16 14:41:44 +08:00
果冻橙 5cc85f3cc1
doc: fix theme editor bgcolor (#6358) 2023-03-16 08:27:37 +08:00
tangjinzhou f3935ebb4f doc: update site 2023-03-14 13:38:47 +08:00
tangjinzhou 11c52d487d doc: update doc site 2023-03-14 10:30:18 +08:00
tangjinzhou 295c417f49 fix: remove not use file 2023-03-13 21:24:27 +08:00
tangjinzhou 27c5a6c96a fix: qrcode type 2023-03-13 15:22:48 +08:00
tangjinzhou fc7cadb3f9 release 4.0.0-alpha.1 2023-03-13 15:08:43 +08:00
tangjinzhou ad1d6443f2 fix: tag click event not trigger 2023-03-13 12:08:38 +08:00
tangjinzhou 77d0d188f0 doc: format code 2023-03-13 11:58:59 +08:00
tangjinzhou b22bd85828 fix: cssinjs effect error 2023-03-13 11:11:40 +08:00
果冻橙 f819a1b209
Feat v4 theme editor (#6349)
* feat: add theme editor container

* feat: add theme editor layout

* add left panel

* add vue-colorful & fix bug

* 修复hue组件抖动问题

* fix bug && add demo

* fix bug

* fix demo preview

* fix theme editor components demo

* add theme editor token drawer

* add theme editor token drawer

* fix bug

* open commment

* fix error demo

* fix theme editor bug
2023-03-13 09:54:21 +08:00
tangjinzhou dde2ff140d fix: token effect error 2023-03-12 23:48:46 +08:00
果冻橙 f429148734
Feat v4 theme editor (#6348)
* feat: add theme editor container

* feat: add theme editor layout

* add left panel

* add vue-colorful & fix bug

* 修复hue组件抖动问题

* fix bug && add demo

* fix bug

* fix demo preview

* fix theme editor components demo
2023-03-12 15:15:52 +08:00
tangjinzhou 23a213acda Merge remote-tracking branch 'origin/main' into feat-v4 2023-03-08 13:44:43 +08:00
tangjinzhou d241a06f9d Merge remote-tracking branch 'origin/main' into feat-v4 2023-03-04 08:37:28 +08:00
tangjinzhou 1d9a521669 fix: floatbutton animation not work 2023-03-03 17:25:11 +08:00
tangjinzhou a04cae1221 fix: groupsize context error 2023-03-03 17:13:48 +08:00
tangjinzhou add208aefb refactor: float-button 2023-03-03 16:58:47 +08:00
tangjinzhou 355c41b4aa refactor: qrcode #6315 2023-03-03 14:56:23 +08:00
果冻橙 3f5f3ecabf
Feat v4 floatbutton (#6294)
* feat: add float-button components

* fix type &  demo display

* fix components entry

* fix review bug

* fix bug

* fix .value
2023-03-02 10:59:44 +08:00
selicens 41a455f881
feat: add qrcode (#6315)
* feat: add qrcode

* fix: qrcode bug

* fix: qrcode value required

* refactor: props  deconstruct
2023-03-02 10:46:16 +08:00
zkwolf eda7247c2c
fix: inject value maybe undefined && tag style invalid (#6320)
* fix: inject value maybe undefined

* fix(tag): style invalid
2023-02-28 21:57:11 +08:00
tangjinzhou f85485e733 doc: add theme-editor 2023-02-28 16:47:38 +08:00
tangjinzhou a1e967dfc2 refactor: watermark type 2023-02-28 11:01:43 +08:00
Zev Zhu 6058ca5576
feat: add watermark (#6300)
* feat: add watermark

* feat: add watermark demo

* feat: add mutationObserver

* feat: add watermark demo
2023-02-28 10:35:10 +08:00
zkwolf dd063b8275
fix(dropdown): open invalid (#6316) 2023-02-28 10:25:46 +08:00
tangjinzhou 9c6a9fb47c fix: tag warning 2023-02-27 16:06:26 +08:00
tangjinzhou 516b2e5a0c refactor: rename _style to style 2023-02-27 16:00:05 +08:00
tangjinzhou d3a919b0bf chore: update style 2023-02-27 15:54:40 +08:00
tangjinzhou 261e7d0857 chore: update token error 2023-02-27 11:00:19 +08:00
tangjinzhou b393a0a2dd doc: refactor doc 2023-02-24 23:58:46 +08:00
tangjinzhou 2b80870461 doc: update doc 2023-02-23 21:42:41 +08:00
tangjinzhou 33a47bc27a chore: update build script 2023-02-23 17:20:38 +08:00
tangjinzhou 53b146ab88 refactor: remove not use code 2023-02-23 17:19:50 +08:00
tangjinzhou f3ffcdbc7e doc: update cover 2023-02-23 12:21:23 +08:00
tangjinzhou 37b5d02b6d fix: use open, remove visible 2023-02-23 11:58:23 +08:00
tangjinzhou 1b51e6ffb3 fix: directive not work 2023-02-23 10:01:30 +08:00
tangjinzhou f39d4894e4 refactor: form 2023-02-21 23:11:05 +08:00
一堆菠萝 975d70e7ed
fix: some type & doc (#6292)
* fix: typo (#6218)

* fix:  typo

* docs<upload>: docs update

* fix: type of minute in props disabledDateTime of DatePicker (#6233)

* docs: typo (#6256)

* feat: tooltip added overlayInnerStyle attribute

* Update abstractTooltipProps.ts

* Update Tooltip.tsx

---------

Co-authored-by: lyn <76365499@qq.com>
Co-authored-by: H1mple <35363759+baohangxing@users.noreply.github.com>
Co-authored-by: tangjinzhou <415800467@qq.com>
2023-02-21 14:10:35 +08:00
tangjinzhou c301c63e8b feat: radio add disabled context 2023-02-21 12:06:31 +08:00
果冻橙 e04f73dfef
refactor:radio (#6299)
* refactor:radio

* fix attrs
2023-02-21 11:33:54 +08:00
tangjinzhou 8fcb3fdfe3 refactor: drawer 2023-02-20 23:26:23 +08:00
tangjinzhou c7b15a96a8 refactor: image 2023-02-20 15:38:42 +08:00
tangjinzhou e8918ce589 refactor: auto-complete 2023-02-20 14:17:36 +08:00
tangjinzhou 62dda88ea0 refactor: cascader 2023-02-20 14:08:09 +08:00
tangjinzhou 3741931363 docs: update doc toc 2023-02-20 11:58:26 +08:00
tangjinzhou 7af22a70f9 perf: table 2023-02-20 11:15:17 +08:00
tangjinzhou 087dfa2f1b feat: tree-select add context size 2023-02-20 11:04:25 +08:00
果冻橙 799eeed346
refactor: tree select (#6296) 2023-02-20 10:32:25 +08:00
tangjinzhou 124aae72a4 feat: select add context size 2023-02-20 10:28:16 +08:00
果冻橙 39e5824699
refactor:select (#6295)
* refactor:select

* update doc

* delete useless
2023-02-20 00:17:22 +08:00
tangjinzhou 9df8317ece refactor: segmented #6286 2023-02-20 00:05:54 +08:00
selicens 62e7f94aba
feat: add segmented (#6286) 2023-02-18 16:16:44 +08:00
tangjinzhou 47385347ee refactor: tabs #6288 2023-02-17 23:14:26 +08:00
yang 6240ab2885
[tabs] :less to cssinjs (#6288)
* update

* switch

* Style adjustment

* refactor(Card): less to cssinjs

* tabs: less to cssinjs 开发ing

* add function cssinjs

* Eliminate irrelevant code

* Eliminate irrelevant code 2

* update components

* Eliminate irrelevant input  code
2023-02-17 22:08:24 +08:00
tangjinzhou 328e42a9be feat: tree add leafIcon 2023-02-17 22:02:59 +08:00
tangjinzhou 634675e032 refactor: rename locale file 2023-02-17 22:02:59 +08:00
果冻橙 7ddf882a99
Feat v4 fix type errors (#6285)
* fix compile type errors

* fix menuprops type import

* fix lint errors

* fix lint errors

* fix format error

* fix node version

* fix run dist error

* fix run lint

* fix as any

* fix string type
2023-02-17 22:01:30 +08:00
果冻橙 895b43338d
refactor:tree (#6276) 2023-02-17 10:04:45 +08:00
果冻橙 9f53d53cb8
refactor:timepicker (#6270)
* refactor:timepicker

* docs:update & refactor: timepicker type
2023-02-17 10:03:34 +08:00
果冻橙 cd47a277da
refactor:calendar (#6269)
* refactor:calendar

* docs:update
2023-02-17 10:02:38 +08:00
tangjinzhou adec5211f1 feat: table add expandColumnTitle slot 2023-02-17 09:49:21 +08:00
tangjinzhou a6a270b44a refactor: table 2023-02-16 19:23:44 +08:00
果冻橙 8472c25633
refactor:table (#6267)
* refactor:table

* docs:update & refactor: table type

---------

Co-authored-by: tangjinzhou <415800467@qq.com>
2023-02-16 07:44:48 +08:00
tangjinzhou c1ed77f67a feat: number add compactSize & disabledContext 2023-02-15 15:49:23 +08:00
果冻橙 df6a1fdb71
refactor:inputnumber (#6265)
* refactor:inputnumber

* docs:update & refactor: inputnumber type

---------

Co-authored-by: tangjinzhou <415800467@qq.com>
2023-02-15 15:37:49 +08:00
tangjinzhou 321989b9c2 feat: update collapse type 2023-02-15 15:33:54 +08:00
果冻橙 2f51f2d3af
refactor:collapse (#6266)
* refactor:collapse

* fix collapse props version

* docs:update & refactor: collapse type & fix collapsible
2023-02-15 15:28:52 +08:00
tangjinzhou dc9987aea8 fix: steps icon clss error 2023-02-15 14:34:11 +08:00
果冻橙 3715ded674
refactor:steps (#6264)
* refactor:steps

* fix ...attrs

* fix StepsToken error

* docs:update & refactor: steps type
2023-02-15 14:08:45 +08:00
tangjinzhou 04e3819b0b perf: timeline 2023-02-15 14:03:11 +08:00
果冻橙 587c1ca89d
refactor:timeline (#6263)
* refactor:timeline

* docs:update & refactor: timeline type
2023-02-15 13:52:47 +08:00
tangjinzhou 8a233d7c3a perf: upload motion 2023-02-15 13:38:57 +08:00
果冻橙 0464c84afc
refcator:upload (#6261)
* refcator:upload

* docs:update & refactor: upload type

* Update style.ts

---------

Co-authored-by: tangjinzhou <415800467@qq.com>
2023-02-15 10:19:49 +08:00
tangjinzhou 7e29eb2163 doc: update mentions demo 2023-02-14 15:50:16 +08:00
Zev Zhu 92795a828f
refactor: mentions (#6255)
* refactor: mentions

* refactor: mentions menu provider
2023-02-14 14:09:23 +08:00
tangjinzhou 44e5d09f22 style: update pagination props type 2023-02-14 14:06:14 +08:00
果冻橙 f6afd7fffc
refactor:pagination (#6251)
* refactor:pagination

* docs:update & refactor: pagination type
2023-02-14 14:02:22 +08:00
tangjinzhou 7de1be6a9a feat: checkbox add disabled context 2023-02-14 13:58:37 +08:00
果冻橙 19ec975deb
refactor:checkbox (#6248)
* refactor:checkbox

* docs:update & refactor: checkbox type
2023-02-14 13:49:06 +08:00
tangjinzhou 4ccb1c3e19 perf: transfer 2023-02-13 20:46:02 +08:00
果冻橙 68d295d7ef
refactor:transfer (#6247)
* refactor:transfer

* merge v4 branch & fix theme interface conflict

* docs:update & refactor: transfer type
2023-02-13 20:21:29 +08:00
果冻橙 bbfb3cef7d
refactor:carousel (#6262)
* refactor:carousel

* docs:update & refactor: carousel type

---------

Co-authored-by: tangjinzhou <415800467@qq.com>
2023-02-13 17:46:06 +08:00
tangjinzhou e9ce4eb2d5 refactor: card #6258 2023-02-13 17:35:49 +08:00
yang cb08f8551a
refactor(crad): less to cssinjs (#6258)
* update

* switch

* Style adjustment

* refactor(Card): less to cssinjs

* Eliminate invalid code

* optimization and adjustment css

* Adjust the css

* Optimize each item

* adjustment css
2023-02-13 17:21:48 +08:00
tangjinzhou f0e5da3b69 feat: slider deprecated tooltipVisible 2023-02-12 15:24:58 +08:00
果冻橙 2f049329a5
refactor:slider (#6250) 2023-02-12 15:00:38 +08:00
tangjinzhou 350dbfedbb docs: update result cover 2023-02-12 14:48:12 +08:00
bqy_fe 4b2ffd7127
refactor(result): less to cssinjs (#6246)
* refactor(result): less to cssinjs

* fix: class name is overridden
2023-02-12 14:44:50 +08:00
tangjinzhou a5389a22ea doc: update layout cover 2023-02-12 14:37:02 +08:00
bqy_fe 7a34c99935
refactor(layout): less to cssinjs (#6249) 2023-02-12 14:34:58 +08:00
songsong0707 dc480bd4b3
refactor: rate style (#6254) 2023-02-12 11:24:00 +08:00
tangjinzhou 1d774507c0 refactor: datepicker type 2023-02-12 11:18:49 +08:00
果冻橙 80918cba98
refactor:datepicker (#6245) 2023-02-12 10:37:06 +08:00
tangjinzhou 197e209b4e fix: typography #6244 2023-02-12 10:05:44 +08:00
果冻橙 82c4c8f0d3
refactor:typography (#6244)
* refactor:typography

* fix return

* fix import type
2023-02-12 09:56:57 +08:00
tangjinzhou 23b81b0e17 perf: space compact 2023-02-12 09:49:00 +08:00
bqy_fe f0649999fb
refactor(Space): less to cssinjs & add compact mode (#6229)
* refactor(Space): less to cssinjs & add compact mode

* chore(space): update md

* chore(space): add demo

* chore(space): add some demo

* feat(button): add compact mode

* fix: reactivity lose

* docs: fix props version

---------

Co-authored-by: tangjinzhou <415800467@qq.com>
2023-02-12 09:26:39 +08:00
tangjinzhou e2d4f8c2e3 feat: update type 2023-02-08 15:14:43 +08:00
果冻橙 de77b0175d
refactor:list (#6241)
* refactor:list

* fix inheritAttrs: false & attrs.class
2023-02-08 14:14:08 +08:00
果冻橙 26f98b7b10
refactor:statistic (#6240)
* refactor:statistic

* fix inheritAttrs: false & attrs.class
2023-02-08 14:11:53 +08:00
果冻橙 a9fbf98f0e
refactor:pageheader (#6239)
* refactor:pageheader

* fix inheritAttrs: false & attrs.class
2023-02-08 14:10:45 +08:00
果冻橙 fee7c04d67
refactor:comment (#6238)
* refactor:comment

* fix inheritAttrs: false & attrs.class
2023-02-08 14:09:32 +08:00
tangjinzhou 8658806e3f feat: input add disabled 2023-02-08 11:04:16 +08:00
果冻橙 4f3ce35e74
refactor:input (#6237)
* refactor:input

* fix inheritAttrs:false

* fix attrs.class
2023-02-08 07:50:04 +08:00
Zev Zhu 69c17dc255
refactor: switch (#6236)
* refactor: switch style

* refactor: delete switch style
2023-02-07 23:19:09 +08:00
tangjinzhou a40816880a refactor: progress #6234 2023-02-07 11:08:42 +08:00
Zev Zhu 2c1afa5e72
refactor: progress style (#6234)
* refactor: progress

* refactor: progress style

* fix: progress attrs
2023-02-07 10:25:02 +08:00
tangjinzhou 81e26a900e fix: empty props #6230 2023-02-07 10:06:05 +08:00
bqy_fe fc0f0d8a96
refactor(empty): less to cssinjs (#6230)
* refactor(empty): less to cssinjs

* chore: remove unuse code

* fix: reactivity lose
2023-02-07 09:57:31 +08:00
bqy_fe a205615af9
refactor(tag): less to cssinjs (#6227) 2023-02-03 09:50:40 +08:00
tangjinzhou 9b5a07220b refactor: popover & popconfirm 2023-02-02 22:18:42 +08:00
tangjinzhou 47c84cdbad refactor: dropdown 2023-02-02 22:18:42 +08:00
zkwolf 989bedda47
fix(button): link and text should not have wave (#6226) 2023-02-02 18:08:36 +08:00
Zev Zhu dd57d1e305
refactor: skeleton (#6224)
* refactor: skeleton

* refactor: skeleton style

* chore: modify skeleton demo style
2023-02-02 18:07:46 +08:00
zkwolf 158cca7f8a
test: test case error (#6225)
* fix: inject value maybe undefined

* fix: tootip emit correct value

* fix: rollback warning suffix avoid test break

* doc(grid): remove unused type="flex"
2023-02-02 18:05:58 +08:00
tangjinzhou 8099391e97 fix: spin error #6222 2023-02-01 17:33:59 +08:00
Zev Zhu 7939eb1718
refactor: spin (#6222)
* fix: typo (#6218)

* fix:  typo

* docs<upload>: docs update

* refactor: spin

* refactor: spin

* refactor: spin

* refactor: spinnn

* refactor: spin

---------

Co-authored-by: lyn <76365499@qq.com>
2023-02-01 17:17:56 +08:00
tangjinzhou 34373ca05d refactor: ts 2023-02-01 15:49:24 +08:00
tangjinzhou 4ef70b1503 doc: update demo 2023-01-31 22:49:08 +08:00
tangjinzhou 31776a2cf8 fix: row ts type not work 2023-01-31 22:37:36 +08:00
zkwolf 31ca070a18
refactor: grid (#6220)
* refactor: grid

* fix(grid): align & justify responsive

* chore: update demo and snapshot
2023-01-31 22:20:43 +08:00
tangjinzhou 1d01df4b85 refactor: tooltip 2023-01-30 22:28:00 +08:00
zkwolf 337d958c67
fix: custom class (#6217) 2023-01-29 14:50:30 +08:00
tangjinzhou 94e981e00b refactor: menu 2023-01-28 19:11:32 +08:00
tangjinzhou 221b203cbb refactor: modal 2023-01-28 10:02:40 +08:00
tangjinzhou dfe462ec6f refactor: locale-provider 2023-01-28 08:53:47 +08:00
tangjinzhou 8110d8cbbd refactor: rename locale 2023-01-28 08:39:47 +08:00
bqy_fe c903de3c0e
refactor(icon): remove style dir (#6215) 2023-01-28 08:25:17 +08:00
bqy_fe 44d7917afd
refactor(divider): less to cssinjs (#6214)
* refactor(divider): less to cssinjs

* fix: add inheritAttrs
2023-01-28 08:22:49 +08:00
tangjinzhou 73ce708868 refactor: message & notification 2023-01-27 22:36:28 +08:00
tangjinzhou d211688059 fix: responsive reactive #6213 2023-01-27 16:54:13 +08:00
zkwolf 9d5343ae9c
refactor: descriptions (#6213)
* refactor: descriptions

* fix: ts error

Co-authored-by: tangjinzhou <415800467@qq.com>
2023-01-27 16:46:58 +08:00
tangjinzhou 2d54e2124f fix: type error 2023-01-27 16:29:47 +08:00
tangjinzhou b5d7d582cd refactor: configprovider 2023-01-27 16:00:17 +08:00
tangjinzhou 0399ce0ec7 style: update util 2023-01-26 22:14:20 +08:00
tangjinzhou 94c2887c81 fix: button classname error 2023-01-26 22:13:01 +08:00
tangjinzhou 75e4b72c21 refactor: button 2023-01-26 21:42:27 +08:00
tangjinzhou 287a8d0c4e refactor: Breadcrumb 2023-01-26 16:52:06 +08:00
tangjinzhou 1e4e3cb3b4 refactor: badge 2023-01-26 11:13:29 +08:00
tangjinzhou e64a19a05a refactor: backtop 2023-01-26 10:13:10 +08:00
tangjinzhou 6c735fee67 refactor: anchor & add items 2023-01-25 17:23:03 +08:00
tangjinzhou f8ddc430cf refactor: avatar 2023-01-25 16:39:56 +08:00
tangjinzhou 641714734a doc: update component cover 2023-01-25 16:22:35 +08:00
tangjinzhou 46862d749b refactor: affix support cssinjs 2023-01-25 16:16:25 +08:00
tangjinzhou 1f33babc89 feat: alert add action slot 2023-01-25 15:27:03 +08:00
tangjinzhou b2841a27ae refactor: cssinjs 2023-01-25 11:28:53 +08:00
tangjinzhou c0d7d041b4 refactor: cssinjs 2023-01-25 10:28:10 +08:00
tangjinzhou 10b52e0072 refactor: ccsinjs 2023-01-24 22:51:59 +08:00
tangjinzhou d64c6a8d53 Merge remote-tracking branch 'origin/main' into feat-v3.3 2023-01-17 18:39:55 +08:00
tangjinzhou 2eb071ce30 release 3.3.0-beta.4 2022-12-01 21:26:57 +08:00
tangjinzhou 6bd8a9b984 test: update snap 2022-11-25 09:55:31 +08:00
tangjinzhou 040956819f Merge remote-tracking branch 'origin/main' into feat-v3.3 2022-11-24 19:28:21 +08:00
tangjinzhou 0f634e27d5 fix: popover button style 2022-09-13 20:04:00 +08:00
tangjinzhou 9815f817d4 fix: type import error 2022-08-28 09:00:25 +08:00
tangjinzhou d933f3edd5 fix: table column null error, close #5888 2022-08-12 16:19:32 +08:00
tangjinzhou dd60465373 chore: update webpack confgi 2022-08-11 22:26:35 +08:00
tangjinzhou 60a8be3014 release 3.3.0-beta.3 2022-08-11 14:27:54 +08:00
tangjinzhou a26ac3e9f4 feat: rating character add params 2022-08-11 14:24:39 +08:00
tangjinzhou e7fdb128e3 Merge remote-tracking branch 'origin/main' into feat-v3.3 2022-08-11 14:12:39 +08:00
tangjinzhou 8d0155878e Merge remote-tracking branch 'origin/main' into feat-v3.3 2022-08-07 20:03:09 +08:00
tangjinzhou e5e98e5776 feat: add tooltip-border-radius 2022-08-06 17:16:11 +08:00
meteorlxy 05357a8c3f
feat(Divider): add divider-horizontal-gutter variable (#5820) 2022-07-24 09:08:40 +08:00
tangjinzhou 86450c2a1b perf: import icons #5822 2022-07-24 08:56:44 +08:00
tangjinzhou 9ea87fb973 release 3.3.0-beta.2 2022-07-02 22:28:43 +08:00
tangjinzhou dae579a88e chore: update tools 2022-07-02 22:22:01 +08:00
tangjinzhou 58e8fd3e2e doc: update changelog 2022-07-02 21:04:01 +08:00
Amour1688 aae9a48dd0
chore: bundle esm output (#5772) 2022-07-02 21:02:48 +08:00
tangjinzhou 09c5a3e53f Merge remote-tracking branch 'origin/main' into feat-v3.3 2022-07-02 21:01:41 +08:00
tangjinzhou e42fdd7a06 Merge remote-tracking branch 'origin/main' into feat-v3.3 2022-07-02 09:54:19 +08:00
tangjinzhou 8b6a771318 Merge remote-tracking branch 'origin/main' into feat-v3.3 2022-06-24 10:52:47 +08:00
tangjinzhou bb4b86a82e feat: merge main 2022-06-13 11:07:06 +08:00
tangjinzhou 9280b418d7
Merge branch 'main' into feat-v3.3 2022-05-23 14:30:18 +08:00
tangjinzhou efe600e89e test: update snap 2022-05-23 10:42:09 +08:00
tangjinzhou 8b34bdfa5e doc: add 3.3.0 changelog 2022-05-23 09:26:07 +08:00
tangjinzhou 3b1d48b4b4 test: update test 2022-05-22 21:45:48 +08:00
tangjinzhou dd1a535943 test: update test 2022-05-22 17:01:43 +08:00
tangjinzhou 5b583962db style: lint format 2022-05-22 16:39:57 +08:00
tangjinzhou 37d35f7801 feat: table add filterResetToDefaultFilteredValue & filterSearch funcion 2022-05-22 14:23:53 +08:00
tangjinzhou a4b6c0aee4 feat: transfer add status 2022-05-22 10:35:19 +08:00
tangjinzhou 03f559a0dc feat: tree-select add status & placement 2022-05-22 10:10:43 +08:00
tangjinzhou bf1226d3bb feat: timepicker add status & placement 2022-05-21 22:23:52 +08:00
tangjinzhou 527dec6078 feat: select add status & placement 2022-05-21 22:03:56 +08:00
tangjinzhou af9371fe6f style: tooltip 2022-05-21 17:44:43 +08:00
tangjinzhou 5c136e0286 style: tag 2022-05-21 17:40:52 +08:00
tangjinzhou a32d29149f style: tabs 2022-05-21 17:38:19 +08:00
tangjinzhou e6a46b43ac feat: add some less var 2022-05-21 17:31:39 +08:00
tangjinzhou 9d1e5d72b5 fix: Switch disabled color in dark theme 2022-05-21 17:27:32 +08:00
tangjinzhou 63a688f94c feat: steps add small dot 2022-05-21 17:25:20 +08:00
tangjinzhou 21f9a1178a feat: dd aria-* to Spin 2022-05-21 17:21:53 +08:00
tangjinzhou 76573fc252 refactor: rename slider js to ts 2022-05-21 17:14:41 +08:00
tangjinzhou 208c7ac6de feat: skeleton add block input 2022-05-21 16:51:10 +08:00
tangjinzhou 44be8722f8 refactor: radio context 2022-05-21 16:29:11 +08:00
tangjinzhou a435e2c090 fix: apply scale transform to disabled star 2022-05-21 15:52:09 +08:00
tangjinzhou 8475542b2f style: upload 2022-05-21 15:50:39 +08:00
tangjinzhou 40a65d19da feat: upload add crossOrigin 2022-05-21 15:23:45 +08:00
tangjinzhou 8ad9317d11 Merge remote-tracking branch 'origin/main' into feat-v3.3 2022-05-21 15:14:29 +08:00
tangjinzhou 76585f75b9 style: popover & progress 2022-05-19 22:28:59 +08:00
tangjinzhou 3656dd5dbb style: pagination 2022-05-19 22:22:58 +08:00
tangjinzhou 7b60f2a8e6 style: page-header 2022-05-19 22:14:53 +08:00
tangjinzhou 5cf2707e11 feat: notification add top & bottom placement 2022-05-19 17:42:45 +08:00
tangjinzhou d716421745 feat: mentions add status 2022-05-19 17:34:41 +08:00
tangjinzhou c6f692222d Merge remote-tracking branch 'origin/main' into feat-v3.3 2022-05-19 17:20:31 +08:00
tangjinzhou c1a1b93553 style: update message 2022-05-19 16:38:19 +08:00
tangjinzhou 6e41fbd01f feat: inputnumber add status & upIcon & downIcon 2022-05-19 11:03:26 +08:00
tangjinzhou 093fa555ba feat: input add clearIcon & status 2022-05-18 22:51:45 +08:00
tangjinzhou e9d41efcec feat: add image progress 2022-05-16 14:56:35 +08:00
tangjinzhou d5348f0361 feat(row): add support for space-evenly 2022-05-16 14:51:48 +08:00
tangjinzhou e4f678f665 feat: add skipFlatten 2022-05-16 14:31:46 +08:00
tangjinzhou f00b9535d2 feat: dropdown add arrow 2022-05-16 10:57:15 +08:00
tangjinzhou a1ac22443e feat: drawer add rtl 2022-05-15 15:04:40 +08:00
tangjinzhou 4eb8088645 feat: datePicker add status & placement 2022-05-15 14:48:46 +08:00
tangjinzhou 353f470c11 style: config-provider 2022-05-15 10:28:34 +08:00
tangjinzhou 73f7f9e3b9 style: update checkbox 2022-05-14 15:50:50 +08:00
tangjinzhou 5bc17f0578 feat: cascader add status & showCheckedStrategy 2022-05-14 15:40:17 +08:00
tangjinzhou dbe7fe78ce feat: autocomplete add status 2022-05-14 14:57:40 +08:00
tangjinzhou 6e1f30666b refactor: form 2022-05-11 21:52:51 +08:00
tangjinzhou c4a61f210f feat: menu add itemsType 2022-05-11 09:58:23 +08:00
tangjinzhou 0244e7f5b4 refactor: Simplify Button Group Style 2022-05-10 16:18:44 +08:00
tangjinzhou 3aedf48eaf feat: Breadcrumb accessibility improvements 2022-05-10 15:48:14 +08:00
tangjinzhou 78045b4b5b fix: Badge Animation enter and leave in RTL 2022-05-10 15:43:23 +08:00
tangjinzhou 894a5b955c fix: BackTop responsive in RTL 2022-05-10 15:41:07 +08:00
tangjinzhou a8dbea7c32 style: update some code 2022-05-10 15:36:18 +08:00
tangjinzhou 1d08e80165 feat: anchor add activeLink arg 2022-05-10 15:35:44 +08:00
463 changed files with 220313 additions and 14789 deletions

View File

@ -7,4 +7,7 @@ es/
lib/ lib/
_site/ _site/
dist/ dist/
components/version/version.tsx site/dist/
components/version/version.ts
site/src/router/demoRoutes.js
locale/

View File

@ -15,9 +15,21 @@ module.exports = {
'plugin:vue/vue3-recommended', 'plugin:vue/vue3-recommended',
'plugin:import/recommended', 'plugin:import/recommended',
'plugin:import/typescript', 'plugin:import/typescript',
'prettier', '@vue/typescript/recommended',
'@vue/prettier',
// 'prettier',
], ],
// extends: [
// 'eslint:recommended',
// 'plugin:vue/vue3-recommended',
// '@vue/typescript/recommended',
// '@vue/prettier',
// ],
plugins: ['markdown', 'jest', '@typescript-eslint', 'import'], plugins: ['markdown', 'jest', '@typescript-eslint', 'import'],
globals: {
h: true,
defineProps: 'readonly',
},
overrides: [ overrides: [
{ {
files: ['*.md'], files: ['*.md'],
@ -28,12 +40,11 @@ module.exports = {
}, },
{ {
files: ['*.ts', '*.tsx'], files: ['*.ts', '*.tsx'],
extends: ['@vue/typescript/recommended', '@vue/prettier', '@vue/prettier/@typescript-eslint'], // extends: ['@vue/typescript/recommended', '@vue/prettier'],
parserOptions: { parserOptions: {
project: './tsconfig.json', project: './tsconfig.json',
}, },
rules: { rules: {
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/ban-types': 0, '@typescript-eslint/ban-types': 0,
'@typescript-eslint/consistent-type-imports': 'error', '@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/explicit-module-boundary-types': 0, '@typescript-eslint/explicit-module-boundary-types': 0,
@ -51,17 +62,21 @@ module.exports = {
parser: 'vue-eslint-parser', parser: 'vue-eslint-parser',
parserOptions: { parserOptions: {
parser: '@typescript-eslint/parser', parser: '@typescript-eslint/parser',
ecmaVersion: 2021,
}, },
rules: { rules: {
'no-console': 'off', 'no-console': 'off',
'@typescript-eslint/no-unused-vars': [ 'vue/no-reserved-component-names': 'off',
'error',
{ vars: 'all', args: 'after-used', ignoreRestSiblings: true },
],
}, },
}, },
], ],
rules: { rules: {
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/no-empty-function': 0,
'@typescript-eslint/no-unused-vars': [
'error',
{ vars: 'all', args: 'after-used', ignoreRestSiblings: true, argsIgnorePattern: '^_' },
],
'import/no-named-as-default': 'off', 'import/no-named-as-default': 'off',
'import/namespace': [2, { allowComputed: true }], 'import/namespace': [2, { allowComputed: true }],
'import/no-named-as-default-member': 'off', 'import/no-named-as-default-member': 'off',
@ -94,7 +109,4 @@ module.exports = {
], ],
'vue/multi-word-component-names': 'off', 'vue/multi-word-component-names': 'off',
}, },
globals: {
h: true,
},
}; };

View File

@ -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/
@ -13,5 +13,5 @@ contact_links:
url: https://www.paypal.me/tangjinzhou url: https://www.paypal.me/tangjinzhou
about: Love Ant Design Vue? Please consider supporting us via Paypal. about: Love Ant Design Vue? Please consider supporting us via Paypal.
- name: 支付宝/微信 赞助 - name: 支付宝/微信 赞助
url: https://qn.antdv.com/alipay-and-wechat.png url: https://aliyuncdn.antdv.com/alipay-and-wechat.png
about: Ant Design Vue 的健康持续发展需要您的支持,🙏 about: Ant Design Vue 的健康持续发展需要您的支持,🙏

View File

@ -4,12 +4,15 @@ on:
schedule: schedule:
- cron: "0 0 * * *" - cron: "0 0 * * *"
permissions:
contents: read
jobs: jobs:
close-issues: close-issues:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: need reproduce - name: need reproduce
uses: actions-cool/issues-helper@v1.7 uses: actions-cool/issues-helper@v3
with: with:
actions: 'close-issues' actions: 'close-issues'
labels: '🤔 Need Reproduce' labels: '🤔 Need Reproduce'

View File

@ -1,18 +1,25 @@
name: Issue Reply name: Issue Labeled
on: on:
issues: issues:
types: [labeled] types: [labeled]
permissions:
contents: read
jobs: jobs:
issue-reply: issue-labeled:
permissions:
issues: write # for actions-cool/issues-helper to update issues
pull-requests: write # for actions-cool/issues-helper to update PRs
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Need Reproduce - name: Need Reproduce
if: github.event.label.name == '🤔 Need Reproduce' if: github.event.label.name == '🤔 Need Reproduce'
uses: actions-cool/issues-helper@v1.2 uses: actions-cool/issues-helper@v3
with: with:
actions: 'create-comment' actions: 'create-comment'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }} issue-number: ${{ github.event.issue.number }}
body: | body: |
Hello @${{ github.event.issue.user.login }}. Please provide a online reproduction by forking this [link for vue2](https://codesandbox.io/s/2wpk21kzvr)、 [link for vue3](https://codesandbox.io/s/agitated-franklin-1w72v) or a minimal GitHub repository. Make sure to choose the correct version. Hello @${{ github.event.issue.user.login }}. Please provide a online reproduction by forking this [link for vue2](https://codesandbox.io/s/2wpk21kzvr)、 [link for vue3](https://codesandbox.io/s/agitated-franklin-1w72v) or a minimal GitHub repository. Make sure to choose the correct version.
@ -21,9 +28,10 @@ jobs:
- name: help wanted - name: help wanted
if: github.event.label.name == 'help wanted' if: github.event.label.name == 'help wanted'
uses: actions-cool/issues-helper@v1.2 uses: actions-cool/issues-helper@v3
with: with:
actions: 'create-comment' actions: 'create-comment'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }} issue-number: ${{ github.event.issue.number }}
body: | body: |
Hello @${{ github.event.issue.user.login }}. We totally like your proposal/feedback, welcome to send us a Pull Request for it. Please send your Pull Request to proper branch, fill the Pull Request Template here, provide changelog/TypeScript/documentation/test cases if needed and make sure CI passed, we will review it soon. We appreciate your effort in advance and looking forward to your contribution! Hello @${{ github.event.issue.user.login }}. We totally like your proposal/feedback, welcome to send us a Pull Request for it. Please send your Pull Request to proper branch, fill the Pull Request Template here, provide changelog/TypeScript/documentation/test cases if needed and make sure CI passed, we will review it soon. We appreciate your effort in advance and looking forward to your contribution!
@ -32,12 +40,37 @@ jobs:
- name: Usage - name: Usage
if: github.event.label.name == 'Usage' if: github.event.label.name == 'Usage'
uses: actions-cool/issues-helper@v1.2 uses: actions-cool/issues-helper@v3
with: with:
actions: 'create-comment, close-issue' actions: 'create-comment, close-issue'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }} issue-number: ${{ github.event.issue.number }}
body: | body: |
Hello @${{ github.event.issue.user.login }}, we use GitHub issues to trace bugs or discuss plans of Ant Design Vue. So, please don't ask usage questions here. You can try to open a new discussion in [antdv discussions](https://github.com/vueComponent/ant-design-vue/discussions), select `Q&A` to ask questions, also can ask questions on [Stack Overflow](http://stackoverflow.com/questions/) or [Segment Fault](https://segmentfault.com). Hello @${{ github.event.issue.user.login }}, we use GitHub issues to trace bugs or discuss plans of Ant Design Vue. So, please don't ask usage questions here. You can try to open a new discussion in [antdv discussions](https://github.com/vueComponent/ant-design-vue/discussions), select `Q&A` to ask questions, also can ask questions on [Stack Overflow](http://stackoverflow.com/questions/) or [Segment Fault](https://segmentfault.com).
你好 @${{ github.event.issue.user.login }}Ant Design Vue Issue 板块是用于 bug 反馈与需求讨论的地方。请勿询问如何使用的问题,你可以试着在 [antdv discussions](https://github.com/vueComponent/ant-design-vue/discussions) 新开一个 discussion选择 `Q&A` 类别进行提问,也可以在 [Stack Overflow](http://stackoverflow.com/questions/) 或者 [Segment Fault](https://segmentfault.com/) 中提问。 你好 @${{ github.event.issue.user.login }}Ant Design Vue Issue 板块是用于 bug 反馈与需求讨论的地方。请勿询问如何使用的问题,你可以试着在 [antdv discussions](https://github.com/vueComponent/ant-design-vue/discussions) 新开一个 discussion选择 `Q&A` 类别进行提问,也可以在 [Stack Overflow](http://stackoverflow.com/questions/) 或者 [Segment Fault](https://segmentfault.com/) 中提问。
- name: 1.x
if: github.event.label.name == '1.x'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment,close-issue'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
Hi @${{ github.event.issue.user.login }}. Current version (1.x) is off the maintenance period. We may not accept pull request or fix bug with it anymore. This topic will be auto closed.
你好 @${{ github.event.issue.user.login }}当前版本1.x已经过了维护期。我们不会再接受对其的相关 PR 与 issue。当前 topic 会被自动关闭。
- name: 2.x
if: github.event.label.name == '2.x'
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment,close-issue'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
Hi @${{ github.event.issue.user.login }}. Current version (2.x) is off the maintenance period. We may not accept pull request or fix bug with it anymore. This topic will be auto closed.
你好 @${{ github.event.issue.user.login }}当前版本2.x已经过了维护期。我们不会再接受对其的相关 PR 与 issue。当前 topic 会被自动关闭。

View File

@ -4,8 +4,16 @@ on:
issues: issues:
types: [opened] types: [opened]
permissions:
contents: read
jobs: jobs:
check-issue: issue-open-check:
permissions:
contents: read # for visiky/dingtalk-release-notify to get latest release
issues: write # for actions-cool/issues-helper to update issues
pull-requests: write # for actions-cool/issues-helper to update PRs
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions-cool/check-user-permission@v1.0.0 - uses: actions-cool/check-user-permission@v1.0.0
@ -15,7 +23,7 @@ jobs:
- name: check invalid - name: check invalid
if: (contains(github.event.issue.body, 'issue-helper') == false) && (steps.checkUser.outputs.result == 'false') if: (contains(github.event.issue.body, 'issue-helper') == false) && (steps.checkUser.outputs.result == 'false')
uses: actions-cool/issues-helper@v1.2 uses: actions-cool/issues-helper@v3
with: with:
actions: 'create-comment,add-labels,close-issue' actions: 'create-comment,add-labels,close-issue'
issue-number: ${{ github.event.issue.number }} issue-number: ${{ github.event.issue.number }}

View File

@ -1,20 +0,0 @@
name: PR Labeled
on:
pull_request_target:
types: [labeled]
jobs:
reply:
runs-on: ubuntu-latest
steps:
- name: Usage
if: github.event.label.name == 'Usage'
uses: actions-cool/issues-helper@v1.2
with:
actions: 'create-comment, close-issue'
issue-number: ${{ github.event.pull_request.number }}
body: |
Hello @${{ github.event.pull_request.user.login }}, we use GitHub PR to build and perfect of Ant Design Vue. So, please don't ask usage questions here. You can try to open a new discussion in [antdv discussions](https://github.com/vueComponent/ant-design-vue/discussions), select `Q&A` to ask questions, also can ask questions on [Stack Overflow](http://stackoverflow.com/questions/) or [Segment Fault](https://segmentfault.com).
你好 @${{ github.event.pull_request.user.login }}Ant Design Vue PR 是用于建设、完善项目的地方。请勿询问如何使用的问题,你可以试着在 [antdv discussions](https://github.com/vueComponent/ant-design-vue/discussions) 新开一个 discussion选择 `Q&A` 类别进行提问,也可以在 [Stack Overflow](http://stackoverflow.com/questions/) 或者 [Segment Fault](https://segmentfault.com/) 中提问。

1
.npmrc Normal file
View File

@ -0,0 +1 @@
enable-pre-post-scripts=true

View File

@ -10,6 +10,159 @@
--- ---
## 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 Paginations 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
- 🌟 Added Flex component [#7052](https://github.com/vueComponent/ant-design-vue/issues/7052)
- 🌟 ConfigProvider adds wave configuration [#7036](https://github.com/vueComponent/ant-design-vue/issues/7036)
- 🌟 Watermark supports dark mode [#7067](https://github.com/vueComponent/ant-design-vue/issues/7067)
- 🐞 Fix Space duplicate Key problem [#7048](https://github.com/vueComponent/ant-design-vue/issues/7048)
- 🐞 Fix Upload disabled priority error issue [#7047](https://github.com/vueComponent/ant-design-vue/issues/7047)
- 🐞 Fix Carousel rendering error in jsx [#7077](https://github.com/vueComponent/ant-design-vue/issues/7077)
- 🐞 Fix Message offset position problem [#7093](https://github.com/vueComponent/ant-design-vue/issues/7093)
- 🐞 Fix the problem of animation failure when using Collapse custom prefix [#7074](https://github.com/vueComponent/ant-design-vue/issues/7074)
## 4.0.6
- 🐞 Fix the Dropdown onVisibleChange failure issue introduced in 4.0.4 [#7031](https://github.com/vueComponent/ant-design-vue/issues/7031)
## 4.0.5
- 🐞 Fix cssinjs performance issue [#7023](https://github.com/vueComponent/ant-design-vue/issues/7023)
## 4.0.4
- 🌟 Added esm target file
- 🌟 Added tooltip attribute to FormItem [#7014](https://github.com/vueComponent/ant-design-vue/issues/7014)
- 🐞 Fix useMessage getContainer not taking effect [#6942](https://github.com/vueComponent/ant-design-vue/issues/6942)
- 🐞 Fix the problem of Image triggering onPreviewVisibleChange event multiple times [#6945](https://github.com/vueComponent/ant-design-vue/issues/6945)
- 🐞 Fix the problem that Checkbox global disabled does not take effect [#6970](https://github.com/vueComponent/ant-design-vue/issues/6970)
- 🐞 Fix Drawer contentWrapperStyle not taking effect [#6983](https://github.com/vueComponent/ant-design-vue/issues/6983)
- 🐞 Optimize Select Dropdown and other drop-down list scroll bar display hidden logic [#6987](https://github.com/vueComponent/ant-design-vue/issues/6987)
- 🐞 Fix the problem of hiding when there are components such as input in the drop-down list such as Select Dropdown [#7020](https://github.com/vueComponent/ant-design-vue/issues/7020)
## 4.0.3
- 🐞 Fix the problem of style loss under shadow Dom [#6912](https://github.com/vueComponent/ant-design-vue/issues/6912)
- 🐞 Upgrade Icon dependency and fix icon css missing problem under shadow Dom [#6914](https://github.com/vueComponent/ant-design-vue/issues/6914)
## 4.0.2
- 🐞 Fix useMessage causing body to be removed [#6880](https://github.com/vueComponent/ant-design-vue/issues/6880)
- 🐞 Fix the problem that the water ripple effect does not disappear after Button loading is switched [#6895](https://github.com/vueComponent/ant-design-vue/issues/6895)
- 🐞 Fixed the problem that flip does not reset after Image is closed [#6913](https://github.com/vueComponent/ant-design-vue/issues/6913)
- 🐞 Fix ImageGroup animation effect loss problem [#6898](https://github.com/vueComponent/ant-design-vue/issues/6898)
- 🐞 Fix Modal missing onUpdate:open attribute declaration [#6876](https://github.com/vueComponent/ant-design-vue/issues/6876)
- 🐞 Fixed the issue of multiple clicks being triggered at the edge of Transfer's Checkbox [#6902](https://github.com/vueComponent/ant-design-vue/issues/6902)
## 4.0.1
- 🌟 FloatButton add Badge support [#6738](https://github.com/vueComponent/ant-design-vue/issues/6738)
- 🌟 Image preview zoom in and out sensitivity adjustment [#6784](https://github.com/vueComponent/ant-design-vue/issues/6784)
- 🌟 Add flip feature to Image [#6785](https://github.com/vueComponent/ant-design-vue/issues/6785)
- 🌟 Add App component to provide context [#6735](https://github.com/vueComponent/ant-design-vue/issues/6735)
- 🌟 Style extraction feature for SSR [#6757](https://github.com/vueComponent/ant-design-vue/issues/6757)
- 🌟 Support px2rem [#6817](https://github.com/vueComponent/ant-design-vue/issues/6817)
- 🌟 Tag supports borderless mode [#6819](https://github.com/vueComponent/ant-design-vue/issues/6819)
- 🌟 Avatar group mode supports shape [#6822](https://github.com/vueComponent/ant-design-vue/issues/6822)
- 🌟 AutoComplete supports borderless and custom clearIcon [#6829](https://github.com/vueComponent/ant-design-vue/issues/6829)
- 🌟 InputPassword supports controlled visible [#6863](https://github.com/vueComponent/ant-design-vue/issues/6863)
- 🐞 Fix the style misalignment problem when InputGroup is large [#6866](https://github.com/vueComponent/ant-design-vue/issues/6866)
- 🐞 Fix the problem that Checkable Tag cannot customize class [#6854](https://github.com/vueComponent/ant-design-vue/issues/6854)
- 🐞 Fix the rendering problem in Tabs animation mode [#6855](https://github.com/vueComponent/ant-design-vue/issues/6855)
- 🐞 Fix the problem that the Image height attribute does not take effect [#6840](https://github.com/vueComponent/ant-design-vue/issues/6840)
- 🐞 Fix InputNumber trigger mouseup event [#6772](https://github.com/vueComponent/ant-design-vue/issues/6772)
- 🐞 Fix the Dropdown style problem when Tabs are collapsed [#6757](https://github.com/vueComponent/ant-design-vue/issues/6757)
- 🐞 Fix Table expandedRowRender property does not take effect [#6783](https://github.com/vueComponent/ant-design-vue/issues/6783)
- 🐞 Fix dayjs not packaged into dist [#6767](https://github.com/vueComponent/ant-design-vue/issues/6767)
- 🐞 Fix clipPath browser compatibility issue [#6770](https://github.com/vueComponent/ant-design-vue/issues/6770)
- 🐞 Fix Carousel autoplay responsive problem [#6768](https://github.com/vueComponent/ant-design-vue/issues/6768)
- 🐞 Fix PageHeader ghost style problem [#6761](https://github.com/vueComponent/ant-design-vue/issues/6761)
- 🐞 Fix Checkbox not triggering Form validation [#6741](https://github.com/vueComponent/ant-design-vue/issues/6741)
- 🐞 Fix the problem that the Input prefix attribute does not take effect [#6810](https://github.com/vueComponent/ant-design-vue/issues/6810)
- 🐞 Fix Badge style problem in Avatar [#6874](https://github.com/vueComponent/ant-design-vue/issues/6874)
## 4.0 ## 4.0
### 🔥🔥🔥 4.0 official version released 🔥🔥🔥 ### 🔥🔥🔥 4.0 official version released 🔥🔥🔥

View File

@ -10,6 +10,159 @@
--- ---
## 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
- 🌟 新增 Flex 组件 [#7052](https://github.com/vueComponent/ant-design-vue/issues/7052)
- 🌟 ConfigProvider 新增 wave 配置 [#7036](https://github.com/vueComponent/ant-design-vue/issues/7036)
- 🌟 Watermark 支持暗黑模式 [#7067](https://github.com/vueComponent/ant-design-vue/issues/7067)
- 🐞 修复 Space 重复 Key 问题 [#7048](https://github.com/vueComponent/ant-design-vue/issues/7048)
- 🐞 修复 Upload disabled 优先级错误问题 [#7047](https://github.com/vueComponent/ant-design-vue/issues/7047)
- 🐞 修复 Carousel 在 jsx 中渲染错误问题 [#7077](https://github.com/vueComponent/ant-design-vue/issues/7077)
- 🐞 修复 Message 偏移位置问题 [#7093](https://github.com/vueComponent/ant-design-vue/issues/7093)
- 🐞 修复 Collapse 自定义 prefix 时动画失效问题 [#7074](https://github.com/vueComponent/ant-design-vue/issues/7074)
## 4.0.6
- 🐞 修复 4.0.4 引入的 Dropdown onVisibleChange 失效问题 [#7031](https://github.com/vueComponent/ant-design-vue/issues/7031)
## 4.0.5
- 🐞 修复 cssinjs 性能问题 [#7023](https://github.com/vueComponent/ant-design-vue/issues/7023)
## 4.0.4
- 🌟 新增 esm 目标文件
- 🌟 FormItem 新增 tooltip 属性 [#7014](https://github.com/vueComponent/ant-design-vue/issues/7014)
- 🐞 修复 useMessage getContainer 不生效问题 [#6942](https://github.com/vueComponent/ant-design-vue/issues/6942)
- 🐞 修复 Image 多次触发 onPreviewVisibleChange 事件问题 [#6945](https://github.com/vueComponent/ant-design-vue/issues/6945)
- 🐞 修复 Checkbox 全局 disabled 不生效问题 [#6970](https://github.com/vueComponent/ant-design-vue/issues/6970)
- 🐞 修复 Drawer contentWrapperStyle 不生效问题 [#6983](https://github.com/vueComponent/ant-design-vue/issues/6983)
- 🐞 优化 Select Dropdown 等下拉列表滚动条显示隐藏逻辑 [#6987](https://github.com/vueComponent/ant-design-vue/issues/6987)
- 🐞 修复 Select Dropdown 等下拉列表中有 input 等组件时,隐藏问题 [#7020](https://github.com/vueComponent/ant-design-vue/issues/7020)
## 4.0.3
- 🐞 修复 shadow Dom 下样式丢失问题 [#6912](https://github.com/vueComponent/ant-design-vue/issues/6912)
- 🐞 升级 Icon 依赖,修复 shadow Dom 下 icon css 丢失问题 [#6914](https://github.com/vueComponent/ant-design-vue/issues/6914)
## 4.0.2
- 🐞 修复 useMessage 导致 body 被移除问题 [#6880](https://github.com/vueComponent/ant-design-vue/issues/6880)
- 🐞 修复 Button loading 切换后,水波纹效果不消失问题 [#6895](https://github.com/vueComponent/ant-design-vue/issues/6895)
- 🐞 修复 Image 关闭后 flip 没有重置问题 [#6913](https://github.com/vueComponent/ant-design-vue/issues/6913)
- 🐞 修复 ImageGroup 动画效果丢失问题 [#6898](https://github.com/vueComponent/ant-design-vue/issues/6898)
- 🐞 修复 Modal 缺少 onUpdate:open 属性声明 [#6876](https://github.com/vueComponent/ant-design-vue/issues/6876)
- 🐞 修复 Transfer 的 Checkbox 边缘处会触发多次 click 问题 [#6902](https://github.com/vueComponent/ant-design-vue/issues/6902)
## 4.0.1
- 🌟 FloatButton 添加 Badge 支持 [#6738](https://github.com/vueComponent/ant-design-vue/issues/6738)
- 🌟 Image 预览放大缩小灵敏度调整 [#6784](https://github.com/vueComponent/ant-design-vue/issues/6784)
- 🌟 Image 新增翻转特性 [#6785](https://github.com/vueComponent/ant-design-vue/issues/6785)
- 🌟 新增 App 组件,用于提供上下文 [#6735](https://github.com/vueComponent/ant-design-vue/issues/6735)
- 🌟 样式抽离特性用于 SSR [#6757](https://github.com/vueComponent/ant-design-vue/issues/6757)
- 🌟 支持 px2rem [#6817](https://github.com/vueComponent/ant-design-vue/issues/6817)
- 🌟 Tag 支持无边框模式 [#6819](https://github.com/vueComponent/ant-design-vue/issues/6819)
- 🌟 Avatar group 模式支持 shape [#6822](https://github.com/vueComponent/ant-design-vue/issues/6822)
- 🌟 AutoComplete 支持无边框和自定义 clearIcon [#6829](https://github.com/vueComponent/ant-design-vue/issues/6829)
- 🌟 InputPassword 支持受控 visible [#6863](https://github.com/vueComponent/ant-design-vue/issues/6863)
- 🐞 修复 InputGroup 在 large 时样式错位问题 [#6866](https://github.com/vueComponent/ant-design-vue/issues/6866)
- 🐞 修复 Checkable Tag 无法自定义 class 问题 [#6854](https://github.com/vueComponent/ant-design-vue/issues/6854)
- 🐞 修复 Tabs 动画模式下渲染问题 [#6855](https://github.com/vueComponent/ant-design-vue/issues/6855)
- 🐞 修复 Image height 属性不生效问题 [#6840](https://github.com/vueComponent/ant-design-vue/issues/6840)
- 🐞 修复 InputNumber 触发 mouseup 事件问题 [#6772](https://github.com/vueComponent/ant-design-vue/issues/6772)
- 🐞 修复 Tabs 折叠时 Dropdown 样式问题 [#6757](https://github.com/vueComponent/ant-design-vue/issues/6757)
- 🐞 修复 Table expandedRowRender 属性不生效 [#6783](https://github.com/vueComponent/ant-design-vue/issues/6783)
- 🐞 修复 dayjs 未打包进 dist 问题 [#6767](https://github.com/vueComponent/ant-design-vue/issues/6767)
- 🐞 解决 clipPath 浏览器兼容问题 [#6770](https://github.com/vueComponent/ant-design-vue/issues/6770)
- 🐞 修复 Carousel autoplay 响应式问题 [#6768](https://github.com/vueComponent/ant-design-vue/issues/6768)
- 🐞 修复 PageHeader ghost 样式问题 [#6761](https://github.com/vueComponent/ant-design-vue/issues/6761)
- 🐞 修复 Checkbox 没有触发 Form 校验问题 [#6741](https://github.com/vueComponent/ant-design-vue/issues/6741)
- 🐞 修复 Input prefix 属性未生效问题 [#6810](https://github.com/vueComponent/ant-design-vue/issues/6810)
- 🐞 修复 Badge 在 Avatar 中样式问题 [#6874](https://github.com/vueComponent/ant-design-vue/issues/6874)
## 4.0 ## 4.0
### 🔥🔥🔥 4.0 正式版发布 🔥🔥🔥 ### 🔥🔥🔥 4.0 正式版发布 🔥🔥🔥

View File

@ -1,6 +1,6 @@
<p align="center"> <p align="center">
<a href="https://www.antdv.com/"> <a href="https://www.antdv.com/">
<img width="200" src="https://qn.antdv.com/logo.png"> <img width="200" src="https://aliyuncdn.antdv.com/logo.png">
</a> </a>
</p> </p>
@ -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 组件库。
![test](https://github.com/vueComponent/ant-design-vue/workflows/test/badge.svg) [![codecov](https://img.shields.io/codecov/c/github/vueComponent/ant-design-vue/master.svg?style=flat-square)](https://codecov.io/gh/vueComponent/ant-design-vue) [![npm package](https://img.shields.io/npm/v/ant-design-vue.svg?style=flat-square)](https://www.npmjs.org/package/ant-design-vue) [![NPM downloads](http://img.shields.io/npm/dm/ant-design-vue.svg?style=flat-square)](http://www.npmtrends.com/ant-design-vue) [![backers](https://opencollective.com/ant-design-vue/backers/badge.svg)](#backers) [![sponsors](https://opencollective.com/ant-design-vue/sponsors/badge.svg)](#sponsors) [![extension-for-VSCode](https://img.shields.io/badge/extension%20for-VSCode-blue.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=ant-design-vue.vscode-ant-design-vue-helper) [![issues-helper](https://img.shields.io/badge/Issues%20Manage%20By-issues--helper-orange?style=flat-square)](https://github.com/actions-cool/issues-helper) ![test](https://github.com/vueComponent/ant-design-vue/workflows/test/badge.svg) [![codecov](https://img.shields.io/codecov/c/github/vueComponent/ant-design-vue/master.svg?style=flat-square)](https://codecov.io/gh/vueComponent/ant-design-vue) [![npm package](https://img.shields.io/npm/v/ant-design-vue.svg?style=flat-square)](https://www.npmjs.org/package/ant-design-vue) [![NPM downloads](http://img.shields.io/npm/dm/ant-design-vue.svg?style=flat-square)](http://www.npmtrends.com/ant-design-vue) [![backers](https://opencollective.com/ant-design-vue/backers/badge.svg)](#backers) [![sponsors](https://opencollective.com/ant-design-vue/sponsors/badge.svg)](#sponsors) [![extension-for-VSCode](https://img.shields.io/badge/extension%20for-VSCode-blue.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=ant-design-vue.vscode-ant-design-vue-helper) [![issues-helper](https://img.shields.io/badge/Issues%20Manage%20By-issues--helper-orange?style=flat-square)](https://github.com/actions-cool/issues-helper)
@ -26,6 +26,12 @@ An enterprise-class UI components based on Ant Design and Vue 3.
- 开箱即用的高质量 Vue 组件。 - 开箱即用的高质量 Vue 组件。
- 共享 [Ant Design of React](http://ant-design.gitee.io/docs/spec/introduce-cn) 设计工具体系。 - 共享 [Ant Design of React](http://ant-design.gitee.io/docs/spec/introduce-cn) 设计工具体系。
## 关注我们
收藏加关注,第一时间获取更新动态!
![star us](https://user-images.githubusercontent.com/6937879/261937060-e0501ab3-9388-4712-a25d-3f2ba2271865.gif)
## 支持环境 ## 支持环境
- 现代浏览器。1.x 版本支持 IE 9+(需要 [polyfills](https://www.antdv.com/docs/vue/getting-started-cn/#兼容性) - 现代浏览器。1.x 版本支持 IE 9+(需要 [polyfills](https://www.antdv.com/docs/vue/getting-started-cn/#兼容性)
@ -67,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 界面解决方案 |
## 问答 ## 问答
@ -81,24 +88,33 @@ ant-design-vue 是 MIT 协议的开源项目。为了项目能够更好的持续
- [Patreon](https://www.patreon.com/tangjinzhou) - [Patreon](https://www.patreon.com/tangjinzhou)
- [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://qn.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>
## [更多赞助者 (通过 Patreon、支付宝、微信、paypal 等等)](https://github.com/vueComponent/ant-design-vue/blob/master/BACKERS.md) ## [更多赞助者 (通过 Patreon、支付宝、微信、paypal 等等)](https://github.com/vueComponent/ant-design-vue/blob/master/BACKERS.md)
## 贡献者
感谢所有为 ant-design-vue 做出贡献的人!
<a href="https://github.com/vueComponent/ant-design-vue/graphs/contributors">
<img src="https://contrib.rocks/image?repo=vueComponent/ant-design-vue&max=100&columns=15" />
</a>

View File

@ -1,6 +1,6 @@
<p align="center"> <p align="center">
<a href="https://www.antdv.com/"> <a href="https://www.antdv.com/">
<img width="200" src="https://qn.antdv.com/logo.png"> <img width="200" src="https://aliyuncdn.antdv.com/logo.png">
</a> </a>
</p> </p>
@ -26,6 +26,12 @@ English | [简体中文](./README-zh_CN.md)
- A set of high-quality Vue components out of the box. - A set of high-quality Vue components out of the box.
- Shared [Ant Design of React](https://ant.design/docs/spec/introduce) design resources. - Shared [Ant Design of React](https://ant.design/docs/spec/introduce) design resources.
## Getting started & staying tuned with us.
Star us, and you will receive all releases notifications from GitHub without any delay!
![star us](https://user-images.githubusercontent.com/6937879/261937060-e0501ab3-9388-4712-a25d-3f2ba2271865.gif)
## Environment Support ## Environment Support
- Modern browsers. v1.x support Internet Explorer 9+ (with [polyfills](https://www.antdv.com/docs/vue/getting-started/#compatibility)) - Modern browsers. v1.x support Internet Explorer 9+ (with [polyfills](https://www.antdv.com/docs/vue/getting-started/#compatibility))
@ -39,7 +45,7 @@ English | [简体中文](./README-zh_CN.md)
## Using npm or yarn ## Using npm or yarn
**We recommend using npm or yarn to install**it not only makes development easierbut also allow you to take advantage of the rich ecosystem of Javascript packages and tooling. **We recommend using npm or yarn to install**, it not only makes development easier, but also allow you to take advantage of the rich ecosystem of Javascript packages and tooling.
```bash ```bash
$ npm install ant-design-vue --save $ npm install ant-design-vue --save
@ -49,7 +55,7 @@ $ npm install ant-design-vue --save
$ yarn add ant-design-vue $ yarn add ant-design-vue
``` ```
If you are in a bad network environmentyou can try other registries and tools like [cnpm](https://github.com/cnpm/cnpm). If you are in a bad network environment, you can try other registries and tools like [cnpm](https://github.com/cnpm/cnpm).
## Links ## Links
@ -67,6 +73,7 @@ If you are in a bad network environmentyou 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
@ -75,7 +82,8 @@ ant-design-vue is an MIT-licensed open source project. In order to achieve bette
- [Patreon](https://www.patreon.com/tangjinzhou) - [Patreon](https://www.patreon.com/tangjinzhou)
- [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://qn.antdv.com/alipay-and-wechat.png) - [支付宝或微信](https://aliyuncdn.antdv.com/alipay-and-wechat.png)
- ETH: 0x30cc48515d8ae9fefa20ab87226ad7e8ab9c3bc2
## Sponsors ## Sponsors
@ -85,6 +93,14 @@ Become a sponsor and get your logo on our README on Github with a link to your s
## [More Sponsor (From Patreon、alipay、wechat、paypal...)](https://github.com/vueComponent/ant-design-vue/blob/master/BACKERS.md) ## [More Sponsor (From Patreon、alipay、wechat、paypal...)](https://github.com/vueComponent/ant-design-vue/blob/master/BACKERS.md)
## Contributors
Thank you to all the people who already contributed to ant-design-vue!
<a href="https://github.com/vueComponent/ant-design-vue/graphs/contributors">
<img src="https://contrib.rocks/image?repo=vueComponent/ant-design-vue&max=100&columns=15" />
</a>
[![Let's fund issues in this repository](https://issuehunt.io/static/embed/issuehunt-button-v1.svg)](https://issuehunt.io/repos/104172832) [![Let's fund issues in this repository](https://issuehunt.io/static/embed/issuehunt-button-v1.svg)](https://issuehunt.io/repos/104172832)
This project is tested with BrowserStack. This project is tested with BrowserStack.

View File

@ -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;
} }

View File

@ -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,

View File

@ -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;

View File

@ -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;
}

View File

@ -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,

View File

@ -22,7 +22,7 @@ const imageOptions = {
limit: 10000, limit: 10000,
}; };
function getWebpackConfig(modules) { function getWebpackConfig(modules, esm = false) {
const pkg = require(getProjectPath('package.json')); const pkg = require(getProjectPath('package.json'));
const babelConfig = require('./getBabelCommonConfig')(modules || false); const babelConfig = require('./getBabelCommonConfig')(modules || false);
@ -197,9 +197,25 @@ All rights reserved.
}, },
}, },
]; ];
config.output.library = distFileBaseName; if (esm) {
entry = ['./index.esm'];
config.experiments = {
...config.experiments,
outputModule: true,
};
config.output.chunkFormat = 'module';
config.output.library = {
type: 'module',
};
config.target = 'es2019';
} else {
config.output.libraryTarget = 'umd'; config.output.libraryTarget = 'umd';
config.output.library = distFileBaseName;
config.output.globalObject = 'this'; config.output.globalObject = 'this';
}
const entryName = esm ? `${distFileBaseName}.esm` : distFileBaseName;
config.optimization = { config.optimization = {
minimizer: [ minimizer: [
new TerserPlugin({ new TerserPlugin({
@ -213,7 +229,7 @@ All rights reserved.
// Development // Development
const uncompressedConfig = merge({}, config, { const uncompressedConfig = merge({}, config, {
entry: { entry: {
[distFileBaseName]: entry, [entryName]: entry,
}, },
mode: 'development', mode: 'development',
plugins: [ plugins: [
@ -226,7 +242,7 @@ All rights reserved.
// Production // Production
const prodConfig = merge({}, config, { const prodConfig = merge({}, config, {
entry: { entry: {
[`${distFileBaseName}.min`]: entry, [`${entryName}.min`]: entry,
}, },
mode: 'production', mode: 'production',
plugins: [ plugins: [

View File

@ -368,7 +368,7 @@ function pub(done) {
} }
} }
let startTime = new Date(); const startTime = new Date();
gulp.task('compile-with-es', done => { gulp.task('compile-with-es', done => {
console.log('start compile at ', startTime); console.log('start compile at ', startTime);
console.log('[Parallel] Compile to es...'); console.log('[Parallel] Compile to es...');
@ -452,7 +452,7 @@ gulp.task(
newVersion.trim() === version newVersion.trim() === version
) { ) {
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
runCmd('npm', ['run', 'pub'], code => { runCmd('npm', ['run', 'pub'], _code => {
done(); done();
}); });
} else { } else {

View File

@ -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]],
); );
};
}, },
}); });

View File

@ -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;

View File

@ -3,7 +3,7 @@ import { getOptionProps } from './props-util';
export default { export default {
methods: { methods: {
setState(state = {}, callback) { setState(state = {}, callback: () => any) {
let newState = typeof state === 'function' ? state(this.$data, this.$props) : state; let newState = typeof state === 'function' ? state(this.$data, this.$props) : state;
if (this.getDerivedStateFromProps) { if (this.getDerivedStateFromProps) {
const s = this.getDerivedStateFromProps(getOptionProps(this), { const s = this.getDerivedStateFromProps(getOptionProps(this), {
@ -26,6 +26,7 @@ export default {
}, },
__emit() { __emit() {
// 直接调用事件底层组件不需要vueTool记录events // 直接调用事件底层组件不需要vueTool记录events
// eslint-disable-next-line prefer-rest-params
const args = [].slice.call(arguments, 0); const args = [].slice.call(arguments, 0);
let eventName = args[0]; let eventName = args[0];
eventName = `on${eventName[0].toUpperCase()}${eventName.substring(1)}`; eventName = `on${eventName[0].toUpperCase()}${eventName.substring(1)}`;

View File

@ -3,7 +3,7 @@ import {
defineComponent, defineComponent,
nextTick, nextTick,
onBeforeMount, onBeforeMount,
onBeforeUnmount, onMounted,
onUpdated, onUpdated,
Teleport, Teleport,
watch, watch,
@ -23,12 +23,24 @@ export default defineComponent({
// getContainer // getContainer
let container: HTMLElement; let container: HTMLElement;
const { shouldRender } = useInjectPortal(); const { shouldRender } = useInjectPortal();
onBeforeMount(() => {
isSSR = false; function setContainer() {
if (shouldRender.value) { if (shouldRender.value) {
container = props.getContainer(); container = props.getContainer();
} }
}
onBeforeMount(() => {
isSSR = false;
// drawer
setContainer();
}); });
onMounted(() => {
if (container) return;
// https://github.com/vueComponent/ant-design-vue/issues/6937
setContainer();
});
const stopWatch = watch(shouldRender, () => { const stopWatch = watch(shouldRender, () => {
if (shouldRender.value && !container) { if (shouldRender.value && !container) {
container = props.getContainer(); container = props.getContainer();
@ -44,11 +56,11 @@ export default defineComponent({
} }
}); });
}); });
onBeforeUnmount(() => { // onBeforeUnmount(() => {
if (container && container.parentNode) { // if (container && container.parentNode) {
container.parentNode.removeChild(container); // container.parentNode.removeChild(container);
} // }
}); // });
return () => { return () => {
if (!shouldRender.value) return null; if (!shouldRender.value) return null;
if (isSSR) { if (isSSR) {

View File

@ -7,7 +7,6 @@ import {
onMounted, onMounted,
onBeforeUnmount, onBeforeUnmount,
onUpdated, onUpdated,
getCurrentInstance,
nextTick, nextTick,
computed, computed,
} from 'vue'; } from 'vue';
@ -61,11 +60,14 @@ 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 removeCurrentContainer = () => { const removeCurrentContainer = () => {
// Portal will remove from `parentNode`. // Portal will remove from `parentNode`.
// Let's handle this again to avoid refactor issue. // Let's handle this again to avoid refactor issue.
if (container.value === defaultContainer) {
container.value?.parentNode?.removeChild(container.value); container.value?.parentNode?.removeChild(container.value);
}
container.value = null; container.value = null;
}; };
let parent: HTMLElement = null; let parent: HTMLElement = null;
@ -82,8 +84,6 @@ export default defineComponent({
return true; return true;
}; };
// attachToParent();
const defaultContainer = document.createElement('div');
const getContainer = () => { const getContainer = () => {
if (!supportDom) { if (!supportDom) {
return null; return null;
@ -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}

View File

@ -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']);
};
},
});

View File

@ -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');
});
});

View File

@ -1,35 +0,0 @@
function onCompositionStart(e) {
e.target.composing = true;
}
function onCompositionEnd(e) {
// 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, event, handler, options) {
el.addEventListener(event, handler, options);
}
const antInput = {
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;

View File

@ -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;

View File

@ -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;

View File

@ -1,16 +1,20 @@
export type KeyType = string | number; export type KeyType = string | number;
type ValueType = [number, any]; // [times, realValue] type ValueType = [number, any]; // [times, realValue]
const SPLIT = '%';
class Entity { class Entity {
instanceId: string;
constructor(instanceId: string) {
this.instanceId = instanceId;
}
/** @private Internal cache map. Do not access this directly */ /** @private Internal cache map. Do not access this directly */
cache = new Map<string, ValueType>(); cache = new Map<string, ValueType>();
get(keys: KeyType[] | string): ValueType | null { get(keys: KeyType[] | string): ValueType | null {
return this.cache.get(Array.isArray(keys) ? keys.join('%') : keys) || null; return this.cache.get(Array.isArray(keys) ? keys.join(SPLIT) : keys) || null;
} }
update(keys: KeyType[] | string, valueFn: (origin: ValueType | null) => ValueType | null) { update(keys: KeyType[] | string, valueFn: (origin: ValueType | null) => ValueType | null) {
const path = Array.isArray(keys) ? keys.join('%') : keys; const path = Array.isArray(keys) ? keys.join(SPLIT) : keys;
const prevValue = this.cache.get(path)!; const prevValue = this.cache.get(path)!;
const nextValue = valueFn(prevValue); const nextValue = valueFn(prevValue);

View File

@ -1,29 +1,41 @@
import type { ShallowRef, ExtractPropTypes, InjectionKey, Ref } from 'vue'; import type { ShallowRef, ExtractPropTypes, InjectionKey, Ref } from 'vue';
import { provide, defineComponent, unref, inject, watch, shallowRef } from 'vue'; import {
provide,
defineComponent,
unref,
inject,
watch,
shallowRef,
getCurrentInstance,
} from 'vue';
import CacheEntity from './Cache'; import CacheEntity from './Cache';
import type { Linter } from './linters/interface'; import type { Linter } from './linters/interface';
import type { Transformer } from './transformers/interface'; import type { Transformer } from './transformers/interface';
import { arrayType, booleanType, objectType, someType, stringType, withInstall } from '../type'; import { arrayType, booleanType, objectType, someType, stringType, withInstall } from '../type';
import initDefaultProps from '../props-util/initDefaultProps';
export const ATTR_TOKEN = 'data-token-hash'; export const ATTR_TOKEN = 'data-token-hash';
export const ATTR_MARK = 'data-css-hash'; export const ATTR_MARK = 'data-css-hash';
export const ATTR_DEV_CACHE_PATH = 'data-dev-cache-path'; export const ATTR_CACHE_PATH = 'data-cache-path';
// Mark css-in-js instance in style element // Mark css-in-js instance in style element
export const CSS_IN_JS_INSTANCE = '__cssinjs_instance__'; export const CSS_IN_JS_INSTANCE = '__cssinjs_instance__';
export const CSS_IN_JS_INSTANCE_ID = Math.random().toString(12).slice(2);
export function createCache() { export function createCache() {
const cssinjsInstanceId = Math.random().toString(12).slice(2);
// Tricky SSR: Move all inline style to the head.
// PS: We do not recommend tricky mode.
if (typeof document !== 'undefined' && document.head && document.body) { if (typeof document !== 'undefined' && document.head && document.body) {
const styles = document.body.querySelectorAll(`style[${ATTR_MARK}]`) || []; const styles = document.body.querySelectorAll(`style[${ATTR_MARK}]`) || [];
const { firstChild } = document.head; const { firstChild } = document.head;
Array.from(styles).forEach(style => { Array.from(styles).forEach(style => {
(style as any)[CSS_IN_JS_INSTANCE] = (style as any)[CSS_IN_JS_INSTANCE] = (style as any)[CSS_IN_JS_INSTANCE] || cssinjsInstanceId;
(style as any)[CSS_IN_JS_INSTANCE] || CSS_IN_JS_INSTANCE_ID;
// Not force move if no head // Not force move if no head
// Not force move if no head
if ((style as any)[CSS_IN_JS_INSTANCE] === cssinjsInstanceId) {
document.head.insertBefore(style, firstChild); document.head.insertBefore(style, firstChild);
}
}); });
// Deduplicate of moved styles // Deduplicate of moved styles
@ -31,7 +43,7 @@ export function createCache() {
Array.from(document.querySelectorAll(`style[${ATTR_MARK}]`)).forEach(style => { Array.from(document.querySelectorAll(`style[${ATTR_MARK}]`)).forEach(style => {
const hash = style.getAttribute(ATTR_MARK)!; const hash = style.getAttribute(ATTR_MARK)!;
if (styleHash[hash]) { if (styleHash[hash]) {
if ((style as any)[CSS_IN_JS_INSTANCE] === CSS_IN_JS_INSTANCE_ID) { if ((style as any)[CSS_IN_JS_INSTANCE] === cssinjsInstanceId) {
style.parentNode?.removeChild(style); style.parentNode?.removeChild(style);
} }
} else { } else {
@ -40,7 +52,7 @@ export function createCache() {
}); });
} }
return new CacheEntity(); return new CacheEntity(cssinjsInstanceId);
} }
export type HashPriority = 'low' | 'high'; export type HashPriority = 'low' | 'high';
@ -76,19 +88,45 @@ const StyleContextKey: InjectionKey<ShallowRef<Partial<StyleContextProps>>> =
Symbol('StyleContextKey'); Symbol('StyleContextKey');
export type UseStyleProviderProps = Partial<StyleContextProps> | Ref<Partial<StyleContextProps>>; export type UseStyleProviderProps = Partial<StyleContextProps> | Ref<Partial<StyleContextProps>>;
// fix: https://github.com/vueComponent/ant-design-vue/issues/7023
const getCache = () => {
const instance = getCurrentInstance();
let cache: CacheEntity;
if (instance && instance.appContext) {
const globalCache = instance.appContext?.config?.globalProperties?.__ANTDV_CSSINJS_CACHE__;
if (globalCache) {
cache = globalCache;
} else {
cache = createCache();
if (instance.appContext.config.globalProperties) {
instance.appContext.config.globalProperties.__ANTDV_CSSINJS_CACHE__ = cache;
}
}
} else {
cache = createCache();
}
return cache;
};
const defaultStyleContext: StyleContextProps = { const defaultStyleContext: StyleContextProps = {
cache: createCache(), cache: createCache(),
defaultCache: true, defaultCache: true,
hashPriority: 'low', hashPriority: 'low',
}; };
// fix: https://github.com/vueComponent/ant-design-vue/issues/6912
export const useStyleInject = () => { export const useStyleInject = () => {
return inject(StyleContextKey, shallowRef({ ...defaultStyleContext })); const cache = getCache();
return inject(StyleContextKey, shallowRef({ ...defaultStyleContext, cache }));
}; };
export const useStyleProvider = (props: UseStyleProviderProps) => { export const useStyleProvider = (props: UseStyleProviderProps) => {
const parentContext = useStyleInject(); const parentContext = useStyleInject();
const context = shallowRef<Partial<StyleContextProps>>({ ...defaultStyleContext }); const context = shallowRef<Partial<StyleContextProps>>({
...defaultStyleContext,
cache: createCache(),
});
watch( watch(
[props, parentContext], [() => unref(props), parentContext],
() => { () => {
const mergedContext: Partial<StyleContextProps> = { const mergedContext: Partial<StyleContextProps> = {
...parentContext.value, ...parentContext.value,
@ -142,7 +180,7 @@ export const StyleProvider = withInstall(
defineComponent({ defineComponent({
name: 'AStyleProvider', name: 'AStyleProvider',
inheritAttrs: false, inheritAttrs: false,
props: initDefaultProps(styleProviderProps(), defaultStyleContext), props: styleProviderProps(),
setup(props, { slots }) { setup(props, { slots }) {
useStyleProvider(props); useStyleProvider(props);
return () => slots.default?.(); return () => slots.default?.();

View File

@ -1,5 +1,5 @@
import hash from '@emotion/hash'; import hash from '@emotion/hash';
import { ATTR_TOKEN, CSS_IN_JS_INSTANCE, CSS_IN_JS_INSTANCE_ID } from '../StyleContext'; import { ATTR_TOKEN, CSS_IN_JS_INSTANCE, useStyleInject } from '../StyleContext';
import type Theme from '../theme/Theme'; import type Theme from '../theme/Theme';
import useGlobalCache from './useGlobalCache'; import useGlobalCache from './useGlobalCache';
import { flattenToken, token2key } from '../util'; import { flattenToken, token2key } from '../util';
@ -8,11 +8,15 @@ 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> { export interface Option<DerivativeToken, DesignToken> {
/** /**
* Generate token with salt. * Generate token with salt.
* This is used to generate different hashId even same derivative token for different version. * This is used to generate different hashId even same derivative token for different version.
@ -30,6 +34,18 @@ export interface Option<DerivativeToken> {
* It's ok to useMemo outside but this has better cache strategy. * It's ok to useMemo outside but this has better cache strategy.
*/ */
formatToken?: (mergedToken: any) => DerivativeToken; formatToken?: (mergedToken: any) => DerivativeToken;
/**
* Get final token with origin token, override token and theme.
* The parameters do not contain formatToken since it's passed by user.
* @param origin The original token.
* @param override Extra tokens to override.
* @param theme Theme instance. Could get derivative token by `theme.getDerivativeToken`
*/
getComputedToken?: (
origin: DesignToken,
override: object,
theme: Theme<any, any>,
) => DerivativeToken;
} }
const tokenKeys = new Map<string, number>(); const tokenKeys = new Map<string, number>();
@ -37,20 +53,22 @@ function recordCleanToken(tokenKey: string) {
tokenKeys.set(tokenKey, (tokenKeys.get(tokenKey) || 0) + 1); tokenKeys.set(tokenKey, (tokenKeys.get(tokenKey) || 0) + 1);
} }
function removeStyleTags(key: string) { function removeStyleTags(key: string, instanceId: string) {
if (typeof document !== 'undefined') { if (typeof document !== 'undefined') {
const styles = document.querySelectorAll(`style[${ATTR_TOKEN}="${key}"]`); const styles = document.querySelectorAll(`style[${ATTR_TOKEN}="${key}"]`);
styles.forEach(style => { styles.forEach(style => {
if ((style as any)[CSS_IN_JS_INSTANCE] === CSS_IN_JS_INSTANCE_ID) { if ((style as any)[CSS_IN_JS_INSTANCE] === instanceId) {
style.parentNode?.removeChild(style); style.parentNode?.removeChild(style);
} }
}); });
} }
} }
const TOKEN_THRESHOLD = 0;
// Remove will check current keys first // Remove will check current keys first
function cleanTokenStyle(tokenKey: string) { function cleanTokenStyle(tokenKey: string, instanceId: string) {
tokenKeys.set(tokenKey, (tokenKeys.get(tokenKey) || 0) - 1); tokenKeys.set(tokenKey, (tokenKeys.get(tokenKey) || 0) - 1);
const tokenKeyList = Array.from(tokenKeys.keys()); const tokenKeyList = Array.from(tokenKeys.keys());
@ -60,14 +78,36 @@ function cleanTokenStyle(tokenKey: string) {
return count <= 0; return count <= 0;
}); });
if (cleanableKeyList.length < tokenKeyList.length) { // Should keep tokens under threshold for not to insert style too often
if (tokenKeyList.length - cleanableKeyList.length > TOKEN_THRESHOLD) {
cleanableKeyList.forEach(key => { cleanableKeyList.forEach(key => {
removeStyleTags(key); removeStyleTags(key, instanceId);
tokenKeys.delete(key); tokenKeys.delete(key);
}); });
} }
} }
export const getComputedToken = <DerivativeToken = object, DesignToken = DerivativeToken>(
originToken: DesignToken,
overrideToken: object,
theme: Theme<any, any>,
format?: (token: DesignToken) => DerivativeToken,
) => {
const derivativeToken = theme.getDerivativeToken(originToken);
// Merge with override
let mergedDerivativeToken = {
...derivativeToken,
...overrideToken,
};
// Format if needed
if (format) {
mergedDerivativeToken = format(mergedDerivativeToken);
}
return mergedDerivativeToken;
};
/** /**
* Cache theme derivative token as global shared one * Cache theme derivative token as global shared one
* @param theme Theme entity * @param theme Theme entity
@ -78,8 +118,10 @@ function cleanTokenStyle(tokenKey: string) {
export default function useCacheToken<DerivativeToken = object, DesignToken = DerivativeToken>( export default function useCacheToken<DerivativeToken = object, DesignToken = DerivativeToken>(
theme: Ref<Theme<any, any>>, theme: Ref<Theme<any, any>>,
tokens: Ref<Partial<DesignToken>[]>, tokens: Ref<Partial<DesignToken>[]>,
option: Ref<Option<DerivativeToken>> = ref({}), option: Ref<Option<DerivativeToken, DesignToken>> = ref({}),
) { ) {
const style = useStyleInject();
// Basic - We do basic cache here // Basic - We do basic cache here
const mergedToken = computed(() => Object.assign({}, ...tokens.value)); const mergedToken = computed(() => Object.assign({}, ...tokens.value));
const tokenStr = computed(() => flattenToken(mergedToken.value)); const tokenStr = computed(() => flattenToken(mergedToken.value));
@ -94,19 +136,15 @@ export default function useCacheToken<DerivativeToken = object, DesignToken = De
overrideTokenStr.value, overrideTokenStr.value,
]), ]),
() => { () => {
const { salt = '', override = EMPTY_OVERRIDE, formatToken } = option.value; const {
const derivativeToken = theme.value.getDerivativeToken(mergedToken.value); salt = '',
override = EMPTY_OVERRIDE,
// Merge with override formatToken,
let mergedDerivativeToken = { getComputedToken: compute,
...derivativeToken, } = option.value;
...override, const mergedDerivativeToken = compute
}; ? compute(mergedToken.value, override, theme.value)
: getComputedToken(mergedToken.value, override, theme.value, formatToken);
// Format if needed
if (formatToken) {
mergedDerivativeToken = formatToken(mergedDerivativeToken);
}
// Optimize for `useStyleRegister` performance // Optimize for `useStyleRegister` performance
const tokenKey = token2key(mergedDerivativeToken, salt); const tokenKey = token2key(mergedDerivativeToken, salt);
@ -115,12 +153,11 @@ 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 => {
// Remove token will remove all related style // Remove token will remove all related style
cleanTokenStyle(cache[0]._tokenKey); cleanTokenStyle(cache[0]._tokenKey, style.value?.cache.instanceId);
}, },
); );

View File

@ -16,7 +16,8 @@ if (
process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'production' &&
typeof module !== 'undefined' && typeof module !== 'undefined' &&
module && module &&
(module as any).hot (module as any).hot &&
typeof window !== 'undefined'
) { ) {
const win = window as any; const win = window as any;
if (typeof win.webpackHotUpdate === 'function') { if (typeof win.webpackHotUpdate === 'function') {

View File

@ -0,0 +1,91 @@
import canUseDom from '../../../../_util/canUseDom';
import { ATTR_MARK } from '../../StyleContext';
export const ATTR_CACHE_MAP = 'data-ant-cssinjs-cache-path';
/**
* This marks style from the css file.
* Which means not exist in `<style />` tag.
*/
export const CSS_FILE_STYLE = '_FILE_STYLE__';
export function serialize(cachePathMap: Record<string, string>) {
return Object.keys(cachePathMap)
.map(path => {
const hash = cachePathMap[path];
return `${path}:${hash}`;
})
.join(';');
}
let cachePathMap: Record<string, string>;
let fromCSSFile = true;
/**
* @private Test usage only. Can save remove if no need.
*/
export function reset(mockCache?: Record<string, string>, fromFile = true) {
cachePathMap = mockCache!;
fromCSSFile = fromFile;
}
export function prepare() {
if (!cachePathMap) {
cachePathMap = {};
if (canUseDom()) {
const div = document.createElement('div');
div.className = ATTR_CACHE_MAP;
div.style.position = 'fixed';
div.style.visibility = 'hidden';
div.style.top = '-9999px';
document.body.appendChild(div);
let content = getComputedStyle(div).content || '';
content = content.replace(/^"/, '').replace(/"$/, '');
// Fill data
content.split(';').forEach(item => {
const [path, hash] = item.split(':');
cachePathMap[path] = hash;
});
// Remove inline record style
const inlineMapStyle = document.querySelector(`style[${ATTR_CACHE_MAP}]`);
if (inlineMapStyle) {
fromCSSFile = false;
inlineMapStyle.parentNode?.removeChild(inlineMapStyle);
}
document.body.removeChild(div);
}
}
}
export function existPath(path: string) {
prepare();
return !!cachePathMap[path];
}
export function getStyleAndHash(path: string): [style: string | null, hash: string] {
const hash = cachePathMap[path];
let styleStr: string | null = null;
if (hash && canUseDom()) {
if (fromCSSFile) {
styleStr = CSS_FILE_STYLE;
} else {
const style = document.querySelector(`style[${ATTR_MARK}="${cachePathMap[path]}"]`);
if (style) {
styleStr = style.innerHTML;
} else {
// Clean up since not exist anymore
delete cachePathMap[path];
}
}
}
return [styleStr, hash];
}

View File

@ -3,32 +3,38 @@ import type * as CSS from 'csstype';
// @ts-ignore // @ts-ignore
import unitless from '@emotion/unitless'; import unitless from '@emotion/unitless';
import { compile, serialize, stringify } from 'stylis'; import { compile, serialize, stringify } from 'stylis';
import type { Theme, Transformer } from '..'; import type { Theme, Transformer } from '../..';
import type Cache from '../Cache'; import type Cache from '../../Cache';
import type Keyframes from '../Keyframes'; import type Keyframes from '../../Keyframes';
import type { Linter } from '../linters'; import type { Linter } from '../../linters';
import { contentQuotesLinter, hashedAnimationLinter } from '../linters'; import { contentQuotesLinter, hashedAnimationLinter } from '../../linters';
import type { HashPriority } from '../StyleContext'; import type { HashPriority } from '../../StyleContext';
import { import {
useStyleInject, useStyleInject,
ATTR_DEV_CACHE_PATH, ATTR_CACHE_PATH,
ATTR_MARK, ATTR_MARK,
ATTR_TOKEN, ATTR_TOKEN,
CSS_IN_JS_INSTANCE, CSS_IN_JS_INSTANCE,
CSS_IN_JS_INSTANCE_ID, } from '../../StyleContext';
} from '../StyleContext'; import { supportLayer } from '../../util';
import { supportLayer } from '../util'; import useGlobalCache from '../useGlobalCache';
import useGlobalCache from './useGlobalCache'; import { removeCSS, updateCSS } from '../../../../vc-util/Dom/dynamicCSS';
import canUseDom from '../../canUseDom';
import { removeCSS, updateCSS } from '../../../vc-util/Dom/dynamicCSS';
import type { Ref } from 'vue'; import type { Ref } from 'vue';
import { computed } from 'vue'; import { computed } from 'vue';
import type { VueNode } from '../../type'; import type { VueNode } from '../../../type';
import canUseDom from '../../../../_util/canUseDom';
import {
ATTR_CACHE_MAP,
existPath,
getStyleAndHash,
serialize as serializeCacheMap,
} from './cacheMapUtil';
const isClientSide = canUseDom(); const isClientSide = canUseDom();
const SKIP_CHECK = '_skip_check_'; const SKIP_CHECK = '_skip_check_';
const MULTI_VALUE = '_multi_value_';
export type CSSProperties = Omit<CSS.PropertiesFallback<number | string>, 'animationName'> & { export type CSSProperties = Omit<CSS.PropertiesFallback<number | string>, 'animationName'> & {
animationName?: CSS.PropertiesFallback<number | string>['animationName'] | Keyframes; animationName?: CSS.PropertiesFallback<number | string>['animationName'] | Keyframes;
}; };
@ -36,16 +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;
value: CSSProperties[K] | Extract<CSSProperties[K], string>[]; [MULTI_VALUE]?: boolean;
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;
@ -59,13 +66,13 @@ export interface CSSObject extends CSSPropertiesWithMultiValues, CSSPseudos, CSS
// == Parser == // == Parser ==
// ============================================================================ // ============================================================================
// Preprocessor style content to browser support one // Preprocessor style content to browser support one
export function normalizeStyle(styleStr: string) { export function normalizeStyle(styleStr: string): string {
const serialized = serialize(compile(styleStr), stringify); const serialized = serialize(compile(styleStr), stringify);
return serialized.replace(/\{%%%\:[^;];}/g, ';'); return serialized.replace(/\{%%%\:[^;];}/g, ';');
} }
function isCompoundCSSProperty(value: CSSObject[string]) { function isCompoundCSSProperty(value: CSSObject[string]) {
return typeof value === 'object' && value && SKIP_CHECK in value; return typeof value === 'object' && value && (SKIP_CHECK in value || MULTI_VALUE in value);
} }
// hash // hash
@ -224,33 +231,46 @@ export const parseStyle = (
styleStr += `${mergedKey}${parsedStr}`; styleStr += `${mergedKey}${parsedStr}`;
} else { } else {
const actualValue = (value as any)?.value ?? value; function appendStyle(cssKey: string, cssValue: any) {
if ( if (
process.env.NODE_ENV !== 'production' && process.env.NODE_ENV !== 'production' &&
(typeof value !== 'object' || !(value as any)?.[SKIP_CHECK]) (typeof value !== 'object' || !(value as any)?.[SKIP_CHECK])
) { ) {
[contentQuotesLinter, hashedAnimationLinter, ...linters].forEach(linter => [contentQuotesLinter, hashedAnimationLinter, ...linters].forEach(linter =>
linter(key, actualValue, { path, hashId, parentSelectors }), linter(cssKey, cssValue, { path, hashId, parentSelectors }),
); );
} }
// //
const styleName = key.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`); const styleName = cssKey.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`);
// Auto suffix with px // Auto suffix with px
let formatValue = actualValue; let formatValue = cssValue;
if (!unitless[key] && typeof formatValue === 'number' && formatValue !== 0) { if (!unitless[cssKey] && typeof formatValue === 'number' && formatValue !== 0) {
formatValue = `${formatValue}px`; formatValue = `${formatValue}px`;
} }
// handle animationName & Keyframe value // handle animationName & Keyframe value
if (key === 'animationName' && (value as Keyframes)?._keyframe) { if (cssKey === 'animationName' && (cssValue as Keyframes)?._keyframe) {
parseKeyframes(value as Keyframes); parseKeyframes(cssValue as Keyframes);
formatValue = (value as Keyframes).getName(hashId); formatValue = (cssValue as Keyframes).getName(hashId);
} }
styleStr += `${styleName}:${formatValue};`; styleStr += `${styleName}:${formatValue};`;
} }
const actualValue = (value as any)?.value ?? value;
if (
typeof value === 'object' &&
(value as any)?.[MULTI_VALUE] &&
Array.isArray(actualValue)
) {
actualValue.forEach(item => {
appendStyle(key, item);
});
} else {
appendStyle(key, actualValue);
}
}
}); });
} }
}); });
@ -293,6 +313,14 @@ export default function useStyleRegister(
path: string[]; path: string[];
hashId?: string; hashId?: string;
layer?: string; layer?: string;
nonce?: string | (() => string);
clientOnly?: boolean;
/**
* Tell cssinjs the insert order of style.
* It's useful when you need to insert style
* before other style to overwrite for the same selector priority.
*/
order?: number;
}>, }>,
styleFn: () => CSSInterpolation, styleFn: () => CSSInterpolation,
) { ) {
@ -309,14 +337,32 @@ export default function useStyleRegister(
} }
// const [cacheStyle[0], cacheStyle[1], cacheStyle[2]] // const [cacheStyle[0], cacheStyle[1], cacheStyle[2]]
useGlobalCache( useGlobalCache<
[
styleStr: string,
tokenKey: string,
styleId: string,
effectStyle: Record<string, string>,
clientOnly: boolean | undefined,
order: number,
]
>(
'style', 'style',
fullPath, fullPath,
// Create cache if needed // Create cache if needed
() => { () => {
const { path, hashId, layer, nonce, clientOnly, order = 0 } = info.value;
const cachePath = fullPath.value.join('|');
// Get style from SSR inline style directly
if (existPath(cachePath)) {
const [inlineCacheStyleStr, styleHash] = getStyleAndHash(cachePath);
if (inlineCacheStyleStr) {
return [inlineCacheStyleStr, tokenKey.value, styleHash, {}, clientOnly, order];
}
}
const styleObj = styleFn(); const styleObj = styleFn();
const { hashPriority, container, transformers, linters } = styleContext.value; const { hashPriority, container, transformers, linters, cache } = styleContext.value;
const { path, hashId, layer } = info.value;
const [parsedStyle, effectStyle] = parseStyle(styleObj, { const [parsedStyle, effectStyle] = parseStyle(styleObj, {
hashId, hashId,
hashPriority, hashPriority,
@ -329,20 +375,29 @@ export default function useStyleRegister(
const styleId = uniqueHash(fullPath.value, styleStr); const styleId = uniqueHash(fullPath.value, styleStr);
if (isMergedClientSide) { if (isMergedClientSide) {
const style = updateCSS(styleStr, styleId, { const mergedCSSConfig: Parameters<typeof updateCSS>[2] = {
mark: ATTR_MARK, mark: ATTR_MARK,
prepend: 'queue', prepend: 'queue',
attachTo: container, attachTo: container,
}); priority: order,
};
(style as any)[CSS_IN_JS_INSTANCE] = CSS_IN_JS_INSTANCE_ID; const nonceStr = typeof nonce === 'function' ? nonce() : nonce;
if (nonceStr) {
mergedCSSConfig.csp = { nonce: nonceStr };
}
const style = updateCSS(styleStr, styleId, mergedCSSConfig);
(style as any)[CSS_IN_JS_INSTANCE] = cache.instanceId;
// Used for `useCacheToken` to remove on batch when token removed // Used for `useCacheToken` to remove on batch when token removed
style.setAttribute(ATTR_TOKEN, tokenKey.value); style.setAttribute(ATTR_TOKEN, tokenKey.value);
// Dev usage to find which cache path made this easily // Dev usage to find which cache path made this easily
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
style.setAttribute(ATTR_DEV_CACHE_PATH, fullPath.value.join('|')); style.setAttribute(ATTR_CACHE_PATH, fullPath.value.join('|'));
} }
// Inject client side effect style // Inject client side effect style
@ -360,7 +415,7 @@ export default function useStyleRegister(
}); });
} }
return [styleStr, tokenKey.value, styleId]; return [styleStr, tokenKey.value, styleId, effectStyle, clientOnly, order];
}, },
// Remove cache if no need // Remove cache if no need
([, , styleId], fromHMR) => { ([, , styleId], fromHMR) => {
@ -399,19 +454,113 @@ export default function useStyleRegister(
// ============================================================================ // ============================================================================
// == SSR == // == SSR ==
// ============================================================================ // ============================================================================
export function extractStyle(cache: Cache) { export function extractStyle(cache: Cache, plain = false) {
// prefix with `style` is used for `useStyleRegister` to cache style context const matchPrefix = `style%`;
const styleKeys = Array.from(cache.cache.keys()).filter(key => key.startsWith('style%'));
// const tokenStyles: Record<string, string[]> = {}; // prefix with `style` is used for `useStyleRegister` to cache style context
const styleKeys = Array.from(cache.cache.keys()).filter(key => key.startsWith(matchPrefix));
// Common effect styles like animation
const effectStyles: Record<string, boolean> = {};
// Mapping of cachePath to style hash
const cachePathMap: Record<string, string> = {};
let styleText = ''; let styleText = '';
styleKeys.forEach(key => { function toStyleStr(
const [styleStr, tokenKey, styleId]: [string, string, string] = cache.cache.get(key)![1]; style: string,
tokenKey?: string,
styleId?: string,
customizeAttrs: Record<string, string> = {},
) {
const attrs: Record<string, string | undefined> = {
...customizeAttrs,
[ATTR_TOKEN]: tokenKey,
[ATTR_MARK]: styleId,
};
styleText += `<style ${ATTR_TOKEN}="${tokenKey}" ${ATTR_MARK}="${styleId}">${styleStr}</style>`; const attrStr = Object.keys(attrs)
.map(attr => {
const val = attrs[attr];
return val ? `${attr}="${val}"` : null;
})
.filter(v => v)
.join(' ');
return plain ? style : `<style ${attrStr}>${style}</style>`;
}
// ====================== Fill Style ======================
type OrderStyle = [order: number, style: string];
const orderStyles: OrderStyle[] = styleKeys
.map(key => {
const cachePath = key.slice(matchPrefix.length).replace(/%/g, '|');
const [styleStr, tokenKey, styleId, effectStyle, clientOnly, order]: [
string,
string,
string,
Record<string, string>,
boolean,
number,
] = cache.cache.get(key)![1];
// Skip client only style
if (clientOnly) {
return null! as OrderStyle;
}
// ====================== Style ======================
// Used for vc-util
const sharedAttrs = {
'data-vc-order': 'prependQueue',
'data-vc-priority': `${order}`,
};
let keyStyleText = toStyleStr(styleStr, tokenKey, styleId, sharedAttrs);
// Save cache path with hash mapping
cachePathMap[cachePath] = styleId;
// =============== Create effect style ===============
if (effectStyle) {
Object.keys(effectStyle).forEach(effectKey => {
// Effect style can be reused
if (!effectStyles[effectKey]) {
effectStyles[effectKey] = true;
keyStyleText += toStyleStr(
normalizeStyle(effectStyle[effectKey]),
tokenKey,
`_effect-${effectKey}`,
sharedAttrs,
);
}
}); });
}
const ret: OrderStyle = [order, keyStyleText];
return ret;
})
.filter(o => o);
orderStyles
.sort((o1, o2) => o1[0] - o2[0])
.forEach(([, style]) => {
styleText += style;
});
// ==================== Fill Cache Path ====================
styleText += toStyleStr(
`.${ATTR_CACHE_MAP}{content:"${serializeCacheMap(cachePathMap)}";}`,
undefined,
undefined,
{
[ATTR_CACHE_MAP]: ATTR_CACHE_MAP,
},
);
return styleText; return styleText;
} }

View File

@ -3,13 +3,15 @@ import type { CSSInterpolation, CSSObject } from './hooks/useStyleRegister';
import useStyleRegister, { extractStyle } from './hooks/useStyleRegister'; import useStyleRegister, { extractStyle } from './hooks/useStyleRegister';
import Keyframes from './Keyframes'; import Keyframes from './Keyframes';
import type { Linter } from './linters'; import type { Linter } from './linters';
import { legacyNotSelectorLinter, logicalPropertiesLinter } from './linters'; import { legacyNotSelectorLinter, logicalPropertiesLinter, parentSelectorLinter } from './linters';
import type { StyleContextProps, StyleProviderProps } from './StyleContext'; import type { StyleContextProps, StyleProviderProps } from './StyleContext';
import { createCache, useStyleInject, useStyleProvider, StyleProvider } from './StyleContext'; import { createCache, useStyleInject, useStyleProvider, StyleProvider } from './StyleContext';
import type { DerivativeFunc, TokenType } from './theme'; import type { DerivativeFunc, TokenType } from './theme';
import { createTheme, Theme } from './theme'; import { createTheme, Theme } from './theme';
import type { Transformer } from './transformers/interface'; import type { Transformer } from './transformers/interface';
import legacyLogicalPropertiesTransformer from './transformers/legacyLogicalProperties'; import legacyLogicalPropertiesTransformer from './transformers/legacyLogicalProperties';
import px2remTransformer from './transformers/px2rem';
import { supportLogicProps, supportWhere } from './util';
const cssinjs = { const cssinjs = {
Theme, Theme,
@ -24,10 +26,12 @@ const cssinjs = {
// Transformer // Transformer
legacyLogicalPropertiesTransformer, legacyLogicalPropertiesTransformer,
px2remTransformer,
// Linters // Linters
logicalPropertiesLinter, logicalPropertiesLinter,
legacyNotSelectorLinter, legacyNotSelectorLinter,
parentSelectorLinter,
// cssinjs // cssinjs
StyleProvider, StyleProvider,
@ -45,10 +49,12 @@ export {
// Transformer // Transformer
legacyLogicalPropertiesTransformer, legacyLogicalPropertiesTransformer,
px2remTransformer,
// Linters // Linters
logicalPropertiesLinter, logicalPropertiesLinter,
legacyNotSelectorLinter, legacyNotSelectorLinter,
parentSelectorLinter,
// cssinjs // cssinjs
StyleProvider, StyleProvider,
@ -64,4 +70,8 @@ export type {
StyleProviderProps, StyleProviderProps,
}; };
export const _experimental = {
supportModernCSS: () => supportWhere() && supportLogicProps(),
};
export default cssinjs; export default cssinjs;

View File

@ -3,3 +3,4 @@ export { default as hashedAnimationLinter } from './hashedAnimationLinter';
export type { Linter } from './interface'; export type { Linter } from './interface';
export { default as legacyNotSelectorLinter } from './legacyNotSelectorLinter'; export { default as legacyNotSelectorLinter } from './legacyNotSelectorLinter';
export { default as logicalPropertiesLinter } from './logicalPropertiesLinter'; export { default as logicalPropertiesLinter } from './logicalPropertiesLinter';
export { default as parentSelectorLinter } from './parentSelectorLinter';

View File

@ -0,0 +1,15 @@
import type { Linter } from '..';
import { lintWarning } from './utils';
const linter: Linter = (_key, _value, info) => {
if (
info.parentSelectors.some(selector => {
const selectors = selector.split(',');
return selectors.some(item => item.split('&').length > 2);
})
) {
lintWarning('Should not use more than one `&` in a selector.', info);
}
};
export default linter;

View File

@ -0,0 +1,76 @@
/**
* respect https://github.com/cuth/postcss-pxtorem
*/
import unitless from '@emotion/unitless';
import type { CSSObject } from '..';
import type { Transformer } from './interface';
export interface Options {
/**
* The root font size.
* @default 16
*/
rootValue?: number;
/**
* The decimal numbers to allow the REM units to grow to.
* @default 5
*/
precision?: number;
/**
* Whether to allow px to be converted in media queries.
* @default false
*/
mediaQuery?: boolean;
}
const pxRegex = /url\([^)]+\)|var\([^)]+\)|(\d*\.?\d+)px/g;
function toFixed(number: number, precision: number) {
const multiplier = Math.pow(10, precision + 1),
wholeNumber = Math.floor(number * multiplier);
return (Math.round(wholeNumber / 10) * 10) / multiplier;
}
const transform = (options: Options = {}): Transformer => {
const { rootValue = 16, precision = 5, mediaQuery = false } = options;
const pxReplace = (m: string, $1: any) => {
if (!$1) return m;
const pixels = parseFloat($1);
// covenant: pixels <= 1, not transform to rem @zombieJ
if (pixels <= 1) return m;
const fixedVal = toFixed(pixels / rootValue, precision);
return `${fixedVal}rem`;
};
const visit = (cssObj: CSSObject): CSSObject => {
const clone: CSSObject = { ...cssObj };
Object.entries(cssObj).forEach(([key, value]) => {
if (typeof value === 'string' && value.includes('px')) {
const newValue = value.replace(pxRegex, pxReplace);
clone[key] = newValue;
}
// no unit
if (!unitless[key] && typeof value === 'number' && value !== 0) {
clone[key] = `${value}px`.replace(pxRegex, pxReplace);
}
// Media queries
const mergedKey = key.trim();
if (mergedKey.startsWith('@') && mergedKey.includes('px') && mediaQuery) {
const newKey = key.replace(pxRegex, pxReplace);
clone[newKey] = clone[key];
delete clone[key];
}
});
return clone;
};
return { visit };
};
export default transform;

View File

@ -2,17 +2,30 @@ import hash from '@emotion/hash';
import { removeCSS, updateCSS } from '../../vc-util/Dom/dynamicCSS'; import { removeCSS, updateCSS } from '../../vc-util/Dom/dynamicCSS';
import canUseDom from '../canUseDom'; import canUseDom from '../canUseDom';
import { Theme } from './theme';
// Create a cache here to avoid always loop generate
const flattenTokenCache = new WeakMap<any, string>();
export function flattenToken(token: any) { export function flattenToken(token: any) {
let str = ''; let str = flattenTokenCache.get(token) || '';
if (!str) {
Object.keys(token).forEach(key => { Object.keys(token).forEach(key => {
const value = token[key]; const value = token[key];
str += key; str += key;
if (value && typeof value === 'object') { if (value instanceof Theme) {
str += value.id;
} else if (value && typeof value === 'object') {
str += flattenToken(value); str += flattenToken(value);
} else { } else {
str += value; str += value;
} }
}); });
// Put in cache
flattenTokenCache.set(token, str);
}
return str; return str;
} }
@ -23,12 +36,18 @@ export function token2key(token: any, salt: string): string {
return hash(`${salt}_${flattenToken(token)}`); return hash(`${salt}_${flattenToken(token)}`);
} }
const layerKey = `layer-${Date.now()}-${Math.random()}`.replace(/\./g, ''); const randomSelectorKey = `random-${Date.now()}-${Math.random()}`.replace(/\./g, '');
const layerWidth = '903px';
function supportSelector(styleStr: string, handleElement?: (ele: HTMLElement) => void): boolean { // Magic `content` for detect selector support
const checkContent = '_bAmBoO_';
function supportSelector(
styleStr: string,
handleElement: (ele: HTMLElement) => void,
supportCheck?: (ele: HTMLElement) => boolean,
): boolean {
if (canUseDom()) { if (canUseDom()) {
updateCSS(styleStr, layerKey); updateCSS(styleStr, randomSelectorKey);
const ele = document.createElement('div'); const ele = document.createElement('div');
ele.style.position = 'fixed'; ele.style.position = 'fixed';
@ -42,10 +61,12 @@ function supportSelector(styleStr: string, handleElement?: (ele: HTMLElement) =>
ele.style.zIndex = '9999999'; ele.style.zIndex = '9999999';
} }
const support = getComputedStyle(ele).width === layerWidth; const support = supportCheck
? supportCheck(ele)
: getComputedStyle(ele).content?.includes(checkContent);
ele.parentNode?.removeChild(ele); ele.parentNode?.removeChild(ele);
removeCSS(layerKey); removeCSS(randomSelectorKey);
return support; return support;
} }
@ -57,12 +78,41 @@ let canLayer: boolean | undefined = undefined;
export function supportLayer(): boolean { export function supportLayer(): boolean {
if (canLayer === undefined) { if (canLayer === undefined) {
canLayer = supportSelector( canLayer = supportSelector(
`@layer ${layerKey} { .${layerKey} { width: ${layerWidth}!important; } }`, `@layer ${randomSelectorKey} { .${randomSelectorKey} { content: "${checkContent}"!important; } }`,
ele => { ele => {
ele.className = layerKey; ele.className = randomSelectorKey;
}, },
); );
} }
return canLayer!; return canLayer!;
} }
let canWhere: boolean | undefined = undefined;
export function supportWhere(): boolean {
if (canWhere === undefined) {
canWhere = supportSelector(
`:where(.${randomSelectorKey}) { content: "${checkContent}"!important; }`,
ele => {
ele.className = randomSelectorKey;
},
);
}
return canWhere!;
}
let canLogic: boolean | undefined = undefined;
export function supportLogicProps(): boolean {
if (canLogic === undefined) {
canLogic = supportSelector(
`.${randomSelectorKey} { inset-block: 93px !important; }`,
ele => {
ele.className = randomSelectorKey;
},
ele => getComputedStyle(ele).bottom === '93px',
);
}
return canLogic!;
}

View File

@ -0,0 +1,13 @@
import type { SizeType } from '../config-provider/SizeContext';
export function isPresetSize(size?: SizeType | string | number): size is SizeType {
return ['small', 'middle', 'large'].includes(size as string);
}
export function isValidGapNumber(size?: SizeType | string | number): size is number {
if (!size) {
// The case of size = 0 is deliberately excluded here, because the default value of the gap attribute in CSS is 0, so if the user passes 0 in, we can directly ignore it.
return false;
}
return typeof size === 'number' && !Number.isNaN(size);
}

View File

@ -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) {

View File

@ -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;

View File

@ -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);

View File

@ -2,6 +2,7 @@ import type { Ref } from 'vue';
import { computed, watchEffect } from 'vue'; import { computed, watchEffect } from 'vue';
import { updateCSS, removeCSS } from '../../vc-util/Dom/dynamicCSS'; import { updateCSS, removeCSS } from '../../vc-util/Dom/dynamicCSS';
import getScrollBarSize from '../../_util/getScrollBarSize'; import getScrollBarSize from '../../_util/getScrollBarSize';
import canUseDom from '../../_util/canUseDom';
const UNIQUE_ID = `vc-util-locker-${Date.now()}`; const UNIQUE_ID = `vc-util-locker-${Date.now()}`;
@ -24,6 +25,9 @@ export default function useScrollLocker(lock?: Ref<boolean>) {
watchEffect( watchEffect(
onClear => { onClear => {
if (!canUseDom()) {
return;
}
if (mergedLock.value) { if (mergedLock.value) {
const scrollbarSize = getScrollBarSize(); const scrollbarSize = getScrollBarSize();
const isOverflow = isBodyOverflowing(); const isOverflow = isBodyOverflowing();

View File

@ -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;

View File

@ -3,7 +3,7 @@
* https://github.com/akiran/json2mq.git * https://github.com/akiran/json2mq.git
*/ */
const camel2hyphen = function (str) { const camel2hyphen = function (str: string) {
return str return str
.replace(/[A-Z]/g, function (match) { .replace(/[A-Z]/g, function (match) {
return '-' + match.toLowerCase(); return '-' + match.toLowerCase();
@ -11,12 +11,12 @@ const camel2hyphen = function (str) {
.toLowerCase(); .toLowerCase();
}; };
const isDimension = function (feature) { const isDimension = function (feature: string) {
const re = /[height|width]$/; const re = /[height|width]$/;
return re.test(feature); return re.test(feature);
}; };
const obj2mq = function (obj) { const obj2mq = function (obj: { [x: string]: any }) {
let mq = ''; let mq = '';
const features = Object.keys(obj); const features = Object.keys(obj);
features.forEach(function (feature, index) { features.forEach(function (feature, index) {
@ -40,7 +40,7 @@ const obj2mq = function (obj) {
return mq; return mq;
}; };
export default function (query) { export default function (query: any[]) {
let mq = ''; let mq = '';
if (typeof query === 'string') { if (typeof query === 'string') {
return query; return query;

View File

@ -1,19 +1,19 @@
import isPlainObject from 'lodash-es/isPlainObject';
import classNames from '../classNames'; import classNames from '../classNames';
import { isVNode, Fragment, Comment, Text, h } from 'vue'; import { isVNode, Fragment, Comment, Text } from 'vue';
import { camelize, hyphenate, isOn, resolvePropValue } from '../util'; import { camelize, hyphenate, isOn, resolvePropValue } from '../util';
import isValid from '../isValid'; import isValid from '../isValid';
import initDefaultProps from './initDefaultProps'; import initDefaultProps from './initDefaultProps';
import type { VueInstance } from '../hooks/_vueuse/unrefElement';
// function getType(fn) { // function getType(fn) {
// const match = fn && fn.toString().match(/^\s*function (\w+)/); // const match = fn && fn.toString().match(/^\s*function (\w+)/);
// return match ? match[1] : ''; // return match ? match[1] : '';
// } // }
const splitAttrs = attrs => { const splitAttrs = (attrs: any) => {
const allAttrs = Object.keys(attrs); const allAttrs = Object.keys(attrs);
const eventAttrs = {}; const eventAttrs: Record<string, any> = {};
const onEvents = {}; const onEvents: Record<string, any> = {};
const extraAttrs = {}; const extraAttrs: Record<string, any> = {};
for (let i = 0, l = allAttrs.length; i < l; i++) { for (let i = 0, l = allAttrs.length; i < l; i++) {
const key = allAttrs[i]; const key = allAttrs[i];
if (isOn(key)) { if (isOn(key)) {
@ -25,7 +25,7 @@ const splitAttrs = attrs => {
} }
return { onEvents, events: eventAttrs, extraAttrs }; return { onEvents, events: eventAttrs, extraAttrs };
}; };
const parseStyleText = (cssText = '', camel) => { const parseStyleText = (cssText = '', camel = false) => {
const res = {}; const res = {};
const listDelimiter = /;(?![^(]*\))/g; const listDelimiter = /;(?![^(]*\))/g;
const propertyDelimiter = /:(.+)/; const propertyDelimiter = /:(.+)/;
@ -42,34 +42,9 @@ const parseStyleText = (cssText = '', camel) => {
return res; return res;
}; };
const hasProp = (instance, prop) => { const hasProp = (instance: any, prop: string) => {
return instance[prop] !== undefined; return instance[prop] !== undefined;
}; };
// 重构后直接使用 hasProp 替换
const slotHasProp = (slot, prop) => {
return hasProp(slot, prop);
};
const getScopedSlots = ele => {
return (ele.data && ele.data.scopedSlots) || {};
};
const getSlots = ele => {
let componentOptions = ele.componentOptions || {};
if (ele.$vnode) {
componentOptions = ele.$vnode.componentOptions || {};
}
const children = ele.children || componentOptions.children || [];
const slots = {};
children.forEach(child => {
if (!isEmptyElement(child)) {
const name = (child.data && child.data.slot) || 'default';
slots[name] = slots[name] || [];
slots[name].push(child);
}
});
return { ...slots, ...getScopedSlots(ele) };
};
export const skipFlattenKey = Symbol('skipFlatten'); export const skipFlattenKey = Symbol('skipFlatten');
const flattenChildren = (children = [], filterEmpty = true) => { const flattenChildren = (children = [], filterEmpty = true) => {
@ -97,39 +72,29 @@ const flattenChildren = (children = [], filterEmpty = true) => {
return res; return res;
}; };
const getSlot = (self, name = 'default', options = {}) => { const getSlot = (self: any, name = 'default', options = {}) => {
if (isVNode(self)) { if (isVNode(self)) {
if (self.type === Fragment) { if (self.type === Fragment) {
return name === 'default' ? flattenChildren(self.children) : []; return name === 'default' ? flattenChildren(self.children as any[]) : [];
} else if (self.children && self.children[name]) { } else if (self.children && self.children[name]) {
return flattenChildren(self.children[name](options)); return flattenChildren(self.children[name](options));
} else { } else {
return []; return [];
} }
} else { } else {
let res = self.$slots[name] && self.$slots[name](options); const res = self.$slots[name] && self.$slots[name](options);
return flattenChildren(res); return flattenChildren(res);
} }
}; };
const getAllChildren = ele => { const findDOMNode = (instance: any) => {
let componentOptions = ele.componentOptions || {};
if (ele.$vnode) {
componentOptions = ele.$vnode.componentOptions || {};
}
return ele.children || componentOptions.children || [];
};
const getSlotOptions = () => {
throw Error('使用 .type 直接取值');
};
const findDOMNode = instance => {
let node = instance?.vnode?.el || (instance && (instance.$el || instance)); let node = instance?.vnode?.el || (instance && (instance.$el || instance));
while (node && !node.tagName) { while (node && !node.tagName) {
node = node.nextSibling; node = node.nextSibling;
} }
return node; return node;
}; };
const getOptionProps = instance => { const getOptionProps = (instance: VueInstance) => {
const res = {}; const res = {};
if (instance.$ && instance.$.vnode) { if (instance.$ && instance.$.vnode) {
const props = instance.$.vnode.props || {}; const props = instance.$.vnode.props || {};
@ -146,7 +111,7 @@ const getOptionProps = instance => {
Object.keys(originProps).forEach(key => { Object.keys(originProps).forEach(key => {
props[camelize(key)] = originProps[key]; props[camelize(key)] = originProps[key];
}); });
const options = instance.type.props || {}; const options = (instance.type as any).props || {};
Object.keys(options).forEach(k => { Object.keys(options).forEach(k => {
const v = resolvePropValue(options, props, k, props[k]); const v = resolvePropValue(options, props, k, props[k]);
if (v !== undefined || k in props) { if (v !== undefined || k in props) {
@ -156,7 +121,7 @@ const getOptionProps = instance => {
} }
return res; return res;
}; };
const getComponent = (instance, prop = 'default', options = instance, execute = true) => { const getComponent = (instance: any, prop = 'default', options = instance, execute = true) => {
let com = undefined; let com = undefined;
if (instance.$) { if (instance.$) {
const temp = instance[prop]; const temp = instance[prop];
@ -184,94 +149,13 @@ const getComponent = (instance, prop = 'default', options = instance, execute =
} }
return com; return com;
}; };
const getComponentFromProp = (instance, prop, options = instance, execute = true) => {
if (instance.$createElement) {
// const h = instance.$createElement;
const temp = instance[prop];
if (temp !== undefined) {
return typeof temp === 'function' && execute ? temp(h, options) : temp;
}
return (
(instance.$scopedSlots[prop] && execute && instance.$scopedSlots[prop](options)) ||
instance.$scopedSlots[prop] ||
instance.$slots[prop] ||
undefined
);
} else {
// const h = instance.context.$createElement;
const temp = getPropsData(instance)[prop];
if (temp !== undefined) {
return typeof temp === 'function' && execute ? temp(h, options) : temp;
}
const slotScope = getScopedSlots(instance)[prop];
if (slotScope !== undefined) {
return typeof slotScope === 'function' && execute ? slotScope(h, options) : slotScope;
}
const slotsProp = [];
const componentOptions = instance.componentOptions || {};
(componentOptions.children || []).forEach(child => {
if (child.data && child.data.slot === prop) {
if (child.data.attrs) {
delete child.data.attrs.slot;
}
if (child.tag === 'template') {
slotsProp.push(child.children);
} else {
slotsProp.push(child);
}
}
});
return slotsProp.length ? slotsProp : undefined;
}
};
const getAllProps = ele => { const getKey = (ele: any) => {
let props = getOptionProps(ele); const key = ele.key;
if (ele.$) {
props = { ...props, ...this.$attrs };
} else {
props = { ...ele.props, ...props };
}
return props;
};
const getPropsData = ins => {
const vnode = ins.$ ? ins.$ : ins;
const res = {};
const originProps = vnode.props || {};
const props = {};
Object.keys(originProps).forEach(key => {
props[camelize(key)] = originProps[key];
});
const options = isPlainObject(vnode.type) ? vnode.type.props : {};
options &&
Object.keys(options).forEach(k => {
const v = resolvePropValue(options, props, k, props[k]);
if (k in props) {
// 仅包含 props不包含默认值
res[k] = v;
}
});
return { ...props, ...res }; // 合并事件、未声明属性等
};
const getValueByProp = (ele, prop) => {
return getPropsData(ele)[prop];
};
const getAttrs = ele => {
let data = ele.data;
if (ele.$vnode) {
data = ele.$vnode.data;
}
return data ? data.attrs || {} : {};
};
const getKey = ele => {
let key = ele.key;
return key; return key;
}; };
export function getEvents(ele = {}, on = true) { export function getEvents(ele: any = {}, on = true) {
let props = {}; let props = {};
if (ele.$) { if (ele.$) {
props = { ...props, ...ele.$attrs }; props = { ...props, ...ele.$attrs };
@ -281,27 +165,9 @@ export function getEvents(ele = {}, on = true) {
return splitAttrs(props)[on ? 'onEvents' : 'events']; return splitAttrs(props)[on ? 'onEvents' : 'events'];
} }
export function getEvent(child, event) { export function getClass(ele: any) {
return child.props && child.props[event];
}
// 获取 xxx.native 或者 原生标签 事件
export function getDataEvents(child) {
let events = {};
if (child.data && child.data.on) {
events = child.data.on;
}
return { ...events };
}
// use getListeners instead this.$listeners
// https://github.com/vueComponent/ant-design-vue/issues/1705
export function getListeners(context) {
return (context.$vnode ? context.$vnode.componentOptions.listeners : context.$listeners) || {};
}
export function getClass(ele) {
const props = (isVNode(ele) ? ele.props : ele.$attrs) || {}; const props = (isVNode(ele) ? ele.props : ele.$attrs) || {};
let tempCls = props.class || {}; const tempCls = props.class || {};
let cls = {}; let cls = {};
if (typeof tempCls === 'string') { if (typeof tempCls === 'string') {
tempCls.split(' ').forEach(c => { tempCls.split(' ').forEach(c => {
@ -318,7 +184,7 @@ export function getClass(ele) {
} }
return cls; return cls;
} }
export function getStyle(ele, camel) { export function getStyle(ele: any, camel?: boolean) {
const props = (isVNode(ele) ? ele.props : ele.$attrs) || {}; const props = (isVNode(ele) ? ele.props : ele.$attrs) || {};
let style = props.style || {}; let style = props.style || {};
if (typeof style === 'string') { if (typeof style === 'string') {
@ -332,19 +198,19 @@ export function getStyle(ele, camel) {
return style; return style;
} }
export function getComponentName(opts) { export function getComponentName(opts: any) {
return opts && (opts.Ctor.options.name || opts.tag); return opts && (opts.Ctor.options.name || opts.tag);
} }
export function isFragment(c) { export function isFragment(c: any) {
return c.length === 1 && c[0].type === Fragment; return c.length === 1 && c[0].type === Fragment;
} }
export function isEmptyContent(c) { export function isEmptyContent(c: any) {
return c === undefined || c === null || c === '' || (Array.isArray(c) && c.length === 0); return c === undefined || c === null || c === '' || (Array.isArray(c) && c.length === 0);
} }
export function isEmptyElement(c) { export function isEmptyElement(c: any) {
return ( return (
c && c &&
(c.type === Comment || (c.type === Comment ||
@ -353,11 +219,11 @@ export function isEmptyElement(c) {
); );
} }
export function isEmptySlot(c) { export function isEmptySlot(c: any) {
return !c || c().every(isEmptyElement); return !c || c().every(isEmptyElement);
} }
export function isStringElement(c) { export function isStringElement(c: any) {
return c && c.type === Text; return c && c.type === Text;
} }
@ -375,7 +241,7 @@ export function filterEmpty(children = []) {
return res.filter(c => !isEmptyElement(c)); return res.filter(c => !isEmptyElement(c));
} }
export function filterEmptyWithUndefined(children) { export function filterEmptyWithUndefined(children: any[]) {
if (children) { if (children) {
const coms = filterEmpty(children); const coms = filterEmpty(children);
return coms.length ? coms : undefined; return coms.length ? coms : undefined;
@ -384,34 +250,18 @@ export function filterEmptyWithUndefined(children) {
} }
} }
export function mergeProps() { function isValidElement(element: any) {
const args = [].slice.call(arguments, 0);
const props = {};
args.forEach((p = {}) => {
for (const [k, v] of Object.entries(p)) {
props[k] = props[k] || {};
if (isPlainObject(v)) {
Object.assign(props[k], v);
} else {
props[k] = v;
}
}
});
return props;
}
function isValidElement(element) {
if (Array.isArray(element) && element.length === 1) { if (Array.isArray(element) && element.length === 1) {
element = element[0]; element = element[0];
} }
return element && element.__v_isVNode && typeof element.type !== 'symbol'; // remove text node return element && element.__v_isVNode && typeof element.type !== 'symbol'; // remove text node
} }
function getPropsSlot(slots, props, prop = 'default') { function getPropsSlot(slots: any, props: any, prop = 'default') {
return props[prop] ?? slots[prop]?.(); return props[prop] ?? slots[prop]?.();
} }
export const getTextFromElement = ele => { export const getTextFromElement = (ele: any) => {
if (isValidElement(ele) && isStringElement(ele[0])) { if (isValidElement(ele) && isStringElement(ele[0])) {
return ele[0].children; return ele[0].children;
} }
@ -422,21 +272,12 @@ export {
hasProp, hasProp,
getOptionProps, getOptionProps,
getComponent, getComponent,
getComponentFromProp,
getSlotOptions,
slotHasProp,
getPropsData,
getKey, getKey,
getAttrs,
getValueByProp,
parseStyleText, parseStyleText,
initDefaultProps, initDefaultProps,
isValidElement, isValidElement,
camelize, camelize,
getSlots,
getSlot, getSlot,
getAllProps,
getAllChildren,
findDOMNode, findDOMNode,
flattenChildren, flattenChildren,
getPropsSlot, getPropsSlot,

View File

@ -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

View File

@ -0,0 +1,82 @@
// import { StyleProvider } from '../../cssinjs';
import { extractStyle } from '../index';
import { ConfigProvider } from '../../../components';
import { theme } from '../../../index';
const testGreenColor = '#008000';
describe('Static-Style-Extract', () => {
it('should extract static styles', () => {
const cssText = extractStyle();
expect(cssText).not.toContain(testGreenColor);
expect(cssText).toMatchSnapshot();
});
it('should extract static styles with customTheme', () => {
const cssText = extractStyle(node => {
return (
<ConfigProvider
theme={{
token: {
colorPrimary: testGreenColor,
},
}}
>
{node}
</ConfigProvider>
);
});
expect(cssText).toContain(testGreenColor);
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', () => {
// const cssText = extractStyle(
// (node) => (
// <StyleProvider hashPriority='high'>
// <ConfigProvider
// theme={{
// token: {
// colorPrimary: testGreenColor,
// },
// }}
// >
// {node}
// </ConfigProvider>
// </StyleProvider>
// ),
// );
// expect(cssText).toContain(testGreenColor);
// expect(cssText).not.toContain(':where');
// expect(cssText).toMatchSnapshot();
//
// const cssText2 = extractStyle((node) => (
// <ConfigProvider
// theme={{
// token: {
// colorPrimary: testGreenColor,
// },
// }}
// >
// {node}
// </ConfigProvider>
// ));
// expect(cssText2).toContain(':where');
// });
});

View File

@ -0,0 +1,90 @@
import { createCache, extractStyle as extStyle, StyleProvider } from '../cssinjs';
import * as antd from '../../components';
import { renderToString } from 'vue/server-renderer';
import type { CustomRender } from './interface';
const blackList: string[] = [
'ConfigProvider',
'Grid',
'Tour',
'SelectOptGroup',
'SelectOption',
'MentionsOption',
'TreeNode',
'TreeSelectNode',
'LocaleProvider',
];
const pickerMap = {
MonthPicker: 'month',
WeekPicker: 'week',
QuarterPicker: 'quarter',
};
const compChildNameMap = {
MenuDivider: 'Menu',
MenuItem: 'Menu',
MenuItemGroup: 'Menu',
SubMenu: 'Menu',
TableColumn: 'Table',
TableColumnGroup: 'Table',
TableSummary: 'Table',
TableSummaryRow: 'Table',
TableSummaryCell: 'Table',
TabPane: 'Tabs',
TimelineItem: 'Timeline',
};
const defaultNode = () => (
<>
{Object.keys(antd)
.filter(name => !blackList.includes(name) && name[0] === name[0].toUpperCase())
.map(compName => {
const Comp = antd[compName];
if (compName === 'Dropdown') {
return (
<Comp key={compName} menu={{ items: [] }}>
<div />
</Comp>
);
}
if (compName === 'Anchor') {
return <Comp key={compName} items={[]} />;
}
if (compName in pickerMap) {
const Comp = antd['DatePicker'];
const type = pickerMap[compName];
return <Comp key={compName} picker={type} />;
}
if (compName in compChildNameMap) {
const ParentComp = antd[compChildNameMap[compName]];
return (
<ParentComp>
<Comp />
</ParentComp>
);
}
if (compName === 'QRCode' || compName === 'Segmented') {
return (
<Comp key={compName} value={''}>
<div />
</Comp>
);
}
return <Comp key={compName} />;
})}
</>
);
export function extractStyle(customTheme?: CustomRender): string {
const cache = createCache();
renderToString(
<StyleProvider cache={cache}>
{customTheme ? customTheme(defaultNode()) : defaultNode()}
</StyleProvider>,
);
// Grab style from cache
const styleText = extStyle(cache, true);
return styleText;
}

View File

@ -0,0 +1,3 @@
import type { VueNode } from '../type';
export type CustomRender = (node: VueNode) => VueNode;

View File

@ -1,7 +1,7 @@
// Test via a getter in the options object to see if the passive property is accessed // Test via a getter in the options object to see if the passive property is accessed
let supportsPassive = false; let supportsPassive = false;
try { try {
let opts = Object.defineProperty({}, 'passive', { const opts = Object.defineProperty({}, 'passive', {
get() { get() {
supportsPassive = true; supportsPassive = true;
}, },

View File

@ -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;

View File

@ -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);
}
}

View File

@ -31,7 +31,9 @@ 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;
export type VueNode = VNodeChildAtom | VNodeChildAtom[] | JSX.Element;
// eslint-disable-next-line no-undef
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;
@ -90,3 +92,5 @@ export function someType<T>(types?: any[], defaultVal?: T) {
} }
export type CustomSlotsType<T> = SlotsType<T>; export type CustomSlotsType<T> = SlotsType<T>;
export type AnyObject = Record<PropertyKey, any>;

View File

@ -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 } 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> &
@ -40,6 +40,10 @@ export function deepCloneElement<T, U>(
if (Array.isArray(vnode)) { if (Array.isArray(vnode)) {
return vnode.map(item => deepCloneElement(item, nodeProps, override, mergeRef)); return vnode.map(item => deepCloneElement(item, nodeProps, override, mergeRef));
} else { } else {
// 需要判断是否为vnode方可进行clone操作
if (!isVNode(vnode)) {
return vnode;
}
const cloned = cloneElement(vnode, nodeProps, override, mergeRef); const cloned = cloneElement(vnode, nodeProps, override, mergeRef);
if (Array.isArray(cloned.children)) { if (Array.isArray(cloned.children)) {
cloned.children = deepCloneElement(cloned.children as VNode<T, U>[]); cloned.children = deepCloneElement(cloned.children as VNode<T, U>[]);
@ -47,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?.();
}

View File

@ -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;

View File

@ -26,36 +26,35 @@ export default defineComponent({
}, },
setup(props, { slots }) { setup(props, { slots }) {
const instance = getCurrentInstance(); const instance = getCurrentInstance();
const { prefixCls } = useConfigInject('wave', props); const { prefixCls, wave } = useConfigInject('wave', props);
// ============================== Style =============================== // ============================== Style ===============================
const [, hashId] = useStyle(prefixCls); const [, hashId] = useStyle(prefixCls);
// =============================== Wave =============================== // =============================== Wave ===============================
const showWave = useWave( const showWave = useWave(
instance,
computed(() => classNames(prefixCls.value, hashId.value)), computed(() => classNames(prefixCls.value, hashId.value)),
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(() => {
watch( watch(
() => props.disabled, () => props.disabled,
() => { () => {
clear(); clear();
nextTick(() => { nextTick(() => {
const node = findDOMNode(instance); const node: HTMLElement = findDOMNode(instance);
node?.removeEventListener('click', onClick, true);
if (!node || node.nodeType !== 1 || props.disabled) { if (!node || node.nodeType !== 1 || props.disabled) {
return; return;
} }
// Click handler // Click handler
const onClick = (e: MouseEvent) => { onClick = (e: MouseEvent) => {
// Fix radio button click twice // Fix radio button click twice
if ( if (
(e.target as HTMLElement).tagName === 'INPUT' || (e.target as HTMLElement).tagName === 'INPUT' ||

View File

@ -1,16 +1,25 @@
import type { ComponentInternalInstance, 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 }>,
): VoidFunction { ): VoidFunction {
const instance = getCurrentInstance();
let stopWave: () => void;
function showWave() { function showWave() {
const node = findDOMNode(instance); const node = findDOMNode(instance);
stopWave?.();
showWaveEffect(node, className.value); if (wave?.value?.disabled || !node) {
return;
} }
stopWave = showWaveEffect(node, className.value);
}
onBeforeUnmount(() => {
stopWave?.();
});
return showWave; return showWave;
} }

View File

@ -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?.()}

View File

@ -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';

View File

@ -0,0 +1,41 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders ./components/app/demo/basic.vue correctly 1`] = `
<div class="ant-app">
<!--teleport start-->
<!--teleport end-->
<!--teleport start-->
<!--teleport end-->
<div class="ant-space ant-space-horizontal ant-space-align-center">
<div class="ant-space-item" style="margin-right: 8px;"><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Open message</span>
</button></div>
<!---->
<div class="ant-space-item" style="margin-right: 8px;"><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Open modal</span>
</button></div>
<!---->
<div class="ant-space-item"><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Open notification</span>
</button></div>
<!---->
</div>
</div>
`;
exports[`renders ./components/app/demo/myPage.vue correctly 1`] = `
<div class="ant-space ant-space-horizontal ant-space-align-center">
<div class="ant-space-item" style="margin-right: 8px;"><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Open message</span>
</button></div>
<!---->
<div class="ant-space-item" style="margin-right: 8px;"><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Open modal</span>
</button></div>
<!---->
<div class="ant-space-item"><button class="ant-btn ant-btn-primary" type="button">
<!----><span>Open notification</span>
</button></div>
<!---->
</div>
`;

View File

@ -0,0 +1,3 @@
import demoTest from '../../../tests/shared/demoTest';
demoTest('app');

44
components/app/context.ts Normal file
View File

@ -0,0 +1,44 @@
import { provide, inject, reactive } from 'vue';
import type { InjectionKey } from 'vue';
import type { MessageInstance, ConfigOptions as MessageConfig } from '../message/interface';
import type { NotificationInstance, NotificationConfig } from '../notification/interface';
import type { ModalStaticFunctions } from '../modal/confirm';
export type AppConfig = {
message?: MessageConfig;
notification?: NotificationConfig;
};
export const AppConfigContextKey: InjectionKey<AppConfig> = Symbol('appConfigContext');
export const useProvideAppConfigContext = (appConfigContext: AppConfig) => {
return provide(AppConfigContextKey, appConfigContext);
};
export const useInjectAppConfigContext = () => {
return inject(AppConfigContextKey, {});
};
type ModalType = Omit<ModalStaticFunctions, 'warn'>;
export interface useAppProps {
message: MessageInstance;
notification: NotificationInstance;
modal: ModalType;
}
export const AppContextKey: InjectionKey<useAppProps> = Symbol('appContext');
export const useProvideAppContext = (appContext: useAppProps) => {
return provide(AppContextKey, appContext);
};
const defaultAppContext: useAppProps = reactive({
message: {},
notification: {},
modal: {},
} as useAppProps);
export const useInjectAppContext = () => {
return inject(AppContextKey, defaultAppContext);
};

View File

@ -0,0 +1,26 @@
<docs>
---
order: 0
title:
zh-CN: 基本使用
en-US: Basic Usage
---
## zh-CN
获取 `message``notification``modal` 静态方法
## en-US
Static method for `message`, `notification`, `modal`.
</docs>
<template>
<a-app>
<my-page />
</a-app>
</template>
<script lang="ts" setup>
import myPage from './myPage.vue';
</script>

View File

@ -0,0 +1,19 @@
<template>
<demo-sort :cols="1">
<basic />
</demo-sort>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import Basic from './basic.vue';
import CN from '../index.zh-CN.md';
import US from '../index.en-US.md';
export default defineComponent({
CN,
US,
components: {
Basic,
},
});
</script>

View File

@ -0,0 +1,32 @@
<template>
<a-space>
<a-button type="primary" @click="showMessage">Open message</a-button>
<a-button type="primary" @click="showModal">Open modal</a-button>
<a-button type="primary" @click="showNotification">Open notification</a-button>
</a-space>
</template>
<script setup lang="ts">
import { App } from 'ant-design-vue';
const { message, modal, notification } = App.useApp();
const showMessage = () => {
message.success('Success!');
};
const showModal = () => {
modal.warning({
title: 'This is a warning message',
content: 'some messages...some messages...',
});
};
const showNotification = () => {
notification.info({
message: `Notification topLeft`,
description: 'Hello, Ant Design Vue!!',
placement: 'topLeft',
});
};
</script>

View File

@ -0,0 +1,130 @@
---
category: Components
cols: 1
type: Other
title: App
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*TBTSR4PyVmkAAAAAAAAAAAAADrJ8AQ/original
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*JGb3RIzyOCkAAAAAAAAAAAAADrJ8AQ/original
tag: New
---
Application wrapper for some global usages.
## When To Use
- Provide reset styles based on `.ant-app` element.
- You could use static methods of `message/notification/Modal` form `useApp` without writing `contextHolder` manually.
## API
### App
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| message | Global config for Message | [MessageConfig](/components/message/#messageconfig) | - | 4.x |
| notification | Global config for Notification | [NotificationConfig](/components/notification/#notificationconfig) | - | 4.x |
## How to use
### Basic usage
App provides upstream and downstream method calls through `provide/inject`, because useApp needs to be used as a subcomponent, we recommend encapsulating App at the top level in the application.
```html
/*myPage.vue*/
<template>
<a-space>
<a-button type="primary" @click="showMessage">Open message</a-button>
<a-button type="primary" @click="showModal">Open modal</a-button>
<a-button type="primary" @click="showNotification">Open notification</a-button>
</a-space>
</template>
<script setup lang="ts">
import { App } from 'ant-design-vue';
const { message, modal, notification } = App.useApp();
const showMessage = () => {
message.success('Success!');
};
const showModal = () => {
modal.warning({
title: 'This is a warning message',
content: 'some messages...some messages...',
});
};
const showNotification = () => {
notification.info({
message: `Notification topLeft`,
description: 'Hello, Ant Design Vue!!',
placement: 'topLeft',
});
};
</script>
```
Note: App.useApp must be available under App.
#### Embedded usage scenarios (if not necessary, try not to do nesting)
```html
<a-app>
<a-space>
...
<a-app>...</a-app>
</a-space>
</a-app>
```
#### Sequence with ConfigProvider
The App component can only use the token in the `ConfigProvider`, if you need to use the Token, the ConfigProvider and the App component must appear in pairs.
```html
<a-config-provider theme="{{ ... }}">
<a-app>...</a-app>
</a-config-provider>
```
#### Global scene (pinia scene)
```ts
import { App } from 'ant-design-vue';
import type { MessageInstance } from 'ant-design-vue/es/message/interface';
import type { ModalStaticFunctions } from 'ant-design-vue/es/modal/confirm';
import type { NotificationInstance } from 'ant-design-vue/es/notification/interface';
export const useGlobalStore = defineStore('global', () => {
const message: MessageInstance = ref();
const notification: NotificationInstance = ref();
const modal: Omit<ModalStaticFunctions, 'warn'> = ref();
(() => {
const staticFunction = App.useApp();
message.value = staticFunction.message;
modal.value = staticFunction.modal;
notification.value = staticFunction.notification;
})();
return { message, notification, modal };
});
```
```html
// sub page
<template>
<a-space>
<a-button type="primary" @click="showMessage">Open message</a-button>
</a-space>
</template>
<script setup>
import { useGlobalStore } from '@/stores/global';
const global = useGlobalStore();
const showMessage = () => {
global.message.success('Success!');
};
</script>
```

83
components/app/index.tsx Normal file
View File

@ -0,0 +1,83 @@
import { defineComponent, computed } from 'vue';
import type { App as TypeApp, Plugin } from 'vue';
import { initDefaultProps } from '../_util/props-util';
import classNames from '../_util/classNames';
import { objectType } from '../_util/type';
import useConfigInject from '../config-provider/hooks/useConfigInject';
import useMessage from '../message/useMessage';
import useModal from '../modal/useModal';
import useNotification from '../notification/useNotification';
import type { AppConfig } from './context';
import {
useProvideAppConfigContext,
useInjectAppConfigContext,
useProvideAppContext,
useInjectAppContext,
} from './context';
import useStyle from './style';
export const AppProps = () => {
return {
rootClassName: String,
message: objectType<AppConfig['message']>(),
notification: objectType<AppConfig['notification']>(),
};
};
const useApp = () => {
return useInjectAppContext();
};
const App = defineComponent({
name: 'AApp',
props: initDefaultProps(AppProps(), {}),
setup(props, { slots }) {
const { prefixCls } = useConfigInject('app', props);
const [wrapSSR, hashId] = useStyle(prefixCls);
const customClassName = computed(() => {
return classNames(hashId.value, prefixCls.value, props.rootClassName);
});
const appConfig = useInjectAppConfigContext();
const mergedAppConfig = computed(() => ({
message: { ...appConfig.message, ...props.message },
notification: { ...appConfig.notification, ...props.notification },
}));
useProvideAppConfigContext(mergedAppConfig.value);
const [messageApi, messageContextHolder] = useMessage(mergedAppConfig.value.message);
const [notificationApi, notificationContextHolder] = useNotification(
mergedAppConfig.value.notification,
);
const [ModalApi, ModalContextHolder] = useModal();
const memoizedContextValue = computed(() => ({
message: messageApi,
notification: notificationApi,
modal: ModalApi,
}));
useProvideAppContext(memoizedContextValue.value);
return () => {
return wrapSSR(
<div class={customClassName.value}>
{ModalContextHolder()}
{messageContextHolder()}
{notificationContextHolder()}
{slots.default?.()}
</div>,
);
};
},
});
App.useApp = useApp;
App.install = function (app: TypeApp) {
app.component(App.name, App);
};
export default App as typeof App &
Plugin & {
readonly useApp: typeof useApp;
};

View File

@ -0,0 +1,131 @@
---
category: Components
subtitle: 包裹组件
cols: 1
type: 其它
title: App
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*TBTSR4PyVmkAAAAAAAAAAAAADrJ8AQ/original
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*JGb3RIzyOCkAAAAAAAAAAAAADrJ8AQ/original
tag: New
---
新的包裹组件,提供重置样式和提供消费上下文的默认环境。
## 何时使用
- 提供可消费 provide/inject 的 `message.xxx`、`Modal.xxx`、`notification.xxx` 的静态方法,可以简化 useMessage 等方法需要手动植入 `contextHolder` 的问题。
- 提供基于 `.ant-app` 的默认重置样式,解决原生元素没有 antd 规范样式的问题。
## API
### App
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| message | App 内 Message 的全局配置 | [MessageConfig](/components/message-cn/#messageconfig) | - | 4.x |
| notification | App 内 Notification 的全局配置 | [NotificationConfig](/components/notification-cn/#notificationconfig) | - | 4.x |
## 如何使用
### 基础用法
App 组件通过 `provide/inject` 提供上下文方法调用,因而 useApp 需要作为子组件才能使用,我们推荐在应用中顶层包裹 App。
```html
/*myPage.vue*/
<template>
<a-space>
<a-button type="primary" @click="showMessage">Open message</a-button>
<a-button type="primary" @click="showModal">Open modal</a-button>
<a-button type="primary" @click="showNotification">Open notification</a-button>
</a-space>
</template>
<script setup lang="ts">
import { App } from 'ant-design-vue';
const { message, modal, notification } = App.useApp();
const showMessage = () => {
message.success('Success!');
};
const showModal = () => {
modal.warning({
title: 'This is a warning message',
content: 'some messages...some messages...',
});
};
const showNotification = () => {
notification.info({
message: `Notification topLeft`,
description: 'Hello, Ant Design Vue!!',
placement: 'topLeft',
});
};
</script>
```
注意App.useApp 必须在 App 之下方可使用。
#### 内嵌使用场景(如无必要,尽量不做嵌套)
```html
<a-app>
<a-space>
...
<a-app>...</a-app>
</a-space>
</a-app>
```
#### 与 ConfigProvider 先后顺序
App 组件只能在 `ConfigProvider` 之下才能使用 Design Token 如果需要使用其样式重置能力,则 ConfigProvider 与 App 组件必须成对出现。
```html
<a-config-provider theme="{{ ... }}">
<a-app>...</a-app>
</a-config-provider>
```
#### 全局场景 (pinia 场景)
```ts
import { App } from 'ant-design-vue';
import type { MessageInstance } from 'ant-design-vue/es/message/interface';
import type { ModalStaticFunctions } from 'ant-design-vue/es/modal/confirm';
import type { NotificationInstance } from 'ant-design-vue/es/notification/interface';
export const useGlobalStore = defineStore('global', () => {
const message: MessageInstance = ref();
const notification: NotificationInstance = ref();
const modal: Omit<ModalStaticFunctions, 'warn'> = ref();
(() => {
const staticFunction = App.useApp();
message.value = staticFunction.message;
modal.value = staticFunction.modal;
notification.value = staticFunction.notification;
})();
return { message, notification, modal };
});
```
```html
// sub page
<template>
<a-space>
<a-button type="primary" @click="showMessage">Open message</a-button>
</a-space>
</template>
<script setup>
import { useGlobalStore } from '@/stores/global';
const global = useGlobalStore();
const showMessage = () => {
global.message.success('Success!');
};
</script>
```

View File

@ -0,0 +1,22 @@
import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook } from '../../theme/internal';
export type ComponentToken = {};
interface AppToken extends FullToken<'App'> {}
// =============================== Base ===============================
const genBaseStyle: GenerateStyle<AppToken> = token => {
const { componentCls, colorText, fontSize, lineHeight, fontFamily } = token;
return {
[componentCls]: {
color: colorText,
fontSize,
lineHeight,
fontFamily,
},
};
};
// ============================== Export ==============================
export default genComponentStyleHook('App', token => [genBaseStyle(token)]);

View File

@ -1,5 +1,28 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders ./components/auto-complete/demo/allow-clear.vue correctly 1`] = `
<div style="width: 200px;" class="ant-select ant-select-show-search ant-select-auto-complete ant-select-single ant-select-allow-clear ant-select-show-search">
<!---->
<div class="ant-select-selector"><span class="ant-select-selection-search"><input type="search" id="rc_select_TEST_OR_SSR" autocomplete="off" class="ant-select-selection-search-input" role="combobox" aria-haspopup="listbox" aria-owns="rc_select_TEST_OR_SSR_list" aria-autocomplete="list" aria-controls="rc_select_TEST_OR_SSR_list" aria-activedescendant="rc_select_TEST_OR_SSR_list_0"></span>
<!----><span class="ant-select-selection-placeholder">Clearable</span>
</div>
<!---->
<!---->
<!---->
</div>
<br>
<br>
<div style="width: 200px;" class="ant-select ant-select-show-search ant-select-auto-complete ant-select-single ant-select-allow-clear ant-select-show-search">
<!---->
<div class="ant-select-selector"><span class="ant-select-selection-search"><input type="search" id="rc_select_TEST_OR_SSR" autocomplete="off" class="ant-select-selection-search-input" role="combobox" aria-haspopup="listbox" aria-owns="rc_select_TEST_OR_SSR_list" aria-autocomplete="list" aria-controls="rc_select_TEST_OR_SSR_list" aria-activedescendant="rc_select_TEST_OR_SSR_list_0"></span>
<!----><span class="ant-select-selection-placeholder">Customized clear icon</span>
</div>
<!---->
<!---->
<!---->
</div>
`;
exports[`renders ./components/auto-complete/demo/basic.vue correctly 1`] = ` exports[`renders ./components/auto-complete/demo/basic.vue correctly 1`] = `
<div style="width: 200px;" class="ant-select ant-select-show-search ant-select-auto-complete ant-select-single ant-select-show-search"> <div style="width: 200px;" class="ant-select ant-select-show-search ant-select-auto-complete ant-select-single ant-select-show-search">
<!----> <!---->
@ -12,6 +35,18 @@ exports[`renders ./components/auto-complete/demo/basic.vue correctly 1`] = `
</div> </div>
`; `;
exports[`renders ./components/auto-complete/demo/border-less.vue correctly 1`] = `
<div style="width: 200px;" class="ant-select ant-select-borderless ant-select-show-search ant-select-auto-complete ant-select-single ant-select-show-search">
<!---->
<div class="ant-select-selector"><span class="ant-select-selection-search"><input type="search" id="rc_select_TEST_OR_SSR" autocomplete="off" class="ant-select-selection-search-input" role="combobox" aria-haspopup="listbox" aria-owns="rc_select_TEST_OR_SSR_list" aria-autocomplete="list" aria-controls="rc_select_TEST_OR_SSR_list" aria-activedescendant="rc_select_TEST_OR_SSR_list_0"></span>
<!----><span class="ant-select-selection-placeholder">border less</span>
</div>
<!---->
<!---->
<!---->
</div>
`;
exports[`renders ./components/auto-complete/demo/certain-category.vue correctly 1`] = ` exports[`renders ./components/auto-complete/demo/certain-category.vue correctly 1`] = `
<div class="certain-category-search-wrapper" style="width: 250px;"> <div class="certain-category-search-wrapper" style="width: 250px;">
<div popupclassname="certain-category-search-dropdown" class="ant-select certain-category-search ant-select-show-search ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search" style="width: 250px;"> <div popupclassname="certain-category-search-dropdown" class="ant-select certain-category-search ant-select-show-search ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search" style="width: 250px;">

View File

@ -0,0 +1,69 @@
<docs>
---
order: 8
title:
zh-CN: 自定义清除按钮
en-US: Customize clear button
---
## zh-CN
自定义清除按钮
## en-US
Customize clear button.
</docs>
<template>
<a-auto-complete
v-model:value="value"
:options="options"
style="width: 200px"
placeholder="Clearable"
:allow-clear="true"
@select="onSelect"
@search="onSearch"
/>
<br />
<br />
<a-auto-complete
v-model:value="value"
:options="options"
style="width: 200px"
placeholder="Customized clear icon"
:allow-clear="true"
@select="onSelect"
@search="onSearch"
>
<template #clearIcon>
<close-outlined />
</template>
</a-auto-complete>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { CloseOutlined } from '@ant-design/icons-vue';
interface MockVal {
value: string;
}
const mockVal = (str: string, repeat = 1): MockVal => {
return {
value: str.repeat(repeat),
};
};
const value = ref('');
const options = ref<MockVal[]>([]);
const onSearch = (searchText: string) => {
console.log('searchText');
options.value = !searchText
? []
: [mockVal(searchText), mockVal(searchText, 2), mockVal(searchText, 3)];
};
const onSelect = (value: string) => {
console.log('onSelect', value);
};
</script>

View File

@ -0,0 +1,53 @@
<docs>
---
order: 7
title:
zh-CN: 无边框
en-US: Border less
---
## zh-CN
没有边框
## en-US
border less.
</docs>
<template>
<a-auto-complete
v-model:value="value"
:options="options"
style="width: 200px"
placeholder="border less"
:bordered="false"
@select="onSelect"
@search="onSearch"
/>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
interface MockVal {
value: string;
}
const mockVal = (str: string, repeat = 1): MockVal => {
return {
value: str.repeat(repeat),
};
};
const value = ref('');
const options = ref<MockVal[]>([]);
const onSearch = (searchText: string) => {
console.log('searchText');
options.value = !searchText
? []
: [mockVal(searchText), mockVal(searchText, 2), mockVal(searchText, 3)];
};
const onSelect = (value: string) => {
console.log('onSelect', value);
};
</script>

View File

@ -7,6 +7,8 @@
<certain-category /> <certain-category />
<uncertain-category /> <uncertain-category />
<statusVue /> <statusVue />
<border-less />
<allow-clear />
</demo-sort> </demo-sort>
</template> </template>
@ -18,6 +20,8 @@ import NonCaseSensitive from './non-case-sensitive.vue';
import CertainCategory from './certain-category.vue'; import CertainCategory from './certain-category.vue';
import UncertainCategory from './uncertain-category.vue'; import UncertainCategory from './uncertain-category.vue';
import statusVue from './status.vue'; import statusVue from './status.vue';
import BorderLess from './border-less.vue';
import AllowClear from './allow-clear.vue';
import CN from '../index.zh-CN.md'; import CN from '../index.zh-CN.md';
import US from '../index.en-US.md'; import US from '../index.en-US.md';
@ -34,6 +38,8 @@ export default defineComponent({
NonCaseSensitive, NonCaseSensitive,
CertainCategory, CertainCategory,
UncertainCategory, UncertainCategory,
BorderLess,
AllowClear,
}, },
setup() { setup() {
return {}; return {};

View File

@ -30,6 +30,8 @@ The differences with Select are:
| allowClear | Show clear button, effective in multiple mode only. | boolean | false | | | allowClear | Show clear button, effective in multiple mode only. | boolean | false | |
| autofocus | get focus when component mounted | boolean | false | | | autofocus | get focus when component mounted | boolean | false | |
| backfill | backfill selected item the input when using keyboard | boolean | false | | | backfill | backfill selected item the input when using keyboard | boolean | false | |
| bordered | Whether has border style | boolean | true | 4.0 |
| clearIcon | Use slot custom clear icon | slot | `<CloseCircleFilled />` | 4.0 |
| default (for customize input element) | customize input element | slot | `<Input />` | | | default (for customize input element) | customize input element | slot | `<Input />` | |
| defaultActiveFirstOption | Whether active first option by default | boolean | true | | | defaultActiveFirstOption | Whether active first option by default | boolean | true | |
| defaultOpen | Initial open state of dropdown | boolean | - | | | defaultOpen | Initial open state of dropdown | boolean | - | |

View File

@ -50,10 +50,13 @@ 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;
dataSource: any; dataSource: any;
clearIcon: any;
}>, }>,
setup(props, { slots, attrs, expose }) { setup(props, { slots, attrs, expose }) {
warning( warning(

View File

@ -31,6 +31,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*WERTQ6qvgEYAAA
| allowClear | 支持清除, 单选模式有效 | boolean | false | | | allowClear | 支持清除, 单选模式有效 | boolean | false | |
| autofocus | 自动获取焦点 | boolean | false | | | autofocus | 自动获取焦点 | boolean | false | |
| backfill | 使用键盘选择选项的时候把选中项回填到输入框中 | boolean | false | | | backfill | 使用键盘选择选项的时候把选中项回填到输入框中 | boolean | false | |
| bordered | 是否有边框 | boolean | true | 4.0 |
| clearIcon | 使用插槽自定义清除按钮 | slot | `<CloseCircleFilled />` | 4.0 |
| default (自定义输入框) | 自定义输入框 | slot | `<Input />` | | | default (自定义输入框) | 自定义输入框 | slot | `<Input />` | |
| defaultActiveFirstOption | 是否默认高亮第一个选项。 | boolean | true | | | defaultActiveFirstOption | 是否默认高亮第一个选项。 | boolean | true | |
| defaultOpen | 是否默认展开下拉菜单 | boolean | - | | | defaultOpen | 是否默认展开下拉菜单 | boolean | - | |

View File

@ -11,7 +11,7 @@ import useConfigInject from '../config-provider/hooks/useConfigInject';
import ResizeObserver from '../vc-resize-observer'; import ResizeObserver from '../vc-resize-observer';
import eagerComputed from '../_util/eagerComputed'; import eagerComputed from '../_util/eagerComputed';
import useStyle from './style'; import useStyle from './style';
import { useInjectSize } from './SizeContext'; import { useAvatarInjectContext } from './AvatarContext';
export type AvatarSize = 'large' | 'small' | 'default' | number | ScreenSizeMap; export type AvatarSize = 'large' | 'small' | 'default' | number | ScreenSizeMap;
@ -56,9 +56,9 @@ const Avatar = defineComponent({
const { prefixCls } = useConfigInject('avatar', props); const { prefixCls } = useConfigInject('avatar', props);
const [wrapSSR, hashId] = useStyle(prefixCls); const [wrapSSR, hashId] = useStyle(prefixCls);
const groupSize = useInjectSize(); const avatarCtx = useAvatarInjectContext();
const size = computed(() => { const size = computed(() => {
return props.size === 'default' ? groupSize.value : props.size; return props.size === 'default' ? avatarCtx.size : props.size;
}); });
const screens = useBreakpoint(); const screens = useBreakpoint();
const responsiveSize = eagerComputed(() => { const responsiveSize = eagerComputed(() => {
@ -135,6 +135,7 @@ const Avatar = defineComponent({
return () => { return () => {
const { shape, src, alt, srcset, draggable, crossOrigin } = props; const { shape, src, alt, srcset, draggable, crossOrigin } = props;
const mergeShape = avatarCtx.shape ?? shape;
const icon = getPropsSlot(slots, props, 'icon'); const icon = getPropsSlot(slots, props, 'icon');
const pre = prefixCls.value; const pre = prefixCls.value;
const classString = { const classString = {
@ -142,7 +143,7 @@ const Avatar = defineComponent({
[pre]: true, [pre]: true,
[`${pre}-lg`]: size.value === 'large', [`${pre}-lg`]: size.value === 'large',
[`${pre}-sm`]: size.value === 'small', [`${pre}-sm`]: size.value === 'small',
[`${pre}-${shape}`]: shape, [`${pre}-${mergeShape}`]: true,
[`${pre}-image`]: src && isImgExist.value, [`${pre}-image`]: src && isImgExist.value,
[`${pre}-icon`]: icon, [`${pre}-icon`]: icon,
[hashId.value]: true, [hashId.value]: true,

View File

@ -0,0 +1,16 @@
import type { InjectionKey } from 'vue';
import { inject, provide } from 'vue';
import type { ScreenSizeMap } from '../_util/responsiveObserve';
export type AvatarSize = 'large' | 'small' | 'default' | number | ScreenSizeMap;
export interface AvatarContextType {
size?: AvatarSize;
shape?: 'circle' | 'square';
}
const AvatarContextKey: InjectionKey<AvatarContextType> = Symbol('AvatarContextKey');
export const useAvatarInjectContext = () => {
return inject(AvatarContextKey, {});
};
export const useAvatarProviderContext = (context: AvatarContextType) => {
return provide(AvatarContextKey, context);
};

View File

@ -3,11 +3,11 @@ import type { AvatarSize } from './Avatar';
import Avatar from './Avatar'; import Avatar from './Avatar';
import Popover from '../popover'; import Popover from '../popover';
import type { PropType, ExtractPropTypes, CSSProperties } from 'vue'; import type { PropType, ExtractPropTypes, CSSProperties } from 'vue';
import { computed, defineComponent } from 'vue'; import { computed, defineComponent, watchEffect } from 'vue';
import { flattenChildren, getPropsSlot } from '../_util/props-util'; import { flattenChildren, getPropsSlot } from '../_util/props-util';
import useConfigInject from '../config-provider/hooks/useConfigInject'; import useConfigInject from '../config-provider/hooks/useConfigInject';
import useStyle from './style'; import useStyle from './style';
import { useProviderSize } from './SizeContext'; import { useAvatarProviderContext } from './AvatarContext';
export const groupProps = () => ({ export const groupProps = () => ({
prefixCls: String, prefixCls: String,
@ -23,6 +23,7 @@ export const groupProps = () => ({
type: [Number, String, Object] as PropType<AvatarSize>, type: [Number, String, Object] as PropType<AvatarSize>,
default: 'default' as AvatarSize, default: 'default' as AvatarSize,
}, },
shape: { type: String as PropType<'circle' | 'square'>, default: 'circle' },
}); });
export type AvatarGroupProps = Partial<ExtractPropTypes<ReturnType<typeof groupProps>>>; export type AvatarGroupProps = Partial<ExtractPropTypes<ReturnType<typeof groupProps>>>;
@ -36,13 +37,17 @@ const Group = defineComponent({
const { prefixCls, direction } = useConfigInject('avatar', props); const { prefixCls, direction } = useConfigInject('avatar', props);
const groupPrefixCls = computed(() => `${prefixCls.value}-group`); const groupPrefixCls = computed(() => `${prefixCls.value}-group`);
const [wrapSSR, hashId] = useStyle(prefixCls); const [wrapSSR, hashId] = useStyle(prefixCls);
useProviderSize(computed(() => props.size)); watchEffect(() => {
const context = { size: props.size, shape: props.shape };
useAvatarProviderContext(context);
});
return () => { return () => {
const { const {
maxPopoverPlacement = 'top', maxPopoverPlacement = 'top',
maxCount, maxCount,
maxStyle, maxStyle,
maxPopoverTrigger = 'hover', maxPopoverTrigger = 'hover',
shape,
} = props; } = props;
const cls = { const cls = {
@ -72,7 +77,7 @@ const Group = defineComponent({
placement={maxPopoverPlacement} placement={maxPopoverPlacement}
overlayClassName={`${groupPrefixCls.value}-popover`} overlayClassName={`${groupPrefixCls.value}-popover`}
> >
<Avatar style={maxStyle}>{`+${numOfChildren - maxCount}`}</Avatar> <Avatar style={maxStyle} shape={shape}>{`+${numOfChildren - maxCount}`}</Avatar>
</Popover>, </Popover>,
); );
return wrapSSR( return wrapSSR(

View File

@ -1,17 +0,0 @@
import type { InjectionKey, Ref } from 'vue';
import { computed, inject, ref, provide } from 'vue';
import type { ScreenSizeMap } from '../_util/responsiveObserve';
export type AvatarSize = 'large' | 'small' | 'default' | number | ScreenSizeMap;
const SizeContextKey: InjectionKey<Ref<AvatarSize>> = Symbol('SizeContextKey');
export const useInjectSize = () => {
return inject(SizeContextKey, ref('default' as AvatarSize));
};
export const useProviderSize = (size: Ref<AvatarSize>) => {
const parentSize = useInjectSize();
provide(
SizeContextKey,
computed(() => size.value || parentSize.value),
);
return size;
};

View File

@ -16,29 +16,20 @@ Usually used for reminders and notifications.
</docs> </docs>
<template> <template>
<span style="margin-right: 24px"> <a-space :size="24">
<a-badge :count="1"> <a-badge :count="1">
<a-avatar shape="square"> <a-avatar shape="square">
<template #icon><UserOutlined /></template> <template #icon><UserOutlined /></template>
</a-avatar> </a-avatar>
</a-badge> </a-badge>
</span>
<span>
<a-badge dot> <a-badge dot>
<a-avatar shape="square"> <a-avatar shape="square">
<template #icon><UserOutlined /></template> <template #icon><UserOutlined /></template>
</a-avatar> </a-avatar>
</a-badge> </a-badge>
</span> </a-space>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { UserOutlined } from '@ant-design/icons-vue'; import { UserOutlined } from '@ant-design/icons-vue';
</script> </script>
<style scoped>
#components-avatar-demo-badge .ant-avatar {
margin-top: 0;
margin-right: 0;
}
</style>

View File

@ -16,6 +16,8 @@ Three sizes and two shapes are available.
</docs> </docs>
<template> <template>
<a-space direction="vertical" :size="32">
<a-space wrap :size="16">
<a-avatar :size="64"> <a-avatar :size="64">
<template #icon><UserOutlined /></template> <template #icon><UserOutlined /></template>
</a-avatar> </a-avatar>
@ -28,7 +30,8 @@ Three sizes and two shapes are available.
<a-avatar size="small"> <a-avatar size="small">
<template #icon><UserOutlined /></template> <template #icon><UserOutlined /></template>
</a-avatar> </a-avatar>
<br /> </a-space>
<a-space wrap :size="16">
<a-avatar shape="square" :size="64"> <a-avatar shape="square" :size="64">
<template #icon><UserOutlined /></template> <template #icon><UserOutlined /></template>
</a-avatar> </a-avatar>
@ -41,6 +44,8 @@ Three sizes and two shapes are available.
<a-avatar shape="square" size="small"> <a-avatar shape="square" size="small">
<template #icon><UserOutlined /></template> <template #icon><UserOutlined /></template>
</a-avatar> </a-avatar>
</a-space>
</a-space>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -8,27 +8,22 @@ title:
## zh-CN ## zh-CN
对于字符型的头像当字符串较长时字体大小可以根据头像宽度自动调整 对于字符型的头像当字符串较长时字体大小可以根据头像宽度自动调整也可使用 `gap`` 来设置字符距离左右两侧边界单位像素。
## en-US ## en-US
For letter type Avatar, when the letters are too long to display, the font size can be automatically adjusted according to the width of the Avatar. For letter type Avatar, when the letters are too long to display, the font size can be automatically adjusted according to the width of the Avatar. You can also use `gap` to set the unit distance between left and right sides.
</docs> </docs>
<template> <template>
<a-avatar <a-avatar size="large" :style="{ backgroundColor: color, verticalAlign: 'middle' }" :gap="gap">
shape="square"
size="large"
:style="{ backgroundColor: color, verticalAlign: 'middle' }"
>
{{ avatarValue }} {{ avatarValue }}
</a-avatar> </a-avatar>
<a-button <a-button size="small" :style="{ margin: '0 16px', verticalAlign: 'middle' }" @click="changeUser">
size="small" ChangeUser
:style="{ marginLeft: '16px', verticalAlign: 'middle' }" </a-button>
@click="changeValue" <a-button size="small" :style="{ verticalAlign: 'middle' }" @click="changeGap">
> ChangeGap
改变
</a-button> </a-button>
</template> </template>
@ -39,9 +34,16 @@ const UserList = ['U', 'Lucy', 'Tom', 'Edward'];
const colorList = ['#f56a00', '#7265e6', '#ffbf00', '#00a2ae']; const colorList = ['#f56a00', '#7265e6', '#ffbf00', '#00a2ae'];
const avatarValue = ref(UserList[0]); const avatarValue = ref(UserList[0]);
const color = ref(colorList[0]); const color = ref(colorList[0]);
const changeValue = () => { const changeUser = () => {
const index = UserList.indexOf(avatarValue.value); const index = UserList.indexOf(avatarValue.value);
avatarValue.value = index < UserList.length - 1 ? UserList[index + 1] : UserList[0]; avatarValue.value = index < UserList.length - 1 ? UserList[index + 1] : UserList[0];
color.value = index < colorList.length - 1 ? colorList[index + 1] : colorList[0]; color.value = index < colorList.length - 1 ? colorList[index + 1] : colorList[0];
}; };
const GapList = [4, 3, 2, 1];
const gap = ref(GapList[0]);
const changeGap = () => {
const index = GapList.indexOf(gap.value);
gap.value = index < GapList.length - 1 ? GapList[index + 1] : GapList[0];
};
</script> </script>

View File

@ -17,20 +17,22 @@ Avatar group display.
<template> <template>
<a-avatar-group> <a-avatar-group>
<a-avatar src="https://joeschmoe.io/api/v1/random" /> <a-avatar src="https://xsgames.co/randomusers/avatar.php?g=pixel&key=1" />
<a href="https://www.antdv.com">
<a-avatar style="background-color: #f56a00">K</a-avatar> <a-avatar style="background-color: #f56a00">K</a-avatar>
</a>
<a-tooltip title="Ant User" placement="top"> <a-tooltip title="Ant User" placement="top">
<a-avatar style="background-color: #87d068"> <a-avatar style="background-color: #87d068">
<template #icon><UserOutlined /></template> <template #icon><UserOutlined /></template>
</a-avatar> </a-avatar>
</a-tooltip> </a-tooltip>
<a-avatar style="background-color: #1890ff"> <a-avatar style="background-color: #1890ff">
<template #icon><UserOutlined /></template> <template #icon><AntDesignOutlined /></template>
</a-avatar> </a-avatar>
</a-avatar-group> </a-avatar-group>
<a-divider /> <a-divider />
<a-avatar-group :max-count="2" :max-style="{ color: '#f56a00', backgroundColor: '#fde3cf' }"> <a-avatar-group :max-count="2" :max-style="{ color: '#f56a00', backgroundColor: '#fde3cf' }">
<a-avatar src="https://joeschmoe.io/api/v1/random" /> <a-avatar src="https://xsgames.co/randomusers/avatar.php?g=pixel&key=2" />
<a-avatar style="background-color: #1890ff">K</a-avatar> <a-avatar style="background-color: #1890ff">K</a-avatar>
<a-tooltip title="Ant User" placement="top"> <a-tooltip title="Ant User" placement="top">
<a-avatar style="background-color: #87d068"> <a-avatar style="background-color: #87d068">
@ -38,7 +40,7 @@ Avatar group display.
</a-avatar> </a-avatar>
</a-tooltip> </a-tooltip>
<a-avatar style="background-color: #1890ff"> <a-avatar style="background-color: #1890ff">
<template #icon><UserOutlined /></template> <template #icon><AntDesignOutlined /></template>
</a-avatar> </a-avatar>
</a-avatar-group> </a-avatar-group>
<a-divider /> <a-divider />
@ -50,7 +52,7 @@ Avatar group display.
backgroundColor: '#fde3cf', backgroundColor: '#fde3cf',
}" }"
> >
<a-avatar src="https://joeschmoe.io/api/v1/random" /> <a-avatar src="https://xsgames.co/randomusers/avatar.php?g=pixel&key=3" />
<a-avatar style="background-color: #1890ff">K</a-avatar> <a-avatar style="background-color: #1890ff">K</a-avatar>
<a-tooltip title="Ant User" placement="top"> <a-tooltip title="Ant User" placement="top">
<a-avatar style="background-color: #87d068"> <a-avatar style="background-color: #87d068">
@ -58,11 +60,42 @@ Avatar group display.
</a-avatar> </a-avatar>
</a-tooltip> </a-tooltip>
<a-avatar style="background-color: #1890ff"> <a-avatar style="background-color: #1890ff">
<template #icon><AntDesignOutlined /></template>
</a-avatar>
</a-avatar-group>
<a-divider />
<a-avatar-group
:max-count="2"
max-popover-trigger="click"
size="large"
:max-style="{ color: '#f56a00', backgroundColor: '#fde3cf', cursor: 'pointer' }"
>
<a-avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
<a-avatar style="background-color: #f56a00">K</a-avatar>
<a-tooltip title="Ant User" placement="top">
<a-avatar style="background-color: #87d068">
<template #icon><UserOutlined /></template> <template #icon><UserOutlined /></template>
</a-avatar> </a-avatar>
</a-tooltip>
<a-avatar style="background-color: #1890ff">
<template #icon><AntDesignOutlined /></template>
</a-avatar>
</a-avatar-group>
<a-divider />
<a-avatar-group shape="square">
<a-avatar style="background-color: #fde3cf">A</a-avatar>
<a-avatar style="background-color: #f56a00">K</a-avatar>
<a-tooltip title="Ant User" placement="top">
<a-avatar style="background-color: #87d068">
<template #icon><UserOutlined /></template>
</a-avatar>
</a-tooltip>
<a-avatar style="background-color: #1890ff">
<template #icon><AntDesignOutlined /></template>
</a-avatar>
</a-avatar-group> </a-avatar-group>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { UserOutlined } from '@ant-design/icons-vue'; import { UserOutlined, AntDesignOutlined } from '@ant-design/icons-vue';
</script> </script>

View File

@ -36,10 +36,3 @@ export default defineComponent({
}, },
}); });
</script> </script>
<style>
[id^='components-avatar-demo-'] .ant-avatar {
margin-top: 16px;
margin-right: 16px;
}
</style>

View File

@ -16,6 +16,7 @@ Image, Icon and letter are supported, and the latter two kinds avatar can have c
</docs> </docs>
<template> <template>
<a-space :size="16" wrap>
<a-avatar> <a-avatar>
<template #icon> <template #icon>
<UserOutlined /> <UserOutlined />
@ -23,13 +24,14 @@ Image, Icon and letter are supported, and the latter two kinds avatar can have c
</a-avatar> </a-avatar>
<a-avatar>U</a-avatar> <a-avatar>U</a-avatar>
<a-avatar :size="40">USER</a-avatar> <a-avatar :size="40">USER</a-avatar>
<a-avatar src="https://joeschmoe.io/api/v1/random" /> <a-avatar src="https://www.antdv.com/assets/logo.1ef800a8.svg" />
<a-avatar style="color: #f56a00; background-color: #fde3cf">U</a-avatar> <a-avatar style="color: #f56a00; background-color: #fde3cf">U</a-avatar>
<a-avatar style="background-color: #87d068"> <a-avatar style="background-color: #87d068">
<template #icon> <template #icon>
<UserOutlined /> <UserOutlined />
</template> </template>
</a-avatar> </a-avatar>
</a-space>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>

View File

@ -34,3 +34,4 @@ Avatars can be used to represent people or objects. It supports images, `Icon`s,
| maxPopoverTrigger | Set the trigger of excess avatar Popover | `hover` \| `focus` \| `click` | `hover` | 3.0 | | maxPopoverTrigger | Set the trigger of excess avatar Popover | `hover` \| `focus` \| `click` | `hover` | 3.0 |
| maxStyle | The style of excess avatar style | CSSProperties | - | | | maxStyle | The style of excess avatar style | CSSProperties | - | |
| size | The size of the avatar | number \| `large` \| `small` \| `default` \| { xs: number, sm: number, ...} | `default` | | | size | The size of the avatar | number \| `large` \| `small` \| `default` \| { xs: number, sm: number, ...} | `default` | |
| shape | The shape of the avatar | `circle` \| `square` | `circle` | 4.0 |

View File

@ -39,3 +39,4 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*YbgyQaRGz-UAAA
| maxPopoverTrigger | 设置多余头像 Popover 的触发方式 | `hover` \| `focus` \| `click` | `hover` | 3.0 | | maxPopoverTrigger | 设置多余头像 Popover 的触发方式 | `hover` \| `focus` \| `click` | `hover` | 3.0 |
| maxStyle | 多余头像样式 | CSSProperties | - | | | maxStyle | 多余头像样式 | CSSProperties | - | |
| size | 设置头像的大小 | number \| `large` \| `small` \| `default` \| { xs: number, sm: number, ...} | `default` | | | size | 设置头像的大小 | number \| `large` \| `small` \| `default` \| { xs: number, sm: number, ...} | `default` | |
| shape | 设置头像的形状 | `circle` \| `square` | `circle` | 4.0 |

View File

@ -3,20 +3,57 @@ import type { FullToken, GenerateStyle } from '../../theme/internal';
import { genComponentStyleHook, mergeToken } from '../../theme/internal'; import { genComponentStyleHook, mergeToken } from '../../theme/internal';
import { resetComponent } from '../../style'; import { resetComponent } from '../../style';
export interface ComponentToken {} export interface ComponentToken {
/**
* @desc
* @descEN Background color of Avatar
*/
containerSize: number;
/**
* @desc
* @descEN Size of large Avatar
*/
containerSizeLG: number;
/**
* @desc
* @descEN Size of small Avatar
*/
containerSizeSM: number;
/**
* @desc
* @descEN Font size of Avatar
*/
textFontSize: number;
/**
* @desc
* @descEN Font size of large Avatar
*/
textFontSizeLG: number;
/**
* @desc
* @descEN Font size of small Avatar
*/
textFontSizeSM: number;
/**
* @desc
* @descEN Spacing between avatars in a group
*/
groupSpace: number;
/**
* @desc
* @descEN Overlapping of avatars in a group
*/
groupOverlapping: number;
/**
* @desc
* @descEN Border color of avatars in a group
*/
groupBorderColor: string;
}
type AvatarToken = FullToken<'Avatar'> & { type AvatarToken = FullToken<'Avatar'> & {
avatarBg: string; avatarBg: string;
avatarColor: string; avatarColor: string;
avatarSizeBase: number;
avatarSizeLG: number;
avatarSizeSM: number;
avatarFontSizeBase: number;
avatarFontSizeLG: number;
avatarFontSizeSM: number;
avatarGroupOverlapping: number;
avatarGroupSpace: number;
avatarGroupBorderColor: string;
avatarBgColor: string; avatarBgColor: string;
}; };
@ -27,12 +64,12 @@ const genBaseStyle: GenerateStyle<AvatarToken> = token => {
iconCls, iconCls,
avatarBg, avatarBg,
avatarColor, avatarColor,
avatarSizeBase, containerSize,
avatarSizeLG, containerSizeLG,
avatarSizeSM, containerSizeSM,
avatarFontSizeBase, textFontSize,
avatarFontSizeLG, textFontSizeLG,
avatarFontSizeSM, textFontSizeSM,
borderRadius, borderRadius,
borderRadiusLG, borderRadiusLG,
borderRadiusSM, borderRadiusSM,
@ -89,14 +126,14 @@ const genBaseStyle: GenerateStyle<AvatarToken> = token => {
display: 'block', display: 'block',
}, },
...avatarSizeStyle(avatarSizeBase, avatarFontSizeBase, borderRadius), ...avatarSizeStyle(containerSize, textFontSize, borderRadius),
[`&-lg`]: { [`&-lg`]: {
...avatarSizeStyle(avatarSizeLG, avatarFontSizeLG, borderRadiusLG), ...avatarSizeStyle(containerSizeLG, textFontSizeLG, borderRadiusLG),
}, },
[`&-sm`]: { [`&-sm`]: {
...avatarSizeStyle(avatarSizeSM, avatarFontSizeSM, borderRadiusSM), ...avatarSizeStyle(containerSizeSM, textFontSizeSM, borderRadiusSM),
}, },
'> img': { '> img': {
@ -110,27 +147,40 @@ const genBaseStyle: GenerateStyle<AvatarToken> = token => {
}; };
const genGroupStyle: GenerateStyle<AvatarToken> = token => { const genGroupStyle: GenerateStyle<AvatarToken> = token => {
const { componentCls, avatarGroupBorderColor, avatarGroupSpace } = token; const { componentCls, groupBorderColor, groupOverlapping, groupSpace } = token;
return { return {
[`${componentCls}-group`]: { [`${componentCls}-group`]: {
display: 'inline-flex', display: 'inline-flex',
[`${componentCls}`]: { [`${componentCls}`]: {
borderColor: avatarGroupBorderColor, borderColor: groupBorderColor,
}, },
[`> *:not(:first-child)`]: { [`> *:not(:first-child)`]: {
marginInlineStart: avatarGroupSpace, marginInlineStart: groupOverlapping,
},
},
[`${componentCls}-group-popover`]: {
[`${componentCls} + ${componentCls}`]: {
marginInlineStart: groupSpace,
}, },
}, },
}; };
}; };
export default genComponentStyleHook('Avatar', token => { export default genComponentStyleHook(
'Avatar',
token => {
const { colorTextLightSolid, colorTextPlaceholder } = token;
const avatarToken = mergeToken<AvatarToken>(token, {
avatarBg: colorTextPlaceholder,
avatarColor: colorTextLightSolid,
});
return [genBaseStyle(avatarToken), genGroupStyle(avatarToken)];
},
token => {
const { const {
colorTextLightSolid,
controlHeight, controlHeight,
controlHeightLG, controlHeightLG,
controlHeightSM, controlHeightSM,
@ -141,24 +191,21 @@ export default genComponentStyleHook('Avatar', token => {
fontSizeHeading3, fontSizeHeading3,
marginXS, marginXS,
marginXXS,
colorBorderBg, colorBorderBg,
colorTextPlaceholder,
} = token; } = token;
return {
containerSize: controlHeight,
containerSizeLG: controlHeightLG,
containerSizeSM: controlHeightSM,
const avatarToken = mergeToken<AvatarToken>(token, { textFontSize: Math.round((fontSizeLG + fontSizeXL) / 2),
avatarBg: colorTextPlaceholder, textFontSizeLG: fontSizeHeading3,
avatarColor: colorTextLightSolid, textFontSizeSM: fontSize,
avatarSizeBase: controlHeight, groupSpace: marginXXS,
avatarSizeLG: controlHeightLG, groupOverlapping: -marginXS,
avatarSizeSM: controlHeightSM, groupBorderColor: colorBorderBg,
};
avatarFontSizeBase: Math.round((fontSizeLG + fontSizeXL) / 2), },
avatarFontSizeLG: fontSizeHeading3, );
avatarFontSizeSM: fontSize,
avatarGroupSpace: -marginXS,
avatarGroupBorderColor: colorBorderBg,
});
return [genBaseStyle(avatarToken), genGroupStyle(avatarToken)];
});

View File

@ -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';
@ -107,7 +107,7 @@ export default defineComponent({
const statusCls = computed(() => ({ const statusCls = computed(() => ({
[`${prefixCls.value}-status-dot`]: hasStatus.value, [`${prefixCls.value}-status-dot`]: hasStatus.value,
[`${prefixCls.value}-status-${props.status}`]: !!props.status, [`${prefixCls.value}-status-${props.status}`]: !!props.status,
[`${prefixCls.value}-status-${props.color}`]: isInternalColor.value, [`${prefixCls.value}-color-${props.color}`]: isInternalColor.value,
})); }));
const statusStyle = computed(() => { const statusStyle = computed(() => {
@ -125,7 +125,7 @@ export default defineComponent({
[`${prefixCls.value}-multiple-words`]: [`${prefixCls.value}-multiple-words`]:
!isDotRef.value && displayCount.value && displayCount.value.toString().length > 1, !isDotRef.value && displayCount.value && displayCount.value.toString().length > 1,
[`${prefixCls.value}-status-${props.status}`]: !!props.status, [`${prefixCls.value}-status-${props.status}`]: !!props.status,
[`${prefixCls.value}-status-${props.color}`]: isInternalColor.value, [`${prefixCls.value}-color-${props.color}`]: isInternalColor.value,
})); }));
return () => { return () => {

View File

@ -33,19 +33,19 @@ exports[`renders ./components/badge/demo/change.vue correctly 1`] = `
exports[`renders ./components/badge/demo/colors.vue correctly 1`] = ` exports[`renders ./components/badge/demo/colors.vue correctly 1`] = `
<h4 style="margin-bottom: 16px;">Presets:</h4> <h4 style="margin-bottom: 16px;">Presets:</h4>
<div> <div>
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-pink"></span><span class="ant-badge-status-text">pink</span></span></div> <div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-pink"></span><span class="ant-badge-status-text">pink</span></span></div>
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-red"></span><span class="ant-badge-status-text">red</span></span></div> <div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-red"></span><span class="ant-badge-status-text">red</span></span></div>
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-yellow"></span><span class="ant-badge-status-text">yellow</span></span></div> <div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-yellow"></span><span class="ant-badge-status-text">yellow</span></span></div>
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-orange"></span><span class="ant-badge-status-text">orange</span></span></div> <div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-orange"></span><span class="ant-badge-status-text">orange</span></span></div>
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-cyan"></span><span class="ant-badge-status-text">cyan</span></span></div> <div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-cyan"></span><span class="ant-badge-status-text">cyan</span></span></div>
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-green"></span><span class="ant-badge-status-text">green</span></span></div> <div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-green"></span><span class="ant-badge-status-text">green</span></span></div>
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-blue"></span><span class="ant-badge-status-text">blue</span></span></div> <div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-blue"></span><span class="ant-badge-status-text">blue</span></span></div>
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-purple"></span><span class="ant-badge-status-text">purple</span></span></div> <div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-purple"></span><span class="ant-badge-status-text">purple</span></span></div>
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-geekblue"></span><span class="ant-badge-status-text">geekblue</span></span></div> <div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-geekblue"></span><span class="ant-badge-status-text">geekblue</span></span></div>
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-magenta"></span><span class="ant-badge-status-text">magenta</span></span></div> <div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-magenta"></span><span class="ant-badge-status-text">magenta</span></span></div>
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-volcano"></span><span class="ant-badge-status-text">volcano</span></span></div> <div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-volcano"></span><span class="ant-badge-status-text">volcano</span></span></div>
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-gold"></span><span class="ant-badge-status-text">gold</span></span></div> <div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-gold"></span><span class="ant-badge-status-text">gold</span></span></div>
<div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-lime"></span><span class="ant-badge-status-text">lime</span></span></div> <div><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-color-lime"></span><span class="ant-badge-status-text">lime</span></span></div>
</div> </div>
<div class="ant-divider ant-divider-horizontal ant-divider-with-text ant-divider-with-text-left" role="separator"><span class="ant-divider-inner-text">Custom</span></div> <div class="ant-divider ant-divider-horizontal ant-divider-with-text ant-divider-with-text-left" role="separator"><span class="ant-divider-inner-text">Custom</span></div>
<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot" style="background: rgb(255, 85, 0); color: rgb(255, 85, 0);"></span><span class="ant-badge-status-text">#f50</span></span> <span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot" style="background: rgb(255, 85, 0); color: rgb(255, 85, 0);"></span><span class="ant-badge-status-text">#f50</span></span>
@ -89,6 +89,8 @@ exports[`renders ./components/badge/demo/overflow.vue correctly 1`] = `
`; `;
exports[`renders ./components/badge/demo/ribbon.vue correctly 1`] = ` exports[`renders ./components/badge/demo/ribbon.vue correctly 1`] = `
<div style="width: 100%;" class="ant-space ant-space-vertical">
<div class="ant-space-item" style="margin-bottom: 8px;">
<div class="ant-ribbon-wrapper "> <div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small"> <div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head"> <div class="ant-card-head">
@ -106,6 +108,9 @@ exports[`renders ./components/badge/demo/ribbon.vue correctly 1`] = `
<div class="ant-ribbon-corner"></div> <div class="ant-ribbon-corner"></div>
</div> </div>
</div> </div>
</div>
<!---->
<div class="ant-space-item" style="margin-bottom: 8px;">
<div class="ant-ribbon-wrapper "> <div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small"> <div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head"> <div class="ant-card-head">
@ -123,6 +128,9 @@ exports[`renders ./components/badge/demo/ribbon.vue correctly 1`] = `
<div class="ant-ribbon-corner"></div> <div class="ant-ribbon-corner"></div>
</div> </div>
</div> </div>
</div>
<!---->
<div class="ant-space-item" style="margin-bottom: 8px;">
<div class="ant-ribbon-wrapper "> <div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small"> <div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head"> <div class="ant-card-head">
@ -140,6 +148,9 @@ exports[`renders ./components/badge/demo/ribbon.vue correctly 1`] = `
<div class="ant-ribbon-corner"></div> <div class="ant-ribbon-corner"></div>
</div> </div>
</div> </div>
</div>
<!---->
<div class="ant-space-item" style="margin-bottom: 8px;">
<div class="ant-ribbon-wrapper "> <div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small"> <div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head"> <div class="ant-card-head">
@ -157,6 +168,9 @@ exports[`renders ./components/badge/demo/ribbon.vue correctly 1`] = `
<div class="ant-ribbon-corner"></div> <div class="ant-ribbon-corner"></div>
</div> </div>
</div> </div>
</div>
<!---->
<div class="ant-space-item" style="margin-bottom: 8px;">
<div class="ant-ribbon-wrapper "> <div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small"> <div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head"> <div class="ant-card-head">
@ -174,6 +188,9 @@ exports[`renders ./components/badge/demo/ribbon.vue correctly 1`] = `
<div class="ant-ribbon-corner"></div> <div class="ant-ribbon-corner"></div>
</div> </div>
</div> </div>
</div>
<!---->
<div class="ant-space-item" style="margin-bottom: 8px;">
<div class="ant-ribbon-wrapper "> <div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small"> <div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head"> <div class="ant-card-head">
@ -191,6 +208,9 @@ exports[`renders ./components/badge/demo/ribbon.vue correctly 1`] = `
<div class="ant-ribbon-corner"></div> <div class="ant-ribbon-corner"></div>
</div> </div>
</div> </div>
</div>
<!---->
<div class="ant-space-item" style="margin-bottom: 8px;">
<div class="ant-ribbon-wrapper "> <div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small"> <div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head"> <div class="ant-card-head">
@ -208,6 +228,9 @@ exports[`renders ./components/badge/demo/ribbon.vue correctly 1`] = `
<div class="ant-ribbon-corner"></div> <div class="ant-ribbon-corner"></div>
</div> </div>
</div> </div>
</div>
<!---->
<div class="ant-space-item">
<div class="ant-ribbon-wrapper "> <div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small"> <div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head"> <div class="ant-card-head">
@ -225,6 +248,9 @@ exports[`renders ./components/badge/demo/ribbon.vue correctly 1`] = `
<div class="ant-ribbon-corner"></div> <div class="ant-ribbon-corner"></div>
</div> </div>
</div> </div>
</div>
<!---->
</div>
`; `;
exports[`renders ./components/badge/demo/status.vue correctly 1`] = ` exports[`renders ./components/badge/demo/status.vue correctly 1`] = `
@ -234,15 +260,18 @@ exports[`renders ./components/badge/demo/status.vue correctly 1`] = `
<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-processing"></span><span class="ant-badge-status-text"><!----></span></span> <span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-processing"></span><span class="ant-badge-status-text"><!----></span></span>
<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-warning"></span><span class="ant-badge-status-text"><!----></span></span> <span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-warning"></span><span class="ant-badge-status-text"><!----></span></span>
<br> <br>
<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-success"></span><span class="ant-badge-status-text">Success</span></span> <div class="ant-space ant-space-vertical">
<br> <div class="ant-space-item" style="margin-bottom: 8px;"><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-success"></span><span class="ant-badge-status-text">Success</span></span></div>
<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-error"></span><span class="ant-badge-status-text">Error</span></span> <!---->
<br> <div class="ant-space-item" style="margin-bottom: 8px;"><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-error"></span><span class="ant-badge-status-text">Error</span></span></div>
<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-default"></span><span class="ant-badge-status-text">Default</span></span> <!---->
<br> <div class="ant-space-item" style="margin-bottom: 8px;"><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-default"></span><span class="ant-badge-status-text">Default</span></span></div>
<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-processing"></span><span class="ant-badge-status-text">Processing</span></span> <!---->
<br> <div class="ant-space-item" style="margin-bottom: 8px;"><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-processing"></span><span class="ant-badge-status-text">Processing</span></span></div>
<span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-warning"></span><span class="ant-badge-status-text">warning</span></span> <!---->
<div class="ant-space-item"><span class="ant-badge ant-badge-status ant-badge-not-a-wrapper"><span class="ant-badge-status-dot ant-badge-status-warning"></span><span class="ant-badge-status-text">warning</span></span></div>
<!---->
</div>
`; `;
exports[`renders ./components/badge/demo/title.vue correctly 1`] = ` exports[`renders ./components/badge/demo/title.vue correctly 1`] = `

View File

@ -16,6 +16,7 @@ Use ribbon badge.
</docs> </docs>
<template> <template>
<a-space direction="vertical" style="width: 100%">
<a-badge-ribbon text="Hippies"> <a-badge-ribbon text="Hippies">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card> <a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon> </a-badge-ribbon>
@ -40,4 +41,5 @@ Use ribbon badge.
<a-badge-ribbon text="Hippies" color="magenta"> <a-badge-ribbon text="Hippies" color="magenta">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card> <a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon> </a-badge-ribbon>
</a-space>
</template> </template>

View File

@ -22,13 +22,12 @@ Standalone badge with status.
<a-badge status="processing" /> <a-badge status="processing" />
<a-badge status="warning" /> <a-badge status="warning" />
<br /> <br />
<a-space direction="vertical">
<a-badge status="success" text="Success" /> <a-badge status="success" text="Success" />
<br />
<a-badge status="error" text="Error" /> <a-badge status="error" text="Error" />
<br />
<a-badge status="default" text="Default" /> <a-badge status="default" text="Default" />
<br />
<a-badge status="processing" text="Processing" /> <a-badge status="processing" text="Processing" />
<br />
<a-badge status="warning" text="warning" /> <a-badge status="warning" text="warning" />
</a-space>
</template> </template>

View File

@ -73,9 +73,12 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
const ribbonPrefixCls = `${antCls}-ribbon`; const ribbonPrefixCls = `${antCls}-ribbon`;
const ribbonWrapperPrefixCls = `${antCls}-ribbon-wrapper`; const ribbonWrapperPrefixCls = `${antCls}-ribbon-wrapper`;
const statusPreset = genPresetColor(token, (colorKey, { darkColor }) => ({ const colorPreset = genPresetColor(token, (colorKey, { darkColor }) => ({
[`${componentCls}-status-${colorKey}`]: { [`&${componentCls} ${componentCls}-color-${colorKey}`]: {
background: darkColor, background: darkColor,
[`&:not(${componentCls}-count)`]: {
color: darkColor,
},
}, },
})); }));
@ -150,9 +153,9 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
insetInlineEnd: 0, insetInlineEnd: 0,
transform: 'translate(50%, -50%)', transform: 'translate(50%, -50%)',
transformOrigin: '100% 0%', transformOrigin: '100% 0%',
[`${iconCls}-spin`]: { [`&${iconCls}-spin`]: {
animationName: antBadgeLoadingCircle, animationName: antBadgeLoadingCircle,
animationDuration: token.motionDurationMid, animationDuration: '1s',
animationIterationCount: 'infinite', animationIterationCount: 'infinite',
animationTimingFunction: 'linear', animationTimingFunction: 'linear',
}, },
@ -175,7 +178,7 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
backgroundColor: token.colorSuccess, backgroundColor: token.colorSuccess,
}, },
[`${componentCls}-status-processing`]: { [`${componentCls}-status-processing`]: {
position: 'relative', overflow: 'visible',
color: token.colorPrimary, color: token.colorPrimary,
backgroundColor: token.colorPrimary, backgroundColor: token.colorPrimary,
@ -207,13 +210,13 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
[`${componentCls}-status-warning`]: { [`${componentCls}-status-warning`]: {
backgroundColor: token.colorWarning, backgroundColor: token.colorWarning,
}, },
...statusPreset,
[`${componentCls}-status-text`]: { [`${componentCls}-status-text`]: {
marginInlineStart: marginXS, marginInlineStart: marginXS,
color: token.colorText, color: token.colorText,
fontSize: token.fontSize, fontSize: token.fontSize,
}, },
}, },
...colorPreset,
[`${componentCls}-zoom-appear, ${componentCls}-zoom-enter`]: { [`${componentCls}-zoom-appear, ${componentCls}-zoom-enter`]: {
animationName: antZoomBadgeIn, animationName: antZoomBadgeIn,
animationDuration: token.motionDurationSlow, animationDuration: token.motionDurationSlow,
@ -284,7 +287,6 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
...resetComponent(token), ...resetComponent(token),
position: 'absolute', position: 'absolute',
top: marginXS, top: marginXS,
height: badgeFontHeight,
padding: `0 ${token.paddingXS}px`, padding: `0 ${token.paddingXS}px`,
color: token.colorPrimary, color: token.colorPrimary,
lineHeight: `${badgeFontHeight}px`, lineHeight: `${badgeFontHeight}px`,

View File

@ -8,7 +8,7 @@ import DownOutlined from '@ant-design/icons-vue/DownOutlined';
import useConfigInject from '../config-provider/hooks/useConfigInject'; import useConfigInject from '../config-provider/hooks/useConfigInject';
import type { MouseEventHandler } from '../_util/EventInterface'; import type { MouseEventHandler } from '../_util/EventInterface';
import { eventType, objectType } from '../_util/type'; import { eventType, objectType } from '../_util/type';
import type { CustomSlotsType } from '../_util/type'; import type { CustomSlotsType, VueNode } from '../_util/type';
export const breadcrumbItemProps = () => ({ export const breadcrumbItemProps = () => ({
prefixCls: String, prefixCls: String,
@ -38,7 +38,7 @@ export default defineComponent({
* if overlay is have * if overlay is have
* Wrap a Dropdown * Wrap a Dropdown
*/ */
const renderBreadcrumbNode = (breadcrumbItem: JSX.Element, prefixCls: string) => { const renderBreadcrumbNode = (breadcrumbItem: VueNode, prefixCls: string) => {
const overlay = getPropsSlot(slots, props, 'overlay'); const overlay = getPropsSlot(slots, props, 'overlay');
if (overlay) { if (overlay) {
return ( return (
@ -59,7 +59,7 @@ export default defineComponent({
const separator = getPropsSlot(slots, props, 'separator') ?? '/'; const separator = getPropsSlot(slots, props, 'separator') ?? '/';
const children = getPropsSlot(slots, props); const children = getPropsSlot(slots, props);
const { class: cls, style, ...restAttrs } = attrs; const { class: cls, style, ...restAttrs } = attrs;
let link: JSX.Element; let link: VueNode;
if (props.href !== undefined) { if (props.href !== undefined) {
link = ( link = (
<a class={`${prefixCls.value}-link`} onClick={handleClick} {...restAttrs}> <a class={`${prefixCls.value}-link`} onClick={handleClick} {...restAttrs}>

View File

@ -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';

Some files were not shown because too many files have changed in this diff Show More