Compare commits

...

145 Commits

Author SHA1 Message Date
MadCcc
3a4a4abe1a docs: changelog 5.28.1 (#55658)
* docs: changelog 5.28.1

* chore: udpate

* chore: update

* Update CHANGELOG.zh-CN.md

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: MadCcc <1075746765@qq.com>

* Update CHANGELOG.zh-CN.md

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: MadCcc <1075746765@qq.com>

---------

Signed-off-by: MadCcc <1075746765@qq.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-11-10 17:42:21 +08:00
lijianan
2037fa7834 fix(locale): add missing locale (#55656) 2025-11-09 16:09:41 +08:00
renovate[bot]
f3d75842fa chore(deps): update softprops/action-gh-release action to v2.4.2 (#55654)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-09 10:21:06 +08:00
afc163
a4b8185a74 Revert "fix: clicking does nothing after occur error in actionFn (#55519)" (#55651)
This reverts commit 2b12ef528d.
2025-11-09 01:21:02 +08:00
Tony
ce9a5dc2fd docs: add classNames and styles to Tooltip shared API documentation (#55645) 2025-11-08 08:41:55 +08:00
TianHua Liu
2b12ef528d fix: clicking does nothing after occur error in actionFn (#55519) 2025-11-08 00:07:19 +08:00
Wanpan
44526a56a7 fix: use dotActiveWidth token (#55615) 2025-11-07 19:05:35 +08:00
ustcfury
2f6846d2a5 fix: Select underlined height (#55607)
Co-authored-by: furyzhao <furyzhao@tencent.com>
2025-11-06 10:21:35 +08:00
afc163
8471922710 demo: fix extra padding in Carousel demos (#55613) 2025-11-05 13:12:06 +08:00
Wanpan
3966a9fcc8 fix(carousel): The transform animation is invalid when the drawing is first performed. (#55589)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: 遇见同学 <1875694521@qq.com>
2025-11-05 10:01:20 +08:00
ustcfury
dee2365bed fix: input underlined hover color (#55609)
to #55608

Co-authored-by: furyzhao <furyzhao@tencent.com>
Co-authored-by: 遇见同学 <1875694521@qq.com>
2025-11-04 23:02:05 +08:00
afc163
39843ae9b2 docs: update icon component import code and documentation warnings (#55594) 2025-11-04 23:00:52 +08:00
ayangweb
51949965ce type: optimize LiteralUnion type and add Primitive type (#55599) 2025-11-04 23:00:08 +08:00
ayangweb
be0d352579 docs(icon): automatically scroll to the top after icon search (#55596) 2025-11-04 15:23:07 +08:00
ayangweb
bf1a3393fc type(flex): fix missing preset size support for gap (#55591) 2025-11-04 14:00:31 +08:00
thinkasany
d11b6c7807 chore(decription): improve classNames (#55573)
* chore(decription): improve classNames

* Refactor classNames import and usage in Cell component

Signed-off-by: lijianan <574980606@qq.com>

---------

Signed-off-by: lijianan <574980606@qq.com>
Co-authored-by: lijianan <574980606@qq.com>
2025-11-03 00:26:56 +08:00
lijianan
d928c9b2fb chore: rename isValidNode (#55570)
* chore: rename isValidNode

* update

* update demo code
2025-11-02 21:59:48 +08:00
lijianan
15a17dee7c fix: uses correct style for content rendering (#55572)
* fix: uses correct style for content rendering

* update
2025-11-02 21:16:34 +08:00
lijianan
fbfc09901e chore: use classNames (#55571)
* chore: use classNames

* Update components/table/hooks/useSorter.tsx

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: lijianan <574980606@qq.com>

---------

Signed-off-by: lijianan <574980606@qq.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-11-02 20:41:41 +08:00
afc163
0db00b0886 docs: release 5.28.0 (#55564)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-11-01 23:31:41 +08:00
lijianan
041f6d6692 autospace-fix (#55562) 2025-11-01 22:45:15 +08:00
Peace
45b929dfd7 docs(drawer): add closable api (#55548)
* docs: add closable api

* docs: improve documentation description

* Update components/drawer/index.zh-CN.md

Signed-off-by: thinkasany <480968828@qq.com>

* Update components/drawer/index.en-US.md

Signed-off-by: thinkasany <480968828@qq.com>

---------

Signed-off-by: thinkasany <480968828@qq.com>
Co-authored-by: 叶文俊 <yewenjun@mistong.com>
Co-authored-by: thinkasany <480968828@qq.com>
2025-11-01 10:44:54 +08:00
lijianan
d33d8cf959 test: simplify style test case again (#55539)
* test: simplify test case

* update

* update

* update

* test: simplify style test case

* update

* update

* update

* update

* test: simplify style test case again

* update

* update

* update color to rgb
2025-10-31 15:19:47 +08:00
lijianan
0bd374b94e test: fix CI fail (#55541) 2025-10-31 15:07:13 +08:00
lijianan
352f6c6c78 test: simplify style test case (#55538)
* test: simplify test case

* update

* update

* update

* test: simplify style test case

* update

* update

* update

* update
2025-10-31 12:46:16 +08:00
lijianan
ec658c9842 test: simplify test case (#55537)
* test: simplify test case

* update

* update

* update
2025-10-31 11:42:54 +08:00
github-actions[bot]
134a474ed4 chore: upgrade deps (#55528)
Co-authored-by: afc163 <507615+afc163@users.noreply.github.com>
2025-10-30 08:15:42 +08:00
iola1999
9e792c72c2 site: remove infinite loop in theme transition (#55527) 2025-10-29 20:30:10 +08:00
lijianan
1ff663afa8 chore: code optimization, rm unnecessary nested function (#55517) 2025-10-29 13:25:56 +08:00
lijianan
1c0f1cdc06 docs: rm children api (#55515)
* docs: rm children api

* update

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
2025-10-29 10:55:38 +08:00
lijianan
259e533757 demo: update Select to data drive (#55507)
* demo: update Select to data drive

* Update components/form/demo/advanced-search.tsx

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: lijianan <574980606@qq.com>

* update more

* update more

* update more

* update snap

* update snap

* update snap

* update snap

* update

---------

Signed-off-by: lijianan <574980606@qq.com>
Co-authored-by: 遇见同学 <1875694521@qq.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-10-28 17:15:24 +08:00
lijianan
7f921b0ad4 fix: add process.env.NODE_ENV for useLocalStorage (#55506) 2025-10-28 15:04:07 +08:00
𝑾𝒖𝒙𝒉
cf34c4a1eb chore(demo): remove usage of internal utility methods and types from … (#55421) 2025-10-28 11:56:34 +08:00
ug
2ee85ee240 docs: Add llms documentation (#54940)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: liuqiang <qiang.liu@xinjifamily.com>
Co-authored-by: ug <62086147+765477020@users.noreply.github.com>
2025-10-28 11:55:58 +08:00
二货爱吃白萝卜
d29f4721b6 docs: See Conf no jumping (#55390)
* chore: update logic

* chore: clean up

* update useLocalStorage hook

* chore: test logic

* chore: banner hardcode

* chore: fix build

---------

Co-authored-by: lijianan <574980606@qq.com>
2025-10-28 10:55:49 +08:00
lijianan
e1ff71744e docs: add api anchor (#55495)
* docs: add docs anchor for RequestOptions

* update
2025-10-27 14:20:26 +08:00
github-actions[bot]
26c3b09eeb chore: auto merge branches (#55492)
chore: sync feature to master
2025-10-27 05:43:32 +00:00
lijianan
682c460673 docs: fix docs typo (#55493)
* docs: fix docs typo

* update

* update

* update
2025-10-27 13:13:06 +08:00
afc163
6e958871c4 fix: Segmented style conflict with React DevTools 7.0 (#55438)
Co-authored-by: lijianan <574980606@qq.com>
Co-authored-by: thinkasany <480968828@qq.com>
Co-authored-by: 遇见同学 <1875694521@qq.com>
2025-10-27 10:54:16 +08:00
ug
27a9c8a57c fix(Modal):Watermark crashes when wrapping Modal with modalRender (#55435)
Co-authored-by: liuqiang <qiang.liu@xinjifamily.com>
Co-authored-by: 遇见同学 <1875694521@qq.com>
2025-10-27 10:03:53 +08:00
github-actions[bot]
8a81accfaf chore: auto merge branches (#55479)
chore: merge master into feature
2025-10-26 09:47:24 +00:00
lijianan
41b5dce953 perf: try to reduce bundle size (#55478)
* refactor: reuse useForceUpdate hook

* update

* perf: try to reduce bundle size

* update
2025-10-26 17:18:36 +08:00
thinkasany
80a1f69588 fix: add image missing memo deps (#55477)
Co-authored-by: 遇见同学 <1875694521@qq.com>
2025-10-26 17:00:39 +08:00
lijianan
40531626c1 refactor: remove useState, reuse useForceUpdate hook (#55476)
* refactor: reuse useForceUpdate hook

* update
2025-10-26 16:38:18 +08:00
thinkasany
d7ee8cc377 fix: add ColorPicker missing memo deps (#55475)
* fix: add ColorPicker missing memo deps

* fix

* fix
2025-10-26 16:21:25 +08:00
lijianan
246c14b442 fix: add missing dependency (#55467)
Co-authored-by: thinkasany <480968828@qq.com>
2025-10-26 15:22:07 +08:00
lijianan
bf7cd94b89 chore: rm unnecessary useMemo (#55468)
* chore: rm unnecessary useMemo

* rename
2025-10-26 10:07:41 +08:00
renovate[bot]
d3ac9eddd0 chore(deps): update actions/upload-artifact action to v5 (#55470)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-26 09:04:35 +08:00
renovate[bot]
5a69863ac1 chore(deps): update actions/download-artifact action to v6 (#55469)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-26 09:03:23 +08:00
Yasin B. Kalkan
00e392e66d Fix color node reference and class name indexing (#55461)
Signed-off-by: Yasin B. Kalkan <yasinburakkalkan@gmail.com>
2025-10-25 21:09:18 +08:00
thinkasany
1d0b0a440c fix: add alert missing memo deps (#55457)
Co-authored-by: 遇见同学 <1875694521@qq.com>
2025-10-25 13:25:30 +08:00
thinkasany
8ab7fa52d4 chore: bump eslint-plugin-react-hooks@7.0.1 (#55456)
* chore: rm useless eslint comment

* eslint-plugin-react-hooks@7.0.1
2025-10-25 13:24:40 +08:00
github-actions[bot]
c6bff1aca6 chore: auto merge branches (#55454)
chore: sync master into feature
2025-10-25 02:47:55 +00:00
lijianan
c13ac86af2 fix: item styles should be merge (#55453) 2025-10-25 10:26:19 +08:00
lijianan
db2b6c93f6 chore: code style optimization (#55450)
* chore: code style optimization

* update
2025-10-25 10:24:24 +08:00
thinkasany
da7c8192a3 chore: rm useless NonNullAssertedOptionalChain (#55448)
Co-authored-by: 遇见同学 <1875694521@qq.com>
2025-10-25 10:17:25 +08:00
lijianan
94a2574e4a chore: fix lint error (#55451)
* test

* fix lint error

* fix lint error

* fix lint error

* fix lint error

* fix lint error

* fix lint error

* fix lint error

* update

* update

* update

* update

* update

* update
2025-10-25 10:06:51 +08:00
thinkasany
384646768d chore: add colorPicker missing memo deps (#55446) 2025-10-24 23:22:52 +08:00
jiAng
addf5ba2f7 feat: add itemActiveColor/itemActiveColorHover token on Pagination (#55195)
Co-authored-by: 遇见同学 <1875694521@qq.com>
Co-authored-by: thinkasany <480968828@qq.com>
2025-10-24 22:21:03 +08:00
github-actions[bot]
1592b9c4df chore: auto merge branches (#55441)
chore: sync master into feature
2025-10-24 13:31:24 +00:00
afc163
2933bd66ce chore: update biome config and report template (#55440)
* chore: update biome config and report template

* Apply suggestion from @afc163

Signed-off-by: afc163 <afc163@gmail.com>

---------

Signed-off-by: afc163 <afc163@gmail.com>
2025-10-24 20:27:58 +08:00
𝑾𝒖𝒙𝒉
60000bc14e fix(DirectoryTree): fieldNames cause defaultExpandAll to not work error (#55420) 2025-10-24 17:50:25 +08:00
lijianan
1c30401023 type: update any type to function (#55434) 2025-10-24 16:32:46 +08:00
lijianan
553ac801d3 type: update undefined type to optional (#55436) 2025-10-24 16:31:14 +08:00
divyeshagrawal
34297362a3 chore: remove unused devDependencies (#55433)
* Chore: Remove unused dependencies

* Chore: Add EOL

* Chore: Add remark-cli

* Chore: Add EOL
2025-10-24 15:46:43 +08:00
lijianan
44223967ae chore: rm useUniqueMemo hook (#55412) 2025-10-23 10:48:30 +08:00
lijianan
f187eeafb3 test: update any type with React.ReactElement (#55410) 2025-10-23 08:09:15 +08:00
lijianan
5fe4cff30d chore: unified code style (#55411) 2025-10-23 08:08:09 +08:00
thinkasany
8095b8c467 chore: improve avatar code style (#55408) 2025-10-23 04:14:01 +08:00
github-actions[bot]
4aeb941bec chore: auto merge branches (#55405)
chore: merge master into feature
2025-10-22 11:52:41 +00:00
lijianan
ec44482a1b chore: unified code style (#55406) 2025-10-22 19:31:22 +08:00
SocietyNiu
2131d9f7e2 docs: fix auto theme mode (#55397)
* fix: fix the auto theme mode

* fix: fix the index page background color display issue under auto theme mode

* docs: fix index css

---------

Co-authored-by: 遇见同学 <1875694521@qq.com>
2025-10-22 18:51:50 +08:00
zancheng
2bceb47f3a style(Segmented): Support gradient background (#55391) 2025-10-22 10:00:33 +08:00
lijianan
70cba6b961 site: add useLocalStorage hook (#55401)
* site: add useLocalStorage hook

* update

* update

* update
2025-10-22 09:57:34 +08:00
thinkasany
4c6f5d965b fix(space): add missing deps (#55399)
Co-authored-by: 遇见同学 <1875694521@qq.com>
2025-10-21 21:34:02 +08:00
afc163
5c122a805d style: Statistic skeleton showing active animation defaultly (#55398) 2025-10-21 20:28:09 +08:00
ug
d792286afe docs: Update React documentation links from reactjs.org to react.dev (#55392)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: liuqiang <qiang.liu@xinjifamily.com>
2025-10-21 17:14:21 +08:00
二货爱吃白萝卜
6d879793fd docs: add see conf config (#55389) 2025-10-21 16:08:15 +08:00
github-actions[bot]
e06b9533c0 chore: auto merge branches (#55384)
chore: merge master into feature
2025-10-21 02:44:15 +00:00
lijianan
4195a736e2 fix: update missing prefixCls dependency (#55378)
* docs: add mousePosition prop

* fix: update missing prefixCls dependency

* clear

---------

Co-authored-by: 遇见同学 <1875694521@qq.com>
2025-10-21 09:50:34 +08:00
lijianan
563e855dec fix: update missing responsiveMap dependency (#55385)
* fix: update missing responsiveMap dependency

* update
2025-10-21 09:28:45 +08:00
xrkffgg
a31d11d8a7 docs: add changelog 5.27.6 (#55380) 2025-10-20 16:44:32 +08:00
lijianan
2367a516c4 site: update missing isLight dependency (#55377)
* site: update missing themeData dependency

* update

---------

Co-authored-by: 遇见同学 <1875694521@qq.com>
2025-10-20 09:16:47 +08:00
lijianan
af1a78a83f refactor: avoid unnecessary re-renders by explicitly listing deps (#55376) 2025-10-20 08:37:24 +08:00
github-actions[bot]
9e2ca60497 chore: auto merge branches (#55372)
chore: merge master into feature
2025-10-19 15:47:58 +00:00
lijianan
072c9fa707 type: update any type to ConfirmDialogProps (#55371) 2025-10-19 23:21:17 +08:00
lijianan
a0a32ff450 fix: add missing getConfirmFunc dependency (#55370)
* fix: add missing getConfirmFunc dependency

* fix: add missing getConfirmFunc dependency
2025-10-19 22:53:07 +08:00
thinkasany
25001647a7 Revert "refactor(modal): use modalRef replace createRef (#55368)" (#55369)
This reverts commit 3b47ac3630.
2025-10-19 20:07:41 +08:00
thinkasany
3b47ac3630 refactor(modal): use modalRef replace createRef (#55368) 2025-10-19 16:28:58 +08:00
thinkasany
7a70bafe42 chore: rm useless eslint comments (#55367)
* chore: rm useless eslint comments

* rerun ci
2025-10-19 15:57:16 +08:00
lijianan
c0408b70aa fix: add missing checkedActiveItems dep (#55366) 2025-10-19 13:59:15 +08:00
lijianan
90696b1632 fix: add missing schema dep for useMergeSemantic (#55364)
* fix: add missing schema dep for useMergeSemantic

* update

* update
2025-10-19 13:19:08 +08:00
github-actions[bot]
1252e72856 chore: auto merge branches (#55362)
chore: merge master into feature
2025-10-19 02:36:25 +00:00
lijianan
f442fa2518 Merge branch master into feature-merge-master 2025-10-19 09:50:23 +08:00
lijianan
b447d9c22a Merge branch master into feature-merge-master 2025-10-19 09:44:18 +08:00
github-actions[bot]
f981a12895 chore: auto merge branches (#55348)
chore: sync master into feature
2025-10-18 07:43:33 +00:00
github-actions[bot]
474245dd7b chore: auto merge branches (#55341)
chore: sync master into feature
2025-10-17 16:12:08 +00:00
EmilyyyLiu
62bd8e367d feat[Input]: deprecated addon* attribute (#55315)
* feat[Input]: deprecated addon* attribute

* Update components/input/Input.tsx

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: thinkasany <480968828@qq.com>

* test: update snap

* test: Restore addon demo

* test: update snap

* tsat: update snap

---------

Signed-off-by: thinkasany <480968828@qq.com>
Co-authored-by: 刘欢 <lh01217311@antgroup.com>
Co-authored-by: thinkasany <480968828@qq.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-10-16 15:14:53 +08:00
github-actions[bot]
cea58dc907 chore: auto merge branches (#55323)
chore: sync master into feature
2025-10-15 14:27:29 +00:00
github-actions[bot]
479963ccbc chore: auto merge branches (#55306)
chore: sync master into feature
2025-10-14 12:20:22 +00:00
github-actions[bot]
a534480899 chore: auto merge branches (#55287)
chore: merge master into feature
2025-10-13 01:49:54 +00:00
github-actions[bot]
785f7fd8a3 chore: auto merge branches (#55260)
chore: merge master into feature
2025-10-10 11:23:19 +00:00
github-actions[bot]
d82c775248 chore: auto merge branches (#55248)
chore: sync master into feature
2025-10-09 12:28:50 +00:00
ug
76fe1be8a6 feat(splitter): Support onCollapse event (#54673)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: afc163 <afc163@gmail.com>
Co-authored-by: liuqiang <qiang.liu@xinjifamily.com>
Co-authored-by: Wanpan <wanpan96@163.com>
Co-authored-by: 遇见同学 <1875694521@qq.com>
2025-10-09 17:11:38 +08:00
github-actions[bot]
de674acfc9 chore: auto merge branches (#55235)
chore: merge master into feature
2025-10-06 18:32:55 +00:00
github-actions[bot]
5bbb3726b8 chore: auto merge branches (#55227)
chore: merge master into feature
2025-10-03 16:21:50 +00:00
github-actions[bot]
eef4faa527 chore: auto merge branches (#55211)
chore: merge master into feature
2025-10-01 06:26:44 +00:00
github-actions[bot]
4760c2af89 chore: auto merge branches (#55202)
chore: sync master into feature
2025-09-30 15:44:04 +00:00
github-actions[bot]
c61c5abd69 chore: auto merge branches (#55175)
chore: sync master into feature
2025-09-28 05:06:15 +00:00
thinkasany
dd3de44261 chore: lint fix 2025-09-28 12:44:31 +08:00
thinkasany
b16183b209 Merge remote-tracking branch 'origin/master' into feature-merge-master 2025-09-28 12:15:04 +08:00
lijianan
8a77e20d93 docs: update cn => en (#55159) 2025-09-26 23:58:57 +08:00
EmilyyyLiu
6647881b09 feat: Add defaultRequest to customRequest (#55146)
* chore: Upgrade rc-upload

* docs: add documents

* docs: change document

* docs: add link to RequestOptions

* test: update site snap

---------

Co-authored-by: 刘欢 <lh01217311@antgroup.com>
2025-09-26 16:17:33 +08:00
github-actions[bot]
631610433d chore: auto merge branches (#55148)
chore: sync master into feature
2025-09-25 12:01:00 +00:00
github-actions[bot]
247b95a89e chore: auto merge branches (#55111)
chore: sync master into feature
2025-09-21 05:48:27 +00:00
github-actions[bot]
b7dc1324b1 chore: auto merge branches (#55095)
chore: merge master into feature
2025-09-19 15:14:15 +00:00
lijianan
4b2364bde0 feat: add boostLevel prop and support value segmentation (#55063)
* feat: add boostLevel prop and support value segmentation

* test: update snap
2025-09-19 10:22:06 +08:00
github-actions[bot]
fc649c4a44 chore: auto merge branches (#55051)
chore: sync master into feature
2025-09-18 00:16:07 +00:00
github-actions[bot]
f73f6063d7 chore: auto merge branches (#55018)
chore: merge master into feature
2025-09-14 11:17:45 +00:00
github-actions[bot]
7dccd7a449 chore: auto merge branches (#55008)
chore: merge master into feature
2025-09-13 17:49:19 +00:00
github-actions[bot]
568f8074a4 chore: auto merge branches (#54989)
chore: sync master into feature
2025-09-12 15:38:01 +00:00
github-actions[bot]
f81e47a0b4 chore: auto merge branches (#54926)
chore: merge master into feature
2025-09-08 12:08:07 +00:00
github-actions[bot]
a983e79481 chore: auto merge branches (#54903)
chore: sync master into feature
2025-09-06 06:37:46 +00:00
github-actions[bot]
ba93683692 chore: auto merge branches (#54863)
chore: sync master into feature
2025-09-03 13:26:16 +00:00
LeiZhang
7d4bd5bd8c feat: The transfer & tree component inherits the form disable (#54831)
* feat: The transfer&tree component inherits the form disable

* test: add snap

* test: add form diabled demo

* test: add snap

---------

Co-authored-by: 路振凯 <l>
2025-09-02 16:29:23 +08:00
Trần Quang Khánh
e0683bbd41 feat(TreeSelect): support global config for switcher icon (#54821)
* feat(TreeSelect): support global config for switcher icon

* chore: update config provider document

---------

Co-authored-by: Khanh Tran <quangkhanhdeveloper@gmail.com>
2025-09-02 09:54:59 +08:00
thinkasany
fbc8cc03a7 chore: improve code style (#54834)
* chore: improve code style

* Apply suggestion from @afc163

Signed-off-by: afc163 <afc163@gmail.com>

---------

Signed-off-by: afc163 <afc163@gmail.com>
Co-authored-by: afc163 <afc163@gmail.com>
2025-09-01 21:46:03 +08:00
github-actions[bot]
7d2860e4f4 chore: auto merge branches (#54832)
chore: sync master into feature
2025-09-01 11:29:30 +00:00
EmilyyyLiu
827b22bf55 feat: The mentions component inherits the form's disable (#54829)
* feat: The mentions component inherits the form's disable

* Update components/mentions/index.tsx

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: EmilyyyLiu <100924403+EmilyyyLiu@users.noreply.github.com>

* test: add test

* test: add demo

* test: update snap

---------

Signed-off-by: EmilyyyLiu <100924403+EmilyyyLiu@users.noreply.github.com>
Co-authored-by: 刘欢 <lh01217311@antgroup.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-09-01 17:56:19 +08:00
Trần Quang Khánh
5facf03416 docs(ConfigProvider): update correct cn version for Image (#54823)
Co-authored-by: Khanh Tran <quangkhanhdeveloper@gmail.com>
2025-08-31 23:45:36 +08:00
thinkasany
48c5ed40f2 feat: add component token support for notification background colors (#54802)
Co-authored-by: afc163 <afc163@gmail.com>
fix: notification wrong bg (#54800)
2025-08-29 14:14:16 +08:00
EmilyyyLiu
864b177fdd fix: make suffixIcon=undefined behave same as when unset (#54790)
* fix: make suffixIcon=undefined behave same as when unset

* Update components/date-picker/generatePicker/generateSinglePicker.tsx

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: EmilyyyLiu <100924403+EmilyyyLiu@users.noreply.github.com>

* Update components/date-picker/generatePicker/generateRangePicker.tsx

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: EmilyyyLiu <100924403+EmilyyyLiu@users.noreply.github.com>

* feat: useSuffixIcon

* feat: suffixIcon component

* Update components/date-picker/generatePicker/SuffixIcon.tsx

Co-authored-by: afc163 <afc163@gmail.com>
Signed-off-by: EmilyyyLiu <100924403+EmilyyyLiu@users.noreply.github.com>

* feat: add debug demo

* test: update snap

---------

Signed-off-by: EmilyyyLiu <100924403+EmilyyyLiu@users.noreply.github.com>
Co-authored-by: 刘欢 <lh01217311@antgroup.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: afc163 <afc163@gmail.com>
2025-08-29 12:06:11 +08:00
thinkasany
8838b8f178 chore: improve code style (#54799)
* chore: improve code style

* clean memo
2025-08-29 11:20:30 +08:00
ug
9244e8039e Docs(Grid): Improve the Grid document. (#54793)
* update

* update

* update

---------

Co-authored-by: liuqiang <qiang.liu@xinjifamily.com>
2025-08-28 19:53:31 +08:00
github-actions[bot]
c579e2fd8e chore: auto merge branches (#54786)
chore: sync master into feature
2025-08-28 08:26:25 +00:00
Trần Quang Khánh
a1c2f3b4d2 feat(Image): support fallback global config (#54702)
* feat(Image): support fallback global config

* feat(Image): update config provider document

---------

Co-authored-by: Khanh Tran <quangkhanhdeveloper@gmail.com>
Co-authored-by: thinkasany <480968828@qq.com>
2025-08-28 10:25:10 +08:00
lijianan
f98c8f9617 fix: add miss dep for useMemo (#54772)
* fix: add miss dep for useMemo

* Update components/drawer/DrawerPanel.tsx

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: thinkasany <480968828@qq.com>

---------

Signed-off-by: thinkasany <480968828@qq.com>
Co-authored-by: thinkasany <480968828@qq.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2025-08-27 17:15:09 +08:00
github-actions[bot]
9bf6ba06c8 chore: auto merge branches (#54765)
chore: merge master into feature
2025-08-27 08:28:08 +00:00
Wanpan
da30965089 feat: Upload add pictureCardSize token (#54756) 2025-08-27 10:22:34 +08:00
David Hsing
e01b76c4a4 feat: Add Drawer closable placement prop for close icon position (#54067)
Co-authored-by: afc163 <afc163@gmail.com>
Co-authored-by: thinkasany <480968828@qq.com>
2025-08-26 15:42:14 +08:00
ug
6a302f1133 feat(Row): The "gutter" parameter supports the string type. (#54628)
Co-authored-by: liuqiang <qiang.liu@xinjifamily.com>
2025-08-25 14:04:34 +08:00
github-actions[bot]
f40cedc3bb chore: auto merge branches (#54744)
chore: merge master into feature
2025-08-23 08:34:07 +00:00
github-actions[bot]
410d38921d chore: auto merge branches (#54710)
chore: sync master into feature
2025-08-19 02:41:47 +00:00
github-actions[bot]
a06e74ebb3 chore: auto merge branches (#54684)
chore: sync master into feature
2025-08-14 15:13:49 +00:00
github-actions[bot]
b1702668bf chore: auto merge branches (#54653)
chore: sync master into feature
2025-08-11 13:10:19 +00:00
343 changed files with 9631 additions and 2217 deletions

View File

@@ -20,6 +20,9 @@
html {
scrollbar-width: thin;
scrollbar-color: #eaeaea transparent;
@supports (text-autospace: normal) {
text-autospace: normal;
}
}
.rc-footer {

View File

@@ -0,0 +1,107 @@
import React, { useCallback, useEffect } from 'react';
const ANT_SYNC_STORAGE_EVENT_KEY = 'ANT_SYNC_STORAGE_EVENT_KEY';
const isFunction = (val: any): val is (...args: any[]) => any => {
return typeof val === 'function';
};
interface Options<T> {
defaultValue?: T;
serializer?: (value: T) => string;
deserializer?: (value: string) => T;
onError?: (error: unknown) => void;
}
const useLocalStorage = <T>(key: string, options: Options<T> = {}) => {
const storage = typeof window !== 'undefined' ? localStorage : null;
const { serializer, deserializer, onError, defaultValue } = options;
const mergedSerializer = typeof serializer === 'function' ? serializer : JSON.stringify;
const mergedDeserializer = typeof deserializer === 'function' ? deserializer : JSON.parse;
const handleError = typeof onError === 'function' ? onError : console.error;
const getStoredValue = () => {
try {
const rawData = storage?.getItem(key);
if (rawData) {
return mergedDeserializer(rawData);
}
} catch (e) {
if (process.env.NODE_ENV !== 'production') {
handleError(e);
}
return defaultValue;
}
return defaultValue;
};
const [state, setState] = React.useState<T>(getStoredValue);
useEffect(() => {
setState(getStoredValue());
}, [key]);
const updateState: React.Dispatch<React.SetStateAction<T>> = (value) => {
const currentState = isFunction(value) ? value(state) : value;
setState(currentState);
try {
let newValue: string | null;
const oldValue = storage?.getItem(key);
if (typeof currentState === 'undefined') {
newValue = null;
storage?.removeItem(key);
} else {
newValue = mergedSerializer(currentState);
storage?.setItem(key, newValue);
}
dispatchEvent(
new CustomEvent(ANT_SYNC_STORAGE_EVENT_KEY, {
detail: { key, newValue, oldValue, storageArea: storage },
}),
);
} catch (e) {
if (process.env.NODE_ENV !== 'production') {
handleError(e);
}
}
};
const shouldSync = (ev: StorageEvent) => {
return ev && ev.key === key && ev.storageArea === storage;
};
const onNativeStorage = useCallback(
(event: StorageEvent) => {
if (shouldSync(event)) {
setState(getStoredValue());
}
},
[key],
);
const onCustomStorage = useCallback(
(event: Event) => {
if (shouldSync(event as StorageEvent)) {
setState(getStoredValue());
}
},
[key],
);
useEffect(() => {
window?.addEventListener('storage', onNativeStorage);
window?.addEventListener(ANT_SYNC_STORAGE_EVENT_KEY, onCustomStorage);
return () => {
window?.removeEventListener('storage', onNativeStorage);
window?.removeEventListener(ANT_SYNC_STORAGE_EVENT_KEY, onCustomStorage);
};
}, [key, onNativeStorage, onCustomStorage]);
return [state, updateState] as const;
};
export default useLocalStorage;

View File

@@ -85,10 +85,6 @@ const useThemeAnimation = () => {
);
document
.startViewTransition(async () => {
// wait for theme change end
while (colorBgElevated === animateRef.current.colorBgElevated) {
await new Promise<void>((resolve) => setTimeout(resolve, 1000 / 60));
}
const root = document.documentElement;
root.classList.remove(isDark ? 'dark' : 'light');
root.classList.add(isDark ? 'light' : 'dark');

View File

@@ -31,15 +31,17 @@ const locales = {
const useStyle = createStyles(({ token, css, cx }, siteConfig: SiteContextProps) => {
const textShadow = `0 0 4px ${token.colorBgContainer}`;
const isDark = siteConfig.theme.includes('dark');
const mask = cx(css`
position: absolute;
inset: 0;
backdrop-filter: blur(2px);
opacity: 1;
background-color: ${isDark ? 'rgba(0, 0, 0, 0.2)' : 'rgba(255, 255, 255, 0.2)'};
background-color: rgba(255, 255, 255, 0.2);
transition: all 1s ease;
pointer-events: none;
[data-prefers-color='dark'] & {
background-color: rgba(0, 0, 0, 0.2);
}
`);
const block = cx(css`

View File

@@ -389,10 +389,9 @@ const Theme: React.FC = () => {
themeType,
...ThemesInfo[themeType],
};
setThemeData(mergedData);
form.setFieldsValue(mergedData);
}, [themeType]);
}, [form, themeType]);
const isDark = React.use(DarkContext);
@@ -433,23 +432,14 @@ const Theme: React.FC = () => {
token: { ...themeToken, colorPrimary: colorPrimaryValue },
algorithm: algorithmFn,
components: {
Layout: isLight
? {
headerBg: 'transparent',
bodyBg: 'transparent',
}
: {},
Layout: isLight ? { headerBg: 'transparent', bodyBg: 'transparent' } : {},
Menu: isLight
? {
itemBg: 'transparent',
subMenuItemBg: 'transparent',
activeBarBorderWidth: 0,
}
? { itemBg: 'transparent', subMenuItemBg: 'transparent', activeBarBorderWidth: 0 }
: {},
...(themeType === 'v4' ? defaultTheme.components : {}),
},
}),
[themeToken, colorPrimaryValue, algorithmFn, themeType],
[themeToken, colorPrimaryValue, algorithmFn, isLight, themeType],
);
// ================================ Render ================================

View File

@@ -60,7 +60,15 @@ export type Extras = {
export type Icons = Icon[];
export type HeadingBanner = {
[key in 'cn' | 'en']: {
title?: string;
href?: string;
};
};
export type SiteData = {
headingBanner: HeadingBanner;
articles: Articles;
authors: Authors;
recommendations: Recommendations;
@@ -82,10 +90,27 @@ export function preLoad(list: string[]) {
}
}
// Banner 硬编码,以防止页面闪烁问题
export const getBannerData = (): null | {
title: string;
href: string;
} => {
return {
title: 'See Conf 2025 震撼来袭 - 探索 AI 时代的用户体验与工程实践',
href: 'https://seeconf.antfin.com/',
};
};
export const useAntdSiteConfig = () => {
const { data, error, isLoading } = useSWR<Partial<SiteData>, Error>(
`https://render.alipay.com/p/h5data/antd4-config_website-h5data.json`,
(url: string) => fetch(url).then((res) => res.json()),
{
suspense: false,
// revalidateOnMount: false,
revalidateIfStale: false,
revalidateOnFocus: false,
},
);
return { data, error, isLoading };
};

View File

@@ -1,10 +1,11 @@
import React, { Suspense, useEffect } from 'react';
import React, { Suspense } from 'react';
import { App, Button, ConfigProvider, Skeleton } from 'antd';
import { enUS, zhCN } from 'antd-token-previewer';
import type { ThemeConfig } from 'antd/es/config-provider/context';
import { Helmet } from 'dumi';
import useLocale from '../../hooks/useLocale';
import useLocalStorage from '../../hooks/useLocalStorage';
const ThemeEditor = React.lazy(() => import('antd-token-previewer/lib/ThemeEditor'));
@@ -33,24 +34,18 @@ const locales = {
},
};
const ANT_DESIGN_V5_THEME_EDITOR_THEME = 'ant-design-v5-theme-editor-theme';
const ANT_THEME_EDITOR_THEME = 'ant-theme-editor-theme';
const CustomTheme: React.FC = () => {
const { message } = App.useApp();
const [locale, lang] = useLocale(locales);
const [theme, setTheme] = React.useState<ThemeConfig>({});
useEffect(() => {
const storedConfig = localStorage.getItem(ANT_DESIGN_V5_THEME_EDITOR_THEME);
if (storedConfig) {
const themeConfig = JSON.parse(storedConfig);
setTheme(themeConfig);
}
}, []);
const [themeConfig, setThemeConfig] = useLocalStorage<ThemeConfig>(ANT_THEME_EDITOR_THEME, {
defaultValue: {},
});
const handleSave = () => {
localStorage.setItem(ANT_DESIGN_V5_THEME_EDITOR_THEME, JSON.stringify(theme));
setThemeConfig(themeConfig);
message.success(locale.saveSuccessfully);
};
@@ -65,11 +60,9 @@ const CustomTheme: React.FC = () => {
<ThemeEditor
advanced
hideAdvancedSwitcher
theme={{ name: 'Custom Theme', key: 'test', config: theme }}
theme={{ name: 'Custom Theme', key: 'test', config: themeConfig }}
style={{ height: 'calc(100vh - 64px)' }}
onThemeChange={(newTheme) => {
setTheme(newTheme.config);
}}
onThemeChange={(newTheme) => setThemeConfig(newTheme.config)}
locale={lang === 'cn' ? zhCN : enUS}
actions={
<Button type="primary" onClick={handleSave}>

View File

@@ -20,7 +20,9 @@
const isEnabled = always || enabledCondition.every(Boolean);
if (!isEnabled) return;
if (!isEnabled) {
return;
}
const prefixCls = 'antd-mirror-notify';
const primaryColor = '#1677ff';

View File

@@ -139,7 +139,10 @@ const ComponentMeta: React.FC<ComponentMetaProps> = (props) => {
}, [component, repo, source]);
// ======================== Render ========================
const importList = `import { ${transformComponentName(component)} } from "antd";`;
const importCode =
component === 'Icon'
? `import { AntDesignOutlined } from '@ant-design/icons';`
: `import { ${transformComponentName(component)} } from 'antd';`;
return (
<Descriptions
@@ -153,14 +156,14 @@ const ComponentMeta: React.FC<ComponentMetaProps> = (props) => {
{
label: locale.import,
children: (
<CopyToClipboard text={`import { ${component} } from "antd";`} onCopy={onCopy}>
<CopyToClipboard text={importCode} onCopy={onCopy}>
<Tooltip
placement="right"
title={copied ? locale.copied : locale.copy}
onOpenChange={onOpenChange}
>
<Typography.Text className={styles.code} onClick={onCopy}>
{importList}
{importCode}
</Typography.Text>
</Tooltip>
</CopyToClipboard>

View File

@@ -7,8 +7,8 @@ import classNames from 'classnames';
import ImagePreview from '../ImagePreview';
import type { ImagePreviewProps } from '../ImagePreview';
const isNotEmpty = (val: any) => {
return typeof val !== 'undefined' && val !== null && val !== '';
const isNonNullable = <T,>(val: T): val is NonNullable<T> => {
return val !== undefined && val !== null;
};
const useStyle = createStyles(({ css, token }) => {
@@ -51,8 +51,8 @@ const FlexWithImagePreview: React.FC<
return (
<Flex className={classNames(styles.wrapper, className)} style={style} {...rest}>
<Flex align="flex-start" justify="flex-start" vertical>
{isNotEmpty(title) && <div className={styles.title}>{title}</div>}
{isNotEmpty(description) && <div className={styles.description}>{description}</div>}
{isNonNullable(title) && <div className={styles.title}>{title}</div>}
{isNonNullable(description) && <div className={styles.description}>{description}</div>}
</Flex>
<ImagePreview {...imagePreviewProps}>{children}</ImagePreview>
</Flex>

View File

@@ -48,6 +48,8 @@ const IconSearch: React.FC = () => {
const handleSearchIcon = debounce((e: React.ChangeEvent<HTMLInputElement>) => {
setDisplayState((prevState) => ({ ...prevState, searchKey: e.target.value }));
document.getElementById('list-of-icons')?.scrollIntoView({ behavior: 'smooth' });
}, 300);
const handleChangeTheme = useCallback((value: ThemeType) => {

View File

@@ -164,7 +164,6 @@ const CodePreview: React.FC<CodePreviewProps> = ({
</div>
),
})),
// eslint-disable-next-line react-hooks/exhaustive-deps
[
entryName,
error,

View File

@@ -72,10 +72,10 @@ const Palette: React.FC<PaletteProps> = (props) => {
key={i}
ref={(node) => {
if (node) {
colorNodesRef.current[`${name}-${i}`] = node;
colorNodesRef.current[`${name}-${i + 1}`] = node;
}
}}
className={`main-color-item palette-${name}-${i}`}
className={`main-color-item palette-${name}-${i + 1}`}
style={{
color: (name === 'yellow' ? i > 6 : i > 5) ? firstColor : lastColor,
fontWeight: i === 6 ? 'bold' : 'normal',

View File

@@ -11,17 +11,17 @@ import type { MenuProps } from 'antd';
import { CompactTheme, DarkTheme } from 'antd-token-previewer/es/icons';
import { FormattedMessage, useLocation } from 'dumi';
import useLocalStorage from '../../../hooks/useLocalStorage';
import useThemeAnimation from '../../../hooks/useThemeAnimation';
import type { SiteContextProps } from '../../slots/SiteContext';
import SiteContext from '../../slots/SiteContext';
import { getLocalizedPathname, isZhCN, isLocalStorageNameSupported } from '../../utils';
import { getLocalizedPathname, isZhCN } from '../../utils';
import Link from '../Link';
import ThemeIcon from './ThemeIcon';
export type ThemeName = 'light' | 'dark' | 'auto' | 'compact' | 'motion-off' | 'happy-work';
// 主题持久化存储键名
const ANT_DESIGN_SITE_THEME = 'ant-design-site-theme';
export const ANT_DESIGN_SITE_THEME = 'ant-design-site-theme';
export interface ThemeSwitchProps {
value?: ThemeName[];
@@ -33,6 +33,10 @@ const ThemeSwitch: React.FC<ThemeSwitchProps> = () => {
const toggleAnimationTheme = useThemeAnimation();
const lastThemeKey = useRef<string>(theme.includes('dark') ? 'dark' : 'light');
const [, setTheme] = useLocalStorage<ThemeName>(ANT_DESIGN_SITE_THEME, {
defaultValue: undefined,
});
const badge = <Badge color="blue" style={{ marginTop: -1 }} />;
// 主题选项配置
@@ -133,14 +137,9 @@ const ThemeSwitch: React.FC<ThemeSwitchProps> = () => {
const filteredTheme = theme.filter((t) => !['light', 'dark', 'auto'].includes(t));
const newTheme = [...filteredTheme, themeKey];
updateSiteConfig({
theme: newTheme,
});
setTheme(themeKey);
// 持久化到 localStorage
if (isLocalStorageNameSupported()) {
localStorage.setItem(ANT_DESIGN_SITE_THEME, themeKey);
}
updateSiteConfig({ theme: newTheme });
} else {
// 其他主题选项是开关式的
const hasTheme = theme.includes(themeKey);

View File

@@ -12,15 +12,18 @@ import { getSandpackCssText } from '@codesandbox/sandpack-react';
import { theme as antdTheme, App } from 'antd';
import type { MappingAlgorithm } from 'antd';
import type { DirectionType, ThemeConfig } from 'antd/es/config-provider';
import dayjs from 'dayjs';
import { createSearchParams, useOutlet, useSearchParams, useServerInsertedHTML } from 'dumi';
import { DarkContext } from '../../hooks/useDark';
import useLayoutState from '../../hooks/useLayoutState';
import useLocalStorage from '../../hooks/useLocalStorage';
import { getBannerData } from '../../pages/index/components/util';
import { ANT_DESIGN_SITE_THEME } from '../common/ThemeSwitch';
import type { ThemeName } from '../common/ThemeSwitch';
import SiteThemeProvider from '../SiteThemeProvider';
import type { SiteContextProps } from '../slots/SiteContext';
import SiteContext from '../slots/SiteContext';
import { isLocalStorageNameSupported } from '../utils';
import '@ant-design/v5-patch-for-react-19';
@@ -28,10 +31,8 @@ type Entries<T> = { [K in keyof T]: [K, T[K]] }[keyof T][];
type SiteState = Partial<Omit<SiteContextProps, 'updateSiteConfig'>>;
const RESPONSIVE_MOBILE = 768;
export const ANT_DESIGN_NOT_SHOW_BANNER = 'ANT_DESIGN_NOT_SHOW_BANNER';
// 主题持久化存储键名
const ANT_DESIGN_SITE_THEME = 'ant-design-site-theme';
export const ANT_DESIGN_NOT_SHOW_BANNER = 'ANT_DESIGN_NOT_SHOW_BANNER';
// Compatible with old anchors
if (typeof window !== 'undefined') {
@@ -43,9 +44,13 @@ if (typeof window !== 'undefined') {
}
}
const getAlgorithm = (themes: ThemeName[] = []) =>
const getAlgorithm = (themes: ThemeName[] = [], systemTheme: 'dark' | 'light') =>
themes
.map((theme) => {
// auto 模式下根据系统主题切换
if (theme === 'auto' && systemTheme === 'dark') {
return antdTheme.darkAlgorithm;
}
if (theme === 'dark') {
return antdTheme.darkAlgorithm;
}
@@ -56,21 +61,11 @@ const getAlgorithm = (themes: ThemeName[] = []) =>
})
.filter(Boolean);
// 获取最终主题优先级URL Query > Local Storage > Site (Memory)
const getFinalTheme = (urlTheme: ThemeName[]): ThemeName[] => {
// 只认 light/dark
const baseTheme = urlTheme.filter((t) => !['light', 'dark', 'auto'].includes(t));
const urlColor = urlTheme.find((t) => t === 'light' || t === 'dark');
if (urlColor) return [...baseTheme, urlColor];
if (isLocalStorageNameSupported()) {
const stored = localStorage.getItem(ANT_DESIGN_SITE_THEME) as ThemeName;
if (stored && ['light', 'dark', 'auto'].includes(stored)) {
return [...baseTheme, stored];
}
const getSystemTheme = (): 'light' | 'dark' => {
if (typeof window === 'undefined') {
return 'light';
}
// 默认 auto
return [...baseTheme, 'auto'];
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
};
const GlobalLayout: React.FC = () => {
@@ -84,6 +79,32 @@ const GlobalLayout: React.FC = () => {
bannerVisible: false,
});
const [storedTheme] = useLocalStorage<ThemeName>(ANT_DESIGN_SITE_THEME, {
defaultValue: undefined,
});
const [bannerLastTime] = useLocalStorage<string>(ANT_DESIGN_NOT_SHOW_BANNER, {
defaultValue: undefined,
});
// 获取最终主题优先级URL Query > Local Storage > Site (Memory)
const getFinalTheme = (urlTheme: ThemeName[]): ThemeName[] => {
// 只认 light/dark
const baseTheme = urlTheme.filter((t) => !['light', 'dark', 'auto'].includes(t));
const urlColor = urlTheme.find((t) => t === 'light' || t === 'dark');
if (urlColor) {
return [...baseTheme, urlColor];
}
if (['light', 'dark', 'auto'].includes(storedTheme)) {
return [...baseTheme, storedTheme];
}
return [...baseTheme, 'auto'];
};
const [systemTheme, setSystemTheme] = React.useState<'light' | 'dark'>(() => getSystemTheme());
const bannerData = getBannerData();
// TODO: This can be remove in v6
const useCssVar = searchParams.get('cssVar') !== 'false';
@@ -111,10 +132,6 @@ const GlobalLayout: React.FC = () => {
} else {
nextSearchParams.delete('theme');
}
// 设置 data-prefers-color
if (color) {
document.querySelector('html')?.setAttribute('data-prefers-color', color);
}
}
});
@@ -122,7 +139,6 @@ const GlobalLayout: React.FC = () => {
setSearchParams(nextSearchParams);
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[searchParams, setSearchParams],
);
@@ -130,6 +146,17 @@ const GlobalLayout: React.FC = () => {
updateSiteConfig({ isMobile: window.innerWidth < RESPONSIVE_MOBILE });
}, [updateSiteConfig]);
// 设置 data-prefers-color 属性
useEffect(() => {
const color = theme.find((t) => t === 'light' || t === 'dark');
const html = document.querySelector<HTMLHtmlElement>('html');
if (theme.includes('auto') && systemTheme) {
html?.setAttribute('data-prefers-color', systemTheme);
} else if (color) {
html?.setAttribute('data-prefers-color', color);
}
}, [systemTheme, theme]);
// 监听系统主题变化
useEffect(() => {
if (typeof window === 'undefined') {
@@ -138,7 +165,10 @@ const GlobalLayout: React.FC = () => {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const handleSystemThemeChange = () => {};
const handleSystemThemeChange = (e: MediaQueryListEvent) => {
const newSystemTheme = e.matches ? 'dark' : 'light';
setSystemTheme(newSystemTheme);
};
mediaQuery.addEventListener('change', handleSystemThemeChange);
@@ -153,17 +183,18 @@ const GlobalLayout: React.FC = () => {
const finalTheme = getFinalTheme(urlTheme);
const _direction = searchParams.get('direction') as DirectionType;
const storedBannerVisible = bannerLastTime && dayjs().diff(dayjs(bannerLastTime), 'day') >= 1;
const isZhCN = typeof window !== 'undefined' && window.location.pathname.includes('-cn');
const hasBannerContent = isZhCN && !!bannerData;
setSiteState({
theme: finalTheme,
direction: _direction === 'rtl' ? 'rtl' : 'ltr',
bannerVisible: hasBannerContent && (bannerLastTime ? !!storedBannerVisible : true),
});
// 设置 data-prefers-color 属性
const colorTheme = finalTheme.find((t) => ['light', 'dark'].includes(t));
if (colorTheme) {
document.documentElement.setAttribute('data-prefers-color', colorTheme);
}
// Handle isMobile
updateMobileMode();
@@ -177,7 +208,6 @@ const GlobalLayout: React.FC = () => {
return () => {
window.removeEventListener('resize', updateMobileMode);
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [searchParams, updateMobileMode]);
const siteContextValue = React.useMemo<SiteContextProps>(
@@ -195,12 +225,12 @@ const GlobalLayout: React.FC = () => {
// 算法优先级auto 时用系统主题算法
const themeForAlgorithm = theme;
return {
algorithm: getAlgorithm(themeForAlgorithm),
algorithm: getAlgorithm(themeForAlgorithm, systemTheme),
token: { motion: !theme.includes('motion-off') },
cssVar: useCssVar,
hashed: !useCssVar,
};
}, [theme, useCssVar]);
}, [theme, useCssVar, systemTheme]);
const styleCache = React.useMemo(() => createCache(), []);
@@ -239,7 +269,9 @@ const GlobalLayout: React.FC = () => {
));
return (
<DarkContext value={theme.includes('dark')}>
<DarkContext
value={theme.includes('dark') || (theme.includes('auto') && systemTheme === 'dark')}
>
<StyleProvider
cache={styleCache}
linters={[legacyNotSelectorLinter, parentSelectorLinter, NaNLinter]}

View File

@@ -40,12 +40,10 @@ const Content: React.FC<React.PropsWithChildren> = ({ children }) => {
useLayoutEffect(() => {
setShowDebug(process.env.NODE_ENV === 'development' || isDebugDemo);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isDebugDemo]);
const contextValue = useMemo<DemoContextProps>(
() => ({ showDebug, setShowDebug, codeType, setCodeType }),
// eslint-disable-next-line react-hooks/exhaustive-deps
[showDebug, codeType],
);

View File

@@ -8,6 +8,8 @@ import { useLocation, useSiteData } from 'dumi';
import DumiSearchBar from 'dumi/theme-default/slots/SearchBar';
import useLocale from '../../../hooks/useLocale';
import useLocalStorage from '../../../hooks/useLocalStorage';
import { getBannerData } from '../../../pages/index/components/util';
import ThemeSwitch from '../../common/ThemeSwitch';
import DirectionIcon from '../../icons/DirectionIcon';
import { ANT_DESIGN_NOT_SHOW_BANNER } from '../../layouts/GlobalLayout';
@@ -22,20 +24,7 @@ import SwitchBtn from './SwitchBtn';
const RESPONSIVE_XS = 1120;
const RESPONSIVE_SM = 1200;
const locales = {
cn: {
message: '语雀征文 · 说说你和开源的故事,赢取 Ant Design 精美周边 🎁',
shortMessage: '语雀征文 · 说说你和开源的故事,赢取 Ant Design 精美周边 🎁',
more: '前往了解',
link: 'https://www.yuque.com/opensource2023',
},
en: {
message: '',
shortMessage: '',
more: '',
link: '',
},
};
export const ANT_LOCAL_TYPE_KEY = 'ANT_LOCAL_TYPE_KEY';
const useStyle = createStyles(({ token, css }) => {
const searchIconColor = '#ced4d9';
@@ -162,11 +151,12 @@ interface HeaderState {
// ================================= Header =================================
const Header: React.FC = () => {
const [locale, lang] = useLocale(locales);
const [, lang] = useLocale();
const { pkg } = useSiteData();
const themeConfig = getThemeConfig();
const [headerState, setHeaderState] = useState<HeaderState>({
menuVisible: false,
windowWidth: 1400,
@@ -179,24 +169,33 @@ const Header: React.FC = () => {
const { styles } = useStyle();
const [, setTopBannerDay] = useLocalStorage<string>(ANT_DESIGN_NOT_SHOW_BANNER, {
defaultValue: undefined,
});
const [, setLocalType] = useLocalStorage<string>(ANT_LOCAL_TYPE_KEY, {
defaultValue: undefined,
});
const handleHideMenu = useCallback(() => {
setHeaderState((prev) => ({ ...prev, menuVisible: false }));
}, []);
const onWindowResize = useCallback(() => {
setHeaderState((prev) => ({ ...prev, windowWidth: window.innerWidth }));
}, []);
const onMenuVisibleChange = useCallback((visible: boolean) => {
setHeaderState((prev) => ({ ...prev, menuVisible: visible }));
}, []);
const onDirectionChange = () => {
updateSiteConfig({ direction: direction !== 'rtl' ? 'rtl' : 'ltr' });
};
const onBannerClose = () => {
updateSiteConfig({ bannerVisible: false });
if (utils.isLocalStorageNameSupported()) {
localStorage.setItem(ANT_DESIGN_NOT_SHOW_BANNER, dayjs().toISOString());
}
setTopBannerDay(dayjs().toISOString());
};
useEffect(() => {
@@ -238,9 +237,8 @@ const Header: React.FC = () => {
const currentProtocol = `${window.location.protocol}//`;
const currentHref = window.location.href.slice(currentProtocol.length);
if (utils.isLocalStorageNameSupported()) {
localStorage.setItem('locale', utils.isZhCN(pathname) ? 'en-US' : 'zh-CN');
}
setLocalType(utils.isZhCN(pathname) ? 'en-US' : 'zh-CN');
window.location.href =
currentProtocol +
currentHref.replace(
@@ -272,6 +270,12 @@ const Header: React.FC = () => {
const isHome = ['', 'index', 'index-cn'].includes(pathname);
const isZhCN = lang === 'cn';
const isRTL = direction === 'rtl';
// Get banner data from site config
const bannerData = getBannerData();
const bannerTitle = bannerData?.title || '';
const bannerHref = bannerData?.href || '';
let responsive: null | 'narrow' | 'crowded' = null;
if (windowWidth < RESPONSIVE_XS) {
responsive = 'crowded';
@@ -375,7 +379,7 @@ const Header: React.FC = () => {
<MenuOutlined className="nav-phone-icon" />
</Popover>
)}
{isZhCN && bannerVisible && (
{isZhCN && bannerVisible && bannerTitle && bannerHref && (
<ConfigProvider
theme={{
token: {
@@ -387,23 +391,25 @@ const Header: React.FC = () => {
<Alert
className={styles.banner}
message={
<>
<span>{isMobile ? locale.shortMessage : locale.message}</span>
<a
className={styles.link}
href={locale.link}
target="_blank"
rel="noreferrer"
onClick={() => {
window.gtag?.('event', '点击', {
event_category: 'top_banner',
event_label: locale.link,
});
}}
>
{locale.more}
</a>
</>
bannerTitle && bannerHref ? (
<>
<span>{bannerTitle}</span>
<a
className={styles.link}
href={bannerHref}
target="_blank"
rel="noreferrer"
onClick={() => {
window.gtag?.('event', '点击', {
event_category: 'top_banner',
event_label: bannerHref,
});
}}
>
</a>
</>
) : null
}
type="info"
banner

View File

@@ -2,6 +2,7 @@ import * as React from 'react';
import type { DirectionType } from 'antd/es/config-provider';
import type { ThemeName } from '../common/ThemeSwitch';
import { getBannerData } from '../../pages/index/components/util';
export interface SiteContextProps {
isMobile: boolean;
@@ -13,7 +14,7 @@ export interface SiteContextProps {
const SiteContext = React.createContext<SiteContextProps>({
isMobile: false,
bannerVisible: false,
bannerVisible: !!getBannerData(),
direction: 'ltr',
theme: ['light'],
updateSiteConfig: () => {},

View File

@@ -1,6 +1,7 @@
import semver from 'semver';
import flatten from 'lodash/flatten';
import flattenDeep from 'lodash/flattenDeep';
import semver from 'semver';
import deprecatedVersions from '../../../BUG_VERSIONS.json';
import themeConfig from '../themeConfig';
@@ -157,19 +158,6 @@ export function getLocalizedPathname(
return { pathname: fullPath, search };
}
export function isLocalStorageNameSupported() {
const testKey = 'test';
const storage = window.localStorage;
try {
storage.setItem(testKey, '1');
storage.removeItem(testKey);
return true;
} catch (error) {
console.error('Your web browser does not support storing settings locally.', error);
return false;
}
}
export function loadScript(src: string) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
@@ -177,7 +165,7 @@ export function loadScript(src: string) {
script.src = src;
script.onload = resolve;
script.onerror = reject;
document.head!.appendChild(script);
document.head.appendChild(script);
});
}

View File

@@ -131,17 +131,6 @@ export default defineConfig({
headScripts: [
`
(function () {
function isLocalStorageNameSupported() {
const testKey = 'test';
const storage = window.localStorage;
try {
storage.setItem(testKey, '1');
storage.removeItem(testKey);
return true;
} catch (error) {
return false;
}
}
// 优先级提高到所有静态资源的前面,语言不对,加载其他静态资源没意义
const pathname = location.pathname;
@@ -171,7 +160,7 @@ export default defineConfig({
}
// 首页无视链接里面的语言设置 https://github.com/ant-design/ant-design/issues/4552
if (isLocalStorageNameSupported() && (pathname === '/' || pathname === '/index-cn')) {
if (pathname === '/' || pathname === '/index-cn') {
const lang =
(window.localStorage && localStorage.getItem('locale')) ||
((navigator.language || navigator.browserLanguage).toLowerCase() === 'zh-cn'

View File

@@ -39,7 +39,9 @@ jobs:
const now = new Date();
for (const issue of issues) {
if (issue.pull_request) continue;
if (issue.pull_request) {
continue;
}
const updatedAt = new Date(issue.updated_at);
const daysInactive = (now - updatedAt) / (1000 * 60 * 60 * 24);

View File

@@ -30,7 +30,7 @@ jobs:
- name: run e2e test
run: bun run test:site
- name: upload site artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: site
path: _site/
@@ -42,7 +42,7 @@ jobs:
- name: Upload PR number
if: ${{ always() }}
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: pr
path: ./pr-id.txt

View File

@@ -41,7 +41,9 @@ jobs:
}, {});
const total = Object.keys(jobs).length;
if(total === 0) core.setFailed('no jobs found');
if (total === 0) {
core.setFailed('no jobs found');
}
// the name here must be the same as `jobs.xxx.{name}` in preview-build.yml
// set output

View File

@@ -45,7 +45,7 @@ jobs:
fi
- name: upload site artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: real-site
path: _site/
@@ -63,7 +63,7 @@ jobs:
- uses: oven-sh/setup-bun@v2
- name: download site artifact
uses: actions/download-artifact@v5
uses: actions/download-artifact@v6
with:
name: real-site
path: _site
@@ -105,7 +105,7 @@ jobs:
needs: build-site
steps:
- name: download site artifact
uses: actions/download-artifact@v5
uses: actions/download-artifact@v6
with:
name: real-site
path: _site
@@ -117,7 +117,7 @@ jobs:
cd ..
- name: Upload to Release
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090 # v2.4.1
uses: softprops/action-gh-release@5be0e66d93ac7ed76da52eca8bb058f665c3a5fe # v2.4.2
with:
fail_on_unmatched_files: true
files: website.tar.gz

View File

@@ -76,7 +76,7 @@ jobs:
mkdir persist-coverage
mv coverage/coverage-final.json persist-coverage/react-test-${{matrix.module}}-${{strategy.job-index}}.json
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v5
name: upload coverages
with:
name: coverage-artifacts-${{ matrix.module }}-${{ strategy.job-index }}
@@ -123,7 +123,7 @@ jobs:
- uses: oven-sh/setup-bun@v2
- run: bun install
- uses: actions/download-artifact@v5
- uses: actions/download-artifact@v6
with:
pattern: coverage-artifacts-*
merge-multiple: true
@@ -179,7 +179,7 @@ jobs:
run: bun run test:dekko
# Artifact build files
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v5
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
with:
name: build artifacts

View File

@@ -79,7 +79,7 @@ jobs:
mkdir persist-coverage
mv coverage/coverage-final.json persist-coverage/react-test-${{matrix.module}}-${{strategy.job-index}}.json
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v5
name: upload coverages
with:
name: coverage-artifacts-${{ matrix.module }}-${{ strategy.job-index }}
@@ -126,7 +126,7 @@ jobs:
- uses: oven-sh/setup-bun@v2
- run: bun install
- uses: actions/download-artifact@v5
- uses: actions/download-artifact@v6
with:
pattern: coverage-artifacts-*
merge-multiple: true
@@ -182,7 +182,7 @@ jobs:
run: bun run test:dekko
# Artifact build files
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v5
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
with:
name: build artifacts

View File

@@ -37,7 +37,7 @@ jobs:
env:
NODE_OPTIONS: --max_old_space_size=4096
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v5
name: artifact snapshot
with:
name: snapshot-artifacts-${{ strategy.job-index }}
@@ -54,7 +54,7 @@ jobs:
- uses: oven-sh/setup-bun@v2
- run: bun install
- uses: actions/download-artifact@v5
- uses: actions/download-artifact@v6
with:
pattern: snapshot-artifacts-*
merge-multiple: true
@@ -71,7 +71,7 @@ jobs:
# Upload report in `visualRegressionReport`
- name: upload report artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
if: ${{ always() }}
with:
name: visual-regression-report
@@ -85,7 +85,7 @@ jobs:
- name: Upload persist key
if: ${{ always() }}
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: visual-regression-diff-ref
path: ./visual-regression-pr-id.txt

View File

@@ -43,7 +43,9 @@ jobs:
}, {});
const total = Object.keys(jobs).length;
if(total === 0) core.setFailed('no jobs found');
if (total === 0) {
core.setFailed('no jobs found');
}
// the name here must be the same as `jobs.xxx.{name}`
console.log('visual-diff report job status: %s', jobs['visual-diff report'].status);

View File

@@ -40,7 +40,9 @@ jobs:
}, {});
const total = Object.keys(jobs).length;
if(total === 0) core.setFailed('no jobs found');
if (total === 0) {
core.setFailed('no jobs found');
}
// the name here must be the same as `jobs.xxx.{name}`
console.log('visual-diff report job status: %s', jobs['test image']);

View File

@@ -31,7 +31,7 @@ jobs:
# Upload `imageSnapshots` on master
- name: upload report artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: image-snapshots
path: imageSnapshots.tar.gz
@@ -43,7 +43,7 @@ jobs:
- name: Upload persist key
if: ${{ always() }}
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: visual-regression-ref
path: ./visual-regression-ref.txt

View File

@@ -15,6 +15,56 @@ tag: vVERSION
---
## 5.28.1
`2025-11-10`
- Carousel
- 🐞 Fix Carousel style issue in vertical mode. [#55615](https://github.com/ant-design/ant-design/pull/55615) [@wanpan11](https://github.com/wanpan11)
- 🐞 Fix Carousel dots animation missing when first render. [#55589](https://github.com/ant-design/ant-design/pull/55589) [@wanpan11](https://github.com/wanpan11)
- 🐞 Fix Descriptions where content style wrongly used `labelStyle`. [#55572](https://github.com/ant-design/ant-design/pull/55572) [@li-jia-nan](https://github.com/li-jia-nan)
- 💄 Adjust the height of the Select component to 32px when `variant="underlined"`. [#55607](https://github.com/ant-design/ant-design/pull/55607) [@ustcfury](https://github.com/ustcfury)
- 💄 When the `underlined` property is enabled for the Input component, the border color changes on mouse hover. [#55609](https://github.com/ant-design/ant-design/pull/55609) [@ustcfury](https://github.com/ustcfury)
- 🛠 Flex `gap` prop support number type. [#55591](https://github.com/ant-design/ant-design/pull/55591) [@ayangweb](https://github.com/ayangweb)
- 🌐 Add missing TimePicker translations for locales: ar_EG, en_GB, gl_ES, bg_BG, ca_ES, cs_CZ, el_GR, es_ES, eu_ES, fi_FI, he_IL, hu_HU, is_IS, kn_IN, kmr_IQ, lv_LV, mk_MK, mn_MN, ms_MY, pl_PL, pt_BR, pt_PT, ro_RO, sk_SK, sl_SI, sv_SE, ta_IN, th_TH, zh_TW, et_EE. [#55656](https://github.com/ant-design/ant-design/pull/55656) [@li-jia-nan](https://github.com/li-jia-nan)
## 5.28.0
`2025-11-01`
- 🆕 Drawer supports `closable.placement` prop to specify the position of the close button. [#54067](https://github.com/ant-design/ant-design/pull/54067) [@davidhsing](https://github.com/davidhsing)
- 🆕 Image component supports `fallback` global configuration. [#54702](https://github.com/ant-design/ant-design/pull/54702) [@Jiyur](https://github.com/Jiyur)
- 🆕 QRCode component supports `boostLevel` prop. [#55063](https://github.com/ant-design/ant-design/pull/55063) [@li-jia-nan](https://github.com/li-jia-nan)
- 🆕 Splitter supports `onCollapse` prop. [#54673](https://github.com/ant-design/ant-design/pull/54673) [@ug-hero](https://github.com/ug-hero)
- 🆕 Statistic displays animation effect by default when set to `loading`. [#55398](https://github.com/ant-design/ant-design/pull/55398) [@afc163](https://github.com/afc163)
- 🆕 TreeSelect supports global configuration for switcher icon. [#54821](https://github.com/ant-design/ant-design/pull/54821) [@Jiyur](https://github.com/Jiyur)
- Segmented
- 💄 Segmented theme variable `itemSelectedBg` supports background gradient. [#55391](https://github.com/ant-design/ant-design/pull/55391) [@zancheng](https://github.com/zancheng)
- 🐞 Fix Segmented abnormal animation after React DevTools upgrade. [#55438](https://github.com/ant-design/ant-design/pull/55438) [@afc163](https://github.com/afc163)
- 🐞 Fix Tree and Transfer components `disabled` inheritance issue. [#54831](https://github.com/ant-design/ant-design/pull/54831) [@cactuser-Lu](https://github.com/cactuser-Lu)
- 🐞 Fix Tree.DirectoryTree `defaultExpandAll` not working when `fieldNames` is defined. [#55420](https://github.com/ant-design/ant-design/pull/55420) [@Wxh16144](https://github.com/Wxh16144)
- Upload
- 🆕 Upload component adds `info.defaultRequest` in `customRequest` parameters. [#55146](https://github.com/ant-design/ant-design/pull/55146) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
- 💄 Upload component supports `pictureCardSize` token. [#54756](https://github.com/ant-design/ant-design/pull/54756) [@wanpan11](https://github.com/wanpan11)
- 💄 Notification supports configuring background color token. [#54802](https://github.com/ant-design/ant-design/pull/54802) [@thinkasany](https://github.com/thinkasany)
- 💄 Pagination supports modifying the text color of active items through `itemActiveColor` and `itemActiveColorHover` tokens. [#55195](https://github.com/ant-design/ant-design/pull/55195) [@Renderz](https://github.com/Renderz)
- 🐞 Fix Select, DatePicker, TreeSelect, Cascader and other components not showing default suffix icon when `suffixIcon` is configured as undefined. [#54790](https://github.com/ant-design/ant-design/pull/54790) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
- 🐞 Fix Mentions component not inheriting `disabled` from external Form. [#54829](https://github.com/ant-design/ant-design/pull/54829) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
- 🐞 Fix Watermark component crashing when wrapping Modal with `modalRender`. [#55435](https://github.com/ant-design/ant-design/pull/55435) [@ug-hero](https://github.com/ug-hero)
- 🗑 Input component deprecates `addonAfter` and `addonBefore` props, use Space.Compact instead. [#55315](https://github.com/ant-design/ant-design/pull/55315) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
- 🤖 Row component `gutter` prop supports string type definition. [#54628](https://github.com/ant-design/ant-design/pull/54628) [@ug-hero](https://github.com/ug-hero)
## 5.27.6
`2025-10-20`
- 🐞 Fix Table `pagination.align` is not working. [#55316](https://github.com/ant-design/ant-design/pull/55316)
- 🛠 Refactor Modal useMemo of ConfirmDialog to resolve useMemo invalid where Object.values generates a new array. [#55376](https://github.com/ant-design/ant-design/pull/55376)
- TypeScript
- 🤖 Add ConfigProvider the `Window` type definition in `getTargetContainer` of . [#55313](https://github.com/ant-design/ant-design/pull/55313)
- 🤖 Add ConfigProvider the `ShadowRoot` type definition in `getTargetContainer` and `getPopupContainer`. [#55278](https://github.com/ant-design/ant-design/pull/55278) [@leshalv](https://github.com/leshalv)
- 🤖 Improve Modal type definition. [#55371](https://github.com/ant-design/ant-design/pull/55371)
## 5.27.5
`2025-10-14`

View File

@@ -15,6 +15,57 @@ tag: vVERSION
---
## 5.28.1
`2025-11-10`
- Carousel
- 🐞 修复 Carousel 组件纵向样式问题。[#55615](https://github.com/ant-design/ant-design/pull/55615) [@wanpan11](https://github.com/wanpan11)
- 🐞 修复 Carousel 首次渲染时指示点动画丢失。[#55589](https://github.com/ant-design/ant-design/pull/55589) [@wanpan11](https://github.com/wanpan11)
- 🐞 修复 Popconfirm 在 `actionFn` 出错时未重置 ref 的问题。[#55519](https://github.com/ant-design/ant-design/pull/55519) [@Taoister39](https://github.com/Taoister39)
- 🐞 修复 Descriptions 组件内容样式错误使用 `labelStyle` 的问题。[#55572](https://github.com/ant-design/ant-design/pull/55572) [@li-jia-nan](https://github.com/li-jia-nan)
- 💄 修正 `underlined` 变体的 Select 组件高度为 32px。[#55607](https://github.com/ant-design/ant-design/pull/55607) [@ustcfury](https://github.com/ustcfury)
- 💄 为 `underlined` 变体的 Input 组件补全 hover 边框颜色样式。[#55609](https://github.com/ant-design/ant-design/pull/55609) [@ustcfury](https://github.com/ustcfury)
- 🛠 Flex `gap` 属性支持 number 类型。[#55591](https://github.com/ant-design/ant-design/pull/55591) [@ayangweb](https://github.com/ayangweb)
- 🌐 补充 TimePicker 多语言翻译覆盖以下语言ar_EG、en_GB、gl_ES、bg_BG、ca_ES、cs_CZ、el_GR、es_ES、eu_ES、fi_FI、he_IL、hu_HU、is_IS、kn_IN、kmr_IQ、lv_LV、mk_MK、mn_MN、ms_MY、pl_PL、pt_BR、pt_PT、ro_RO、sk_SK、sl_SI、sv_SE、ta_IN、th_TH、zh_TW、et_EE。[#55656](https://github.com/ant-design/ant-design/pull/55656) [@li-jia-nan](https://github.com/li-jia-nan)
## 5.28.0
`2025-11-01`
- 🆕 Drawer 支持 `closable.placement` 属性,用于指定关闭按钮的位置。[#54067](https://github.com/ant-design/ant-design/pull/54067) [@davidhsing](https://github.com/davidhsing)
- 🆕 Image 组件支持 `fallback` 全局配置。[#54702](https://github.com/ant-design/ant-design/pull/54702) [@Jiyur](https://github.com/Jiyur)
- 🆕 QRCode 组件支持 `boostLevel` 属性。[#55063](https://github.com/ant-design/ant-design/pull/55063) [@li-jia-nan](https://github.com/li-jia-nan)
- 🆕 Splitter 支持 `onCollapse` 属性。[#54673](https://github.com/ant-design/ant-design/pull/54673) [@ug-hero](https://github.com/ug-hero)
- 🆕 Statistic 设置为 `loading` 时默认展现动画效果。[#55398](https://github.com/ant-design/ant-design/pull/55398) [@afc163](https://github.com/afc163)
- 🆕 TreeSelect 支持切换器图标的全局配置。[#54821](https://github.com/ant-design/ant-design/pull/54821) [@Jiyur](https://github.com/Jiyur)
- Segmented
- 💄 Segmented 的主题变量 `itemSelectedBg` 支持背景渐变。[#55391](https://github.com/ant-design/ant-design/pull/55391) [@zancheng](https://github.com/zancheng)
- 🐞 修复 Segmented 切换动画总是从第一项移动闪烁的问题。[#55438](https://github.com/ant-design/ant-design/pull/55438) [@afc163](https://github.com/afc163)
- 🐞 修复 Tree 和 Transfer 组件的 `disabled` 继承问题。[#54831](https://github.com/ant-design/ant-design/pull/54831) [@cactuser-Lu](https://github.com/cactuser-Lu)
- 🐞 修复 Tree.DirectoryTree 定义 `fieldNames``defaultExpandAll` 不生效的问题。[#55420](https://github.com/ant-design/ant-design/pull/55420) [@Wxh16144](https://github.com/Wxh16144)
- Upload
- 🆕 Upload 组件 `customRequest` 参数中增加 `info.defaultRequest`。[#55146](https://github.com/ant-design/ant-design/pull/55146) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
- 💄 Upload 组件支持 `pictureCardSize` token。[#54756](https://github.com/ant-design/ant-design/pull/54756) [@wanpan11](https://github.com/wanpan11)
- 💄 Notification 支持配置背景颜色的 token。[#54802](https://github.com/ant-design/ant-design/pull/54802) [@thinkasany](https://github.com/thinkasany)
- 💄 Pagination 支持通过 `itemActiveColor``itemActiveColorHover` token 修改高亮项的文字颜色。[#55195](https://github.com/ant-design/ant-design/pull/55195) [@Renderz](https://github.com/Renderz)
- 🐞 修复 Select、DatePicker、TreeSelect、Cascader 等组件 `suffixIcon` 配置值为 undefined 时没有默认后缀图标的问题。[#54790](https://github.com/ant-design/ant-design/pull/54790) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
- 🐞 修复 Mentions 组件没有继承外部 Form 的 `disabled` 的问题。[#54829](https://github.com/ant-design/ant-design/pull/54829) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
- 🐞 修复 Watermark 组件内包裹 Modal 使用 `modalRender` 会导致崩溃的问题。[#55435](https://github.com/ant-design/ant-design/pull/55435) [@ug-hero](https://github.com/ug-hero)
- 🗑 Input 组件废弃 `addonAfter``addonBefore` 属性,使用 Space.Compact 替换。[#55315](https://github.com/ant-design/ant-design/pull/55315) [@EmilyyyLiu](https://github.com/EmilyyyLiu)
- 🤖 Row 组件 `gutter` 属性支持 string 类型定义。[#54628](https://github.com/ant-design/ant-design/pull/54628) [@ug-hero](https://github.com/ug-hero)
## 5.27.6
`2025-10-20`
- 🐞 修复 Table `pagination.align` 属性失效的问题。[#55316](https://github.com/ant-design/ant-design/pull/55316)
- 🛠 重构 Modal 中 ConfirmDialog 的 useMemo以解决 Object.values 生成新数组导致 useMemo 失效的问题。[#55376](https://github.com/ant-design/ant-design/pull/55376)
- TypeScript
- 🤖 补充 ConfigProvider `getTargetContainer``Window` 类型定义。[#55313](https://github.com/ant-design/ant-design/pull/55313)
- 🤖 补充 ConfigProvider 的 `getTargetContainer``getPopupContainer``ShadowRoot` 类型定义。[#55278](https://github.com/ant-design/ant-design/pull/55278) [@leshalv](https://github.com/leshalv)
- 🤖 优化 Modal 中类型定义。[#55371](https://github.com/ant-design/ant-design/pull/55371)
## 5.27.5
`2025-10-14`
@@ -36,7 +87,7 @@ tag: vVERSION
- 🐞 修复 Table 在使 `sticky` 表头或设置 `scroll.y` 时,筛选下拉与 Tooltip 重复显示的问题。[#54910](https://github.com/ant-design/ant-design/pull/54910) [@afc163](https://github.com/afc163)
- 🐞 修复 Table 表头在首次加载时未正确渲染的问题。[#54910](https://github.com/ant-design/ant-design/pull/54910) [@afc163](https://github.com/afc163)
- 🐞 修复 Table 在启用 `scroll.x` 时,固定列的对齐问题。[#54899](https://github.com/ant-design/ant-design/pull/54899) [@afc163](https://github.com/afc163)
- 🐞 修复 Button 仅图标icon-only按钮的内边距受主题影响的问题。 [#54970](https://github.com/ant-design/ant-design/pull/54970) [@guoyunhe](https://github.com/guoyunhe)
- 🐞 修复 Button 仅图标icon-only按钮的内边距受主题影响的问题。[#54970](https://github.com/ant-design/ant-design/pull/54970) [@guoyunhe](https://github.com/guoyunhe)
- 🐞 修复 Splitter 在非受控模式下初次挂载时,`minSize``maxSize` 未生效的问题。[#54939](https://github.com/ant-design/ant-design/pull/54939) [@zombieJ](https://github.com/zombieJ)
- 🐞 修复 Switch 波纹效果与 Tailwind CSS disabled 变体的兼容性问题。[#54933](https://github.com/ant-design/ant-design/pull/54933) [@Jiyur](https://github.com/Jiyur)
- 🐞 修复 Input.Search 在搜索按钮为 `disabled` 时,悬停仍会导致边框和图标变色的问题。[#54892](https://github.com/ant-design/ant-design/pull/54892) [@Jiyur](https://github.com/Jiyur)

View File

@@ -15,7 +15,8 @@
"!scripts/previewEditor/**/*",
"!**/*.tmp",
"!package.json",
"!components/style/antd.css"
"!components/style/antd.css",
"!scripts/visual-regression/report-template.html"
]
},
"formatter": {
@@ -57,6 +58,7 @@
"noExplicitAny": "off",
"noArrayIndexKey": "off",
"noConfusingVoidType": "off",
"noNonNullAssertedOptionalChain": "off",
"noThenProperty": "off",
"noTemplateCurlyInString": "off",
"useIterableCallbackReturn": "off",

View File

@@ -67,7 +67,7 @@ const genPurePanel = <ComponentProps extends BaseProps = BaseProps>(
resizeObserver.disconnect();
};
}
}, []);
}, [prefixCls]);
let mergedProps: WrapProps = {
...props,

View File

@@ -2,8 +2,8 @@ import React, { useEffect } from 'react';
import { CloseOutlined } from '@ant-design/icons';
import { render } from '@testing-library/react';
import { useClosable } from '../hooks';
import type { UseClosableParams } from '../hooks/useClosable';
import useClosable from '../hooks/useClosable';
type ParamsOfUseClosable = [
closable: UseClosableParams['closable'],

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { fireEvent, render } from '../../../tests/utils';
import useSyncState from '../hooks/useSyncState';
import { useSyncState } from '../hooks';
describe('Table', () => {
it('useSyncState', () => {

View File

@@ -1,56 +0,0 @@
import React from 'react';
import { act, render } from '../../../tests/utils';
import useUniqueMemo from '../hooks/useUniqueMemo';
describe('Table', () => {
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.clearAllTimers();
jest.useRealTimers();
});
it('useSyncState', () => {
const sharedObjDeps1 = {};
const sharedObjDeps2 = {};
let calledTimes = 0;
const Test: React.FC<{ depName?: string }> = ({ depName }) => {
useUniqueMemo(() => {
calledTimes += 1;
return depName;
}, [depName, sharedObjDeps1, 'bamboo', sharedObjDeps2]);
return null;
};
// Reuse the same memo
const { rerender } = render(
<>
<Test depName="light" />
<Test depName="light" />
<Test depName="light" />
</>,
);
expect(calledTimes).toBe(1);
// Different deps should clean up the cache
act(() => {
jest.advanceTimersByTime(1000 * 60 * 20);
});
for (let i = 0; i < 20000; i += 1) {
rerender(<Test depName="diff" key={i} />);
}
rerender(<Test depName="clear" />);
calledTimes = 0;
// Back should recompute
rerender(<Test depName="light" />);
expect(calledTimes).toBe(1);
});
});

View File

@@ -300,7 +300,7 @@ describe('Test useZIndex hooks', () => {
if (['SelectLike', 'DatePicker', 'ImagePreview'].includes(key)) {
let comps = document.querySelectorAll<HTMLElement>(selector1);
comps.forEach((comp) => {
expect(comp?.style.zIndex).toBeFalsy();
expect(comp).toHaveStyle({ zIndex: '' });
});
comps = document.querySelectorAll<HTMLElement>(selector2);
comps.forEach((comp) => {
@@ -311,9 +311,9 @@ describe('Test useZIndex hooks', () => {
const operOffset = comp.classList.contains('ant-image-preview-operations-wrapper')
? 1
: 0;
expect(comp?.style.zIndex).toBe(
String(1000 + containerZIndexValue + consumerOffset + operOffset),
);
expect(comp).toHaveStyle({
zIndex: 1000 + containerZIndexValue + consumerOffset + operOffset,
});
});
comps = document.querySelectorAll<HTMLElement>(selector3);
@@ -325,21 +325,21 @@ describe('Test useZIndex hooks', () => {
const operOffset = comp.classList.contains('ant-image-preview-operations-wrapper')
? 1
: 0;
expect(comp?.style.zIndex).toBe(
String(1000 + containerZIndexValue * 2 + consumerOffset + operOffset),
);
expect(comp).toHaveStyle({
zIndex: 1000 + containerZIndexValue * 2 + consumerOffset + operOffset,
});
});
} else {
const element1 = document.querySelector<HTMLElement>(selector1);
const element2 = document.querySelector<HTMLElement>(selector2);
const element3 = document.querySelector<HTMLElement>(selector3);
expect(element1?.style.zIndex).toBe(key === 'Tour' ? '1001' : '');
expect(element2?.style.zIndex).toBe(
String(1000 + containerZIndexValue + consumerZIndexValue),
);
expect(element3?.style.zIndex).toBe(
String(1000 + containerZIndexValue * 2 + consumerZIndexValue),
);
expect(element1).toHaveStyle({ zIndex: key === 'Tour' ? 1001 : '' });
expect(element2).toHaveStyle({
zIndex: 1000 + containerZIndexValue + consumerZIndexValue,
});
expect(element3).toHaveStyle({
zIndex: 1000 + containerZIndexValue * 2 + consumerZIndexValue,
});
}
unmount();
}, 20000);
@@ -399,16 +399,14 @@ describe('Test useZIndex hooks', () => {
<FloatButton />
</WrapWithProvider>,
);
expect(container.querySelector<HTMLElement>('.ant-float-btn')?.style.zIndex).toBe(
// parentZIndex + containerBaseZIndexOffset["FloatButton"]
String(1100 + containerBaseZIndexOffset.FloatButton),
);
const ele = container.querySelector<HTMLElement>('.ant-float-btn');
expect(ele).toHaveStyle({ zIndex: 1100 + containerBaseZIndexOffset.FloatButton });
rerender(
<WrapWithProvider container="FloatButton">
<FloatButton style={{ zIndex: 666 }} />
</WrapWithProvider>,
);
expect(container.querySelector<HTMLElement>('.ant-float-btn')?.style.zIndex).toBe(String(666));
expect(ele).toHaveStyle({ zIndex: 666 });
});
it('not warning for static func', () => {

View File

@@ -0,0 +1,8 @@
export * from './useClosable';
export * from './useForceUpdate';
export * from './useMergeSemantic';
export * from './useMultipleSelect';
export * from './usePatchElement';
export * from './useProxyImperativeHandle';
export * from './useSyncState';
export * from './useZIndex';

View File

@@ -56,10 +56,7 @@ function useClosableConfig(closableCollection?: ClosableCollection | null) {
closeIcon: typeof closeIcon !== 'boolean' && closeIcon !== null ? closeIcon : undefined,
};
if (closable && typeof closable === 'object') {
closableConfig = {
...closableConfig,
...closable,
};
closableConfig = { ...closableConfig, ...closable };
}
return closableConfig;
}, [closable, closeIcon]);
@@ -82,7 +79,7 @@ interface FallbackCloseCollection extends ClosableCollection {
/** Use same object to support `useMemo` optimization */
const EmptyFallbackCloseCollection: FallbackCloseCollection = {};
export default function useClosable(
export const useClosable = (
propCloseCollection?: ClosableCollection,
contextCloseCollection?: ClosableCollection | null,
fallbackCloseCollection: FallbackCloseCollection = EmptyFallbackCloseCollection,
@@ -91,7 +88,7 @@ export default function useClosable(
closeIcon: React.ReactNode,
closeBtnIsDisabled: boolean,
ariaOrDataProps?: HTMLAriaDataAttributes,
] {
] => {
// Align the `props`, `context` `fallback` to config object first
const propCloseConfig = useClosableConfig(propCloseCollection);
const contextCloseConfig = useClosableConfig(contextCloseCollection);
@@ -172,4 +169,4 @@ export default function useClosable(
mergedClosableConfig,
mergedFallbackCloseCollection,
]);
}
};

View File

@@ -1,6 +1,5 @@
import * as React from 'react';
import React from 'react';
export default function useForceUpdate() {
const [, forceUpdate] = React.useReducer((x) => x + 1, 0);
return forceUpdate;
}
export const useForceUpdate = () => {
return React.useReducer((ori) => ori + 1, 0);
};

View File

@@ -1,13 +1,11 @@
import * as React from 'react';
import classnames from 'classnames';
import type { ValidChar } from './interface';
import type { ValidChar } from '../type';
type TemplateSemanticClassNames<T extends string> = Partial<Record<T, string>>;
export type SemanticSchema = {
_default?: string;
} & {
export type SemanticSchema = { _default?: string } & {
[key: `${ValidChar}${string}`]: SemanticSchema;
};
@@ -15,7 +13,7 @@ export type SemanticSchema = {
export function mergeClassNames<
T extends string,
SemanticClassNames extends Partial<Record<T, any>> = TemplateSemanticClassNames<T>,
>(schema: SemanticSchema | undefined, ...classNames: (SemanticClassNames | undefined)[]) {
>(schema?: SemanticSchema, ...classNames: (SemanticClassNames | undefined)[]) {
const mergedSchema = schema || {};
return classNames.reduce((acc: any, cur) => {
@@ -31,8 +29,10 @@ export function mergeClassNames<
} else {
// Covert string to object structure
const { _default: defaultField } = keySchema;
acc[key] = acc[key] || {};
acc[key][defaultField!] = classnames(acc[key][defaultField!], curVal);
if (defaultField) {
acc[key] = acc[key] || {};
acc[key][defaultField] = classnames(acc[key][defaultField], curVal);
}
}
} else {
// Flatten fill
@@ -40,16 +40,16 @@ export function mergeClassNames<
}
});
return acc;
}, {} as SemanticClassNames) as SemanticClassNames;
}, {} as SemanticClassNames);
}
function useSemanticClassNames<ClassNamesType extends object>(
schema: SemanticSchema | undefined,
schema?: SemanticSchema,
...classNames: (Partial<ClassNamesType> | undefined)[]
): Partial<ClassNamesType> {
return React.useMemo(
() => mergeClassNames(schema, ...classNames),
[classNames],
[classNames, schema],
) as ClassNamesType;
}
@@ -58,31 +58,25 @@ function useSemanticStyles<StylesType extends object>(
...styles: (Partial<StylesType> | undefined)[]
) {
return React.useMemo(() => {
return styles.reduce(
(acc, cur = {}) => {
Object.keys(cur).forEach((key) => {
acc[key] = { ...acc[key], ...(cur as Record<string, React.CSSProperties>)[key] };
});
return acc;
},
{} as Record<string, React.CSSProperties>,
);
return styles.reduce<Record<string, React.CSSProperties>>((acc, cur = {}) => {
Object.keys(cur).forEach((key) => {
acc[key] = { ...acc[key], ...(cur as Record<string, React.CSSProperties>)[key] };
});
return acc;
}, {});
}, [styles]) as StylesType;
}
// =========================== Export ===========================
function fillObjectBySchema<T extends object>(obj: T, schema: SemanticSchema): T {
const newObj: any = { ...obj };
Object.keys(schema).forEach((key) => {
if (key !== '_default') {
const nestSchema = (schema as any)[key] as SemanticSchema;
const nextValue = newObj[key] || {};
newObj[key] = nestSchema ? fillObjectBySchema(nextValue, nestSchema) : nextValue;
}
});
return newObj;
}
@@ -90,18 +84,17 @@ function fillObjectBySchema<T extends object>(obj: T, schema: SemanticSchema): T
* Merge classNames and styles from multiple sources.
* When `schema` is provided, it will **must** provide the nest object structure.
*/
export default function useMergeSemantic<ClassNamesType extends object, StylesType extends object>(
export const useMergeSemantic = <ClassNamesType extends object, StylesType extends object>(
classNamesList: (ClassNamesType | undefined)[],
stylesList: (StylesType | undefined)[],
schema?: SemanticSchema,
) {
) => {
const mergedClassNames = useSemanticClassNames(schema, ...classNamesList) as ClassNamesType;
const mergedStyles = useSemanticStyles(...stylesList) as StylesType;
return React.useMemo(() => {
return [
fillObjectBySchema(mergedClassNames, schema!) as ClassNamesType,
fillObjectBySchema(mergedStyles, schema!) as StylesType,
] as const;
}, [mergedClassNames, mergedStyles]);
}
}, [mergedClassNames, mergedStyles, schema]);
};

View File

@@ -1,27 +0,0 @@
export type ValidChar =
| 'a'
| 'b'
| 'c'
| 'd'
| 'e'
| 'f'
| 'g'
| 'h'
| 'i'
| 'j'
| 'k'
| 'l'
| 'm'
| 'n'
| 'o'
| 'p'
| 'q'
| 'r'
| 's'
| 't'
| 'u'
| 'v'
| 'w'
| 'x'
| 'y'
| 'z';

View File

@@ -6,7 +6,7 @@ export type PrevSelectedIndex = null | number;
* @title multipleSelect hooks
* @description multipleSelect by hold down shift key
*/
export default function useMultipleSelect<T, K>(getKey: (item: T) => K) {
export const useMultipleSelect = <T, K>(getKey: (item: T, index: number, array: T[]) => K) => {
const [prevSelectedIndex, setPrevSelectedIndex] = useState<PrevSelectedIndex>(null);
const multipleSelect = useCallback(
@@ -16,7 +16,7 @@ export default function useMultipleSelect<T, K>(getKey: (item: T) => K) {
// add/delete the selected range
const startIndex = Math.min(configPrevSelectedIndex || 0, currentSelectedIndex);
const endIndex = Math.max(configPrevSelectedIndex || 0, currentSelectedIndex);
const rangeKeys = data.slice(startIndex, endIndex + 1).map((item) => getKey(item));
const rangeKeys = data.slice(startIndex, endIndex + 1).map<K>(getKey);
const shouldSelected = rangeKeys.some((rangeKey) => !selectedKeys.has(rangeKey));
const changedKeys: K[] = [];
@@ -39,9 +39,5 @@ export default function useMultipleSelect<T, K>(getKey: (item: T) => K) {
[prevSelectedIndex],
);
const updatePrevSelectedIndex = (val: PrevSelectedIndex) => {
setPrevSelectedIndex(val);
};
return [multipleSelect, updatePrevSelectedIndex] as const;
}
return [multipleSelect, setPrevSelectedIndex] as const;
};

View File

@@ -1,9 +1,9 @@
import * as React from 'react';
export default function usePatchElement(): [
export const usePatchElement = (): [
React.ReactElement[],
(element: React.ReactElement) => () => void,
] {
] => {
const [elements, setElements] = React.useState<React.ReactElement[]>([]);
const patchElement = React.useCallback((element: React.ReactElement) => {
@@ -18,4 +18,4 @@ export default function usePatchElement(): [
}, []);
return [elements, patchElement];
}
};

View File

@@ -22,10 +22,13 @@ function fillProxy(
return element;
}
export default function useProxyImperativeHandle<
export const useProxyImperativeHandle = <
NativeELementType extends HTMLElement,
ReturnRefType extends { nativeElement: NativeELementType },
>(ref: Ref<any> | undefined, init: () => ReturnRefType) {
>(
ref: Ref<any> | undefined,
init: () => ReturnRefType,
) => {
return useImperativeHandle(ref, () => {
const refObj = init();
const { nativeElement } = refObj;
@@ -45,4 +48,4 @@ export default function useProxyImperativeHandle<
// Fallback of IE
return fillProxy(nativeElement, refObj);
});
}
};

View File

@@ -1,13 +1,12 @@
import * as React from 'react';
import useForceUpdate from './useForceUpdate';
import { useForceUpdate } from './useForceUpdate';
type UseSyncStateProps<T> = readonly [() => T, (newValue: T) => void];
export default function useSyncState<T>(initialValue: T): UseSyncStateProps<T> {
export const useSyncState = <T>(initialValue: T): UseSyncStateProps<T> => {
const ref = React.useRef<T>(initialValue);
const forceUpdate = useForceUpdate();
const [, forceUpdate] = useForceUpdate();
return [
() => ref.current,
(newValue: T) => {
@@ -16,4 +15,4 @@ export default function useSyncState<T>(initialValue: T): UseSyncStateProps<T> {
forceUpdate();
},
] as const;
}
};

View File

@@ -1,97 +0,0 @@
import React from 'react';
const BEAT_LIMIT = 1000 * 60 * 10;
/**
* A helper class to map keys to values.
* It supports both primitive keys and object keys.
*/
class ArrayKeyMap<T> {
map = new Map<string, T>();
// Use WeakMap to avoid memory leak
objectIDMap = new WeakMap<object, number>();
nextID = 0;
lastAccessBeat = new Map<string, number>();
// We will clean up the cache when reach the limit
accessBeat = 0;
set(keys: React.DependencyList, value: any) {
// New set will trigger clear
this.clear();
// Set logic
const compositeKey = this.getCompositeKey(keys);
this.map.set(compositeKey, value);
this.lastAccessBeat.set(compositeKey, Date.now());
}
get(keys: React.DependencyList) {
const compositeKey = this.getCompositeKey(keys);
const cache = this.map.get(compositeKey);
this.lastAccessBeat.set(compositeKey, Date.now());
this.accessBeat += 1;
return cache;
}
getCompositeKey(keys: React.DependencyList) {
const ids = keys.map<string>((key) => {
if (key && typeof key === 'object') {
return `obj_${this.getObjectID(key)}`;
}
return `${typeof key}_${key}`;
});
return ids.join('|');
}
getObjectID(obj: object) {
if (this.objectIDMap.has(obj)) {
return this.objectIDMap.get(obj);
}
const id = this.nextID;
this.objectIDMap.set(obj, id);
this.nextID += 1;
return id;
}
clear() {
if (this.accessBeat > 10000) {
const now = Date.now();
this.lastAccessBeat.forEach((beat, key) => {
if (now - beat > BEAT_LIMIT) {
this.map.delete(key);
this.lastAccessBeat.delete(key);
}
});
this.accessBeat = 0;
}
}
}
const uniqueMap = new ArrayKeyMap();
/**
* Like `useMemo`, but this hook result will be shared across all instances.
*/
function useUniqueMemo<T>(memoFn: () => T, deps: React.DependencyList) {
return React.useMemo<T>(() => {
const cachedValue = uniqueMap.get(deps);
if (cachedValue) {
return cachedValue as T;
}
const newValue = memoFn();
uniqueMap.set(deps, newValue);
return newValue;
}, deps);
}
export default useUniqueMemo;

View File

@@ -140,7 +140,7 @@ const useResponsiveObserver = () => {
subscribers.clear();
},
};
}, [token]);
}, [responsiveMap]);
};
export default useResponsiveObserver;

View File

@@ -1,10 +1,14 @@
import type React from 'react';
export type Primitive = null | undefined | string | number | boolean | symbol | bigint;
/** https://github.com/Microsoft/TypeScript/issues/29729 */
export type LiteralUnion<T extends string> = T | (string & {});
export type LiteralUnion<T, U extends Primitive = string> = T | (U & Record<never, never>);
export type AnyObject = Record<PropertyKey, any>;
export type EmptyObject = Record<never, never>;
export type CustomComponent<P = AnyObject> = React.ComponentType<P> | string;
/**
@@ -78,3 +82,31 @@ export type GetContextProp<
T extends React.Context<any>,
PropName extends keyof GetContextProps<T>,
> = NonNullable<GetContextProps<T>[PropName]>;
export type ValidChar =
| 'a'
| 'b'
| 'c'
| 'd'
| 'e'
| 'f'
| 'g'
| 'h'
| 'i'
| 'j'
| 'k'
| 'l'
| 'm'
| 'n'
| 'o'
| 'p'
| 'q'
| 'r'
| 's'
| 't'
| 'u'
| 'v'
| 'w'
| 'x'
| 'y'
| 'z';

View File

@@ -55,7 +55,10 @@ export interface AffixRef {
updatePosition: ReturnType<typeof throttleByAnimationFrame>;
}
type InternalAffixProps = AffixProps & { onTestUpdatePosition?: any };
interface InternalAffixProps extends AffixProps {
onTestUpdatePosition?: () => void;
}
const Affix = React.forwardRef<AffixRef, InternalAffixProps>((props, ref) => {
const {
style,

View File

@@ -10,7 +10,7 @@ import CSSMotion from 'rc-motion';
import pickAttrs from 'rc-util/lib/pickAttrs';
import { composeRef } from 'rc-util/lib/ref';
import type { ClosableType } from '../_util/hooks/useClosable';
import type { ClosableType } from '../_util/hooks';
import { replaceElement } from '../_util/reactNode';
import { devUseWarning } from '../_util/warning';
import { useComponentConfig } from '../config-provider/context';
@@ -176,7 +176,9 @@ const Alert = React.forwardRef<AlertRef, AlertProps>((props, ref) => {
// closeable when closeText or closeIcon is assigned
const isClosable = React.useMemo<boolean>(() => {
if (typeof closable === 'object' && closable.closeIcon) return true;
if (typeof closable === 'object' && closable.closeIcon) {
return true;
}
if (closeText) {
return true;
}
@@ -226,7 +228,7 @@ const Alert = React.forwardRef<AlertRef, AlertProps>((props, ref) => {
return contextClosable.closeIcon;
}
return contextCloseIcon;
}, [closeIcon, closable, closeText, contextCloseIcon]);
}, [closeIcon, closable, contextClosable, closeText, contextCloseIcon]);
const mergedAriaProps = React.useMemo<React.AriaAttributes>(() => {
const merged = closable ?? contextClosable;

View File

@@ -1,7 +1,7 @@
## zh-CN
友好的 [React 错误处理](https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html) 包裹组件。
友好的 [React 错误处理](https://zh-hans.react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary) 包裹组件。
## en-US
ErrorBoundary Component for making error handling easier in [React](https://reactjs.org/blog/2017/07/26/error-handling-in-react-16.html).
ErrorBoundary Component for making error handling easier in [React](https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary).

View File

@@ -246,7 +246,7 @@ const Anchor: React.FC<AnchorProps> = (props) => {
);
setCurrentActiveLink(currentActiveLink);
}, [dependencyListItem, targetOffset, offsetTop]);
}, [links, targetOffset, offsetTop, bounds]);
const handleScrollTo = React.useCallback<(link: string) => void>(
(link) => {

View File

@@ -185,7 +185,7 @@ describe('Anchor Render', () => {
const link = container.querySelector(`a[href="http://www.example.com/#${hash}"]`)!;
fireEvent.click(link);
await waitFakeTimer();
expect(link.classList).toContain('ant-anchor-link-title-active');
expect(link).toHaveClass('ant-anchor-link-title-active');
});
it('scrolls the page when clicking a link', async () => {
@@ -737,11 +737,9 @@ describe('Anchor Render', () => {
/>,
);
expect(container.querySelectorAll('.ant-anchor-ink').length).toBe(1);
expect(
container
.querySelector('.ant-anchor-wrapper')
?.classList.contains('ant-anchor-wrapper-horizontal'),
).toBeTruthy();
expect(container.querySelector('.ant-anchor-wrapper')).toHaveClass(
'ant-anchor-wrapper-horizontal',
);
});
it('nested children via items should be filtered out when direction is horizontal', () => {
@@ -818,7 +816,7 @@ describe('Anchor Render', () => {
const link = container.querySelector(`a[href="http://www.example.com/#${hash}"]`)!;
fireEvent.click(link);
await waitFakeTimer();
expect(link.classList).toContain('ant-anchor-link-title-active');
expect(link).toHaveClass('ant-anchor-link-title-active');
});
it('scrolls the page when clicking a link', async () => {
@@ -1026,25 +1024,29 @@ describe('Anchor Render', () => {
</div>
);
};
const wrapper = await render(<Foo />);
(await wrapper.findByText('part-1')).click();
const { container, findByText } = await render(<Foo />);
(await findByText('part-1')).click();
await waitFakeTimer();
const ink = wrapper.container.querySelector<HTMLSpanElement>('.ant-anchor-ink')!;
const toggleButton = wrapper.container.querySelector('button')!;
const inkElement = container.querySelector<HTMLSpanElement>('.ant-anchor-ink');
const toggleButton = container.querySelector<HTMLElement>('button');
fireEvent.click(toggleButton);
act(() => jest.runAllTimers());
expect(!!ink.style.left).toBe(true);
expect(!!ink.style.width).toBe(true);
expect(ink.style.top).toBe('');
expect(ink.style.height).toBe('');
expect(toggleButton).toBeInTheDocument();
fireEvent.click(toggleButton);
fireEvent.click(toggleButton!);
act(() => jest.runAllTimers());
expect(!!ink.style.top).toBe(true);
expect(!!ink.style.height).toBe(true);
expect(ink.style.left).toBe('');
expect(ink.style.width).toBe('');
expect(inkElement).toHaveStyle({
left: '0px',
width: '0px',
});
fireEvent.click(toggleButton!);
act(() => jest.runAllTimers());
expect(inkElement).toHaveStyle({
top: '0px',
height: '0px',
});
});
});
});

View File

@@ -4,7 +4,7 @@ import type { BaseSelectRef } from 'rc-select';
import toArray from 'rc-util/lib/Children/toArray';
import omit from 'rc-util/lib/omit';
import { useZIndex } from '../_util/hooks/useZIndex';
import { useZIndex } from '../_util/hooks';
import type { InputStatus } from '../_util/statusUtils';
import { devUseWarning } from '../_util/warning';
import type { ConfigConsumerProps } from '../config-provider';
@@ -24,6 +24,7 @@ export interface DataSourceItemObject {
value: string;
text: string;
}
export type DataSourceItemType = DataSourceItemObject | React.ReactNode;
export interface AutoCompleteProps<

View File

@@ -1096,7 +1096,11 @@ exports[`renders components/auto-complete/demo/certain-category.tsx extend conte
</div>
`;
exports[`renders components/auto-complete/demo/certain-category.tsx extend context correctly 2`] = `[]`;
exports[`renders components/auto-complete/demo/certain-category.tsx extend context correctly 2`] = `
[
"Warning: [antd: Input] \`addonAfter\` is deprecated. Please use \`Space.Compact\` instead.",
]
`;
exports[`renders components/auto-complete/demo/custom.tsx extend context correctly 1`] = `
<div
@@ -2424,6 +2428,7 @@ exports[`renders components/auto-complete/demo/form-debug.tsx extend context cor
exports[`renders components/auto-complete/demo/form-debug.tsx extend context correctly 2`] = `
[
"Warning: [antd: Input.Group] \`Input.Group\` is deprecated. Please use \`Space.Compact\` instead.",
"Warning: [antd: Input] \`addonAfter\` is deprecated. Please use \`Space.Compact\` instead.",
]
`;
@@ -2982,7 +2987,11 @@ exports[`renders components/auto-complete/demo/uncertain-category.tsx extend con
</div>
`;
exports[`renders components/auto-complete/demo/uncertain-category.tsx extend context correctly 2`] = `[]`;
exports[`renders components/auto-complete/demo/uncertain-category.tsx extend context correctly 2`] = `
[
"Warning: [antd: Input] \`addonAfter\` is deprecated. Please use \`Space.Compact\` instead.",
]
`;
exports[`renders components/auto-complete/demo/variant.tsx extend context correctly 1`] = `
<div

View File

@@ -46,8 +46,7 @@ Common props ref[Common props](/docs/react/common-props)
| allowClear | Show clear button | boolean \| { clearIcon?: ReactNode } | false | 5.8.0: Support Object type |
| autoFocus | If get focus when component mounted | boolean | false | |
| backfill | If backfill selected item the input when using keyboard | boolean | false | |
| children (for customize input element) | Customize input element | HTMLInputElement \| HTMLTextAreaElement \| React.ReactElement&lt;InputProps> | &lt;Input /> | |
| children (for dataSource) | Data source to auto complete | React.ReactElement&lt;OptionProps> \| Array&lt;React.ReactElement&lt;OptionProps>> | - | |
| children | Customize input element | HTMLInputElement \| HTMLTextAreaElement \| React.ReactElement&lt;InputProps> | &lt;Input /> | |
| classNames | Semantic DOM class | [Record<SemanticDOM, string>](#semantic-dom) | - | 5.25.0 |
| defaultActiveFirstOption | Whether active first option by default | boolean | true | |
| defaultOpen | Initial open state of dropdown | boolean | - | |

View File

@@ -47,8 +47,7 @@ demo:
| allowClear | 支持清除 | boolean \| { clearIcon?: ReactNode } | false | 5.8.0: 支持对象形式 |
| autoFocus | 自动获取焦点 | boolean | false | |
| backfill | 使用键盘选择选项的时候把选中项回填到输入框中 | boolean | false | |
| children (自动完成的数据源) | 自动完成的数据源,不能和自定义输入框同时配置 | React.ReactElement&lt;OptionProps> \| Array&lt;React.ReactElement&lt;OptionProps>> | - | |
| children (自定义输入框) | 自定义输入框,不能和自动完成的数据源同时配置 | HTMLInputElement \| HTMLTextAreaElement \| React.ReactElement&lt;InputProps> | &lt;Input /> | |
| children | 自定义输入框 | HTMLInputElement \| HTMLTextAreaElement \| React.ReactElement&lt;InputProps> | &lt;Input /> | |
| classNames | 语义化结构 class | [Record<SemanticDOM, string>](#semantic-dom) | - | 5.25.0 |
| defaultActiveFirstOption | 是否默认高亮第一个选项 | boolean | true | |
| defaultOpen | 是否默认展开下拉菜单 | boolean | - | |

View File

@@ -129,7 +129,7 @@ const Avatar = React.forwardRef<HTMLSpanElement, AvatarProps>((props, ref) => {
fontSize: currentSize && (icon || children) ? currentSize / 2 : 18,
}
: {};
}, [screens, size]);
}, [screens, size, icon, children]);
if (process.env.NODE_ENV !== 'production') {
const warning = devUseWarning('Avatar');
@@ -205,11 +205,7 @@ const Avatar = React.forwardRef<HTMLSpanElement, AvatarProps>((props, ref) => {
childrenToRender = (
<ResizeObserver onResize={setScaleParam}>
<span
className={`${prefixCls}-string`}
ref={avatarChildrenRef}
style={{ ...childrenStyle }}
>
<span className={`${prefixCls}-string`} ref={avatarChildrenRef} style={childrenStyle}>
{children}
</span>
</ResizeObserver>

View File

@@ -146,11 +146,11 @@ describe('Badge', () => {
// https://github.com/ant-design/ant-design/issues/15349
it('should color style works on Badge', () => {
const { container } = render(
<Badge style={{ color: 'red' }} status="success" text="Success" />,
);
expect((container.querySelector('.ant-badge-status-text')! as HTMLElement).style.color).toEqual(
'red',
<Badge style={{ color: 'rgb(255, 0, 0)' }} status="success" text="Success" />,
);
expect(container.querySelector<HTMLElement>('.ant-badge-status-text')).toHaveStyle({
color: 'rgb(255, 0, 0)',
});
});
// https://github.com/ant-design/ant-design/issues/15799
@@ -247,14 +247,8 @@ describe('Badge', () => {
const { container } = render(
<Badge
count={10}
classNames={{
root: 'test-root',
indicator: 'test-indicator',
}}
styles={{
root: { backgroundColor: 'yellow' },
indicator: { backgroundColor: 'blue' },
}}
classNames={{ root: 'test-root', indicator: 'test-indicator' }}
styles={{ root: { padding: 10 }, indicator: { padding: 20 } }}
>
test
</Badge>,
@@ -267,9 +261,7 @@ describe('Badge', () => {
expect(element?.querySelector<HTMLElement>('sup')).toHaveClass('test-indicator');
// styles
expect(element).toHaveStyle({ backgroundColor: 'rgb(255, 255, 0)' });
expect(element?.querySelector<HTMLElement>('sup')).toHaveStyle({
backgroundColor: 'rgb(0, 0, 255)',
});
expect(element).toHaveStyle({ padding: '10px' });
expect(element?.querySelector<HTMLElement>('sup')).toHaveStyle({ padding: '20px' });
});
});

View File

@@ -37,28 +37,28 @@ describe('Ribbon', () => {
expect(container.querySelectorAll('.ant-ribbon-color-green').length).toEqual(1);
});
it('works with custom color', () => {
const { container: wrapperLeft } = render(
<Badge.Ribbon color="#888" placement="start">
const { container, rerender } = render(
<Badge.Ribbon color="rgb(136, 136, 136)" placement="start">
<div />
</Badge.Ribbon>,
);
expect((wrapperLeft.querySelector('.ant-ribbon')! as HTMLElement).style.background).toEqual(
'rgb(136, 136, 136)',
);
expect((wrapperLeft.querySelector('.ant-ribbon-corner')! as HTMLElement).style.color).toEqual(
'rgb(136, 136, 136)',
);
const { container: wrapperRight } = render(
<Badge.Ribbon color="#888" placement="end">
expect(container.querySelector<HTMLElement>('.ant-ribbon')).toHaveStyle({
backgroundColor: 'rgb(136, 136, 136)',
});
expect(container.querySelector<HTMLElement>('.ant-ribbon-corner')).toHaveStyle({
color: 'rgb(136, 136, 136)',
});
rerender(
<Badge.Ribbon color="rgb(136, 136, 136)" placement="end">
<div />
</Badge.Ribbon>,
);
expect((wrapperRight.querySelector('.ant-ribbon')! as HTMLElement).style.background).toEqual(
'rgb(136, 136, 136)',
);
expect(
(wrapperRight.querySelector('.ant-ribbon-corner')! as HTMLElement).style.color,
).toEqual('rgb(136, 136, 136)');
expect(container.querySelector<HTMLElement>('.ant-ribbon')).toHaveStyle({
backgroundColor: 'rgb(136, 136, 136)',
});
expect(container.querySelector<HTMLElement>('.ant-ribbon-corner')).toHaveStyle({
color: 'rgb(136, 136, 136)',
});
});
});

View File

@@ -2014,7 +2014,11 @@ Array [
]
`;
exports[`renders components/button/demo/debug-icon.tsx extend context correctly 2`] = `[]`;
exports[`renders components/button/demo/debug-icon.tsx extend context correctly 2`] = `
[
"Warning: [antd: Input] \`addonAfter\` is deprecated. Please use \`Space.Compact\` instead.",
]
`;
exports[`renders components/button/demo/disabled.tsx extend context correctly 1`] = `
<div

View File

@@ -1,8 +1,8 @@
import React, { Children, useContext, useEffect, useMemo, useRef, useState } from 'react';
import classNames from 'classnames';
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
import omit from 'rc-util/lib/omit';
import { useComposeRef } from 'rc-util/lib/ref';
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
import { devUseWarning } from '../_util/warning';
import Wave from '../_util/wave';
@@ -154,7 +154,7 @@ const InternalCompoundedButton = React.forwardRef<
}
return ['default', 'outlined'];
}, [type, color, variant, danger, button?.variant, button?.color]);
}, [color, variant, type, danger, button?.color, button?.variant, mergedType]);
const isDanger = mergedColor === 'danger';
const mergedColorText = isDanger ? 'dangerous' : mergedColor;

View File

@@ -1,8 +1,5 @@
import Dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
import React from 'react';
import Dayjs from 'dayjs';
import MockDate from 'mockdate';
import type { PickerPanelProps } from 'rc-picker';
import dayjsGenerateConfig from 'rc-picker/lib/generate/dayjs';
@@ -17,9 +14,12 @@ import ConfigProvider from '../../config-provider';
import Group from '../../radio/group';
import Button from '../../radio/radioButton';
import Select from '../../select';
import type { DefaultOptionType } from '../../select';
import Header from '../Header';
import type { CalendarHeaderProps } from '../Header';
import 'dayjs/locale/zh-cn';
const ref: {
calendarProps?: PickerPanelProps;
calendarHeaderProps?: CalendarHeaderProps<unknown>;
@@ -375,15 +375,10 @@ describe('Calendar', () => {
// Year
const headerRender = jest.fn(({ value }) => {
const year = value.year();
const options = [];
const options: DefaultOptionType[] = [];
for (let i = year - 100; i < year + 100; i += 1) {
options.push(
<Select.Option className="year-item" key={i} value={i}>
{i}
</Select.Option>,
);
options.push({ label: i, value: i });
}
return (
<Select
size="small"
@@ -391,9 +386,8 @@ describe('Calendar', () => {
className="my-year-select"
onChange={onYearChange}
value={String(year)}
>
{options}
</Select>
options={options}
/>
);
});
const uiWithYear = <Calendar fullscreen={false} headerRender={headerRender} />;
@@ -412,23 +406,17 @@ describe('Calendar', () => {
const headerRenderWithMonth = jest.fn(({ value }) => {
const start = 0;
const end = 12;
const monthOptions = [];
const months: string[] = [];
const monthOptions: DefaultOptionType[] = [];
const current = value.clone();
const localeData = value.localeData();
const months = [];
for (let i = 0; i < 12; i += 1) {
current.month(i);
months.push(localeData.monthsShort(current));
}
for (let index = start; index < end; index += 1) {
monthOptions.push(
<Select.Option className="month-item" key={index} value={index}>
{months[index]}
</Select.Option>,
);
monthOptions.push({ label: months[index], value: index });
}
const month = value.month();
return (
<Select
@@ -437,9 +425,8 @@ describe('Calendar', () => {
className="my-month-select"
onChange={onMonthChange}
value={String(month)}
>
{monthOptions}
</Select>
options={monthOptions}
/>
);
});
const uiWithMonth = <Calendar fullscreen={false} headerRender={headerRenderWithMonth} />;

View File

@@ -65,8 +65,12 @@ const App: React.FC = () => {
};
const cellRender: CalendarProps<Dayjs>['cellRender'] = (current, info) => {
if (info.type === 'date') return dateCellRender(current);
if (info.type === 'month') return monthCellRender(current);
if (info.type === 'date') {
return dateCellRender(current);
}
if (info.type === 'month') {
return monthCellRender(current);
}
return info.originNode;
};

View File

@@ -327,7 +327,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
4
</h3>
@@ -347,7 +347,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
1
</h3>
@@ -367,7 +367,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
2
</h3>
@@ -387,7 +387,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
3
</h3>
@@ -407,7 +407,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
4
</h3>
@@ -427,7 +427,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
1
</h3>
@@ -447,7 +447,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
2
</h3>
@@ -467,7 +467,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
3
</h3>
@@ -487,7 +487,7 @@ exports[`renders components/carousel/demo/autoplay.tsx extend context correctly
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
4
</h3>
@@ -1036,7 +1036,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
4
</h3>
@@ -1056,7 +1056,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
1
</h3>
@@ -1076,7 +1076,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
2
</h3>
@@ -1096,7 +1096,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
3
</h3>
@@ -1116,7 +1116,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
4
</h3>
@@ -1136,7 +1136,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
1
</h3>
@@ -1156,7 +1156,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
2
</h3>
@@ -1176,7 +1176,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
3
</h3>
@@ -1196,7 +1196,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx extend context correc
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
4
</h3>
@@ -1272,7 +1272,7 @@ exports[`renders components/carousel/demo/fade.tsx extend context correctly 1`]
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
1
</h3>
@@ -1292,7 +1292,7 @@ exports[`renders components/carousel/demo/fade.tsx extend context correctly 1`]
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
2
</h3>
@@ -1312,7 +1312,7 @@ exports[`renders components/carousel/demo/fade.tsx extend context correctly 1`]
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
3
</h3>
@@ -1332,7 +1332,7 @@ exports[`renders components/carousel/demo/fade.tsx extend context correctly 1`]
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
4
</h3>
@@ -1503,7 +1503,7 @@ Array [
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
4
</h3>
@@ -1523,7 +1523,7 @@ Array [
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
1
</h3>
@@ -1543,7 +1543,7 @@ Array [
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
2
</h3>
@@ -1563,7 +1563,7 @@ Array [
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
3
</h3>
@@ -1583,7 +1583,7 @@ Array [
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
4
</h3>
@@ -1603,7 +1603,7 @@ Array [
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
1
</h3>
@@ -1623,7 +1623,7 @@ Array [
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
2
</h3>
@@ -1643,7 +1643,7 @@ Array [
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
3
</h3>
@@ -1663,7 +1663,7 @@ Array [
tabindex="-1"
>
<h3
style="height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
style="margin: 0px; height: 160px; color: rgb(255, 255, 255); line-height: 160px; text-align: center; background: rgb(54, 77, 121);"
>
4
</h3>

View File

@@ -324,7 +324,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
4
</h3>
@@ -344,7 +344,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
1
</h3>
@@ -364,7 +364,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
2
</h3>
@@ -384,7 +384,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
3
</h3>
@@ -404,7 +404,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
4
</h3>
@@ -424,7 +424,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
1
</h3>
@@ -444,7 +444,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
2
</h3>
@@ -464,7 +464,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
3
</h3>
@@ -484,7 +484,7 @@ exports[`renders components/carousel/demo/autoplay.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
4
</h3>
@@ -1027,7 +1027,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
4
</h3>
@@ -1047,7 +1047,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
1
</h3>
@@ -1067,7 +1067,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
2
</h3>
@@ -1087,7 +1087,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
3
</h3>
@@ -1107,7 +1107,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
4
</h3>
@@ -1127,7 +1127,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
1
</h3>
@@ -1147,7 +1147,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
2
</h3>
@@ -1167,7 +1167,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
3
</h3>
@@ -1187,7 +1187,7 @@ exports[`renders components/carousel/demo/dot-duration.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
4
</h3>
@@ -1261,7 +1261,7 @@ exports[`renders components/carousel/demo/fade.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
1
</h3>
@@ -1281,7 +1281,7 @@ exports[`renders components/carousel/demo/fade.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
2
</h3>
@@ -1301,7 +1301,7 @@ exports[`renders components/carousel/demo/fade.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
3
</h3>
@@ -1321,7 +1321,7 @@ exports[`renders components/carousel/demo/fade.tsx correctly 1`] = `
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
4
</h3>
@@ -1490,7 +1490,7 @@ Array [
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
4
</h3>
@@ -1510,7 +1510,7 @@ Array [
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
1
</h3>
@@ -1530,7 +1530,7 @@ Array [
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
2
</h3>
@@ -1550,7 +1550,7 @@ Array [
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
3
</h3>
@@ -1570,7 +1570,7 @@ Array [
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
4
</h3>
@@ -1590,7 +1590,7 @@ Array [
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
1
</h3>
@@ -1610,7 +1610,7 @@ Array [
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
2
</h3>
@@ -1630,7 +1630,7 @@ Array [
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
3
</h3>
@@ -1650,7 +1650,7 @@ Array [
tabindex="-1"
>
<h3
style="height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
style="margin:0;height:160px;color:#fff;line-height:160px;text-align:center;background:#364d79"
>
4
</h3>

View File

@@ -2,6 +2,7 @@ import React from 'react';
import { Carousel } from 'antd';
const contentStyle: React.CSSProperties = {
margin: 0,
height: '160px',
color: '#fff',
lineHeight: '160px',

View File

@@ -2,6 +2,7 @@ import React from 'react';
import { Carousel } from 'antd';
const contentStyle: React.CSSProperties = {
margin: 0,
height: '160px',
color: '#fff',
lineHeight: '160px',

View File

@@ -2,6 +2,7 @@ import React from 'react';
import { Carousel } from 'antd';
const contentStyle: React.CSSProperties = {
margin: 0,
height: '160px',
color: '#fff',
lineHeight: '160px',

View File

@@ -5,6 +5,7 @@ import { Carousel, Radio } from 'antd';
type DotPosition = CarouselProps['dotPosition'];
const contentStyle: React.CSSProperties = {
margin: 0,
height: '160px',
color: '#fff',
lineHeight: '160px',

View File

@@ -1,4 +1,4 @@
import { unit } from '@ant-design/cssinjs';
import { Keyframes, unit } from '@ant-design/cssinjs';
import { resetComponent } from '../../style';
import type { FullToken, GenerateStyle, GetDefaultToken } from '../../theme/internal';
@@ -230,6 +230,16 @@ const genDotsStyle: GenerateStyle<CarouselToken> = (token) => {
colorBgContainer,
motionDurationSlow,
} = token;
const animation = new Keyframes(`${token.prefixCls}-dot-animation`, {
from: {
transform: `translate3d(-100%, 0, 0)`,
},
to: {
transform: `translate3d(0%, 0, 0)`,
},
});
return {
[componentCls]: {
'.slick-dots': {
@@ -283,7 +293,6 @@ const genDotsStyle: GenerateStyle<CarouselToken> = (token) => {
outline: 'none',
cursor: 'pointer',
overflow: 'hidden',
transform: 'translate3d(-100%, 0, 0)',
},
button: {
@@ -322,8 +331,10 @@ const genDotsStyle: GenerateStyle<CarouselToken> = (token) => {
},
'&::after': {
background: colorBgContainer,
transform: 'translate3d(0, 0, 0)',
transition: `transform var(${DotDuration}) ease-out`,
animationName: animation,
animationDuration: `var(${DotDuration})`,
animationTimingFunction: 'ease-out',
animationFillMode: 'forwards',
},
},
},
@@ -335,6 +346,15 @@ const genDotsStyle: GenerateStyle<CarouselToken> = (token) => {
const genCarouselVerticalStyle: GenerateStyle<CarouselToken> = (token) => {
const { componentCls, dotOffset, arrowOffset, marginXXS } = token;
const animation = new Keyframes(`${token.prefixCls}-dot-vertical-animation`, {
from: {
height: 0,
},
to: {
height: token.dotActiveWidth,
},
});
const reverseSizeOfDot = {
width: token.dotHeight,
height: token.dotWidth,
@@ -396,12 +416,19 @@ const genCarouselVerticalStyle: GenerateStyle<CarouselToken> = (token) => {
'&.slick-active': {
...reverseSizeOfDot,
height: token.dotActiveWidth,
button: reverseSizeOfDot,
button: {
...reverseSizeOfDot,
height: token.dotActiveWidth,
},
'&::after': {
...reverseSizeOfDot,
transition: `height var(${DotDuration}) ease-out`,
animationName: animation,
animationDuration: `var(${DotDuration})`,
animationTimingFunction: 'ease-out',
animationFillMode: 'forwards',
},
},
},

View File

@@ -558,14 +558,14 @@ describe('Cascader', () => {
resetWarned();
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
const customStyle = { background: 'red' };
const { container } = render(<Cascader dropdownStyle={customStyle} open />);
const { container } = render(<Cascader dropdownStyle={{ padding: 10 }} open />);
expect(errSpy).toHaveBeenCalledWith(
'Warning: [antd: Cascader] `dropdownStyle` is deprecated. Please use `styles.popup.root` instead.',
);
expect(container.querySelector('.ant-select-dropdown')?.getAttribute('style')).toContain(
'background: red',
);
expect(container.querySelector<HTMLElement>('.ant-select-dropdown')).toHaveStyle({
padding: '10px',
});
errSpy.mockRestore();
});
@@ -595,11 +595,11 @@ describe('Cascader', () => {
resetWarned();
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
const columnStyle = { background: 'red' };
const { getByRole } = render(
<Cascader
options={[{ label: 'test', value: 1 }]}
dropdownMenuColumnStyle={columnStyle}
dropdownMenuColumnStyle={{ padding: 10 }}
open
/>,
);
@@ -607,7 +607,7 @@ describe('Cascader', () => {
'Warning: [antd: Cascader] `dropdownMenuColumnStyle` is deprecated. Please use `popupMenuColumnStyle` instead.',
);
const menuColumn = getByRole('menuitemcheckbox');
expect(menuColumn.style.background).toBe('red');
expect(menuColumn).toHaveStyle({ padding: '10px' });
errSpy.mockRestore();
});

View File

@@ -11,7 +11,7 @@ import RcCascader from 'rc-cascader';
import type { Placement } from 'rc-select/lib/BaseSelect';
import omit from 'rc-util/lib/omit';
import { useZIndex } from '../_util/hooks/useZIndex';
import { useZIndex } from '../_util/hooks';
import type { SelectCommonPlacement } from '../_util/motion';
import { getTransitionName } from '../_util/motion';
import genPurePanel from '../_util/PurePanel';

View File

@@ -82,14 +82,12 @@ describe('Collapse', () => {
</Collapse.Panel>
</Collapse>,
);
expect(
container.querySelector('.ant-collapse-item')?.classList.contains('ant-collapse-item-active'),
).toBe(false);
expect(container.querySelector('.ant-collapse-item')).not.toHaveClass(
'ant-collapse-item-active',
);
fireEvent.click(container.querySelector('.ant-collapse-header')!);
await waitFakeTimer();
expect(
container.querySelector('.ant-collapse-item')?.classList.contains('ant-collapse-item-active'),
).toBe(true);
expect(container.querySelector('.ant-collapse-item')).toHaveClass('ant-collapse-item-active');
jest.useRealTimers();
});

View File

@@ -3,8 +3,6 @@ import { SettingOutlined } from '@ant-design/icons';
import type { CollapseProps } from 'antd';
import { Collapse, Select } from 'antd';
const { Option } = Select;
const text = `
A dog is a type of domesticated animal.
Known for its loyalty and faithfulness,
@@ -64,10 +62,15 @@ const App: React.FC = () => {
/>
<br />
<span>Expand Icon Position: </span>
<Select value={expandIconPosition} style={{ margin: '0 8px' }} onChange={onPositionChange}>
<Option value="start">start</Option>
<Option value="end">end</Option>
</Select>
<Select
value={expandIconPosition}
style={{ margin: '0 8px' }}
onChange={onPositionChange}
options={[
{ label: 'start', value: 'start' },
{ label: 'end', value: 'end' },
]}
/>
</>
);
};

View File

@@ -205,7 +205,7 @@ describe('ColorPicker', () => {
fireEvent.click(container.querySelector('.ant-color-picker-trigger')!);
await waitFakeTimer();
const presetsColors = container
.querySelector('.ant-collapse-content')
?.querySelector('.ant-collapse-content')
?.querySelectorAll('.ant-color-picker-presets-color')!;
expect(container.querySelector('.ant-color-picker-presets')).toBeTruthy();
@@ -217,9 +217,7 @@ describe('ColorPicker', () => {
).toBeTruthy();
fireEvent.click(presetsColors[0]);
expect(
presetsColors[0].classList.contains('ant-color-picker-presets-color-bright'),
).toBeFalsy();
expect(presetsColors[0]).not.toHaveClass('ant-color-picker-presets-color-bright');
expect(
container.querySelector('.ant-color-picker-hex-input input')?.getAttribute('value'),
).toEqual('000000');
@@ -228,9 +226,7 @@ describe('ColorPicker', () => {
);
fireEvent.click(presetsColors[9]);
expect(
presetsColors[9].classList.contains('ant-color-picker-presets-color-bright'),
).toBeTruthy();
expect(presetsColors[9]).toHaveClass('ant-color-picker-presets-color-bright');
expect(
container.querySelector('.ant-color-picker-hex-input input')?.getAttribute('value'),
).toEqual('000000');

View File

@@ -79,7 +79,7 @@ const ColorTrigger = forwardRef<HTMLDivElement, ColorTriggerProps>((props, ref)
default:
return alpha < 100 ? `${hexString.slice(0, 7)},${alpha}%` : hexString;
}
}, [color, format, showText, activeIndex]);
}, [color, format, showText, activeIndex, locale.transparent, colorTextCellPrefixCls]);
// ============================= Render =============================
const containerNode = useMemo<React.ReactNode>(

View File

@@ -4,6 +4,7 @@ import RcColorPicker from '@rc-component/color-picker';
import type { Color } from '@rc-component/color-picker';
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
import { useForceUpdate } from '../../../_util/hooks';
import Segmented from '../../../segmented';
import { AggregationColor } from '../../color';
import { PanelPickerContext } from '../../context';
@@ -70,7 +71,7 @@ const PanelPicker: FC = () => {
if (!isSingle) {
setLockedColor(colors[activeIndex]?.color);
}
}, [gradientDragging, activeIndex]);
}, [isSingle, colors, gradientDragging, activeIndex]);
const activeColor = React.useMemo(() => {
if (isSingle) {
@@ -83,11 +84,12 @@ const PanelPicker: FC = () => {
}
return colors[activeIndex]?.color;
}, [value, activeIndex, isSingle, lockedColor, gradientDragging]);
}, [colors, value, activeIndex, isSingle, lockedColor, gradientDragging]);
// ========================= Picker Color =========================
const [pickerColor, setPickerColor] = React.useState<AggregationColor | null>(activeColor);
const [forceSync, setForceSync] = React.useState(0);
const [forceSync, setForceSync] = useForceUpdate();
const mergedPickerColor = pickerColor?.equals(activeColor) ? activeColor : pickerColor;
@@ -148,7 +150,7 @@ const PanelPicker: FC = () => {
// Back of origin color in case in controlled
// This will set after `onChangeComplete` to avoid `setState` trigger rerender
// which will make `fillColor` get wrong `color.cleared` state
setForceSync((ori) => ori + 1);
setForceSync();
};
const onInputChange = (colorValue: AggregationColor) => {

View File

@@ -57,7 +57,7 @@ export default function useModeColor(
pushOption('gradient', locale.gradientColor);
return [optionList, modes];
}, [mode]);
}, [mode, locale.singleColor, locale.gradientColor]);
// ======================== Post ========================
// We need align `mode` with `color` state

View File

@@ -24801,7 +24801,7 @@ exports[`ConfigProvider components Select configProvider 1`] = `
class="config-select-selection-search"
>
<input
aria-activedescendant="rc_select_TEST_OR_SSR_list_1"
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="true"
@@ -24819,8 +24819,11 @@ exports[`ConfigProvider components Select configProvider 1`] = `
/>
</span>
<span
class="config-select-selection-placeholder"
/>
class="config-select-selection-item"
title="Light"
>
Light
</span>
</span>
</div>
<div
@@ -24833,18 +24836,13 @@ exports[`ConfigProvider components Select configProvider 1`] = `
role="listbox"
style="height: 0px; width: 0px; overflow: hidden;"
>
<div
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_0"
role="presentation"
/>
<div
aria-label="Light"
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_1"
aria-selected="true"
id="rc_select_TEST_OR_SSR_list_0"
role="option"
>
Bamboo
light
</div>
</div>
<div
@@ -24861,14 +24859,8 @@ exports[`ConfigProvider components Select configProvider 1`] = `
style="display: flex; flex-direction: column;"
>
<div
class="config-select-item config-select-item-group"
title="grp"
>
grp
</div>
<div
aria-selected="false"
class="config-select-item config-select-item-option config-select-item-option-grouped config-select-item-option-active"
aria-selected="true"
class="config-select-item config-select-item-option config-select-item-option-active config-select-item-option-selected"
title="Light"
>
<div
@@ -24950,8 +24942,11 @@ exports[`ConfigProvider components Select configProvider componentDisabled 1`] =
/>
</span>
<span
class="config-select-selection-placeholder"
/>
class="config-select-selection-item"
title="Light"
>
Light
</span>
</span>
</div>
<span
@@ -24997,7 +24992,7 @@ exports[`ConfigProvider components Select configProvider componentSize large 1`]
class="config-select-selection-search"
>
<input
aria-activedescendant="rc_select_TEST_OR_SSR_list_1"
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="true"
@@ -25015,8 +25010,11 @@ exports[`ConfigProvider components Select configProvider componentSize large 1`]
/>
</span>
<span
class="config-select-selection-placeholder"
/>
class="config-select-selection-item"
title="Light"
>
Light
</span>
</span>
</div>
<div
@@ -25029,18 +25027,13 @@ exports[`ConfigProvider components Select configProvider componentSize large 1`]
role="listbox"
style="height: 0px; width: 0px; overflow: hidden;"
>
<div
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_0"
role="presentation"
/>
<div
aria-label="Light"
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_1"
aria-selected="true"
id="rc_select_TEST_OR_SSR_list_0"
role="option"
>
Bamboo
light
</div>
</div>
<div
@@ -25057,14 +25050,8 @@ exports[`ConfigProvider components Select configProvider componentSize large 1`]
style="display: flex; flex-direction: column;"
>
<div
class="config-select-item config-select-item-group"
title="grp"
>
grp
</div>
<div
aria-selected="false"
class="config-select-item config-select-item-option config-select-item-option-grouped config-select-item-option-active"
aria-selected="true"
class="config-select-item config-select-item-option config-select-item-option-active config-select-item-option-selected"
title="Light"
>
<div
@@ -25128,7 +25115,7 @@ exports[`ConfigProvider components Select configProvider componentSize middle 1`
class="config-select-selection-search"
>
<input
aria-activedescendant="rc_select_TEST_OR_SSR_list_1"
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="true"
@@ -25146,8 +25133,11 @@ exports[`ConfigProvider components Select configProvider componentSize middle 1`
/>
</span>
<span
class="config-select-selection-placeholder"
/>
class="config-select-selection-item"
title="Light"
>
Light
</span>
</span>
</div>
<div
@@ -25160,18 +25150,13 @@ exports[`ConfigProvider components Select configProvider componentSize middle 1`
role="listbox"
style="height: 0px; width: 0px; overflow: hidden;"
>
<div
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_0"
role="presentation"
/>
<div
aria-label="Light"
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_1"
aria-selected="true"
id="rc_select_TEST_OR_SSR_list_0"
role="option"
>
Bamboo
light
</div>
</div>
<div
@@ -25188,14 +25173,8 @@ exports[`ConfigProvider components Select configProvider componentSize middle 1`
style="display: flex; flex-direction: column;"
>
<div
class="config-select-item config-select-item-group"
title="grp"
>
grp
</div>
<div
aria-selected="false"
class="config-select-item config-select-item-option config-select-item-option-grouped config-select-item-option-active"
aria-selected="true"
class="config-select-item config-select-item-option config-select-item-option-active config-select-item-option-selected"
title="Light"
>
<div
@@ -25259,7 +25238,7 @@ exports[`ConfigProvider components Select configProvider componentSize small 1`]
class="config-select-selection-search"
>
<input
aria-activedescendant="rc_select_TEST_OR_SSR_list_1"
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="true"
@@ -25277,8 +25256,11 @@ exports[`ConfigProvider components Select configProvider componentSize small 1`]
/>
</span>
<span
class="config-select-selection-placeholder"
/>
class="config-select-selection-item"
title="Light"
>
Light
</span>
</span>
</div>
<div
@@ -25291,18 +25273,13 @@ exports[`ConfigProvider components Select configProvider componentSize small 1`]
role="listbox"
style="height: 0px; width: 0px; overflow: hidden;"
>
<div
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_0"
role="presentation"
/>
<div
aria-label="Light"
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_1"
aria-selected="true"
id="rc_select_TEST_OR_SSR_list_0"
role="option"
>
Bamboo
light
</div>
</div>
<div
@@ -25319,14 +25296,8 @@ exports[`ConfigProvider components Select configProvider componentSize small 1`]
style="display: flex; flex-direction: column;"
>
<div
class="config-select-item config-select-item-group"
title="grp"
>
grp
</div>
<div
aria-selected="false"
class="config-select-item config-select-item-option config-select-item-option-grouped config-select-item-option-active"
aria-selected="true"
class="config-select-item config-select-item-option config-select-item-option-active config-select-item-option-selected"
title="Light"
>
<div
@@ -25390,7 +25361,7 @@ exports[`ConfigProvider components Select normal 1`] = `
class="ant-select-selection-search"
>
<input
aria-activedescendant="rc_select_TEST_OR_SSR_list_1"
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="true"
@@ -25408,8 +25379,11 @@ exports[`ConfigProvider components Select normal 1`] = `
/>
</span>
<span
class="ant-select-selection-placeholder"
/>
class="ant-select-selection-item"
title="Light"
>
Light
</span>
</span>
</div>
<div
@@ -25422,18 +25396,13 @@ exports[`ConfigProvider components Select normal 1`] = `
role="listbox"
style="height: 0px; width: 0px; overflow: hidden;"
>
<div
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_0"
role="presentation"
/>
<div
aria-label="Light"
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_1"
aria-selected="true"
id="rc_select_TEST_OR_SSR_list_0"
role="option"
>
Bamboo
light
</div>
</div>
<div
@@ -25450,14 +25419,8 @@ exports[`ConfigProvider components Select normal 1`] = `
style="display: flex; flex-direction: column;"
>
<div
class="ant-select-item ant-select-item-group"
title="grp"
>
grp
</div>
<div
aria-selected="false"
class="ant-select-item ant-select-item-option ant-select-item-option-grouped ant-select-item-option-active"
aria-selected="true"
class="ant-select-item ant-select-item-option ant-select-item-option-active ant-select-item-option-selected"
title="Light"
>
<div
@@ -25521,7 +25484,7 @@ exports[`ConfigProvider components Select prefixCls 1`] = `
class="prefix-Select-selection-search"
>
<input
aria-activedescendant="rc_select_TEST_OR_SSR_list_1"
aria-activedescendant="rc_select_TEST_OR_SSR_list_0"
aria-autocomplete="list"
aria-controls="rc_select_TEST_OR_SSR_list"
aria-expanded="true"
@@ -25539,8 +25502,11 @@ exports[`ConfigProvider components Select prefixCls 1`] = `
/>
</span>
<span
class="prefix-Select-selection-placeholder"
/>
class="prefix-Select-selection-item"
title="Light"
>
Light
</span>
</span>
</div>
<div
@@ -25553,18 +25519,13 @@ exports[`ConfigProvider components Select prefixCls 1`] = `
role="listbox"
style="height: 0px; width: 0px; overflow: hidden;"
>
<div
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_0"
role="presentation"
/>
<div
aria-label="Light"
aria-selected="false"
id="rc_select_TEST_OR_SSR_list_1"
aria-selected="true"
id="rc_select_TEST_OR_SSR_list_0"
role="option"
>
Bamboo
light
</div>
</div>
<div
@@ -25581,14 +25542,8 @@ exports[`ConfigProvider components Select prefixCls 1`] = `
style="display: flex; flex-direction: column;"
>
<div
class="prefix-Select-item prefix-Select-item-group"
title="grp"
>
grp
</div>
<div
aria-selected="false"
class="prefix-Select-item prefix-Select-item-option prefix-Select-item-option-grouped prefix-Select-item-option-active"
aria-selected="true"
class="prefix-Select-item prefix-Select-item-option prefix-Select-item-option-active prefix-Select-item-option-selected"
title="Light"
>
<div
@@ -39939,7 +39894,7 @@ exports[`ConfigProvider components Transfer configProvider 1`] = `
exports[`ConfigProvider components Transfer configProvider componentDisabled 1`] = `
<div
class="config-transfer"
class="config-transfer config-transfer-disabled"
>
<div
class="config-transfer-list"
@@ -39966,6 +39921,7 @@ exports[`ConfigProvider components Transfer configProvider componentDisabled 1`]
<span
aria-label="down"
class="anticon anticon-down config-dropdown-trigger config-transfer-list-header-dropdown"
disabled=""
role="img"
>
<svg
@@ -40136,6 +40092,7 @@ exports[`ConfigProvider components Transfer configProvider componentDisabled 1`]
<span
aria-label="down"
class="anticon anticon-down config-dropdown-trigger config-transfer-list-header-dropdown"
disabled=""
role="img"
>
<svg
@@ -41810,11 +41767,12 @@ exports[`ConfigProvider components Tree configProvider 1`] = `
exports[`ConfigProvider components Tree configProvider componentDisabled 1`] = `
<div>
<div
class="config-tree config-tree-icon-hide"
class="config-tree config-tree-icon-hide config-tree-disabled"
>
<div>
<input
aria-label="for screen reader"
disabled=""
style="width: 0px; height: 0px; display: flex; overflow: hidden; opacity: 0; border: 0px; padding: 0px; margin: 0px;"
tabindex="0"
value=""
@@ -41848,7 +41806,7 @@ exports[`ConfigProvider components Tree configProvider componentDisabled 1`] = `
>
<div
aria-expanded="false"
class="config-tree-treenode config-tree-treenode-switcher-close config-tree-treenode-leaf-last config-tree-treenode-leaf"
class="config-tree-treenode config-tree-treenode-disabled config-tree-treenode-switcher-close config-tree-treenode-leaf-last config-tree-treenode-leaf"
draggable="false"
role="treeitem"
>
@@ -41876,11 +41834,12 @@ exports[`ConfigProvider components Tree configProvider componentDisabled 1`] = `
</div>
</div>
<div
class="config-tree config-tree-block-node config-tree-directory"
class="config-tree config-tree-block-node config-tree-disabled config-tree-directory"
>
<div>
<input
aria-label="for screen reader"
disabled=""
style="width: 0px; height: 0px; display: flex; overflow: hidden; opacity: 0; border: 0px; padding: 0px; margin: 0px;"
tabindex="0"
value=""
@@ -41914,7 +41873,7 @@ exports[`ConfigProvider components Tree configProvider componentDisabled 1`] = `
>
<div
aria-expanded="false"
class="config-tree-treenode config-tree-treenode-switcher-close config-tree-treenode-leaf-last config-tree-treenode-leaf"
class="config-tree-treenode config-tree-treenode-disabled config-tree-treenode-switcher-close config-tree-treenode-leaf-last config-tree-treenode-leaf"
draggable="false"
role="treeitem"
>

View File

@@ -59,11 +59,12 @@ import TreeSelect from '../../tree-select';
import Upload from '../../upload';
dayjs.extend(customParseFormat);
jest.mock('rc-util/lib/Portal');
describe('ConfigProvider', () => {
describe('components', () => {
function testPair(name: string, renderComponent: (props?: any) => React.ReactElement): void {
const testPair = (name: string, renderComponent: (props?: any) => React.ReactElement<any>) => {
const isArray = ['Menu', 'TimePicker', 'Tooltip'].includes(name);
describe(`${name}`, () => {
// normal
@@ -122,7 +123,7 @@ describe('ConfigProvider', () => {
expect(isArray ? container.children : container.firstChild).toMatchSnapshot();
});
});
}
};
// Alert
testPair('Alert', (props) => (
@@ -430,11 +431,12 @@ describe('ConfigProvider', () => {
// Select
testPair('Select', (props) => (
<Select {...props} open>
<Select.OptGroup key="grp">
<Select.Option key="Bamboo">Light</Select.Option>
</Select.OptGroup>
</Select>
<Select
open
defaultValue={'light'}
options={[{ label: 'Light', value: 'light' }]}
{...props}
/>
));
// Skeleton

View File

@@ -82,7 +82,8 @@ describe('ConfigProvider.Locale', () => {
const datepicke = wrapper.container.querySelector<HTMLInputElement>('.ant-picker-input input');
expect(datepicke?.value).toBe('');
expect(datepicke?.placeholder).toBe('请选择日期');
expect(wrapper.container.querySelector('.ant-pagination-item-1')?.className).toContain(
expect(wrapper.container.querySelector<HTMLElement>('.ant-pagination-item-1')).toHaveClass(
'ant-pagination-item-active',
);
@@ -93,6 +94,7 @@ describe('ConfigProvider.Locale', () => {
expect(
wrapper.container.querySelector<HTMLInputElement>('.ant-picker-input input')?.value,
).not.toBe('');
wrapper.rerender(
<ConfigProvider locale={{} as Locale}>
<DatePicker />
@@ -108,7 +110,7 @@ describe('ConfigProvider.Locale', () => {
expect(datepicker?.value).not.toBe('');
expect(datepicker?.value).toContain('-10');
expect(wrapper.container.querySelector('.ant-pagination-item-3')?.className).toContain(
expect(wrapper.container.querySelector('.ant-pagination-item-3')).toHaveClass(
'ant-pagination-item-active',
);
});

View File

@@ -132,6 +132,7 @@ export interface TableConfig extends ComponentStyleConfig {
export interface ImageConfig extends ComponentStyleConfig {
preview?: Partial<Record<'closeIcon', React.ReactNode>>;
fallback?: string;
}
export type CollapseConfig = ComponentStyleConfig & Pick<CollapseProps, 'expandIcon'>;
@@ -214,7 +215,7 @@ export type CascaderConfig = ComponentStyleConfig &
Pick<CascaderProps, 'variant' | 'styles' | 'classNames'>;
export type TreeSelectConfig = ComponentStyleConfig &
Pick<TreeSelectProps, 'variant' | 'styles' | 'classNames'>;
Pick<TreeSelectProps, 'variant' | 'styles' | 'classNames' | 'switcherIcon'>;
export type DatePickerConfig = ComponentStyleConfig &
Pick<DatePickerProps, 'variant' | 'styles' | 'classNames'>;

View File

@@ -36,7 +36,6 @@ type DirectionType = ConfigProviderProps['direction'];
const InputGroup = Input.Group;
const ButtonGroup = Button.Group;
const { Option } = Select;
const { TreeNode } = Tree;
const { Search } = Input;
@@ -100,19 +99,27 @@ const Page: React.FC<{ placement: Placement }> = ({ placement }) => {
const [showBadge, setShowBadge] = useState(true);
const selectBefore = (
<Select defaultValue="Http://" style={{ width: 90 }}>
<Option value="Http://">Http://</Option>
<Option value="Https://">Https://</Option>
</Select>
<Select
defaultValue="Http://"
style={{ width: 90 }}
options={[
{ label: 'Http://', value: 'Http://' },
{ label: 'Https://', value: 'Https://' },
]}
/>
);
const selectAfter = (
<Select defaultValue=".com" style={{ width: 80 }}>
<Option value=".com">.com</Option>
<Option value=".jp">.jp</Option>
<Option value=".cn">.cn</Option>
<Option value=".org">.org</Option>
</Select>
<Select
defaultValue=".com"
style={{ width: 80 }}
options={[
{ label: '.com', value: '.com' },
{ label: '.jp', value: '.jp' },
{ label: '.cn', value: '.cn' },
{ label: '.org', value: '.org' },
]}
/>
);
// ==== Cascader ====
@@ -280,10 +287,13 @@ const Page: React.FC<{ placement: Placement }> = ({ placement }) => {
</InputGroup>
<br />
<InputGroup compact>
<Select defaultValue="Option1">
<Option value="Option1">Option1</Option>
<Option value="Option2">Option2</Option>
</Select>
<Select
defaultValue="Option1"
options={[
{ label: 'Option1', value: 'Option1' },
{ label: 'Option2', value: 'Option2' },
]}
/>
<Input style={{ width: '50%' }} defaultValue="input content" />
<InputNumber />
</InputGroup>
@@ -297,27 +307,41 @@ const Page: React.FC<{ placement: Placement }> = ({ placement }) => {
<br />
<Row>
<Col span={12}>
<Divider orientation="left">Select example</Divider>
<Divider orientation="start">Select example</Divider>
<Space wrap>
<Select mode="multiple" defaultValue="مورچه" style={{ width: 120 }}>
<Option value="jack">Jack</Option>
<Option value="مورچه">مورچه</Option>
<Option value="disabled" disabled>
Disabled
</Option>
<Option value="Yiminghe">yiminghe</Option>
</Select>
<Select defaultValue="مورچه" style={{ width: 120 }} disabled>
<Option value="مورچه">مورچه</Option>
</Select>
<Select defaultValue="مورچه" style={{ width: 120 }} loading>
<Option value="مورچه">مورچه</Option>
</Select>
<Select showSearch style={{ width: 200 }} placeholder="Select a person">
<Option value="jack">Jack</Option>
<Option value="سعید">سعید</Option>
<Option value="tom">Tom</Option>
</Select>
<Select
mode="multiple"
defaultValue="مورچه"
style={{ width: 120 }}
options={[
{ label: 'jack', value: 'jack' },
{ label: 'مورچه', value: 'مورچه' },
{ label: 'disabled', value: 'disabled', disabled: true },
{ label: 'yiminghe', value: 'Yiminghe' },
]}
/>
<Select
disabled
defaultValue="مورچه"
style={{ width: 120 }}
options={[{ label: 'مورچه', value: 'مورچه' }]}
/>
<Select
loading
defaultValue="مورچه"
style={{ width: 120 }}
options={[{ label: 'مورچه', value: 'مورچه' }]}
/>
<Select
showSearch
style={{ width: 200 }}
placeholder="Select a person"
options={[
{ label: 'jack', value: 'jack' },
{ label: 'سعید', value: 'سعید' },
{ label: 'Tom', value: 'tom' },
]}
/>
</Space>
</Col>
<Col span={12}>

View File

@@ -41,7 +41,6 @@ type Locale = ConfigProviderProps['locale'];
dayjs.locale('en');
const { Option } = Select;
const { RangePicker } = DatePicker;
const columns: TableProps['columns'] = [
@@ -132,10 +131,14 @@ const Page: React.FC = () => {
>
<Pagination defaultCurrent={1} total={50} showSizeChanger />
<Space wrap>
<Select showSearch style={{ width: 200 }}>
<Option value="jack">jack</Option>
<Option value="lucy">lucy</Option>
</Select>
<Select
showSearch
style={{ width: 200 }}
options={[
{ label: 'jack', value: 'jack' },
{ label: 'lucy', value: 'lucy' },
]}
/>
<DatePicker />
<TimePicker />
<RangePicker />

View File

@@ -132,7 +132,7 @@ const {
| floatButton | Set FloatButton common props | { backTopIcon?: React.ReactNode } | - | 5.27.0 |
| floatButtonGroup | Set FloatButton.Group common props | { closeIcon?: React.ReactNode } | - | 5.16.0 |
| form | Set Form common props | { className?: string, style?: React.CSSProperties, validateMessages?: [ValidateMessages](/components/form/#validatemessages), requiredMark?: boolean \| `optional`, scrollToFirstError?: boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options) } | - | `requiredMark`: 4.8.0; `colon`: 4.18.0; `scrollToFirstError`: 5.2.0; `className` and `style`: 5.7.0 |
| image | Set Image common props | { className?: string, style?: React.CSSProperties, preview?: { closeIcon?: React.ReactNode } } | - | 5.7.0, `closeIcon`: 5.14.0 |
| image | Set Image common props | { className?: string, style?: React.CSSProperties, preview?: { closeIcon?: React.ReactNode }, fallback?: string } | - | 5.7.0, `closeIcon`: 5.14.0, `fallback`: 5.28.0 |
| input | Set Input common props | { autoComplete?: string, className?: string, style?: React.CSSProperties, allowClear?: boolean \| { clearIcon?: ReactNode } } | - | 4.2.0, `allowClear`: 5.15.0 |
| textArea | Set TextArea common props | { autoComplete?: string, className?: string, style?: React.CSSProperties, allowClear?: boolean \| { clearIcon?: ReactNode } } | - | 5.15.0 |
| layout | Set Layout common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
@@ -168,7 +168,7 @@ const {
| popconfirm | Set Popconfirm common props | { className?: string, style?: React.CSSProperties, classNames?:[Popconfirm\["classNames"\]](/components/popconfirm#api), styles?: [Popconfirm\["styles"\]](/components/popconfirm#api) } | - | 5.23.0 |
| transfer | Set Transfer common props | { className?: string, style?: React.CSSProperties, selectionsIcon?: React.ReactNode } | - | 5.7.0, `selectionsIcon`: 5.14.0 |
| tree | Set Tree common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| treeSelect | Set TreeSelect common props | { classNames?:[TreeSelect\["classNames"\]](/components/tree-select#api), styles?: [TreeSelect\["styles"\]](/components/tree-select#api) } | - | 5.25.0 |
| treeSelect | Set TreeSelect common props | { classNames?:[TreeSelect\["classNames"\]](/components/tree-select#api), styles?: [TreeSelect\["styles"\]](/components/tree-select#api), switcherIcon?: [TreeSelect\["switcherIcon"\]](/components/tree-select#api) } | - | 5.25.0, `switcherIcon`: 5.28.0 |
| typography | Set Typography common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| upload | Set Upload common props | { className?: string, style?: React.CSSProperties, customRequest?: [Upload\["customRequest"\]](/components/upload#api) } | - | 5.7.0, `customRequest`: 5.27.0 |
| wave | Config wave effect | { disabled?: boolean, showEffect?: (node: HTMLElement, info: { className, token, component }) => void } | - | 5.8.0 |

View File

@@ -134,7 +134,7 @@ const {
| floatButton | 设置 FloatButton 组件的通用属性 | { backTopIcon?: React.ReactNode } | - | 5.27.0 |
| floatButtonGroup | 设置 FloatButton.Group 组件的通用属性 | { closeIcon?: React.ReactNode } | - | 5.16.0 |
| form | 设置 Form 组件的通用属性 | { className?: string, style?: React.CSSProperties, validateMessages?: [ValidateMessages](/components/form-cn#validatemessages), `requiredMark`?: boolean \| `optional`, colon?: boolean, scrollToFirstError?: boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options)} | - | `requiredMark`: 4.8.0; `colon`: 4.18.0; `scrollToFirstError`: 5.2.0; `className``style`: 5.7.0 |
| image | 设置 Image 组件的通用属性 | { className?: string, style?: React.CSSProperties, preview?: { closeIcon?: React.ReactNode } } | - | 5.7.0, `closeIcon`: 5.14.0 |
| image | 设置 Image 组件的通用属性 | { className?: string, style?: React.CSSProperties, preview?: { closeIcon?: React.ReactNode }, fallback?: string } | - | 5.7.0, `closeIcon`: 5.14.0, `fallback`: 5.28.0 |
| input | 设置 Input 组件的通用属性 | { autoComplete?: string, className?: string, style?: React.CSSProperties, allowClear?: boolean \| { clearIcon?: ReactNode } } | - | 5.7.0, `allowClear`: 5.15.0 |
| textArea | 设置 TextArea 组件的通用属性 | { autoComplete?: string, className?: string, style?: React.CSSProperties, allowClear?: boolean \| { clearIcon?: ReactNode } } | - | 5.15.0 |
| layout | 设置 Layout 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
@@ -170,7 +170,7 @@ const {
| popconfirm | 设置 Popconfirm 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?:[Popconfirm\["classNames"\]](/components/popconfirm-cn#api), styles?: [Popconfirm\["styles"\]](/components/popconfirm-cn#api) } | - | 5.23.0 |
| transfer | 设置 Transfer 组件的通用属性 | { className?: string, style?: React.CSSProperties, selectionsIcon?: React.ReactNode } | - | 5.7.0, `selectionsIcon`: 5.14.0 |
| tree | 设置 Tree 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| treeSelect | 设置 TreeSelect 组件的通用属性 | { classNames?:[TreeSelect\["classNames"\]](/components/tree-select-cn#api), styles?: [TreeSelect\["styles"\]](/components/tree-select-cn#api) } | - | 5.25.0 |
| treeSelect | 设置 TreeSelect 组件的通用属性 | { classNames?:[TreeSelect\["classNames"\]](/components/tree-select-cn#api), styles?: [TreeSelect\["styles"\]](/components/tree-select-cn#api), switcherIcon?: [TreeSelect\["switcherIcon"\]](/components/tree-select-cn#api) } | - | 5.25.0, `switcherIcon`: 5.28.0 |
| typography | 设置 Typography 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 |
| upload | 设置 Upload 组件的通用属性 | { className?: string, style?: React.CSSProperties, customRequest?: [Upload\["customRequest"\]](/components/upload-cn#api) } | - | 5.7.0, `customRequest`: 5.27.0 |
| wave | 设置水波纹特效 | { disabled?: boolean, showEffect?: (node: HTMLElement, info: { className, token, component }) => void } | - | 5.8.0 |

View File

@@ -480,4 +480,22 @@ describe('DatePicker', () => {
rerender(<DatePicker value={somePoint} allowClear={{}} />);
expect(getClearButton()).toBeTruthy();
});
it('suffixIcon', () => {
const { rerender, container } = render(<DatePicker />);
expect(container.querySelector('.ant-picker-suffix')!.children.length).toBeTruthy();
rerender(<DatePicker suffixIcon />);
expect(container.querySelector('.ant-picker-suffix')!.children.length).toBeTruthy();
rerender(<DatePicker suffixIcon={false} />);
expect(container.querySelector('.ant-picker-suffix')!.children.length).toBeFalsy();
rerender(<DatePicker suffixIcon={null} />);
expect(container.querySelector('.ant-picker-suffix')!.children.length).toBeFalsy();
rerender(<DatePicker suffixIcon={'123'} />);
expect(container.querySelector('.ant-picker-suffix')?.textContent).toBe('123');
expect(container.children).toMatchSnapshot();
});
});

View File

@@ -643,6 +643,31 @@ Array [
]
`;
exports[`DatePicker suffixIcon 1`] = `
Array [
<div
class="ant-picker ant-picker-outlined"
>
<div
class="ant-picker-input"
>
<input
aria-invalid="false"
autocomplete="off"
placeholder="Select date"
size="12"
value=""
/>
<span
class="ant-picker-suffix"
>
123
</span>
</div>
</div>,
]
`;
exports[`DatePicker support DatePicker.generatePicker 1`] = `
<div
class="ant-picker ant-picker-outlined"

View File

@@ -7414,6 +7414,165 @@ exports[`renders components/date-picker/demo/suffix.tsx correctly 1`] = `
</div>
`;
exports[`renders components/date-picker/demo/suffixIcon-debug.tsx correctly 1`] = `
<div
class="ant-space ant-space-vertical ant-space-gap-row-small ant-space-gap-col-small"
>
<div
class="ant-space-item"
>
<div
class="ant-picker ant-picker-outlined"
>
<div
class="ant-picker-input"
>
<input
aria-invalid="false"
autocomplete="off"
placeholder="Select date"
size="12"
value=""
/>
<span
class="ant-picker-suffix"
>
<span
aria-label="calendar"
class="anticon anticon-calendar"
role="img"
>
<svg
aria-hidden="true"
data-icon="calendar"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zm-40 656H184V460h656v380zM184 392V256h128v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h256v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h128v136H184z"
/>
</svg>
</span>
</span>
</div>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-picker ant-picker-outlined"
>
<div
class="ant-picker-input"
>
<input
aria-invalid="false"
autocomplete="off"
placeholder="Select date"
size="12"
value=""
/>
<span
class="ant-picker-suffix"
/>
</div>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-picker ant-picker-outlined"
>
<div
class="ant-picker-input"
>
<input
aria-invalid="false"
autocomplete="off"
placeholder="Select date"
size="12"
value=""
/>
<span
class="ant-picker-suffix"
>
<span
aria-label="calendar"
class="anticon anticon-calendar"
role="img"
>
<svg
aria-hidden="true"
data-icon="calendar"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M880 184H712v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H384v-64c0-4.4-3.6-8-8-8h-56c-4.4 0-8 3.6-8 8v64H144c-17.7 0-32 14.3-32 32v664c0 17.7 14.3 32 32 32h736c17.7 0 32-14.3 32-32V216c0-17.7-14.3-32-32-32zm-40 656H184V460h656v380zM184 392V256h128v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h256v48c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8v-48h128v136H184z"
/>
</svg>
</span>
</span>
</div>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-picker ant-picker-outlined"
>
<div
class="ant-picker-input"
>
<input
aria-invalid="false"
autocomplete="off"
placeholder="Select date"
size="12"
value=""
/>
<span
class="ant-picker-suffix"
/>
</div>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-picker ant-picker-outlined"
>
<div
class="ant-picker-input"
>
<input
aria-invalid="false"
autocomplete="off"
placeholder="Select date"
size="12"
value=""
/>
<span
class="ant-picker-suffix"
>
123
</span>
</div>
</div>
</div>
</div>
`;
exports[`renders components/date-picker/demo/switchable.tsx correctly 1`] = `
<div
class="ant-space ant-space-horizontal ant-space-align-center ant-space-gap-row-small ant-space-gap-col-small"

View File

@@ -2,14 +2,14 @@ import type { render } from '../../../tests/utils';
import { fireEvent } from '../../../tests/utils';
export function openPicker(wrapper: ReturnType<typeof render>, index = 0) {
const inputEle = wrapper.container?.querySelectorAll<HTMLInputElement>('input')?.[index]!;
const inputEle = wrapper.container?.querySelectorAll<HTMLInputElement>('input')?.[index];
fireEvent.mouseDown(inputEle);
fireEvent.focus(inputEle);
fireEvent.click(inputEle);
}
export function closePicker(wrapper: ReturnType<typeof render>, index = 0) {
fireEvent.blur(wrapper.container?.querySelectorAll('input')[index]!);
fireEvent.blur(wrapper.container?.querySelectorAll('input')[index]);
}
export function selectCell(wrapper: ReturnType<typeof render>, text: string | number, index = 0) {

View File

@@ -0,0 +1,7 @@
## zh-CN
suffixIcon 测试。
## en-US
suffixIcon test.

View File

@@ -0,0 +1,14 @@
import React from 'react';
import { DatePicker, Space } from 'antd';
const App: React.FC = () => (
<Space direction="vertical">
<DatePicker suffixIcon />
<DatePicker suffixIcon={false} />
<DatePicker />
<DatePicker suffixIcon={null} />
<DatePicker suffixIcon={'123'} />
</Space>
);
export default App;

View File

@@ -2,19 +2,20 @@ import React, { useState } from 'react';
import type { DatePickerProps, TimePickerProps } from 'antd';
import { DatePicker, Select, Space, TimePicker } from 'antd';
const { Option } = Select;
type PickerType = 'time' | 'date';
const PickerWithType = ({
type,
onChange,
}: {
interface PickerWithTypeProps {
type: PickerType;
onChange: TimePickerProps['onChange'] | DatePickerProps['onChange'];
}) => {
if (type === 'time') return <TimePicker onChange={onChange} />;
if (type === 'date') return <DatePicker onChange={onChange} />;
}
const PickerWithType: React.FC<PickerWithTypeProps> = ({ type, onChange }) => {
if (type === 'time') {
return <TimePicker onChange={onChange} />;
}
if (type === 'date') {
return <DatePicker onChange={onChange} />;
}
return <DatePicker picker={type} onChange={onChange} />;
};
@@ -23,14 +24,19 @@ const App: React.FC = () => {
return (
<Space>
<Select aria-label="Picker Type" value={type} onChange={setType}>
<Option value="time">Time</Option>
<Option value="date">Date</Option>
<Option value="week">Week</Option>
<Option value="month">Month</Option>
<Option value="quarter">Quarter</Option>
<Option value="year">Year</Option>
</Select>
<Select
aria-label="Picker Type"
value={type}
onChange={setType}
options={[
{ label: 'Time', value: 'time' },
{ label: 'Date', value: 'date' },
{ label: 'Week', value: 'week' },
{ label: 'Month', value: 'month' },
{ label: 'Quarter', value: 'quarter' },
{ label: 'Year', value: 'year' },
]}
/>
<PickerWithType type={type} onChange={(value) => console.log(value)} />
</Space>
);

View File

@@ -0,0 +1,36 @@
import React from 'react';
import CalendarOutlined from '@ant-design/icons/CalendarOutlined';
import ClockCircleOutlined from '@ant-design/icons/ClockCircleOutlined';
import type { PickerMode } from 'rc-picker/lib/interface';
import { TIME } from '../generatePicker/constant';
interface SuffixIconProps {
picker?: PickerMode;
hasFeedback?: boolean;
feedbackIcon?: React.ReactNode;
suffixIcon?: React.ReactNode;
}
const SuffixIcon: React.FC<SuffixIconProps> = ({
picker,
hasFeedback,
feedbackIcon,
suffixIcon,
}) => {
if (suffixIcon === null || suffixIcon === false) {
return null;
}
if (suffixIcon === true || suffixIcon === undefined) {
return (
<>
{picker === TIME ? <ClockCircleOutlined /> : <CalendarOutlined />}
{hasFeedback && feedbackIcon}
</>
);
}
return suffixIcon;
};
export default SuffixIcon;

View File

@@ -1,7 +1,5 @@
import * as React from 'react';
import { forwardRef, useContext, useImperativeHandle } from 'react';
import CalendarOutlined from '@ant-design/icons/CalendarOutlined';
import ClockCircleOutlined from '@ant-design/icons/ClockCircleOutlined';
import SwapRightOutlined from '@ant-design/icons/SwapRightOutlined';
import cls from 'classnames';
import { RangePicker as RCRangePicker } from 'rc-picker';
@@ -9,7 +7,7 @@ import type { PickerRef } from 'rc-picker';
import type { GenerateConfig } from 'rc-picker/lib/generate/index';
import ContextIsolator from '../../_util/ContextIsolator';
import { useZIndex } from '../../_util/hooks/useZIndex';
import { useZIndex } from '../../_util/hooks';
import { getMergedStatus, getStatusClassNames } from '../../_util/statusUtils';
import type { AnyObject } from '../../_util/type';
import { devUseWarning } from '../../_util/warning';
@@ -21,13 +19,14 @@ import { FormItemInputContext } from '../../form/context';
import useVariant from '../../form/hooks/useVariants';
import { useLocale } from '../../locale';
import { useCompactItemContext } from '../../space/Compact';
import useMergedPickerSemantic from '../hooks/useMergedPickerSemantic';
import enUS from '../locale/en_US';
import useStyle from '../style';
import { getRangePlaceholder, useIcons } from '../util';
import { TIME } from './constant';
import type { RangePickerProps } from './interface';
import SuffixIcon from './SuffixIcon';
import useComponents from './useComponents';
import useMergedPickerSemantic from '../hooks/useMergedPickerSemantic';
const generateRangePicker = <DateType extends AnyObject = AnyObject>(
generateConfig: GenerateConfig<DateType>,
@@ -55,6 +54,7 @@ const generateRangePicker = <DateType extends AnyObject = AnyObject>(
picker,
styles,
classNames,
suffixIcon,
...restProps
} = props;
@@ -112,14 +112,7 @@ const generateRangePicker = <DateType extends AnyObject = AnyObject>(
// ===================== FormItemInput =====================
const formItemContext = useContext(FormItemInputContext);
const { hasFeedback, status: contextStatus, feedbackIcon } = formItemContext;
const suffixNode = (
<>
{picker === TIME ? <ClockCircleOutlined /> : <CalendarOutlined />}
{hasFeedback && feedbackIcon}
</>
);
const mergedSuffixIcon = <SuffixIcon {...{ picker, hasFeedback, feedbackIcon, suffixIcon }} />;
useImperativeHandle(ref, () => innerRef.current!);
const [contextLocale] = useLocale('Calendar', enUS);
@@ -141,7 +134,7 @@ const generateRangePicker = <DateType extends AnyObject = AnyObject>(
ref={innerRef as any} // Need to modify PickerRef
placement={placement}
placeholder={getRangePlaceholder(locale, picker, placeholder)}
suffixIcon={suffixNode}
suffixIcon={mergedSuffixIcon}
prevIcon={<span className={`${prefixCls}-prev-icon`} />}
nextIcon={<span className={`${prefixCls}-next-icon`} />}
superPrevIcon={<span className={`${prefixCls}-super-prev-icon`} />}

View File

@@ -1,7 +1,5 @@
import * as React from 'react';
import { forwardRef, useContext, useImperativeHandle } from 'react';
import CalendarOutlined from '@ant-design/icons/CalendarOutlined';
import ClockCircleOutlined from '@ant-design/icons/ClockCircleOutlined';
import cls from 'classnames';
import RCPicker from 'rc-picker';
import type { PickerRef } from 'rc-picker';
@@ -9,7 +7,7 @@ import type { GenerateConfig } from 'rc-picker/lib/generate/index';
import type { PickerMode } from 'rc-picker/lib/interface';
import ContextIsolator from '../../_util/ContextIsolator';
import { useZIndex } from '../../_util/hooks/useZIndex';
import { useZIndex } from '../../_util/hooks';
import { getMergedStatus, getStatusClassNames } from '../../_util/statusUtils';
import type { AnyObject } from '../../_util/type';
import { devUseWarning } from '../../_util/warning';
@@ -21,6 +19,7 @@ import { FormItemInputContext } from '../../form/context';
import useVariant from '../../form/hooks/useVariants';
import { useLocale } from '../../locale';
import { useCompactItemContext } from '../../space/Compact';
import useMergedPickerSemantic from '../hooks/useMergedPickerSemantic';
import enUS from '../locale/en_US';
import useStyle from '../style';
import { getPlaceholder, useIcons } from '../util';
@@ -37,8 +36,8 @@ import {
YEARPICKER,
} from './constant';
import type { GenericTimePickerProps, PickerProps, PickerPropsWithMultiple } from './interface';
import SuffixIcon from './SuffixIcon';
import useComponents from './useComponents';
import useMergedPickerSemantic from '../hooks/useMergedPickerSemantic';
const generatePicker = <DateType extends AnyObject = AnyObject>(
generateConfig: GenerateConfig<DateType>,
@@ -69,6 +68,7 @@ const generatePicker = <DateType extends AnyObject = AnyObject>(
onCalendarChange,
styles,
classNames,
suffixIcon,
...restProps
} = props;
@@ -159,13 +159,9 @@ const generatePicker = <DateType extends AnyObject = AnyObject>(
const formItemContext = useContext(FormItemInputContext);
const { hasFeedback, status: contextStatus, feedbackIcon } = formItemContext;
const suffixNode = (
<>
{mergedPicker === 'time' ? <ClockCircleOutlined /> : <CalendarOutlined />}
{hasFeedback && feedbackIcon}
</>
const mergedSuffixIcon = (
<SuffixIcon {...{ picker: mergedPicker, hasFeedback, feedbackIcon, suffixIcon }} />
);
const [contextLocale] = useLocale('DatePicker', enUS);
const locale = { ...contextLocale, ...props.locale! };
@@ -177,7 +173,7 @@ const generatePicker = <DateType extends AnyObject = AnyObject>(
<RCPicker<DateType>
ref={innerRef}
placeholder={getPlaceholder(locale, mergedPicker, placeholder)}
suffixIcon={suffixNode}
suffixIcon={mergedSuffixIcon}
placement={placement}
prevIcon={<span className={`${prefixCls}-prev-icon`} />}
nextIcon={<span className={`${prefixCls}-next-icon`} />}

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