Compare commits

...

302 Commits

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 a2e50dc43e
Feat v4 (#6329)
* refactor(icon): remove style dir (#6215)

* refactor: rename locale

* refactor: locale-provider

* refactor: modal

* refactor: menu

* fix: custom class (#6217)

* refactor: tooltip

* refactor: grid (#6220)

* refactor: grid

* fix(grid): align & justify responsive

* chore: update demo and snapshot

* fix: row ts type not work

* doc: update demo

* refactor: ts

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

* fix: spin error #6222

* 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"

* refactor: skeleton (#6224)

* refactor: skeleton

* refactor: skeleton style

* chore: modify skeleton demo style

* fix(button): link and text should not have wave (#6226)

* refactor: dropdown

* refactor: popover & popconfirm

* refactor(tag): less to cssinjs (#6227)

* refactor(empty): less to cssinjs (#6230)

* refactor(empty): less to cssinjs

* chore: remove unuse code

* fix: reactivity lose

* fix: empty props #6230

* refactor: progress style (#6234)

* refactor: progress

* refactor: progress style

* fix: progress attrs

* refactor: progress #6234

* refactor: switch (#6236)

* refactor: switch style

* refactor: delete switch style

* refactor:input (#6237)

* refactor:input

* fix inheritAttrs:false

* fix attrs.class

* feat: input add disabled

* refactor:comment (#6238)

* refactor:comment

* fix inheritAttrs: false & attrs.class

* refactor:pageheader (#6239)

* refactor:pageheader

* fix inheritAttrs: false & attrs.class

* refactor:statistic (#6240)

* refactor:statistic

* fix inheritAttrs: false & attrs.class

* refactor:list (#6241)

* refactor:list

* fix inheritAttrs: false & attrs.class

* feat: update type

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

* perf: space compact

* refactor:typography (#6244)

* refactor:typography

* fix return

* fix import type

* fix: typography #6244

* refactor:datepicker (#6245)

* refactor: datepicker type

* refactor: rate style (#6254)

* refactor(layout): less to cssinjs (#6249)

* doc: update layout cover

* refactor(result): less to cssinjs (#6246)

* refactor(result): less to cssinjs

* fix: class name is overridden

* docs: update result cover

* refactor:slider (#6250)

* feat: slider  deprecated tooltipVisible

* 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

* refactor: card #6258

* refactor:carousel (#6262)

* refactor:carousel

* docs:update & refactor: carousel type

---------

Co-authored-by: tangjinzhou <415800467@qq.com>

* refactor:transfer (#6247)

* refactor:transfer

* merge v4 branch & fix theme interface conflict

* docs:update & refactor: transfer type

* perf: transfer

* refactor:checkbox (#6248)

* refactor:checkbox

* docs:update & refactor: checkbox type

* feat: checkbox add disabled context

* refactor:pagination (#6251)

* refactor:pagination

* docs:update & refactor: pagination type

* style: update pagination props type

* refactor: mentions (#6255)

* refactor: mentions

* refactor: mentions menu provider

* doc: update mentions demo

* refcator:upload (#6261)

* refcator:upload

* docs:update & refactor: upload type

* Update style.ts

---------

Co-authored-by: tangjinzhou <415800467@qq.com>

* perf: upload motion

* refactor:timeline (#6263)

* refactor:timeline

* docs:update & refactor: timeline type

* perf: timeline

* refactor:steps (#6264)

* refactor:steps

* fix ...attrs

* fix StepsToken error

* docs:update & refactor: steps type

* fix: steps icon clss error

* refactor:collapse (#6266)

* refactor:collapse

* fix collapse props version

* docs:update & refactor: collapse type & fix collapsible

* feat: update collapse type

* refactor:inputnumber (#6265)

* refactor:inputnumber

* docs:update & refactor: inputnumber type

---------

Co-authored-by: tangjinzhou <415800467@qq.com>

* feat: number add compactSize & disabledContext

* refactor:table (#6267)

* refactor:table

* docs:update & refactor: table type

---------

Co-authored-by: tangjinzhou <415800467@qq.com>

* refactor: table

* feat: table add expandColumnTitle slot

* refactor:calendar (#6269)

* refactor:calendar

* docs:update

* refactor:timepicker (#6270)

* refactor:timepicker

* docs:update & refactor: timepicker type

* refactor:tree (#6276)

* 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

* refactor: rename locale file

* feat: tree add leafIcon

* [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

* refactor: tabs #6288

* feat: add segmented (#6286)

* refactor: segmented #6286

* refactor:select (#6295)

* refactor:select

* update doc

* delete useless

* feat: select add context size

* refactor: tree select (#6296)

* feat: tree-select add context size

* perf: table

* docs: update doc toc

* refactor: cascader

* refactor: auto-complete

* refactor: image

* refactor: drawer

* refactor:radio (#6299)

* refactor:radio

* fix attrs

* feat: radio add disabled context

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

* refactor: form

* fix: directive not work

* fix: use open, remove visible

* doc: update cover

* refactor: remove not use code

* chore: update build script

* doc: update doc

* doc: refactor doc

* chore: update token error

* chore: update style

* refactor: rename _style to style

* fix: tag warning

* fix(dropdown): open invalid (#6316)

* feat: add watermark  (#6300)

* feat: add watermark

* feat: add watermark demo

* feat: add mutationObserver

* feat: add watermark demo

* refactor: watermark type

* doc: add theme-editor

* fix: inject value maybe undefined && tag style invalid (#6320)

* fix: inject value maybe undefined

* fix(tag): style invalid

* feat: add qrcode (#6315)

* feat: add qrcode

* fix: qrcode bug

* fix: qrcode value required

* refactor: props  deconstruct

* Feat v4 floatbutton (#6294)

* feat: add float-button components

* fix type &  demo display

* fix components entry

* fix review bug

* fix bug

* fix .value

* refactor: qrcode #6315

* refactor: float-button

* fix: groupsize context error

* fix: floatbutton animation not work

* 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

* fix: token effect error

* 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

* fix: cssinjs effect error

* doc: format code

* fix: tag click event not trigger

* release 4.0.0-alpha.1

* fix: qrcode type

* fix: remove not use file

* doc: update doc site

* doc: update site

* doc: fix theme editor bgcolor (#6358)

* fix: motion not work

* release 4.0.0-alpha.2

* fix: qrcode ; error, close #6362

* fix docs dark theme & add docs coverDark (#6367)

* fix docs dark theme & add docs coverDark

* fix theme Editor edit

* fix: dropdown divider disappear, close  #6365 (#6369)

* doc: update baner

* fix: button wave not work

* 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

* fix: ConfigProvider error for style, close #6368

* release 4.0.0-alpha.4

* style: add dark style for `pre` and `code` (#6382)

* docs: version menu (#6390)

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

* fix: datepicker presets error #6387

* docs: update datepicker doc #6387

* 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

* docs: update site

* refactor: steps #6406

* test: update steps

* perf: shallowRef instead ref

* fix(Modal): fix modal locale (#6423)

* 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

* docs: update compatiple #6415

* 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

* fix: progress borderRadius reactive #6409

* fix(defaultConfigProvider): add getPopupContainer (#6425), close #6419

* fix: qrcode size error, close #6418

* release 4.0.0-alpha.4

* fix: picker import error

* test: add QRCode unit testing (#6441)

* 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

* fix(badge): badge props count default value error (#6433)

* docs: update site responsive

* fix: modal api method i18n not work, close #6438

* release 4.0.0-alpha.5

* chore(docs): update docs (#6446)

* docs(space): update demo

* docs(affix): update docs

* fix: cssinjs compatibility (#6454)

* feat: add convertLegacyToken

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

* feat: remove backtop

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

* feat: anchor add customTitle slot #6447

* docs: update doc anchor

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

* doc: update menu icon

* feat: menu items icon add arg

* fix: antd.min error

* release 4.0.0-alpha.6

* fix: table resizable not work && type error (#6514)

* 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

* fix: submenu type lose theme

* fix: dropdown menu hide error

* fix: dealing with switching topics modal, notification, message does not take effect close #6512 (#6518)

* fix: resolve dark mode not support

* fix: unified expression

* 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

* perf: useModal #6517

* release 4.0.0-beta.1

* docs: fix tab demo error

* fix(config-provider): fix ConfigProvider.config is not function close #6528 (#6529)

* 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

* refactor: useMessage #6527

* refactor: useNotification #6527

* release 4.0.0-beta.2

* 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

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

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

* fix: getPopupContainer not work

* release 4.0.0-beta.3

* release 4.0.0-beta.4

* docs: update grid docs (#6549)

Co-authored-by: zhuzhengjian <zhuzhengjian@hoteamsoft.com>

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

* fix: components bug & update docs (#6548)

* fix bug

* fix test case and update snapshot,fix space merge class

* docs(grid): update migrate docs && delete xxxl in grid docs (#6562)

* 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

* fix(grid): remove grid xxxl attribute (#6572)

* fix: remove grid xxxl attribute

* docs: remove xxxl in grid docs

* fix: tooltip custom color error

* feat: remove Step __legacy

* feat: add tour (#6332)

* feat v4 add tour

* fix type error

* sync tour from antd5.4.6 & fix type error

* fix error

* refactor: tour #6332

* fix: tour center

* fix: picker support v-show

* test: update snap

* test: update tour test

* fix: tour-mask attrs pointer-events (#6577)

* fix: tour animated

* feat: support vue 3.3 slot type

* release 4.0.0-rc.1

* release 4.0.0-rc.2, close #6588

* 4.0.0-rc.3

* chore: remove vue private api

* fix: paginantion error, close #6590

* release 4.0.0-rc.4

* fix: checxbox style

* fix: pagination mini size style

* release 4.0.0-rc.5

* docs: update v4 tabs doc error(#6606) (#6607)

* docs: add ant-design-vue nuxt module (#6620)

* fix: layout-sider and menu transition style(#6637) (#6640)

* docs: fixed the style error of online demo (#6630)

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

* 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

* fix(tour): target position (#6629)

* style: format lint

* docs(form): add form disabled demo (#6658)

* fix: comment node error

* release 4.0

* fix: portalWrapper add autoLock prop (#6687), close #6649

* fix: image animation & zindex, close #6675

* 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

* 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

* docs: export space-compact types (#6716)

* release 4.0.0

---------

Co-authored-by: bqy_fe <1743369777@qq.com>
Co-authored-by: zkwolf <chenhao5866@gmail.com>
Co-authored-by: Zev Zhu <45655660+aibayanyu20@users.noreply.github.com>
Co-authored-by: lyn <76365499@qq.com>
Co-authored-by: 果冻橙 <shifeng199307@gmail.com>
Co-authored-by: songsong0707 <74165917+songsong0707@users.noreply.github.com>
Co-authored-by: yang <30883395+webvs2@users.noreply.github.com>
Co-authored-by: selicens <1244620067@qq.com>
Co-authored-by: 一堆菠萝 <53335668+JavanShen@users.noreply.github.com>
Co-authored-by: H1mple <35363759+baohangxing@users.noreply.github.com>
Co-authored-by: Cherry7 <79909910+CCherry07@users.noreply.github.com>
Co-authored-by: Konv Suu <2583695112@qq.com>
Co-authored-by: luoawai <32483950+luoawai@users.noreply.github.com>
Co-authored-by: 鱼见 <657715602@qq.com>
Co-authored-by: zhuzhengjian <zhuzhengjian@hoteamsoft.com>
Co-authored-by: Cupid Valentine <53572196+valcosmos@users.noreply.github.com>
Co-authored-by: 专业逮虾户aa <30494925+waldonUB@users.noreply.github.com>
Co-authored-by: PanStar <PanStar@users.noreply.github.com>
2023-07-14 11:58: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
huyikai a0e94978f5
docs: update upload demo ts
示例代码在运行时,ts类型报错.原因是试图在可能为 undefined 的对象上使用扩展运算符.
2023-07-03 21:25:29 +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
专业逮虾户aa 8212237045
docs: 🐞change the default setting of "treeNodeFilterProp" from "va… (#6610)
* docs: 📃change the default  setting of  "treeNodeFilterProp" from  "value" to "label"

* revert: ↩revert this config and create another pr to commit
2023-06-01 15:03:54 +08:00
bqy_fe 80edf86d18
fix(image-group): props definition (#6621)
* fix(image-group): props definition

* feat: add ImageGroupProps type definition
2023-06-01 14:58:30 +08:00
Zev Zhu 6f032c9722
docs: add ant-design-vue nuxt module (#6620) 2023-06-01 14:57:23 +08:00
selicens 1001ff3834
docs(tabs): update v3-tabs doc erroe(#6606) (#6608) 2023-06-01 14:56:09 +08:00
selicens 6be947aeb9
docs: update v4 tabs doc error(#6606) (#6607) 2023-06-01 14:55:50 +08:00
Cherry7 3057cfe9ef
doc(TreeSelect): update fieldNames docs (#6623) 2023-06-01 14:55:17 +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 9cff5cb558
Update README.md (#6594) 2023-05-24 16:01:39 +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
514 changed files with 221664 additions and 18355 deletions

View File

@ -7,4 +7,7 @@ es/
lib/
_site/
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:import/recommended',
'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'],
globals: {
h: true,
defineProps: 'readonly',
},
overrides: [
{
files: ['*.md'],
@ -28,12 +40,11 @@ module.exports = {
},
{
files: ['*.ts', '*.tsx'],
extends: ['@vue/typescript/recommended', '@vue/prettier', '@vue/prettier/@typescript-eslint'],
// extends: ['@vue/typescript/recommended', '@vue/prettier'],
parserOptions: {
project: './tsconfig.json',
},
rules: {
'@typescript-eslint/no-explicit-any': 0,
'@typescript-eslint/ban-types': 0,
'@typescript-eslint/consistent-type-imports': 'error',
'@typescript-eslint/explicit-module-boundary-types': 0,
@ -51,17 +62,21 @@ module.exports = {
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2021,
},
rules: {
'no-console': 'off',
'@typescript-eslint/no-unused-vars': [
'error',
{ vars: 'all', args: 'after-used', ignoreRestSiblings: true },
],
'vue/no-reserved-component-names': 'off',
},
},
],
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/namespace': [2, { allowComputed: true }],
'import/no-named-as-default-member': 'off',
@ -94,7 +109,4 @@ module.exports = {
],
'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:
- name: Create new issue
url: https://vuecomponent.github.io/issue-helper/
@ -13,5 +13,5 @@ contact_links:
url: https://www.paypal.me/tangjinzhou
about: Love Ant Design Vue? Please consider supporting us via Paypal.
- name: 支付宝/微信 赞助
url: https://qn.antdv.com/alipay-and-wechat.png
url: https://aliyuncdn.antdv.com/alipay-and-wechat.png
about: Ant Design Vue 的健康持续发展需要您的支持,🙏

View File

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

View File

@ -1,18 +1,25 @@
name: Issue Reply
name: Issue Labeled
on:
issues:
types: [labeled]
permissions:
contents: read
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
steps:
- name: Need Reproduce
if: github.event.label.name == '🤔 Need Reproduce'
uses: actions-cool/issues-helper@v1.2
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
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.
@ -21,9 +28,10 @@ jobs:
- name: help wanted
if: github.event.label.name == 'help wanted'
uses: actions-cool/issues-helper@v1.2
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
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!
@ -32,12 +40,37 @@ jobs:
- name: Usage
if: github.event.label.name == 'Usage'
uses: actions-cool/issues-helper@v1.2
uses: actions-cool/issues-helper@v3
with:
actions: 'create-comment, close-issue'
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.issue.number }}
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).
你好 @${{ 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:
types: [opened]
permissions:
contents: read
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
steps:
- uses: actions-cool/check-user-permission@v1.0.0
@ -15,7 +23,7 @@ jobs:
- name: check invalid
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:
actions: 'create-comment,add-labels,close-issue'
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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
<p align="center">
<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>
</p>
@ -10,7 +10,7 @@
<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)
@ -26,6 +26,12 @@ An enterprise-class UI components based on Ant Design and Vue 3.
- 开箱即用的高质量 Vue 组件。
- 共享 [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/#兼容性)
@ -66,6 +72,8 @@ $ yarn add ant-design-vue
| [vue-cli-plugin-ant-design](https://github.com/vueComponent/vue-cli-plugin-ant-design) | 使用 vue-cli3 快速使用 ant-design-vue 组件库 |
| [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 的组件库 |
| [@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 界面解决方案 |
## 问答
@ -80,24 +88,33 @@ ant-design-vue 是 MIT 协议的开源项目。为了项目能够更好的持续
- [Patreon](https://www.patreon.com/tangjinzhou)
- [opencollective](https://opencollective.com/ant-design-vue)
- [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>
## 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>
## 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>
## [更多赞助者 (通过 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">
<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>
</p>
@ -26,6 +26,12 @@ English | [简体中文](./README-zh_CN.md)
- A set of high-quality Vue components out of the box.
- 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
- 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
**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
$ npm install ant-design-vue --save
@ -49,7 +55,7 @@ $ npm install ant-design-vue --save
$ 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
@ -66,6 +72,8 @@ If you are in a bad network environmentyou can try other registries and tools
| [vue-cli-plugin-ant-design](https://github.com/vueComponent/vue-cli-plugin-ant-design) | Vue-cli 3 plugin to add ant-design-vue |
| [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 |
| [@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
@ -74,7 +82,8 @@ ant-design-vue is an MIT-licensed open source project. In order to achieve bette
- [Patreon](https://www.patreon.com/tangjinzhou)
- [opencollective](https://opencollective.com/ant-design-vue)
- [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
@ -84,4 +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)
## 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)
This project is tested with BrowserStack.

View File

@ -6,7 +6,6 @@ import { genWebTypes } from './web-types';
import { outputFileSync, readFileSync } from 'fs-extra';
import type { Options, VueTag } from './type';
import { getComponentName, normalizePath, toKebabCase } from './utils';
import { genVeturAttributes, genVeturTags } from './vetur';
import { flatMap } from 'lodash';
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);
})
.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));
return tags;
}
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');
fileContent
.split('\n')
@ -62,7 +61,7 @@ function mergeTag(tags: Map<String, VueTag>, mergedTag: VueTag) {
function mergeTags(mergedTagsArr: Map<String, VueTag>[]): VueTag[] {
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 [];
mergedTagsArr.forEach(mergedTags => {
mergedTags.forEach(mergedTag => mergeTag(tags, mergedTag));
@ -78,13 +77,6 @@ export async function parseAndWrite(options: Options): Promise<Number> {
const tagsFromTypings = await readTypings(options);
const tags = mergeTags([tagsFromMarkdown, tagsFromTypings]);
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));
return tags.length;
}

View File

@ -21,7 +21,7 @@ export type Articals = Artical[];
function readLine(input: string) {
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) {
@ -47,7 +47,7 @@ function tableParse(input: string) {
};
while (start < end) {
const target = input.substr(start);
const target = input.substring(start);
const line = readLine(target);
if (!/^\|/.test(target)) {
@ -79,7 +79,7 @@ export function mdParser(input: string): Articals {
const end = input.length;
while (start < end) {
const target = input.substr(start);
const target = input.substring(start);
let match;
if ((match = TITLE_REG.exec(target))) {
@ -91,7 +91,7 @@ export function mdParser(input: string): Articals {
start += match.index + match[0].length;
} 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({
type: 'table',
table,

View File

@ -34,25 +34,6 @@ export type VueTag = {
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 = {
name: string;
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';
const fs = require('fs');
const assign = require('object-assign');
const { getProjectPath } = require('./utils/projectHelper');
module.exports = function () {
@ -9,7 +8,7 @@ module.exports = function () {
if (fs.existsSync(getProjectPath('tsconfig.json'))) {
my = require(getProjectPath('tsconfig.json'));
}
return assign(
return Object.assign(
{
noUnusedParameters: true,
noUnusedLocals: true,

View File

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

View File

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

View File

@ -1,51 +1,167 @@
import { defineComponent, shallowRef, withDirectives } from 'vue';
import antInput from './antInputDirective';
import type { PropType } from 'vue';
import { computed, defineComponent, shallowRef, ref, watch } from 'vue';
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({
compatConfig: { MODE: 3 },
inheritAttrs: false,
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',
},
size: PropTypes.string,
style: PropTypes.oneOfType([String, Object]),
class: PropTypes.string,
},
emits: ['change', 'input'],
setup(_p, { emit }) {
const inputRef = shallowRef(null);
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 { composing } = e.target as any;
if ((e as any).isComposing || composing) {
emit('input', e);
} else {
emit('input', e);
emit('change', e);
emit('change', e);
};
const onCompositionstart = (e: CompositionEvent) => {
isComposing.value = true;
(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) {
inputRef.value.focus();
}
};
return {
inputRef,
focus: () => {
if (inputRef.value) {
inputRef.value.focus();
}
},
blur: () => {
if (inputRef.value) {
inputRef.value.blur();
}
},
handleChange,
const blur = () => {
if (inputRef.value) {
inputRef.value.blur();
}
};
},
render() {
return withDirectives(
(
<input
{...this.$props}
{...this.$attrs}
onInput={this.handleChange}
onChange={this.handleChange}
ref="inputRef"
const handleKeyDown = (e: KeyboardEvent) => {
emit('keydown', e);
};
const handleKeyUp = (e: KeyboardEvent) => {
emit('keyup', e);
};
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: 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 {
methods: {
setState(state = {}, callback) {
setState(state = {}, callback: () => any) {
let newState = typeof state === 'function' ? state(this.$data, this.$props) : state;
if (this.getDerivedStateFromProps) {
const s = this.getDerivedStateFromProps(getOptionProps(this), {
@ -26,6 +26,7 @@ export default {
},
__emit() {
// 直接调用事件底层组件不需要vueTool记录events
// eslint-disable-next-line prefer-rest-params
const args = [].slice.call(arguments, 0);
let eventName = args[0];
eventName = `on${eventName[0].toUpperCase()}${eventName.substring(1)}`;

View File

@ -3,7 +3,7 @@ import {
defineComponent,
nextTick,
onBeforeMount,
onBeforeUnmount,
onMounted,
onUpdated,
Teleport,
watch,
@ -23,12 +23,24 @@ export default defineComponent({
// getContainer
let container: HTMLElement;
const { shouldRender } = useInjectPortal();
onBeforeMount(() => {
isSSR = false;
function setContainer() {
if (shouldRender.value) {
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, () => {
if (shouldRender.value && !container) {
container = props.getContainer();
@ -44,11 +56,11 @@ export default defineComponent({
}
});
});
onBeforeUnmount(() => {
if (container && container.parentNode) {
container.parentNode.removeChild(container);
}
});
// onBeforeUnmount(() => {
// if (container && container.parentNode) {
// container.parentNode.removeChild(container);
// }
// });
return () => {
if (!shouldRender.value) return null;
if (isSSR) {

View File

@ -7,7 +7,6 @@ import {
onMounted,
onBeforeUnmount,
onUpdated,
getCurrentInstance,
nextTick,
computed,
} from 'vue';
@ -30,7 +29,7 @@ const getParent = (getContainer: GetContainer) => {
}
if (getContainer) {
if (typeof getContainer === 'string') {
return document.querySelectorAll(getContainer)[0];
return document.querySelectorAll(getContainer)[0] as HTMLElement;
}
if (typeof getContainer === 'function') {
return getContainer();
@ -61,16 +60,20 @@ export default defineComponent({
const container = shallowRef<HTMLElement>();
const componentRef = shallowRef();
const rafId = shallowRef<number>();
const triggerUpdate = shallowRef(1);
const defaultContainer = canUseDom() && document.createElement('div');
const removeCurrentContainer = () => {
// Portal will remove from `parentNode`.
// Let's handle this again to avoid refactor issue.
container.value?.parentNode?.removeChild(container.value);
if (container.value === defaultContainer) {
container.value?.parentNode?.removeChild(container.value);
}
container.value = null;
};
let parent: HTMLElement = null;
const attachToParent = (force = false) => {
if (force || (container.value && !container.value.parentNode)) {
const parent = getParent(props.getContainer);
parent = getParent(props.getContainer);
if (parent) {
parent.appendChild(container.value);
return true;
@ -81,8 +84,6 @@ export default defineComponent({
return true;
};
// attachToParent();
const defaultContainer = document.createElement('div');
const getContainer = () => {
if (!supportDom) {
return null;
@ -105,8 +106,6 @@ export default defineComponent({
attachToParent();
});
const instance = getCurrentInstance();
useScrollLocker(
computed(() => {
return (
@ -123,11 +122,14 @@ export default defineComponent({
[() => props.visible, () => props.getContainer],
([visible, getContainer], [prevVisible, prevGetContainer]) => {
// Update count
if (supportDom && getParent(props.getContainer) === document.body) {
if (visible && !prevVisible) {
openCount += 1;
} else if (init) {
openCount -= 1;
if (supportDom) {
parent = getParent(props.getContainer);
if (parent === document.body) {
if (visible && !prevVisible) {
openCount += 1;
} else if (init) {
openCount -= 1;
}
}
}
@ -151,15 +153,15 @@ export default defineComponent({
nextTick(() => {
if (!attachToParent()) {
rafId.value = raf(() => {
instance.update();
triggerUpdate.value += 1;
});
}
});
});
onBeforeUnmount(() => {
const { visible, getContainer } = props;
if (supportDom && getParent(getContainer) === document.body) {
const { visible } = props;
if (supportDom && parent === document.body) {
// render func
openCount = visible && openCount ? openCount - 1 : openCount;
}
@ -173,7 +175,7 @@ export default defineComponent({
getOpenCount: () => openCount,
getContainer,
};
if (forceRender || visible || componentRef.value) {
if (triggerUpdate.value && (forceRender || visible || componentRef.value)) {
portal = (
<Portal
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;
type ValueType = [number, any]; // [times, realValue]
const SPLIT = '%';
class Entity {
instanceId: string;
constructor(instanceId: string) {
this.instanceId = instanceId;
}
/** @private Internal cache map. Do not access this directly */
cache = new Map<string, ValueType>();
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) {
const path = Array.isArray(keys) ? keys.join('%') : keys;
const path = Array.isArray(keys) ? keys.join(SPLIT) : keys;
const prevValue = this.cache.get(path)!;
const nextValue = valueFn(prevValue);

View File

@ -1,29 +1,41 @@
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 type { Linter } from './linters/interface';
import type { Transformer } from './transformers/interface';
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_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
export const CSS_IN_JS_INSTANCE = '__cssinjs_instance__';
export const CSS_IN_JS_INSTANCE_ID = Math.random().toString(12).slice(2);
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) {
const styles = document.body.querySelectorAll(`style[${ATTR_MARK}]`) || [];
const { firstChild } = document.head;
Array.from(styles).forEach(style => {
(style as any)[CSS_IN_JS_INSTANCE] =
(style as any)[CSS_IN_JS_INSTANCE] || CSS_IN_JS_INSTANCE_ID;
(style as any)[CSS_IN_JS_INSTANCE] = (style as any)[CSS_IN_JS_INSTANCE] || cssinjsInstanceId;
// Not force move if no head
document.head.insertBefore(style, firstChild);
// Not force move if no head
if ((style as any)[CSS_IN_JS_INSTANCE] === cssinjsInstanceId) {
document.head.insertBefore(style, firstChild);
}
});
// Deduplicate of moved styles
@ -31,7 +43,7 @@ export function createCache() {
Array.from(document.querySelectorAll(`style[${ATTR_MARK}]`)).forEach(style => {
const hash = style.getAttribute(ATTR_MARK)!;
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);
}
} else {
@ -40,7 +52,7 @@ export function createCache() {
});
}
return new CacheEntity();
return new CacheEntity(cssinjsInstanceId);
}
export type HashPriority = 'low' | 'high';
@ -76,19 +88,45 @@ const StyleContextKey: InjectionKey<ShallowRef<Partial<StyleContextProps>>> =
Symbol('StyleContextKey');
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 = {
cache: createCache(),
defaultCache: true,
hashPriority: 'low',
};
// fix: https://github.com/vueComponent/ant-design-vue/issues/6912
export const useStyleInject = () => {
return inject(StyleContextKey, shallowRef({ ...defaultStyleContext }));
const cache = getCache();
return inject(StyleContextKey, shallowRef({ ...defaultStyleContext, cache }));
};
export const useStyleProvider = (props: UseStyleProviderProps) => {
const parentContext = useStyleInject();
const context = shallowRef<Partial<StyleContextProps>>({ ...defaultStyleContext });
const context = shallowRef<Partial<StyleContextProps>>({
...defaultStyleContext,
cache: createCache(),
});
watch(
[props, parentContext],
[() => unref(props), parentContext],
() => {
const mergedContext: Partial<StyleContextProps> = {
...parentContext.value,
@ -142,7 +180,7 @@ export const StyleProvider = withInstall(
defineComponent({
name: 'AStyleProvider',
inheritAttrs: false,
props: initDefaultProps(styleProviderProps(), defaultStyleContext),
props: styleProviderProps(),
setup(props, { slots }) {
useStyleProvider(props);
return () => slots.default?.();

View File

@ -1,5 +1,5 @@
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 useGlobalCache from './useGlobalCache';
import { flattenToken, token2key } from '../util';
@ -8,11 +8,15 @@ import { ref, computed } from 'vue';
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.
// 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.
* 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.
*/
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>();
@ -37,20 +53,22 @@ function recordCleanToken(tokenKey: string) {
tokenKeys.set(tokenKey, (tokenKeys.get(tokenKey) || 0) + 1);
}
function removeStyleTags(key: string) {
function removeStyleTags(key: string, instanceId: string) {
if (typeof document !== 'undefined') {
const styles = document.querySelectorAll(`style[${ATTR_TOKEN}="${key}"]`);
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);
}
});
}
}
const TOKEN_THRESHOLD = 0;
// Remove will check current keys first
function cleanTokenStyle(tokenKey: string) {
function cleanTokenStyle(tokenKey: string, instanceId: string) {
tokenKeys.set(tokenKey, (tokenKeys.get(tokenKey) || 0) - 1);
const tokenKeyList = Array.from(tokenKeys.keys());
@ -60,14 +78,36 @@ function cleanTokenStyle(tokenKey: string) {
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 => {
removeStyleTags(key);
removeStyleTags(key, instanceId);
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
* @param theme Theme entity
@ -78,8 +118,10 @@ function cleanTokenStyle(tokenKey: string) {
export default function useCacheToken<DerivativeToken = object, DesignToken = DerivativeToken>(
theme: Ref<Theme<any, any>>,
tokens: Ref<Partial<DesignToken>[]>,
option: Ref<Option<DerivativeToken>> = ref({}),
option: Ref<Option<DerivativeToken, DesignToken>> = ref({}),
) {
const style = useStyleInject();
// Basic - We do basic cache here
const mergedToken = computed(() => Object.assign({}, ...tokens.value));
const tokenStr = computed(() => flattenToken(mergedToken.value));
@ -94,19 +136,15 @@ export default function useCacheToken<DerivativeToken = object, DesignToken = De
overrideTokenStr.value,
]),
() => {
const { salt = '', override = EMPTY_OVERRIDE, formatToken } = option.value;
const derivativeToken = theme.value.getDerivativeToken(mergedToken.value);
// Merge with override
let mergedDerivativeToken = {
...derivativeToken,
...override,
};
// Format if needed
if (formatToken) {
mergedDerivativeToken = formatToken(mergedDerivativeToken);
}
const {
salt = '',
override = EMPTY_OVERRIDE,
formatToken,
getComputedToken: compute,
} = option.value;
const mergedDerivativeToken = compute
? compute(mergedToken.value, override, theme.value)
: getComputedToken(mergedToken.value, override, theme.value, formatToken);
// Optimize for `useStyleRegister` performance
const tokenKey = token2key(mergedDerivativeToken, salt);
@ -115,12 +153,11 @@ export default function useCacheToken<DerivativeToken = object, DesignToken = De
const hashId = `${hashPrefix}-${hash(tokenKey)}`;
mergedDerivativeToken._hashId = hashId; // Not used
return [mergedDerivativeToken, hashId];
},
cache => {
// 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' &&
typeof module !== 'undefined' &&
module &&
(module as any).hot
(module as any).hot &&
typeof window !== 'undefined'
) {
const win = window as any;
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
import unitless from '@emotion/unitless';
import { compile, serialize, stringify } from 'stylis';
import type { Theme, Transformer } from '..';
import type Cache from '../Cache';
import type Keyframes from '../Keyframes';
import type { Linter } from '../linters';
import { contentQuotesLinter, hashedAnimationLinter } from '../linters';
import type { HashPriority } from '../StyleContext';
import type { Theme, Transformer } from '../..';
import type Cache from '../../Cache';
import type Keyframes from '../../Keyframes';
import type { Linter } from '../../linters';
import { contentQuotesLinter, hashedAnimationLinter } from '../../linters';
import type { HashPriority } from '../../StyleContext';
import {
useStyleInject,
ATTR_DEV_CACHE_PATH,
ATTR_CACHE_PATH,
ATTR_MARK,
ATTR_TOKEN,
CSS_IN_JS_INSTANCE,
CSS_IN_JS_INSTANCE_ID,
} from '../StyleContext';
import { supportLayer } from '../util';
import useGlobalCache from './useGlobalCache';
import canUseDom from '../../canUseDom';
import { removeCSS, updateCSS } from '../../../vc-util/Dom/dynamicCSS';
} from '../../StyleContext';
import { supportLayer } from '../../util';
import useGlobalCache from '../useGlobalCache';
import { removeCSS, updateCSS } from '../../../../vc-util/Dom/dynamicCSS';
import type { Ref } 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 SKIP_CHECK = '_skip_check_';
const MULTI_VALUE = '_multi_value_';
export type CSSProperties = Omit<CSS.PropertiesFallback<number | string>, 'animationName'> & {
animationName?: CSS.PropertiesFallback<number | string>['animationName'] | Keyframes;
};
@ -36,16 +42,17 @@ export type CSSProperties = Omit<CSS.PropertiesFallback<number | string>, 'anima
export type CSSPropertiesWithMultiValues = {
[K in keyof CSSProperties]:
| CSSProperties[K]
| Extract<CSSProperties[K], string>[]
| readonly Extract<CSSProperties[K], string>[]
| {
[SKIP_CHECK]: boolean;
value: CSSProperties[K] | Extract<CSSProperties[K], string>[];
[SKIP_CHECK]?: boolean;
[MULTI_VALUE]?: boolean;
value: CSSProperties[K] | CSSProperties[K][];
};
};
export type CSSPseudos = { [K in CSS.Pseudos]?: CSSObject };
type ArrayCSSInterpolation = CSSInterpolation[];
type ArrayCSSInterpolation = readonly CSSInterpolation[];
export type InterpolationPrimitive = null | undefined | boolean | number | string | CSSObject;
@ -59,13 +66,13 @@ export interface CSSObject extends CSSPropertiesWithMultiValues, CSSPseudos, CSS
// == Parser ==
// ============================================================================
// Preprocessor style content to browser support one
export function normalizeStyle(styleStr: string) {
export function normalizeStyle(styleStr: string): string {
const serialized = serialize(compile(styleStr), stringify);
return serialized.replace(/\{%%%\:[^;];}/g, ';');
}
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
@ -224,32 +231,45 @@ export const parseStyle = (
styleStr += `${mergedKey}${parsedStr}`;
} else {
function appendStyle(cssKey: string, cssValue: any) {
if (
process.env.NODE_ENV !== 'production' &&
(typeof value !== 'object' || !(value as any)?.[SKIP_CHECK])
) {
[contentQuotesLinter, hashedAnimationLinter, ...linters].forEach(linter =>
linter(cssKey, cssValue, { path, hashId, parentSelectors }),
);
}
//
const styleName = cssKey.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`);
// Auto suffix with px
let formatValue = cssValue;
if (!unitless[cssKey] && typeof formatValue === 'number' && formatValue !== 0) {
formatValue = `${formatValue}px`;
}
// handle animationName & Keyframe value
if (cssKey === 'animationName' && (cssValue as Keyframes)?._keyframe) {
parseKeyframes(cssValue as Keyframes);
formatValue = (cssValue as Keyframes).getName(hashId);
}
styleStr += `${styleName}:${formatValue};`;
}
const actualValue = (value as any)?.value ?? value;
if (
process.env.NODE_ENV !== 'production' &&
(typeof value !== 'object' || !(value as any)?.[SKIP_CHECK])
typeof value === 'object' &&
(value as any)?.[MULTI_VALUE] &&
Array.isArray(actualValue)
) {
[contentQuotesLinter, hashedAnimationLinter, ...linters].forEach(linter =>
linter(key, actualValue, { path, hashId, parentSelectors }),
);
actualValue.forEach(item => {
appendStyle(key, item);
});
} else {
appendStyle(key, actualValue);
}
//
const styleName = key.replace(/[A-Z]/g, match => `-${match.toLowerCase()}`);
// Auto suffix with px
let formatValue = actualValue;
if (!unitless[key] && typeof formatValue === 'number' && formatValue !== 0) {
formatValue = `${formatValue}px`;
}
// handle animationName & Keyframe value
if (key === 'animationName' && (value as Keyframes)?._keyframe) {
parseKeyframes(value as Keyframes);
formatValue = (value as Keyframes).getName(hashId);
}
styleStr += `${styleName}:${formatValue};`;
}
});
}
@ -293,6 +313,14 @@ export default function useStyleRegister(
path: string[];
hashId?: 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,
) {
@ -309,14 +337,32 @@ export default function useStyleRegister(
}
// 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',
fullPath,
// 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 { hashPriority, container, transformers, linters } = styleContext.value;
const { path, hashId, layer } = info.value;
const { hashPriority, container, transformers, linters, cache } = styleContext.value;
const [parsedStyle, effectStyle] = parseStyle(styleObj, {
hashId,
hashPriority,
@ -329,20 +375,29 @@ export default function useStyleRegister(
const styleId = uniqueHash(fullPath.value, styleStr);
if (isMergedClientSide) {
const style = updateCSS(styleStr, styleId, {
const mergedCSSConfig: Parameters<typeof updateCSS>[2] = {
mark: ATTR_MARK,
prepend: 'queue',
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
style.setAttribute(ATTR_TOKEN, tokenKey.value);
// Dev usage to find which cache path made this easily
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
@ -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
([, , styleId], fromHMR) => {
@ -399,19 +454,113 @@ export default function useStyleRegister(
// ============================================================================
// == SSR ==
// ============================================================================
export function extractStyle(cache: Cache) {
// prefix with `style` is used for `useStyleRegister` to cache style context
const styleKeys = Array.from(cache.cache.keys()).filter(key => key.startsWith('style%'));
export function extractStyle(cache: Cache, plain = false) {
const matchPrefix = `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 = '';
styleKeys.forEach(key => {
const [styleStr, tokenKey, styleId]: [string, string, string] = cache.cache.get(key)![1];
function toStyleStr(
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;
}

View File

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

View File

@ -3,3 +3,4 @@ export { default as hashedAnimationLinter } from './hashedAnimationLinter';
export type { Linter } from './interface';
export { default as legacyNotSelectorLinter } from './legacyNotSelectorLinter';
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 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) {
let str = '';
Object.keys(token).forEach(key => {
const value = token[key];
str += key;
if (value && typeof value === 'object') {
str += flattenToken(value);
} else {
str += value;
}
});
let str = flattenTokenCache.get(token) || '';
if (!str) {
Object.keys(token).forEach(key => {
const value = token[key];
str += key;
if (value instanceof Theme) {
str += value.id;
} else if (value && typeof value === 'object') {
str += flattenToken(value);
} else {
str += value;
}
});
// Put in cache
flattenTokenCache.set(token, str);
}
return str;
}
@ -23,12 +36,18 @@ export function token2key(token: any, salt: string): string {
return hash(`${salt}_${flattenToken(token)}`);
}
const layerKey = `layer-${Date.now()}-${Math.random()}`.replace(/\./g, '');
const layerWidth = '903px';
const randomSelectorKey = `random-${Date.now()}-${Math.random()}`.replace(/\./g, '');
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()) {
updateCSS(styleStr, layerKey);
updateCSS(styleStr, randomSelectorKey);
const ele = document.createElement('div');
ele.style.position = 'fixed';
@ -42,10 +61,12 @@ function supportSelector(styleStr: string, handleElement?: (ele: HTMLElement) =>
ele.style.zIndex = '9999999';
}
const support = getComputedStyle(ele).width === layerWidth;
const support = supportCheck
? supportCheck(ele)
: getComputedStyle(ele).content?.includes(checkContent);
ele.parentNode?.removeChild(ele);
removeCSS(layerKey);
removeCSS(randomSelectorKey);
return support;
}
@ -57,12 +78,41 @@ let canLayer: boolean | undefined = undefined;
export function supportLayer(): boolean {
if (canLayer === undefined) {
canLayer = supportSelector(
`@layer ${layerKey} { .${layerKey} { width: ${layerWidth}!important; } }`,
`@layer ${randomSelectorKey} { .${randomSelectorKey} { content: "${checkContent}"!important; } }`,
ele => {
ele.className = layerKey;
ele.className = randomSelectorKey;
},
);
}
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';
let result = 0;
if (isWindow(target)) {
result = target[top ? 'pageYOffset' : 'pageXOffset'];
result = target[top ? 'scrollY' : 'scrollX'];
} else if (target instanceof Document) {
result = target.documentElement[method];
} else if (target instanceof HTMLElement) {

View File

@ -28,7 +28,7 @@ export interface ConfigurableLocation {
location?: Location;
}
export const defaultWindow = /* #__PURE__ */ isClient ? window : undefined;
export const defaultDocument = /* #__PURE__ */ isClient ? window.document : undefined;
export const defaultNavigator = /* #__PURE__ */ isClient ? window.navigator : undefined;
export const defaultLocation = /* #__PURE__ */ isClient ? window.location : undefined;
export const defaultWindow = isClient ? window : undefined;
export const defaultDocument = isClient ? window.document : undefined;
export const defaultNavigator = isClient ? window.navigator : 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;
};
export const isIOS =
/* #__PURE__ */ isClient &&
window?.navigator?.userAgent &&
/iP(ad|hone|od)/.test(window.navigator.userAgent);
isClient && 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 =>
Object.prototype.hasOwnProperty.call(val, key);

View File

@ -2,6 +2,7 @@ import type { Ref } from 'vue';
import { computed, watchEffect } from 'vue';
import { updateCSS, removeCSS } from '../../vc-util/Dom/dynamicCSS';
import getScrollBarSize from '../../_util/getScrollBarSize';
import canUseDom from '../../_util/canUseDom';
const UNIQUE_ID = `vc-util-locker-${Date.now()}`;
@ -24,6 +25,9 @@ export default function useScrollLocker(lock?: Ref<boolean>) {
watchEffect(
onClear => {
if (!canUseDom()) {
return;
}
if (mergedLock.value) {
const scrollbarSize = getScrollBarSize();
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
*/
const camel2hyphen = function (str) {
const camel2hyphen = function (str: string) {
return str
.replace(/[A-Z]/g, function (match) {
return '-' + match.toLowerCase();
@ -11,12 +11,12 @@ const camel2hyphen = function (str) {
.toLowerCase();
};
const isDimension = function (feature) {
const isDimension = function (feature: string) {
const re = /[height|width]$/;
return re.test(feature);
};
const obj2mq = function (obj) {
const obj2mq = function (obj: { [x: string]: any }) {
let mq = '';
const features = Object.keys(obj);
features.forEach(function (feature, index) {
@ -40,7 +40,7 @@ const obj2mq = function (obj) {
return mq;
};
export default function (query) {
export default function (query: any[]) {
let mq = '';
if (typeof query === 'string') {
return query;

View File

@ -1,19 +1,19 @@
import isPlainObject from 'lodash-es/isPlainObject';
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 isValid from '../isValid';
import initDefaultProps from './initDefaultProps';
import type { VueInstance } from '../hooks/_vueuse/unrefElement';
// function getType(fn) {
// const match = fn && fn.toString().match(/^\s*function (\w+)/);
// return match ? match[1] : '';
// }
const splitAttrs = attrs => {
const splitAttrs = (attrs: any) => {
const allAttrs = Object.keys(attrs);
const eventAttrs = {};
const onEvents = {};
const extraAttrs = {};
const eventAttrs: Record<string, any> = {};
const onEvents: Record<string, any> = {};
const extraAttrs: Record<string, any> = {};
for (let i = 0, l = allAttrs.length; i < l; i++) {
const key = allAttrs[i];
if (isOn(key)) {
@ -25,7 +25,7 @@ const splitAttrs = attrs => {
}
return { onEvents, events: eventAttrs, extraAttrs };
};
const parseStyleText = (cssText = '', camel) => {
const parseStyleText = (cssText = '', camel = false) => {
const res = {};
const listDelimiter = /;(?![^(]*\))/g;
const propertyDelimiter = /:(.+)/;
@ -42,34 +42,9 @@ const parseStyleText = (cssText = '', camel) => {
return res;
};
const hasProp = (instance, prop) => {
const hasProp = (instance: any, prop: string) => {
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');
const flattenChildren = (children = [], filterEmpty = true) => {
@ -97,39 +72,29 @@ const flattenChildren = (children = [], filterEmpty = true) => {
return res;
};
const getSlot = (self, name = 'default', options = {}) => {
const getSlot = (self: any, name = 'default', options = {}) => {
if (isVNode(self)) {
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]) {
return flattenChildren(self.children[name](options));
} else {
return [];
}
} else {
let res = self.$slots[name] && self.$slots[name](options);
const res = self.$slots[name] && self.$slots[name](options);
return flattenChildren(res);
}
};
const getAllChildren = ele => {
let componentOptions = ele.componentOptions || {};
if (ele.$vnode) {
componentOptions = ele.$vnode.componentOptions || {};
}
return ele.children || componentOptions.children || [];
};
const getSlotOptions = () => {
throw Error('使用 .type 直接取值');
};
const findDOMNode = instance => {
const findDOMNode = (instance: any) => {
let node = instance?.vnode?.el || (instance && (instance.$el || instance));
while (node && !node.tagName) {
node = node.nextSibling;
}
return node;
};
const getOptionProps = instance => {
const getOptionProps = (instance: VueInstance) => {
const res = {};
if (instance.$ && instance.$.vnode) {
const props = instance.$.vnode.props || {};
@ -146,7 +111,7 @@ const getOptionProps = instance => {
Object.keys(originProps).forEach(key => {
props[camelize(key)] = originProps[key];
});
const options = instance.type.props || {};
const options = (instance.type as any).props || {};
Object.keys(options).forEach(k => {
const v = resolvePropValue(options, props, k, props[k]);
if (v !== undefined || k in props) {
@ -156,7 +121,7 @@ const getOptionProps = instance => {
}
return res;
};
const getComponent = (instance, prop = 'default', options = instance, execute = true) => {
const getComponent = (instance: any, prop = 'default', options = instance, execute = true) => {
let com = undefined;
if (instance.$) {
const temp = instance[prop];
@ -184,94 +149,13 @@ const getComponent = (instance, prop = 'default', options = instance, execute =
}
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 => {
let props = getOptionProps(ele);
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;
const getKey = (ele: any) => {
const key = ele.key;
return key;
};
export function getEvents(ele = {}, on = true) {
export function getEvents(ele: any = {}, on = true) {
let props = {};
if (ele.$) {
props = { ...props, ...ele.$attrs };
@ -281,27 +165,9 @@ export function getEvents(ele = {}, on = true) {
return splitAttrs(props)[on ? 'onEvents' : 'events'];
}
export function getEvent(child, event) {
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) {
export function getClass(ele: any) {
const props = (isVNode(ele) ? ele.props : ele.$attrs) || {};
let tempCls = props.class || {};
const tempCls = props.class || {};
let cls = {};
if (typeof tempCls === 'string') {
tempCls.split(' ').forEach(c => {
@ -318,7 +184,7 @@ export function getClass(ele) {
}
return cls;
}
export function getStyle(ele, camel) {
export function getStyle(ele: any, camel?: boolean) {
const props = (isVNode(ele) ? ele.props : ele.$attrs) || {};
let style = props.style || {};
if (typeof style === 'string') {
@ -332,19 +198,19 @@ export function getStyle(ele, camel) {
return style;
}
export function getComponentName(opts) {
export function getComponentName(opts: any) {
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;
}
export function isEmptyContent(c) {
export function isEmptyContent(c: any) {
return c === undefined || c === null || c === '' || (Array.isArray(c) && c.length === 0);
}
export function isEmptyElement(c) {
export function isEmptyElement(c: any) {
return (
c &&
(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);
}
export function isStringElement(c) {
export function isStringElement(c: any) {
return c && c.type === Text;
}
@ -375,7 +241,7 @@ export function filterEmpty(children = []) {
return res.filter(c => !isEmptyElement(c));
}
export function filterEmptyWithUndefined(children) {
export function filterEmptyWithUndefined(children: any[]) {
if (children) {
const coms = filterEmpty(children);
return coms.length ? coms : undefined;
@ -384,34 +250,18 @@ export function filterEmptyWithUndefined(children) {
}
}
export function mergeProps() {
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) {
function isValidElement(element: any) {
if (Array.isArray(element) && element.length === 1) {
element = element[0];
}
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]?.();
}
export const getTextFromElement = ele => {
export const getTextFromElement = (ele: any) => {
if (isValidElement(ele) && isStringElement(ele[0])) {
return ele[0].children;
}
@ -422,21 +272,12 @@ export {
hasProp,
getOptionProps,
getComponent,
getComponentFromProp,
getSlotOptions,
slotHasProp,
getPropsData,
getKey,
getAttrs,
getValueByProp,
parseStyleText,
initDefaultProps,
isValidElement,
camelize,
getSlots,
getSlot,
getAllProps,
getAllChildren,
findDOMNode,
flattenChildren,
getPropsSlot,

View File

@ -22,8 +22,8 @@ export default function scrollTo(y: number, options: ScrollToOptions = {}) {
const time = timestamp - startTime;
const nextScrollTop = easeInOutCubic(time > duration ? duration : time, scrollTop, y, duration);
if (isWindow(container)) {
(container as Window).scrollTo(window.pageXOffset, nextScrollTop);
} else if (container instanceof Document || container.constructor.name === 'HTMLDocument') {
(container as Window).scrollTo(window.scrollX, nextScrollTop);
} else if (container instanceof Document) {
(container as Document).documentElement.scrollTop = nextScrollTop;
} else {
(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
let supportsPassive = false;
try {
let opts = Object.defineProperty({}, 'passive', {
const opts = Object.defineProperty({}, 'passive', {
get() {
supportsPassive = true;
},

View File

@ -5,7 +5,7 @@ import type {
TransitionGroupProps,
TransitionProps,
} from 'vue';
import { nextTick, Transition, TransitionGroup } from 'vue';
import { nextTick } from 'vue';
import { tuple } from './type';
const SelectPlacements = tuple('bottomLeft', 'bottomRight', 'topLeft', 'topRight');
@ -126,6 +126,4 @@ const getTransitionName = (rootPrefixCls: string, motion: string, transitionName
return `${rootPrefixCls}-${motion}`;
};
export { Transition, TransitionGroup, collapseMotion, getTransitionName, getTransitionDirection };
export default Transition;
export { collapseMotion, getTransitionName, getTransitionDirection };

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;
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) => {
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 AnyObject = Record<PropertyKey, any>;

View File

@ -1,6 +1,6 @@
import { filterEmpty } from './props-util';
import type { VNode, VNodeProps } from 'vue';
import { cloneVNode } from 'vue';
import type { Slots, VNode, VNodeArrayChildren, VNodeProps } from 'vue';
import { cloneVNode, isVNode, Comment, Fragment, render as VueRender } from 'vue';
import warning from './warning';
import type { RefObject } from './createRef';
type NodeProps = Record<string, any> &
@ -40,6 +40,10 @@ export function deepCloneElement<T, U>(
if (Array.isArray(vnode)) {
return vnode.map(item => deepCloneElement(item, nodeProps, override, mergeRef));
} else {
// 需要判断是否为vnode方可进行clone操作
if (!isVNode(vnode)) {
return vnode;
}
const cloned = cloneElement(vnode, nodeProps, override, mergeRef);
if (Array.isArray(cloned.children)) {
cloned.children = deepCloneElement(cloned.children as VNode<T, U>[]);
@ -47,3 +51,32 @@ export function deepCloneElement<T, U>(
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);
render(<WaveEffect target={node} className={className} />, holder);
return () => {
render(null, holder);
if (holder.parentElement) {
holder.parentElement.removeChild(holder);
}
};
}
export default showWaveEffect;

View File

@ -26,36 +26,35 @@ export default defineComponent({
},
setup(props, { slots }) {
const instance = getCurrentInstance();
const { prefixCls } = useConfigInject('wave', props);
const { prefixCls, wave } = useConfigInject('wave', props);
// ============================== Style ===============================
const [, hashId] = useStyle(prefixCls);
// =============================== Wave ===============================
const showWave = useWave(
instance,
computed(() => classNames(prefixCls.value, hashId.value)),
wave,
);
let onClick: (e: MouseEvent) => void;
const clear = () => {
const node = findDOMNode(instance);
const node = findDOMNode(instance) as HTMLElement;
node.removeEventListener('click', onClick, true);
};
onMounted(() => {
watch(
() => props.disabled,
() => {
clear();
nextTick(() => {
const node = findDOMNode(instance);
const node: HTMLElement = findDOMNode(instance);
node?.removeEventListener('click', onClick, true);
if (!node || node.nodeType !== 1 || props.disabled) {
return;
}
// Click handler
const onClick = (e: MouseEvent) => {
onClick = (e: MouseEvent) => {
// Fix radio button click twice
if (
(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 showWaveEffect from './WaveEffect';
export default function useWave(
instance: ComponentInternalInstance | null,
className: Ref<string>,
wave?: ComputedRef<{ disabled?: boolean }>,
): VoidFunction {
const instance = getCurrentInstance();
let stopWave: () => void;
function showWave() {
const node = findDOMNode(instance);
showWaveEffect(node, className.value);
stopWave?.();
if (wave?.value?.disabled || !node) {
return;
}
stopWave = showWaveEffect(node, className.value);
}
onBeforeUnmount(() => {
stopWave?.();
});
return showWave;
}

View File

@ -176,7 +176,6 @@ const Affix = defineComponent({
affixStyle: undefined,
placeholderStyle: undefined,
});
currentInstance.update();
// Test if `updatePosition` called
if (process.env.NODE_ENV === 'test') {
emit('testUpdatePosition');
@ -256,7 +255,7 @@ const Affix = defineComponent({
const { prefixCls } = useConfigInject('affix', props);
const [wrapSSR, hashId] = useStyle(prefixCls);
return () => {
const { affixStyle, placeholderStyle } = state;
const { affixStyle, placeholderStyle, status } = state;
const className = classNames({
[prefixCls.value]: affixStyle,
[hashId.value]: true,
@ -271,7 +270,7 @@ const Affix = defineComponent({
]);
return wrapSSR(
<ResizeObserver onResize={updatePosition}>
<div {...restProps} {...attrs} ref={placeholderNode}>
<div {...restProps} {...attrs} ref={placeholderNode} data-measure-status={status}>
{affixStyle && <div style={placeholderStyle} aria-hidden="true" />}
<div class={className} ref={fixedNode} style={affixStyle}>
{slots.default?.()}

View File

@ -1,5 +1,5 @@
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 CheckCircleOutlined from '@ant-design/icons-vue/CheckCircleOutlined';
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 classNames from '../_util/classNames';
import PropTypes from '../_util/vue-types';
import { getTransitionProps, Transition } from '../_util/transition';
import { getTransitionProps } from '../_util/transition';
import { isValidElement } from '../_util/props-util';
import { tuple, withInstall } from '../_util/type';
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
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`] = `
<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>
`;
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`] = `
<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;">

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

View File

@ -30,6 +30,8 @@ The differences with Select are:
| allowClear | Show clear button, effective in multiple mode only. | boolean | false | |
| autofocus | get focus when component mounted | 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 />` | |
| defaultActiveFirstOption | Whether active first option by default | boolean | true | |
| defaultOpen | Initial open state of dropdown | boolean | - | |

View File

@ -50,10 +50,13 @@ const AutoComplete = defineComponent({
props: autoCompleteProps(),
// emits: ['change', 'select', 'focus', 'blur'],
slots: Object as CustomSlotsType<{
option: any;
// deprecated, should use props `options` instead, not slot
options: any;
default: any;
notFoundContent: any;
dataSource: any;
clearIcon: any;
}>,
setup(props, { slots, attrs, expose }) {
warning(

View File

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

View File

@ -11,7 +11,7 @@ import useConfigInject from '../config-provider/hooks/useConfigInject';
import ResizeObserver from '../vc-resize-observer';
import eagerComputed from '../_util/eagerComputed';
import useStyle from './style';
import { useInjectSize } from './SizeContext';
import { useAvatarInjectContext } from './AvatarContext';
export type AvatarSize = 'large' | 'small' | 'default' | number | ScreenSizeMap;
@ -56,9 +56,9 @@ const Avatar = defineComponent({
const { prefixCls } = useConfigInject('avatar', props);
const [wrapSSR, hashId] = useStyle(prefixCls);
const groupSize = useInjectSize();
const avatarCtx = useAvatarInjectContext();
const size = computed(() => {
return props.size === 'default' ? groupSize.value : props.size;
return props.size === 'default' ? avatarCtx.size : props.size;
});
const screens = useBreakpoint();
const responsiveSize = eagerComputed(() => {
@ -135,6 +135,7 @@ const Avatar = defineComponent({
return () => {
const { shape, src, alt, srcset, draggable, crossOrigin } = props;
const mergeShape = avatarCtx.shape ?? shape;
const icon = getPropsSlot(slots, props, 'icon');
const pre = prefixCls.value;
const classString = {
@ -142,7 +143,7 @@ const Avatar = defineComponent({
[pre]: true,
[`${pre}-lg`]: size.value === 'large',
[`${pre}-sm`]: size.value === 'small',
[`${pre}-${shape}`]: shape,
[`${pre}-${mergeShape}`]: true,
[`${pre}-image`]: src && isImgExist.value,
[`${pre}-icon`]: icon,
[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 Popover from '../popover';
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 useConfigInject from '../config-provider/hooks/useConfigInject';
import useStyle from './style';
import { useProviderSize } from './SizeContext';
import { useAvatarProviderContext } from './AvatarContext';
export const groupProps = () => ({
prefixCls: String,
@ -23,6 +23,7 @@ export const groupProps = () => ({
type: [Number, String, Object] as PropType<AvatarSize>,
default: 'default' as AvatarSize,
},
shape: { type: String as PropType<'circle' | 'square'>, default: 'circle' },
});
export type AvatarGroupProps = Partial<ExtractPropTypes<ReturnType<typeof groupProps>>>;
@ -36,13 +37,17 @@ const Group = defineComponent({
const { prefixCls, direction } = useConfigInject('avatar', props);
const groupPrefixCls = computed(() => `${prefixCls.value}-group`);
const [wrapSSR, hashId] = useStyle(prefixCls);
useProviderSize(computed(() => props.size));
watchEffect(() => {
const context = { size: props.size, shape: props.shape };
useAvatarProviderContext(context);
});
return () => {
const {
maxPopoverPlacement = 'top',
maxCount,
maxStyle,
maxPopoverTrigger = 'hover',
shape,
} = props;
const cls = {
@ -72,7 +77,7 @@ const Group = defineComponent({
placement={maxPopoverPlacement}
overlayClassName={`${groupPrefixCls.value}-popover`}
>
<Avatar style={maxStyle}>{`+${numOfChildren - maxCount}`}</Avatar>
<Avatar style={maxStyle} shape={shape}>{`+${numOfChildren - maxCount}`}</Avatar>
</Popover>,
);
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>
<template>
<span style="margin-right: 24px">
<a-space :size="24">
<a-badge :count="1">
<a-avatar shape="square">
<template #icon><UserOutlined /></template>
</a-avatar>
</a-badge>
</span>
<span>
<a-badge dot>
<a-avatar shape="square">
<template #icon><UserOutlined /></template>
</a-avatar>
</a-badge>
</span>
</a-space>
</template>
<script lang="ts" setup>
import { UserOutlined } from '@ant-design/icons-vue';
</script>
<style scoped>
#components-avatar-demo-badge .ant-avatar {
margin-top: 0;
margin-right: 0;
}
</style>

View File

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

View File

@ -8,27 +8,22 @@ title:
## zh-CN
对于字符型的头像当字符串较长时字体大小可以根据头像宽度自动调整
对于字符型的头像当字符串较长时字体大小可以根据头像宽度自动调整也可使用 `gap`` 来设置字符距离左右两侧边界单位像素。
## 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>
<template>
<a-avatar
shape="square"
size="large"
:style="{ backgroundColor: color, verticalAlign: 'middle' }"
>
<a-avatar size="large" :style="{ backgroundColor: color, verticalAlign: 'middle' }" :gap="gap">
{{ avatarValue }}
</a-avatar>
<a-button
size="small"
:style="{ marginLeft: '16px', verticalAlign: 'middle' }"
@click="changeValue"
>
改变
<a-button size="small" :style="{ margin: '0 16px', verticalAlign: 'middle' }" @click="changeUser">
ChangeUser
</a-button>
<a-button size="small" :style="{ verticalAlign: 'middle' }" @click="changeGap">
ChangeGap
</a-button>
</template>
@ -39,9 +34,16 @@ const UserList = ['U', 'Lucy', 'Tom', 'Edward'];
const colorList = ['#f56a00', '#7265e6', '#ffbf00', '#00a2ae'];
const avatarValue = ref(UserList[0]);
const color = ref(colorList[0]);
const changeValue = () => {
const changeUser = () => {
const index = UserList.indexOf(avatarValue.value);
avatarValue.value = index < UserList.length - 1 ? UserList[index + 1] : UserList[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>

View File

@ -17,20 +17,22 @@ Avatar group display.
<template>
<a-avatar-group>
<a-avatar src="https://joeschmoe.io/api/v1/random" />
<a-avatar style="background-color: #f56a00">K</a-avatar>
<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>
<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><UserOutlined /></template>
<template #icon><AntDesignOutlined /></template>
</a-avatar>
</a-avatar-group>
<a-divider />
<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-tooltip title="Ant User" placement="top">
<a-avatar style="background-color: #87d068">
@ -38,7 +40,7 @@ Avatar group display.
</a-avatar>
</a-tooltip>
<a-avatar style="background-color: #1890ff">
<template #icon><UserOutlined /></template>
<template #icon><AntDesignOutlined /></template>
</a-avatar>
</a-avatar-group>
<a-divider />
@ -50,7 +52,7 @@ Avatar group display.
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-tooltip title="Ant User" placement="top">
<a-avatar style="background-color: #87d068">
@ -58,11 +60,42 @@ Avatar group display.
</a-avatar>
</a-tooltip>
<a-avatar style="background-color: #1890ff">
<template #icon><UserOutlined /></template>
<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>
</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>
</template>
<script lang="ts" setup>
import { UserOutlined } from '@ant-design/icons-vue';
import { UserOutlined, AntDesignOutlined } from '@ant-design/icons-vue';
</script>

View File

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

View File

@ -16,20 +16,22 @@ Image, Icon and letter are supported, and the latter two kinds avatar can have c
</docs>
<template>
<a-avatar>
<template #icon>
<UserOutlined />
</template>
</a-avatar>
<a-avatar>U</a-avatar>
<a-avatar :size="40">USER</a-avatar>
<a-avatar src="https://joeschmoe.io/api/v1/random" />
<a-avatar style="color: #f56a00; background-color: #fde3cf">U</a-avatar>
<a-avatar style="background-color: #87d068">
<template #icon>
<UserOutlined />
</template>
</a-avatar>
<a-space :size="16" wrap>
<a-avatar>
<template #icon>
<UserOutlined />
</template>
</a-avatar>
<a-avatar>U</a-avatar>
<a-avatar :size="40">USER</a-avatar>
<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="background-color: #87d068">
<template #icon>
<UserOutlined />
</template>
</a-avatar>
</a-space>
</template>
<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 |
| maxStyle | The style of excess avatar style | CSSProperties | - | |
| 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 |
| maxStyle | 多余头像样式 | CSSProperties | - | |
| 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 { 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'> & {
avatarBg: string;
avatarColor: string;
avatarSizeBase: number;
avatarSizeLG: number;
avatarSizeSM: number;
avatarFontSizeBase: number;
avatarFontSizeLG: number;
avatarFontSizeSM: number;
avatarGroupOverlapping: number;
avatarGroupSpace: number;
avatarGroupBorderColor: string;
avatarBgColor: string;
};
@ -27,12 +64,12 @@ const genBaseStyle: GenerateStyle<AvatarToken> = token => {
iconCls,
avatarBg,
avatarColor,
avatarSizeBase,
avatarSizeLG,
avatarSizeSM,
avatarFontSizeBase,
avatarFontSizeLG,
avatarFontSizeSM,
containerSize,
containerSizeLG,
containerSizeSM,
textFontSize,
textFontSizeLG,
textFontSizeSM,
borderRadius,
borderRadiusLG,
borderRadiusSM,
@ -89,14 +126,14 @@ const genBaseStyle: GenerateStyle<AvatarToken> = token => {
display: 'block',
},
...avatarSizeStyle(avatarSizeBase, avatarFontSizeBase, borderRadius),
...avatarSizeStyle(containerSize, textFontSize, borderRadius),
[`&-lg`]: {
...avatarSizeStyle(avatarSizeLG, avatarFontSizeLG, borderRadiusLG),
...avatarSizeStyle(containerSizeLG, textFontSizeLG, borderRadiusLG),
},
[`&-sm`]: {
...avatarSizeStyle(avatarSizeSM, avatarFontSizeSM, borderRadiusSM),
...avatarSizeStyle(containerSizeSM, textFontSizeSM, borderRadiusSM),
},
'> img': {
@ -110,55 +147,65 @@ const genBaseStyle: GenerateStyle<AvatarToken> = token => {
};
const genGroupStyle: GenerateStyle<AvatarToken> = token => {
const { componentCls, avatarGroupBorderColor, avatarGroupSpace } = token;
const { componentCls, groupBorderColor, groupOverlapping, groupSpace } = token;
return {
[`${componentCls}-group`]: {
display: 'inline-flex',
[`${componentCls}`]: {
borderColor: avatarGroupBorderColor,
borderColor: groupBorderColor,
},
[`> *:not(:first-child)`]: {
marginInlineStart: avatarGroupSpace,
marginInlineStart: groupOverlapping,
},
},
[`${componentCls}-group-popover`]: {
[`${componentCls} + ${componentCls}`]: {
marginInlineStart: groupSpace,
},
},
};
};
export default genComponentStyleHook('Avatar', token => {
const {
colorTextLightSolid,
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 {
controlHeight,
controlHeightLG,
controlHeightSM,
controlHeight,
controlHeightLG,
controlHeightSM,
fontSize,
fontSizeLG,
fontSizeXL,
fontSizeHeading3,
fontSize,
fontSizeLG,
fontSizeXL,
fontSizeHeading3,
marginXS,
marginXXS,
colorBorderBg,
} = token;
return {
containerSize: controlHeight,
containerSizeLG: controlHeightLG,
containerSizeSM: controlHeightSM,
marginXS,
colorBorderBg,
colorTextPlaceholder,
} = token;
textFontSize: Math.round((fontSizeLG + fontSizeXL) / 2),
textFontSizeLG: fontSizeHeading3,
textFontSizeSM: fontSize,
const avatarToken = mergeToken<AvatarToken>(token, {
avatarBg: colorTextPlaceholder,
avatarColor: colorTextLightSolid,
avatarSizeBase: controlHeight,
avatarSizeLG: controlHeightLG,
avatarSizeSM: controlHeightSM,
avatarFontSizeBase: Math.round((fontSizeLG + fontSizeXL) / 2),
avatarFontSizeLG: fontSizeHeading3,
avatarFontSizeSM: fontSize,
avatarGroupSpace: -marginXS,
avatarGroupBorderColor: colorBorderBg,
});
return [genBaseStyle(avatarToken), genGroupStyle(avatarToken)];
});
groupSpace: marginXXS,
groupOverlapping: -marginXS,
groupBorderColor: colorBorderBg,
};
},
);

View File

@ -3,9 +3,9 @@ import ScrollNumber from './ScrollNumber';
import classNames from '../_util/classNames';
import { getPropsSlot, flattenChildren } from '../_util/props-util';
import { cloneElement } from '../_util/vnode';
import { getTransitionProps, Transition } from '../_util/transition';
import { getTransitionProps } from '../_util/transition';
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 useConfigInject from '../config-provider/hooks/useConfigInject';
import isNumeric from '../_util/isNumeric';
@ -107,7 +107,7 @@ export default defineComponent({
const statusCls = computed(() => ({
[`${prefixCls.value}-status-dot`]: hasStatus.value,
[`${prefixCls.value}-status-${props.status}`]: !!props.status,
[`${prefixCls.value}-status-${props.color}`]: isInternalColor.value,
[`${prefixCls.value}-color-${props.color}`]: isInternalColor.value,
}));
const statusStyle = computed(() => {
@ -125,7 +125,7 @@ export default defineComponent({
[`${prefixCls.value}-multiple-words`]:
!isDotRef.value && displayCount.value && displayCount.value.toString().length > 1,
[`${prefixCls.value}-status-${props.status}`]: !!props.status,
[`${prefixCls.value}-status-${props.color}`]: isInternalColor.value,
[`${prefixCls.value}-color-${props.color}`]: isInternalColor.value,
}));
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`] = `
<h4 style="margin-bottom: 16px;">Presets:</h4>
<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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-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-lime"></span><span class="ant-badge-status-text">lime</span></span></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>
<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,141 +89,167 @@ exports[`renders ./components/badge/demo/overflow.vue correctly 1`] = `
`;
exports[`renders ./components/badge/demo/ribbon.vue correctly 1`] = `
<div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head">
<div class="ant-card-head-wrapper">
<div class="ant-card-head-title">Pushes open the window</div>
<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-card ant-card-bordered ant-card-small">
<div class="ant-card-head">
<div class="ant-card-head-wrapper">
<div class="ant-card-head-title">Pushes open the window</div>
<!---->
</div>
<!---->
</div>
<!---->
<div class="ant-card-body">and raises the spyglass.</div>
<!---->
</div>
<!---->
<div class="ant-ribbon ant-ribbon-placement-end"><span class="ant-ribbon-text">Hippies</span>
<div class="ant-ribbon-corner"></div>
</div>
</div>
<!---->
<div class="ant-card-body">and raises the spyglass.</div>
<!---->
</div>
<div class="ant-ribbon ant-ribbon-placement-end"><span class="ant-ribbon-text">Hippies</span>
<div class="ant-ribbon-corner"></div>
</div>
</div>
<div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head">
<div class="ant-card-head-wrapper">
<div class="ant-card-head-title">Pushes open the window</div>
<!---->
<div class="ant-space-item" style="margin-bottom: 8px;">
<div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head">
<div class="ant-card-head-wrapper">
<div class="ant-card-head-title">Pushes open the window</div>
<!---->
</div>
<!---->
</div>
<!---->
<div class="ant-card-body">and raises the spyglass.</div>
<!---->
</div>
<!---->
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-pink"><span class="ant-ribbon-text">Hippies</span>
<div class="ant-ribbon-corner"></div>
</div>
</div>
<!---->
<div class="ant-card-body">and raises the spyglass.</div>
<!---->
</div>
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-pink"><span class="ant-ribbon-text">Hippies</span>
<div class="ant-ribbon-corner"></div>
</div>
</div>
<div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head">
<div class="ant-card-head-wrapper">
<div class="ant-card-head-title">Pushes open the window</div>
<!---->
<div class="ant-space-item" style="margin-bottom: 8px;">
<div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head">
<div class="ant-card-head-wrapper">
<div class="ant-card-head-title">Pushes open the window</div>
<!---->
</div>
<!---->
</div>
<!---->
<div class="ant-card-body">and raises the spyglass.</div>
<!---->
</div>
<!---->
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-red"><span class="ant-ribbon-text">Hippies</span>
<div class="ant-ribbon-corner"></div>
</div>
</div>
<!---->
<div class="ant-card-body">and raises the spyglass.</div>
<!---->
</div>
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-red"><span class="ant-ribbon-text">Hippies</span>
<div class="ant-ribbon-corner"></div>
</div>
</div>
<div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head">
<div class="ant-card-head-wrapper">
<div class="ant-card-head-title">Pushes open the window</div>
<!---->
<div class="ant-space-item" style="margin-bottom: 8px;">
<div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head">
<div class="ant-card-head-wrapper">
<div class="ant-card-head-title">Pushes open the window</div>
<!---->
</div>
<!---->
</div>
<!---->
<div class="ant-card-body">and raises the spyglass.</div>
<!---->
</div>
<!---->
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-cyan"><span class="ant-ribbon-text">Hippies</span>
<div class="ant-ribbon-corner"></div>
</div>
</div>
<!---->
<div class="ant-card-body">and raises the spyglass.</div>
<!---->
</div>
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-cyan"><span class="ant-ribbon-text">Hippies</span>
<div class="ant-ribbon-corner"></div>
</div>
</div>
<div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head">
<div class="ant-card-head-wrapper">
<div class="ant-card-head-title">Pushes open the window</div>
<!---->
<div class="ant-space-item" style="margin-bottom: 8px;">
<div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head">
<div class="ant-card-head-wrapper">
<div class="ant-card-head-title">Pushes open the window</div>
<!---->
</div>
<!---->
</div>
<!---->
<div class="ant-card-body">and raises the spyglass.</div>
<!---->
</div>
<!---->
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-green"><span class="ant-ribbon-text">Hippies</span>
<div class="ant-ribbon-corner"></div>
</div>
</div>
<!---->
<div class="ant-card-body">and raises the spyglass.</div>
<!---->
</div>
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-green"><span class="ant-ribbon-text">Hippies</span>
<div class="ant-ribbon-corner"></div>
</div>
</div>
<div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head">
<div class="ant-card-head-wrapper">
<div class="ant-card-head-title">Pushes open the window</div>
<!---->
<div class="ant-space-item" style="margin-bottom: 8px;">
<div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head">
<div class="ant-card-head-wrapper">
<div class="ant-card-head-title">Pushes open the window</div>
<!---->
</div>
<!---->
</div>
<!---->
<div class="ant-card-body">and raises the spyglass.</div>
<!---->
</div>
<!---->
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-purple"><span class="ant-ribbon-text">Hippies</span>
<div class="ant-ribbon-corner"></div>
</div>
</div>
<!---->
<div class="ant-card-body">and raises the spyglass.</div>
<!---->
</div>
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-purple"><span class="ant-ribbon-text">Hippies</span>
<div class="ant-ribbon-corner"></div>
</div>
</div>
<div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head">
<div class="ant-card-head-wrapper">
<div class="ant-card-head-title">Pushes open the window</div>
<!---->
<div class="ant-space-item" style="margin-bottom: 8px;">
<div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head">
<div class="ant-card-head-wrapper">
<div class="ant-card-head-title">Pushes open the window</div>
<!---->
</div>
<!---->
</div>
<!---->
<div class="ant-card-body">and raises the spyglass.</div>
<!---->
</div>
<!---->
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-volcano"><span class="ant-ribbon-text">Hippies</span>
<div class="ant-ribbon-corner"></div>
</div>
</div>
<!---->
<div class="ant-card-body">and raises the spyglass.</div>
<!---->
</div>
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-volcano"><span class="ant-ribbon-text">Hippies</span>
<div class="ant-ribbon-corner"></div>
</div>
</div>
<div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head">
<div class="ant-card-head-wrapper">
<div class="ant-card-head-title">Pushes open the window</div>
<!---->
<div class="ant-space-item">
<div class="ant-ribbon-wrapper ">
<div class="ant-card ant-card-bordered ant-card-small">
<div class="ant-card-head">
<div class="ant-card-head-wrapper">
<div class="ant-card-head-title">Pushes open the window</div>
<!---->
</div>
<!---->
</div>
<!---->
<div class="ant-card-body">and raises the spyglass.</div>
<!---->
</div>
<!---->
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-magenta"><span class="ant-ribbon-text">Hippies</span>
<div class="ant-ribbon-corner"></div>
</div>
</div>
<!---->
<div class="ant-card-body">and raises the spyglass.</div>
<!---->
</div>
<div class="ant-ribbon ant-ribbon-placement-end ant-ribbon-color-magenta"><span class="ant-ribbon-text">Hippies</span>
<div class="ant-ribbon-corner"></div>
</div>
<!---->
</div>
`;
@ -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-warning"></span><span class="ant-badge-status-text"><!----></span></span>
<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>
<br>
<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>
<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>
<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>
<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 ant-space-vertical">
<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>
<!---->
<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>
<!---->
<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>
<!---->
<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>
<!---->
<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`] = `

View File

@ -16,28 +16,30 @@ Use ribbon badge.
</docs>
<template>
<a-badge-ribbon text="Hippies">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon>
<a-badge-ribbon text="Hippies" color="pink">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon>
<a-badge-ribbon text="Hippies" color="red">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon>
<a-badge-ribbon text="Hippies" color="cyan">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon>
<a-badge-ribbon text="Hippies" color="green">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon>
<a-badge-ribbon text="Hippies" color="purple">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon>
<a-badge-ribbon text="Hippies" color="volcano">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon>
<a-badge-ribbon text="Hippies" color="magenta">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon>
<a-space direction="vertical" style="width: 100%">
<a-badge-ribbon text="Hippies">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon>
<a-badge-ribbon text="Hippies" color="pink">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon>
<a-badge-ribbon text="Hippies" color="red">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon>
<a-badge-ribbon text="Hippies" color="cyan">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon>
<a-badge-ribbon text="Hippies" color="green">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon>
<a-badge-ribbon text="Hippies" color="purple">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon>
<a-badge-ribbon text="Hippies" color="volcano">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon>
<a-badge-ribbon text="Hippies" color="magenta">
<a-card title="Pushes open the window" size="small">and raises the spyglass.</a-card>
</a-badge-ribbon>
</a-space>
</template>

View File

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

View File

@ -73,9 +73,12 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
const ribbonPrefixCls = `${antCls}-ribbon`;
const ribbonWrapperPrefixCls = `${antCls}-ribbon-wrapper`;
const statusPreset = genPresetColor(token, (colorKey, { darkColor }) => ({
[`${componentCls}-status-${colorKey}`]: {
const colorPreset = genPresetColor(token, (colorKey, { darkColor }) => ({
[`&${componentCls} ${componentCls}-color-${colorKey}`]: {
background: darkColor,
[`&:not(${componentCls}-count)`]: {
color: darkColor,
},
},
}));
@ -150,9 +153,9 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
insetInlineEnd: 0,
transform: 'translate(50%, -50%)',
transformOrigin: '100% 0%',
[`${iconCls}-spin`]: {
[`&${iconCls}-spin`]: {
animationName: antBadgeLoadingCircle,
animationDuration: token.motionDurationMid,
animationDuration: '1s',
animationIterationCount: 'infinite',
animationTimingFunction: 'linear',
},
@ -175,7 +178,7 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
backgroundColor: token.colorSuccess,
},
[`${componentCls}-status-processing`]: {
position: 'relative',
overflow: 'visible',
color: token.colorPrimary,
backgroundColor: token.colorPrimary,
@ -207,13 +210,13 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
[`${componentCls}-status-warning`]: {
backgroundColor: token.colorWarning,
},
...statusPreset,
[`${componentCls}-status-text`]: {
marginInlineStart: marginXS,
color: token.colorText,
fontSize: token.fontSize,
},
},
...colorPreset,
[`${componentCls}-zoom-appear, ${componentCls}-zoom-enter`]: {
animationName: antZoomBadgeIn,
animationDuration: token.motionDurationSlow,
@ -284,7 +287,6 @@ const genSharedBadgeStyle: GenerateStyle<BadgeToken> = (token: BadgeToken): CSSO
...resetComponent(token),
position: 'absolute',
top: marginXS,
height: badgeFontHeight,
padding: `0 ${token.paddingXS}px`,
color: token.colorPrimary,
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 type { MouseEventHandler } from '../_util/EventInterface';
import { eventType, objectType } from '../_util/type';
import type { CustomSlotsType } from '../_util/type';
import type { CustomSlotsType, VueNode } from '../_util/type';
export const breadcrumbItemProps = () => ({
prefixCls: String,
@ -38,7 +38,7 @@ export default defineComponent({
* if overlay is have
* Wrap a Dropdown
*/
const renderBreadcrumbNode = (breadcrumbItem: JSX.Element, prefixCls: string) => {
const renderBreadcrumbNode = (breadcrumbItem: VueNode, prefixCls: string) => {
const overlay = getPropsSlot(slots, props, 'overlay');
if (overlay) {
return (
@ -59,7 +59,7 @@ export default defineComponent({
const separator = getPropsSlot(slots, props, 'separator') ?? '/';
const children = getPropsSlot(slots, props);
const { class: cls, style, ...restAttrs } = attrs;
let link: JSX.Element;
let link: VueNode;
if (props.href !== undefined) {
link = (
<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 Transition from '../_util/transition';
const getCollapsedWidth = (node: HTMLSpanElement) => {
if (node) {
node.style.width = '0px';

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