diff --git a/.circleci/config.yml b/.circleci/config.yml index 2e2f2fd3c8b1..1301ae42fcbc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,9 +7,7 @@ version: 2.1 jobs: test-argos-ci: docker: - - image: cimg/node:21.1-browsers - environment: - NODE_OPTIONS: --openssl-legacy-provider + - image: cimg/node:21.2-browsers steps: - checkout - run: diff --git a/.codesandbox/ci.json b/.codesandbox/ci.json index c1e8e1305f2d..96c2526e4c4b 100644 --- a/.codesandbox/ci.json +++ b/.codesandbox/ci.json @@ -1,4 +1,4 @@ { - "sandboxes": ["antd-reproduction-template-y9vgcf"], - "node": "14" + "sandboxes": ["antd-reproduction-template-forked-jyh2k9"], + "node": "18" } diff --git a/.dumi/pages/index/components/PreviewBanner/ComponentsBlock.tsx b/.dumi/pages/index/components/PreviewBanner/ComponentsBlock.tsx index 42dc50702d02..f9f937b3f289 100644 --- a/.dumi/pages/index/components/PreviewBanner/ComponentsBlock.tsx +++ b/.dumi/pages/index/components/PreviewBanner/ComponentsBlock.tsx @@ -19,6 +19,7 @@ import { import { createStyles } from 'antd-style'; import classNames from 'classnames'; +import Tilt from './Tilt'; import useLocale from '../../../../hooks/useLocale'; const { _InternalPanelDoNotUseOrYouWillBeFired: ModalPanel } = Modal; @@ -79,7 +80,7 @@ const useStyle = createStyles(({ token, css }) => { display: flex; flex-direction: column; row-gap: ${gap}px; - opacity: 0.65; + opacity: 0.8; `, flex: css` @@ -117,7 +118,11 @@ const ComponentsBlock: React.FC = (props) => { const { styles } = useStyle(); return ( -
+ {locale.text} @@ -252,7 +257,7 @@ const ComponentsBlock: React.FC = (props) => { -
+ ); }; diff --git a/.dumi/pages/index/components/PreviewBanner/Tilt.tsx b/.dumi/pages/index/components/PreviewBanner/Tilt.tsx new file mode 100644 index 000000000000..51f758ab86f9 --- /dev/null +++ b/.dumi/pages/index/components/PreviewBanner/Tilt.tsx @@ -0,0 +1,33 @@ +import React, { useEffect, useRef } from 'react'; +import VanillaTilt, { type TiltOptions } from 'vanilla-tilt'; + +interface TiltProps extends React.HTMLAttributes { + options?: TiltOptions; +} + +// https://micku7zu.github.io/vanilla-tilt.js/index.html +const defaultTiltOptions = { + scale: 1.02, + max: 8, + speed: 1500, + glare: true, + 'max-glare': 0.8, +}; + +const Tilt: React.FC = ({ options, ...props }) => { + const node = useRef(null); + useEffect(() => { + if (node.current) { + VanillaTilt.init(node.current, { + ...defaultTiltOptions, + ...options, + }); + } + return () => { + (node.current as any)?.vanillaTilt.destroy(); + }; + }, []); + return
; +}; + +export default Tilt; diff --git a/.dumi/pages/index/components/PreviewBanner/index.tsx b/.dumi/pages/index/components/PreviewBanner/index.tsx index 45991dfaba52..e84689170b4e 100644 --- a/.dumi/pages/index/components/PreviewBanner/index.tsx +++ b/.dumi/pages/index/components/PreviewBanner/index.tsx @@ -7,7 +7,6 @@ import useLocale from '../../../../hooks/useLocale'; import SiteContext from '../../../../theme/slots/SiteContext'; import * as utils from '../../../../theme/utils'; import { GroupMask } from '../Group'; -import useMouseTransform from './useMouseTransform'; const ComponentsBlock = React.lazy(() => import('./ComponentsBlock')); @@ -28,7 +27,6 @@ const locales = { const useStyle = () => { const { direction } = React.useContext(ConfigProvider.ConfigContext); const isRTL = direction === 'rtl'; - return createStyles(({ token, css, cx }) => { const textShadow = `0 0 3px ${token.colorBgContainer}`; @@ -37,7 +35,9 @@ const useStyle = () => { inset: 0; backdrop-filter: blur(4px); opacity: 1; - transition: opacity 1s ease; + background: rgba(255, 255, 255, 0.2); + transition: all 1s ease; + pointer-events: none; `); return { @@ -114,10 +114,8 @@ const PreviewBanner: React.FC = (props) => { const { pathname, search } = useLocation(); const isZhCN = utils.isZhCN(pathname); - const [componentsBlockStyle, mouseEvents] = useMouseTransform(); - return ( - + {/* Image Left Top */} = (props) => {
{/* Mobile not show the component preview */} - {!isMobile && } + {isMobile ? null : ( +
+ +
+ )}
diff --git a/.dumi/pages/index/components/PreviewBanner/useMouseTransform.tsx b/.dumi/pages/index/components/PreviewBanner/useMouseTransform.tsx deleted file mode 100644 index a6985067bb6a..000000000000 --- a/.dumi/pages/index/components/PreviewBanner/useMouseTransform.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import React, { startTransition } from 'react'; -import { ConfigProvider } from 'antd'; - -const getTransformRotateStyle = ( - event: React.MouseEvent, - currentTarget: EventTarget & HTMLDivElement, - multiple: number, - isRTL: boolean, -): string => { - const box = currentTarget?.getBoundingClientRect(); - const calcX = -(event.clientY - box.y - box.height / 2) / multiple; - const calcY = (event.clientX - box.x - box.width / 2) / multiple; - return isRTL - ? `rotate3d(${24 + calcX}, ${83 + calcY}, -45, 57deg)` - : `rotate3d(${24 + calcX}, ${-83 + calcY}, 45, 57deg)`; -}; - -const useMouseTransform = ({ transitionDuration = 500, multiple = 36 } = {}) => { - const [componentsBlockStyle, setComponentsBlockStyle] = React.useState({}); - - const { direction } = React.useContext(ConfigProvider.ConfigContext); - - const isRTL = direction === 'rtl'; - - const onMouseMove: React.MouseEventHandler = (event) => { - const { currentTarget } = event; - startTransition(() => { - setComponentsBlockStyle((style) => ({ - ...style, - transform: getTransformRotateStyle(event, currentTarget, multiple, isRTL), - })); - }); - }; - - const onMouseEnter: React.MouseEventHandler = () => { - startTransition(() => { - setComponentsBlockStyle((style) => ({ - ...style, - transition: `transform ${transitionDuration / 1000}s`, - })); - }); - - setTimeout(() => { - startTransition(() => { - setComponentsBlockStyle((style) => ({ - ...style, - transition: '', - })); - }); - }, transitionDuration); - }; - - const onMouseLeave: React.MouseEventHandler = () => { - startTransition(() => { - setComponentsBlockStyle((style) => ({ - ...style, - transition: `transform ${transitionDuration / 1000}s`, - transform: '', - })); - }); - }; - - return [ - componentsBlockStyle, - { - onMouseMove, - onMouseEnter, - onMouseLeave, - }, - ] as const; -}; - -export default useMouseTransform; diff --git a/.dumi/theme/common/LiveCode.tsx b/.dumi/theme/common/LiveCode.tsx index 9f80e95c6e04..960e47529ac0 100644 --- a/.dumi/theme/common/LiveCode.tsx +++ b/.dumi/theme/common/LiveCode.tsx @@ -16,11 +16,11 @@ const useStyle = createStyles(({ token, css }) => { outline: none; &:hover { - border: 1px solid ${colorPrimaryBorder} !important; + box-shadow: inset 0 0 0 1px ${colorPrimaryBorder} !important; } &:focus { - border: 1px solid ${colorPrimary} !important; + box-shadow: inset 0 0 0 1px ${colorPrimary} !important; } } `, diff --git a/.dumi/theme/locales/en-US.json b/.dumi/theme/locales/en-US.json index 6ca8a49d35ef..41dd07030610 100644 --- a/.dumi/theme/locales/en-US.json +++ b/.dumi/theme/locales/en-US.json @@ -111,6 +111,8 @@ "app.footer.seeconf": "Experience Tech Conference", "app.footer.xtech": "Ant Financial Experience Tech", "app.footer.xtech.slogan": "Experience The Beauty", + "app.footer.galacean": "Galacean", + "app.footer.galacean.slogan": "Interactive Graphics Solution", "app.docs.color.pick-primary": "Pick your primary color", "app.docs.color.pick-background": "Pick your background color", "app.docs.components.icon.search.placeholder": "Search icons here, click icon to copy code", diff --git a/.dumi/theme/locales/zh-CN.json b/.dumi/theme/locales/zh-CN.json index 2a37d63e3ea7..1cefada772ef 100644 --- a/.dumi/theme/locales/zh-CN.json +++ b/.dumi/theme/locales/zh-CN.json @@ -110,6 +110,8 @@ "app.footer.seeconf": "蚂蚁体验科技大会", "app.footer.xtech": "蚂蚁体验科技", "app.footer.xtech.slogan": "让用户体验美好", + "app.footer.galacean": "Galacean", + "app.footer.galacean.slogan": "互动图形解决方案", "app.docs.color.pick-primary": "选择你的主色", "app.docs.color.pick-background": "选择你的背景色", "app.docs.components.icon.search.placeholder": "在此搜索图标,点击图标可复制代码", diff --git a/.dumi/theme/slots/Footer/index.tsx b/.dumi/theme/slots/Footer/index.tsx index 6b34e18ed5aa..fa5ab60ad71d 100644 --- a/.dumi/theme/slots/Footer/index.tsx +++ b/.dumi/theme/slots/Footer/index.tsx @@ -363,6 +363,20 @@ const Footer: React.FC = () => { url: 'https://kitchen.alipay.com', openExternal: true, }, + { + icon: ( + Galacean + ), + title: , + description: , + url: 'https://galacean.antgroup.com/', + openExternal: true, + }, { icon: ( { )} {isZhCN && bannerVisible && ( - + - yuque {isMobile ? locale.shortMessage : locale.message} { window.gtag?.('event', '点击', { event_category: 'top_banner', - event_label: 'https://www.yuque.com/yuque/blog/welfare-edu?source=antd', + event_label: locale.link, }); }} > diff --git a/.eslintrc.js b/.eslintrc.js index 12e49328d21e..ca15e6624923 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -25,7 +25,16 @@ module.exports = { }, }, parser: '@typescript-eslint/parser', - plugins: ['react', '@babel', 'jest', '@typescript-eslint', 'react-hooks', 'unicorn', 'markdown'], + plugins: [ + 'react', + '@babel', + 'jest', + '@typescript-eslint', + 'react-hooks', + 'unicorn', + 'markdown', + 'lodash', + ], // https://github.com/typescript-eslint/typescript-eslint/issues/46#issuecomment-470486034 overrides: [ { @@ -156,6 +165,7 @@ module.exports = { 'react/no-unused-class-component-methods': 0, 'import/extensions': 0, 'import/no-cycle': 2, + 'lodash/import-scope': 2, 'import/no-extraneous-dependencies': [ 'error', { diff --git a/.github/lock.yml b/.github/lock.yml deleted file mode 100644 index e5b9a627f1e1..000000000000 --- a/.github/lock.yml +++ /dev/null @@ -1,14 +0,0 @@ -# Configuration for lock-threads - https://github.com/dessant/lock-threads - -# Number of days of inactivity before a closed issue or pull request is locked -daysUntilLock: 365 -# Comment to post before locking. Set to `false` to disable -lockComment: > - This thread has been automatically locked because it has not had recent - activity. Please open a new issue for related bugs and link to relevant - comments in this thread. -# Issues or pull requests with these labels will not be locked -# exemptLabels: -# - no-locking -# Limit to only `issues` or `pulls` -only: issues diff --git a/.github/tests_checker.yml b/.github/tests_checker.yml deleted file mode 100644 index 46378d7461df..000000000000 --- a/.github/tests_checker.yml +++ /dev/null @@ -1,3 +0,0 @@ -comment: 'Could you please add tests to make sure this change works as expected?', -fileExtensions: [.ts', '.tsx', '.json'] -testDir: '__tests__' diff --git a/.github/workflows/issue-labeled.yml b/.github/workflows/issue-labeled.yml index 40f70446d23c..2f818e5a7cf8 100644 --- a/.github/workflows/issue-labeled.yml +++ b/.github/workflows/issue-labeled.yml @@ -40,7 +40,9 @@ jobs: body: | Hello @${{ github.event.issue.user.login }}. Please provide a online reproduction by forking codesandbox of [antd@5.x](https://u.ant.design/codesandbox-repro) or [antd@4.x](https://u.ant.design/codesandbox-repro-4x), or provide a minimal GitHub repository. Issues labeled by `Need Reproduce` will be closed if no activities in 3 days. - 你好 @${{ github.event.issue.user.login }}, 我们需要你提供一个在线的重现实例以便于我们帮你排查问题。你可以通过点击这里创建一个 [antd@5.x](https://u.ant.design/codesandbox-repro) 或 [antd@4.x](https://u.ant.design/codesandbox-repro-4x) 的 codesandbox,或者提供一个最小化的 GitHub 仓库。3 天内未跟进此 issue 将会被自动关闭。 + 你好 @${{ github.event.issue.user.login }},我们需要你提供一个在线的重现实例以便于我们帮你排查问题。你可以通过点击这里创建一个 [antd@5.x](https://u.ant.design/codesandbox-repro) 或 [antd@4.x](https://u.ant.design/codesandbox-repro-4x) 的 codesandbox,或者提供一个最小化的 GitHub 仓库。3 天内未跟进此 issue 将会被自动关闭。 + + > [什么是最小化重现,为什么这是必需的?](https://github.com/ant-design/ant-design/wiki/%E4%BB%80%E4%B9%88%E6%98%AF%E6%9C%80%E5%B0%8F%E5%8C%96%E9%87%8D%E7%8E%B0%EF%BC%8C%E4%B8%BA%E4%BB%80%E4%B9%88%E8%BF%99%E6%98%AF%E5%BF%85%E9%9C%80%E7%9A%84%EF%BC%9F) ![](https://gw.alipayobjects.com/zos/antfincdn/y9kwg7DVCd/reproduce.gif) diff --git a/.github/workflows/pr-open-check.yml b/.github/workflows/pr-open-check.yml index 2c6c89b3c9f8..f30c621392ad 100644 --- a/.github/workflows/pr-open-check.yml +++ b/.github/workflows/pr-open-check.yml @@ -19,10 +19,13 @@ jobs: refuse-issue-label: '🎱 Collaborate PR only' need-creator-authority: 'write' comment: | - Hi @${{ github.event.pull_request.user.login }}. The issue mentioned in this PR needs to be confirmed with the designer or core team. This PR is temporarily not accepted. Thank you again for your contribution! 😊 + Hi @${{ github.event.pull_request.user.login }}. The issue mentioned in this PR needs to be confirmed with the designer or core team. Thank you for your contribution! 😊 - 你好 @${{ github.event.pull_request.user.login }}。这个 PR 提及的 issue 需要和设计师或核心团队进行确认,暂时不接受 PR,再次感谢你的贡献!😊 - close: true + 你好 @${{ github.event.pull_request.user.login }}。这个 PR 提及的 issue 需要和设计师或核心团队进行确认!感谢您的贡献!😊 + close: false + reviewers: | + MadCcc + zombieJ check-changelog: permissions: diff --git a/.github/workflows/preview-build.yml b/.github/workflows/preview-build.yml index 03660a33f417..d8d58e4c1ba9 100644 --- a/.github/workflows/preview-build.yml +++ b/.github/workflows/preview-build.yml @@ -74,7 +74,7 @@ jobs: run: npm run site env: SITE_ENV: development - NODE_OPTIONS: "--max_old_space_size=4096 --openssl-legacy-provider" + NODE_OPTIONS: "--max_old_space_size=4096" - name: upload site artifact uses: actions/upload-artifact@v3 diff --git a/.github/workflows/preview-deploy.yml b/.github/workflows/preview-deploy.yml index 2c6910ea67e3..faff89343859 100644 --- a/.github/workflows/preview-deploy.yml +++ b/.github/workflows/preview-deploy.yml @@ -74,6 +74,7 @@ jobs: # Download site artifact - name: download site artifact + if: ${{ fromJSON(needs.upstream-workflow-summary.outputs.build-success) }} uses: dawidd6/action-download-artifact@v2 with: workflow: ${{ github.event.workflow_run.workflow_id }} @@ -81,7 +82,6 @@ jobs: name: site - name: upload surge service - if: ${{ fromJSON(needs.upstream-workflow-summary.outputs.build-success) }} id: deploy continue-on-error: true run: | diff --git a/.github/workflows/release-tweet.yml b/.github/workflows/release-tweet.yml index 00939457ad8a..449ea8ae6f64 100644 --- a/.github/workflows/release-tweet.yml +++ b/.github/workflows/release-tweet.yml @@ -1,21 +1,21 @@ name: 🐦 Release to Tweet on: - release: - types: [published] + create permissions: contents: read jobs: tweet: + if: ${{ github.event.ref_type == 'tag' && !contains(github.event.ref, 'alpha') }} runs-on: ubuntu-latest steps: - name: Tweet uses: nearform-actions/github-action-notify-twitter@v1 with: message: | - Ant Design (antd@${{ github.event.release.tag_name }}) has been released ~ 🎊🎊🎊 Check out the release notes: ${{ github.event.release.html_url }} + 🤖 Ant Design just released antd@${{ github.event.ref }} ✨🎊✨ Check out the full release note: https://github.com/ant-design/ant-design/releases/tag/${{ github.event.ref }} twitter-app-key: ${{ secrets.TWITTER_API_KEY }} twitter-app-secret: ${{ secrets.TWITTER_API_SECRET_KEY }} twitter-access-token: ${{ secrets.TWITTER_ACCESS_TOKEN }} diff --git a/.github/workflows/site-deploy.yml b/.github/workflows/site-deploy.yml index 5b7e12a470bf..4f2bc798da98 100644 --- a/.github/workflows/site-deploy.yml +++ b/.github/workflows/site-deploy.yml @@ -70,13 +70,13 @@ jobs: - name: build site run: npm run predeploy env: - NODE_OPTIONS: "--max_old_space_size=4096 --openssl-legacy-provider" + NODE_OPTIONS: "--max_old_space_size=4096" - name: build dist and bundle analyzer report run: npm run dist env: ANALYZER: 1 - NODE_OPTIONS: "--max_old_space_size=4096 --openssl-legacy-provider" + NODE_OPTIONS: "--max_old_space_size=4096" - name: Get version id: publish-version diff --git a/.github/workflows/size-limit.yml b/.github/workflows/size-limit.yml index 89b0b50e008c..d42cd6f3a05d 100644 --- a/.github/workflows/size-limit.yml +++ b/.github/workflows/size-limit.yml @@ -63,5 +63,5 @@ jobs: build_script: dist skip_step: install env: - NODE_OPTIONS: "--max_old_space_size=4096 --openssl-legacy-provider" + NODE_OPTIONS: "--max_old_space_size=4096" PRODUCTION_ONLY: 1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1c15128b37db..2e295185ab04 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -131,7 +131,7 @@ jobs: - name: dist run: npm run dist env: - NODE_OPTIONS: "--max_old_space_size=4096 --openssl-legacy-provider" + NODE_OPTIONS: "--max_old_space_size=4096" CI: 1 needs: setup diff --git a/.github/workflows/trigger-argos-with-whitelist-users.yml b/.github/workflows/trigger-argos-with-whitelist-users.yml index 3c310afaf4a8..126f0dd67628 100644 --- a/.github/workflows/trigger-argos-with-whitelist-users.yml +++ b/.github/workflows/trigger-argos-with-whitelist-users.yml @@ -40,9 +40,17 @@ jobs: echo "whitelisted=false" >> $GITHUB_OUTPUT fi - - name: install dependencies - if: ${{ steps.check_user.outputs.whitelisted == 'true' }} - run: yarn + - name: cache package-lock.json + uses: actions/cache@v3 + with: + path: package-temp-dir + key: lock-${{ github.sha }} + + - name: create package-lock.json + run: npm i --package-lock-only --ignore-scripts + + - name: install + run: npm install - name: Build dist file id: build diff --git a/.github/workflows/upgrade-deps.yml b/.github/workflows/upgrade-deps.yml new file mode 100644 index 000000000000..d6169a8c6b2d --- /dev/null +++ b/.github/workflows/upgrade-deps.yml @@ -0,0 +1,60 @@ +name: Upgrade Dependencies + +on: + schedule: + - cron: "0 18 * * *" # every day at 18:00 UTC + # - timezone: Asia/Shanghai # not supported yet https://github.com/orgs/community/discussions/13454 + +jobs: + upgrade-deps: + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/master' + permissions: + pull-requests: write # for peter-evans/create-pull-request to create PRs + contents: write # for git push + steps: + - name: checkout + uses: actions/checkout@v4 + with: + sparse-checkout: | + .github + .ncurc.js + package.json + + - name: setup node + uses: actions/setup-node@v3 + with: + node-version: 18 + + - name: upgrade deps + id: upgrade + run: | + if [ ! -d .tmp ] ; then + mkdir .tmp + fi + $(npx npm-check-updates -u > .tmp/upgrade-deps-logs.txt) 2>&1 || true + if [ -s .tmp/upgrade-deps-logs.txt ]; then + cat .tmp/upgrade-deps-logs.txt + echo "logs<> $GITHUB_OUTPUT + cat .tmp/upgrade-deps-logs.txt >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + fi + + - name: create pull request + id: cpr + uses: peter-evans/create-pull-request@v5 + with: + token: ${{ secrets.GITHUB_TOKEN }} # Cannot be default!!! + assignees: 'afc163, zombieJ, xrkffgg, MadCcc' + title: "chore: upgrade deps" + commit-message: "chore: upgrade deps" + body: | + Upgrade dependencies + + ``` + ${{ steps.upgrade.outputs.logs }} + ``` + branch: auto-upgrade-deps + delete-branch: true + add-paths: | + package.json diff --git a/.ncurc.js b/.ncurc.js new file mode 100644 index 000000000000..a521db4d8050 --- /dev/null +++ b/.ncurc.js @@ -0,0 +1,29 @@ +// doc: https://github.com/raineorshine/npm-check-updates/tree/v16.14.6#readme +const path = require('path'); + +const rcOrg = ['@rc-component/', 'rc-']; +const check = ['@ant-design/', ...rcOrg]; + +// rules: https://github.com/ant-design/ant-design/pull/45593#issuecomment-1784891887 +module.exports = { + packageFile: path.resolve(__dirname, './package.json'), + upgrade: false, // use `npx npm-check-updates -u` to upgrade + packageManager: 'npm', + dep: ['prod'], // check only prod dependencies + // https://github.com/raineorshine/npm-check-updates#filter + filter: (name) => check.some((prefix) => name.startsWith(prefix)), + // https://github.com/raineorshine/npm-check-updates#target + target: (name, semver) => { + const { operator } = semver[0] ?? {}; + + // rc-component + if (rcOrg.some((prefix) => name.startsWith(prefix))) { + // `^` always upgrade latest, otherwise follow semver. + if (operator === '^') { + return 'latest'; + } + } + + return 'semver'; + }, +}; diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index dfdafd7ce544..cbf6f12aced9 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -16,6 +16,91 @@ tag: vVERSION --- +## 5.11.3 + +`2023-11-22` + +- 🐞 Fix Modal static method create `zIndex` too high will cover other popup content. [#46012](https://github.com/ant-design/ant-design/pull/46012) +- Image + - 🆕 Image preview support mobile touch interactive. [#45989](https://github.com/ant-design/ant-design/pull/45989) [@JarvisArt](https://github.com/JarvisArt) + - 🐞 Fixed Image preview `z-index` conflict when in a nested pop-up. [#45979](https://github.com/ant-design/ant-design/pull/45979) [@kiner-tang](https://github.com/kiner-tang) +- 🐞 Fix Collapse header cursor style. [#45994](https://github.com/ant-design/ant-design/pull/45994) +- 🐞 Fix ColorPicker not support Form disabled config. [#45978](https://github.com/ant-design/ant-design/pull/45978) [@RedJue](https://github.com/RedJue) +- 🐞 Fix Typography.Text `ellipsis.tooltip` cannot open under Layout component. [#45962](https://github.com/ant-design/ant-design/pull/45962) +- 🐞 Remove Select native 🔍 icon from search input in Safari. [#46008](https://github.com/ant-design/ant-design/pull/46008) +- 💄 Remove Rate useless style.[#45927](https://github.com/ant-design/ant-design/pull/45927) [@JarvisArt](https://github.com/JarvisArt) +- 🛠 UMD `antd.js` will try to reuse global `@ant-design/cssinjs` first now. [#46009](https://github.com/ant-design/ant-design/pull/46009) +- 🌐 Improve `eu_ES` localization. [#45928](https://github.com/ant-design/ant-design/pull/45928) [@ionlizarazu](https://github.com/ionlizarazu) + +## 5.11.2 + +`2023-11-17` + +- 🆕 Table with `virtual` can now customize `components` except the `components.body`. [#45857](https://github.com/ant-design/ant-design/pull/45857) +- 🐞 Fix Button with href and disabled that could be focused. [#45910](https://github.com/ant-design/ant-design/pull/45910) [@MadCcc](https://github.com/MadCcc) +- 🐞 Fix `zIndex` logic problem that message and notification are covered when multiple Modal are opened. [#45911](https://github.com/ant-design/ant-design/pull/45911) [#45864](https://github.com/ant-design/ant-design/pull/45864) [@kiner-tang](https://github.com/kiner-tang) +- 💄 Fix QRCode `style.padding` is not working. [#45815](https://github.com/ant-design/ant-design/pull/45815) +- 💄 Optimize Carousel dots border radius style. [#45817](https://github.com/ant-design/ant-design/pull/45817) +- TypeScript + - 🤖 Optimize List `gutter` property type definition. [#45791](https://github.com/ant-design/ant-design/pull/45791) [@Asanio06](https://github.com/Asanio06) + +## 5.11.1 + +`2023-11-09` + +- 🐞 Fix Dropdown use wrong `zIndex` when nest items. [#45761](https://github.com/ant-design/ant-design/pull/45761) +- 🐞 Fix Upload should show remove icon when `showRemoveIcon` is specified to true explicitly. [#45752](https://github.com/ant-design/ant-design/pull/45752) +- 🐞 Fix Descriptions use `children` structure missing the Descriptions.Item `key` prop. [#45757](https://github.com/ant-design/ant-design/pull/45757) +- 🐞 Fix Message that token specified in component scope not work. [#45721](https://github.com/ant-design/ant-design/pull/45721) [@MadCcc](https://github.com/MadCcc) +- 🐞 Fix Popconfirm not compatible with `visible` prop. [#45702](https://github.com/ant-design/ant-design/pull/45702) [@linhf123](https://github.com/linhf123) +- 🐞 Fix Tag default background color not correct. [#45711](https://github.com/ant-design/ant-design/pull/45711) [@kiner-tang](https://github.com/kiner-tang) +- 💄 Fix Notification that `style.width` not work. [#45681](https://github.com/ant-design/ant-design/pull/45681) [@MadCcc](https://github.com/MadCcc) +- 🐞 Fix App console unexpected attr warning when set `component=false`. [#45671](https://github.com/ant-design/ant-design/pull/45671) [@li-jia-nan](https://github.com/li-jia-nan) +- TypeScript + - 🤖 App support generic type definition. [#45669](https://github.com/ant-design/ant-design/pull/45669) [@JexLau](https://github.com/JexLau) + +## 5.11.0 + +`2023-11-03` + +- Slider + - 🆕 Slider will show tooltip when focus handler. [#45653](https://github.com/ant-design/ant-design/pull/45653) + - 💄 Slider handler should be movable after click tracker. [#45651](https://github.com/ant-design/ant-design/pull/45651) +- InputNumber + - 🆕 InputNumber support `changeOnBlur` prop to disable trigger `onChange` event when blur. [#45395](https://github.com/ant-design/ant-design/pull/45395) + - 🐞 Fix InputNumber in Form with `hasFeedback` that will lose focus when feedback icon appear. [#45632](https://github.com/ant-design/ant-design/pull/45632) [@MadCcc](https://github.com/MadCcc) + - 🐞 Fix InputNumber dynamic modify `formatter` not working. [#45325](https://github.com/ant-design/ant-design/pull/45325) +- Table + - 🆕 Table `columnTitle` support render function. [#41937](https://github.com/ant-design/ant-design/pull/41937) [@Zhou-Bill](https://github.com/Zhou-Bill) + - 🛠 Refactor Table `ref` to support `scrollTo` to scroll to target `key` or `index` or `top`. [#45245](https://github.com/ant-design/ant-design/pull/45245) +- Tabs + - 🆕 Tabs `items` support tab pane level `destroyInactiveTabPane`. [#45359](https://github.com/ant-design/ant-design/pull/45359) + - 🐞 Fix Tabs overflow blinking when Tab bar has decimal width. [#45370](https://github.com/ant-design/ant-design/pull/45370) +- ConfigProvider + - 🆕 ConfigProvider support RangePicker `className` and `style` properties. [#45479](https://github.com/ant-design/ant-design/pull/45479) [@chenzhuo198](https://github.com/chenzhuo198) + - 🆕 ConfigProvider support Dropdown `className` and `style` properties. [#45621](https://github.com/ant-design/ant-design/pull/45621) [@li-jia-nan](https://github.com/li-jia-nan) +- 🆕 ColorPicker `preset` prop support `defaultOpen` to control whether preset colors is open by default. [#45607](https://github.com/ant-design/ant-design/pull/45607) [@Wxh16144](https://github.com/Wxh16144) +- 🆕 Select support `optionRender` prop. [#45529](https://github.com/ant-design/ant-design/pull/45529) [@RedJue](https://github.com/RedJue) +- 🆕 Pagination support combine `simple` and `showSizeChanger`. [#45538](https://github.com/ant-design/ant-design/pull/45538) +- 🆕 Spin support `fullscreen` to display as backdrop. [#44986](https://github.com/ant-design/ant-design/pull/44986) [@Rafael-Martins](https://github.com/Rafael-Martins) [#45436](https://github.com/ant-design/ant-design/pull/45436) [@li-jia-nan](https://github.com/li-jia-nan) +- 🆕 Form `validateFields` support `dirty` for validating touched and validated fields. [#45389](https://github.com/ant-design/ant-design/pull/45389) +- 🆕 Watermark support `inherit` prop to disable watermark pass to Drawer and Modal. [#45319](https://github.com/ant-design/ant-design/pull/45319) +- 🆕 App support `component` for customization. [#45292](https://github.com/ant-design/ant-design/pull/45292) +- 🆕 Input and Input.TextArea support `count` custom character count (for example, fix emoji character length to `1`); `count.max` supports out-of-range styles; restore emoji to native count to solve the problem of `maxLength` and `value` mismatch. [#45140](https://github.com/ant-design/ant-design/pull/45140) +- 🐞 Fix Dropdown not trigger `onOpenChange` when click menu item to close the popup. [#45378](https://github.com/ant-design/ant-design/pull/45378) +- 💄 Modal static function support `styles`. [#45558](https://github.com/ant-design/ant-design/pull/45558) [@KotoriK](https://github.com/KotoriK) +- 💄 Optimize z-index logic of popup components, and make them don't block each other by default. [#45512](https://github.com/ant-design/ant-design/pull/45512) [#45490](https://github.com/ant-design/ant-design/pull/45490) [@kiner-tang](https://github.com/kiner-tang) + - Optimize z-index logic of Menu. [#45498](https://github.com/ant-design/ant-design/pull/45498) [@kiner-tang](https://github.com/kiner-tang) + - Optimize z-index logic of DatePicker and TimePicker. [#45497](https://github.com/ant-design/ant-design/pull/45497) [@kiner-tang](https://github.com/kiner-tang) + - Optimize z-index logic of Drawer. [#45496](https://github.com/ant-design/ant-design/pull/45496) [#45417](https://github.com/ant-design/ant-design/pull/45417) [@kiner-tang](https://github.com/kiner-tang) + - Optimize z-index logic of Cascader, TreeSelect and AutoComplete. [#45494](https://github.com/ant-design/ant-design/pull/45494) [@kiner-tang](https://github.com/kiner-tang) + - Optimize z-index logic of Dropdown. [#45486](https://github.com/ant-design/ant-design/pull/45486) [@kiner-tang](https://github.com/kiner-tang) + - Optimize z-index logic of Tour. [#45425](https://github.com/ant-design/ant-design/pull/45425) [@kiner-tang](https://github.com/kiner-tang) + - Optimize z-index logic of Tooltip. [#45422](https://github.com/ant-design/ant-design/pull/45422) [@kiner-tang](https://github.com/kiner-tang) + - Optimize z-index logic of Popover. [#45420](https://github.com/ant-design/ant-design/pull/45420) [@kiner-tang](https://github.com/kiner-tang) + - Optimize z-index logic of Popconfirm. [#45421](https://github.com/ant-design/ant-design/pull/45421) [@kiner-tang](https://github.com/kiner-tang) + - Optimize z-index logic of Modal and Select. [#45346](https://github.com/ant-design/ant-design/pull/45346) [@kiner-tang](https://github.com/kiner-tang) + ## 5.10.3 `2023-10-30` diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index cb605d6f3953..354bcceda3f6 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -16,6 +16,91 @@ tag: vVERSION --- +## 5.11.3 + +`2023-11-22` + +- 🐞 修复 Modal 静态方法创建 `zIndex` 过高会覆盖其他弹出内容的问题。[#46012](https://github.com/ant-design/ant-design/pull/46012) +- Image + - 🆕 Image 预览支持移动触摸事件交互。[#45989](https://github.com/ant-design/ant-design/pull/45989) [@JarvisArt](https://github.com/JarvisArt) + - 🐞 修复 Image 预览在嵌套弹框中 `z-index` 设置不正确的问题。[#45979](https://github.com/ant-design/ant-design/pull/45979) [@kiner-tang](https://github.com/kiner-tang) +- 🐞 修复 Collapse 可折叠区域鼠标 `hover` 样式问题。[#45994](https://github.com/ant-design/ant-design/pull/45994) +- 🐞 修复 ColorPicker 不支持 Form 组件的禁用问题。[#45978](https://github.com/ant-design/ant-design/pull/45978) [@RedJue](https://github.com/RedJue) +- 🐞 修复 Typography.Text `code` 在 Layout 下开启 `ellipsis` 时 tooltip 无效的问题。[#45962](https://github.com/ant-design/ant-design/pull/45962) +- 🐞 修复 Select 搜索框在 Safari 下显示多余的 🔍 图标。[#46008](https://github.com/ant-design/ant-design/pull/46008) +- 💄 删除 Rate 组件无用样式。 [#45927](https://github.com/ant-design/ant-design/pull/45927) [@JarvisArt](https://github.com/JarvisArt) +- 🛠 UMD 版本 `antd.js` 现在会优先使用全局的 `@ant-design/cssinjs` 依赖。[#46009](https://github.com/ant-design/ant-design/pull/46009) +- 🌐 补充 `eu_ES` 国际化内容。[#45928](https://github.com/ant-design/ant-design/pull/45928) [@ionlizarazu](https://github.com/ionlizarazu) + +## 5.11.2 + +`2023-11-17` + +- 🆕 放开 Table `virtual` 下 `components` 的限制,现在除了 `components.body` 都可以自定义。[#45857](https://github.com/ant-design/ant-design/pull/45857) +- 🐞 修复 Button 带有链接且禁用时可以被聚焦到的问题。[#45910](https://github.com/ant-design/ant-design/pull/45910) [@MadCcc](https://github.com/MadCcc) +- 🐞 修复 `zIndex` 逻辑,解决多层 Modal 打开时,message 与 notification 被遮盖的问题。[#45911](https://github.com/ant-design/ant-design/pull/45911) [#45864](https://github.com/ant-design/ant-design/pull/45864) [@kiner-tang](https://github.com/kiner-tang) +- 💄 修复 QRCode 设置 `style.padding` 时无效的问题。[#45815](https://github.com/ant-design/ant-design/pull/45815) +- 💄 优化 Carousel 切换条圆角样式。[#45817](https://github.com/ant-design/ant-design/pull/45817) +- TypeScript + - 🤖 优化 List 属性 `gutter` 的类型定义。[#45791](https://github.com/ant-design/ant-design/pull/45791) [@Asanio06](https://github.com/Asanio06) + +## 5.11.1 + +`2023-11-09` + +- 🐞 修复 Dropdown 在嵌套列表时 `zIndex` 错误的问题。[#45761](https://github.com/ant-design/ant-design/pull/45761) +- 🐞 修复 Upload 显式指定 `showRemoveIcon: true` 时删除图标未显示的问题。[#45752](https://github.com/ant-design/ant-design/pull/45752) +- 🐞 修复 Descriptions 使用 `children` 结构语法糖时,会丢失 Descriptions.Item 的 `key` 的问题。[#45757](https://github.com/ant-design/ant-design/pull/45757) +- 🐞 修复 Message 组件在组件范围设置全局 `token` 无效的问题。[#45721](https://github.com/ant-design/ant-design/pull/45721) [@MadCcc](https://github.com/MadCcc) +- 🐞 修复 Popconfirm 不兼容 `visible` 的问题。[#45702](https://github.com/ant-design/ant-design/pull/45702) [@linhf123](https://github.com/linhf123) +- 🐞 修复默认 Tag 的背景颜色不正确的问题。[#45711](https://github.com/ant-design/ant-design/pull/45711) [@kiner-tang](https://github.com/kiner-tang) +- 💄 修复 Notification 组件设置 `style.width` 无效的问题。[#45681](https://github.com/ant-design/ant-design/pull/45681) [@MadCcc](https://github.com/MadCcc) +- 🐞 修复 App 设置 `component=false` 时,会报非预期的属性警告的问题。[#45671](https://github.com/ant-design/ant-design/pull/45671) [@li-jia-nan](https://github.com/li-jia-nan) +- TypeScript + - 🤖 App 支持泛型定义。[#45669](https://github.com/ant-design/ant-design/pull/45669) [@JexLau](https://github.com/JexLau) + +## 5.11.0 + +`2023-11-03` + +- Slider + - 🆕 Slider 聚焦滑块时现在会显示 Tooltip。[#45653](https://github.com/ant-design/ant-design/pull/45653) + - 💄 优化 Slider 交互体验,点击轨道后可直接拖拽滑块。[#45651](https://github.com/ant-design/ant-design/pull/45651) +- InputNumber + - 🆕 InputNumber 添加 `changeOnBlur` 属性以支持在失去焦点时不触发 `onChange` 事件。[#45395](https://github.com/ant-design/ant-design/pull/45395) + - 🐞 修复 InputNumber 组件在 Form 组件中使用并且启用 `hasFeedback` 时,反馈图标出现会使 InputNumber 失去焦点的问题。[#45632](https://github.com/ant-design/ant-design/pull/45632) [@MadCcc](https://github.com/MadCcc) + - 🐞 修复 InputNumber 动态改变 `formatter` 不生效的问题。[#45325](https://github.com/ant-design/ant-design/pull/45325) +- Table + - 🆕 Table 组件 `columnTitle` 支持传入 render 方法。[#41937](https://github.com/ant-design/ant-design/pull/41937) [@Zhou-Bill](https://github.com/Zhou-Bill) + - 🛠 重构 Table `ref` 支持 `scrollTo` 以滚动到目标 `key` 或 `index` 或 `top`。[#45245](https://github.com/ant-design/ant-design/pull/45245) +- Tabs + - 🆕 Tabs `items` 支持单个标签页设置 `destroyInactiveTabPane`。[#45359](https://github.com/ant-design/ant-design/pull/45359) + - 🐞 修复 Tabs 的标签宽度存在小数时,滚动会出现抖动的问题。[#45370](https://github.com/ant-design/ant-design/pull/45370) +- ConfigProvider + - 🆕 ConfigProvider 支持 RangePicker 组件的 `className` 和 `style` 属性。[#45479](https://github.com/ant-design/ant-design/pull/45479) [@chenzhuo198](https://github.com/chenzhuo198) + - 🆕 ConfigProvider 支持 Dropdown 组件的 `className` 和 `style` 属性。[#45621](https://github.com/ant-design/ant-design/pull/45621) [@li-jia-nan](https://github.com/li-jia-nan) +- 🆕 ColorPicker 组件 `preset` 新增 `defaultOpen` 属性,可控制预设颜色默认是否展开。[#45607](https://github.com/ant-design/ant-design/pull/45607) [@Wxh16144](https://github.com/Wxh16144) +- 🆕 Select 组件支持 `optionRender` 方法。[#45529](https://github.com/ant-design/ant-design/pull/45529) [@RedJue](https://github.com/RedJue) +- 🆕 Pagination 组件支持组合 `simple` 和 `showSizeChanger` 使用。[#45538](https://github.com/ant-design/ant-design/pull/45538) +- 🆕 Spin 组件新增 `fullscreen` 属性,支持全屏展示。[#44986](https://github.com/ant-design/ant-design/pull/44986) [@Rafael-Martins](https://github.com/Rafael-Martins) [#45436](https://github.com/ant-design/ant-design/pull/45436) [@li-jia-nan](https://github.com/li-jia-nan) +- 🆕 Form `validateFields` 支持 `dirty` 参数以校验被修改过和校验过的字段。[#45389](https://github.com/ant-design/ant-design/pull/45389) +- 🆕 Watermark 支持 `inherit` 配置,关闭水印传导至弹出 Drawer 与 Modal。[#45319](https://github.com/ant-design/ant-design/pull/45319) +- 🆕 App 支持 `component` 以自定义渲染元素。[#45292](https://github.com/ant-design/ant-design/pull/45292) +- 🆕 Input 与 Input.TextArea 支持 `count` 自定义字符计数(例如固定 emoji 字符长度为 `1`);`count.max` 支持超出范围样式;将 emoji 计数还原为原生计数以解决 `maxLength` 与 `value` 不匹配的问题。[#45140](https://github.com/ant-design/ant-design/pull/45140) +- 🐞 修复 Dropdown 在点击菜单项关闭弹出框时不会触发 `onOpenChange` 的问题。[#45378](https://github.com/ant-design/ant-design/pull/45378) +- 💄 Modal 静态方法支持 `styles` 属性。[#45558](https://github.com/ant-design/ant-design/pull/45558) [@KotoriK](https://github.com/KotoriK) +- 💄 优化弹层组件的 `z-index` 逻辑,使其在默认情况下不会互相遮挡。[#45512](https://github.com/ant-design/ant-design/pull/45512) [#45490](https://github.com/ant-design/ant-design/pull/45490) [@kiner-tang](https://github.com/kiner-tang) + - 优化 Menu 组件 `z-index` 逻辑。[#45498](https://github.com/ant-design/ant-design/pull/45498) [@kiner-tang](https://github.com/kiner-tang) + - 优化 DatePicker、TimePicker 组件 `z-index` 逻辑。[#45497](https://github.com/ant-design/ant-design/pull/45497) [@kiner-tang](https://github.com/kiner-tang) + - 优化 Drawer 组件 `z-index` 逻辑。[#45496](https://github.com/ant-design/ant-design/pull/45496) [#45417](https://github.com/ant-design/ant-design/pull/45417) [@kiner-tang](https://github.com/kiner-tang) + - 优化 Cascader、TreeSelect、AutoComplete 组件 `z-index` 逻辑。[#45494](https://github.com/ant-design/ant-design/pull/45494) [@kiner-tang](https://github.com/kiner-tang) + - 优化 Dropdown 组件 `z-index` 逻辑。[#45486](https://github.com/ant-design/ant-design/pull/45486) [@kiner-tang](https://github.com/kiner-tang) + - 优化 Tour 组件 `z-index` 逻辑。[#45425](https://github.com/ant-design/ant-design/pull/45425) [@kiner-tang](https://github.com/kiner-tang) + - 优化 Tooltip 组件 `z-index` 逻辑。[#45422](https://github.com/ant-design/ant-design/pull/45422) [@kiner-tang](https://github.com/kiner-tang) + - 优化 Popover 组件 `z-index` 逻辑。[#45420](https://github.com/ant-design/ant-design/pull/45420) [@kiner-tang](https://github.com/kiner-tang) + - 优化 Popconfirm 组件 `z-index` 逻辑。[#45421](https://github.com/ant-design/ant-design/pull/45421) [@kiner-tang](https://github.com/kiner-tang) + - 优化 Modal、Select 组件 `z-index` 逻辑。[#45346](https://github.com/ant-design/ant-design/pull/45346) [@kiner-tang](https://github.com/kiner-tang) + ## 5.10.3 `2023-10-30` diff --git a/README-zh_CN.md b/README-zh_CN.md index 1d9e5c6e417c..ff2c60baa56d 100644 --- a/README-zh_CN.md +++ b/README-zh_CN.md @@ -84,7 +84,7 @@ pnpm add antd ## 🔨 示例 -```jsx +```tsx import React from 'react'; import { Button, DatePicker } from 'antd'; @@ -94,6 +94,8 @@ const App = () => ( ); + +export default App; ``` ### 🌈 定制主题 @@ -102,7 +104,7 @@ const App = () => ( ### 🛡 TypeScript -参考 [在 TypeScript 中使用](https://ant.design/docs/react/use-in-typescript-cn)。 +`antd` 使用 TypeScript 编写,具有完整的类型定义,参考 [在 create-react-app 中使用](https://ant.design/docs/react/use-with-create-react-app-cn)。 ## 🌍 国际化 diff --git a/README.md b/README.md index 82971f3c6632..18fbbcd8ea7a 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ pnpm add antd ## 🔨 Usage -```jsx +```tsx import React from 'react'; import { Button, DatePicker } from 'antd'; @@ -94,11 +94,13 @@ const App = () => ( ); + +export default App; ``` ### TypeScript -`antd` is written in TypeScript with complete definitions, check [Use in TypeScript](https://ant.design/docs/react/use-in-typescript) to get started. +`antd` is written in TypeScript with complete definitions, check [Usage with create-react-app](https://ant.design/docs/react/use-with-create-react-app) to get started. ## 🌍 Internationalization @@ -146,11 +148,11 @@ Open your browser and visit http://127.0.0.1:8001 , see more at [Development](ht ## 🤝 Contributing [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) -Read our [contributing guide](https://ant.design/docs/react/contributing) and let's build a better antd together. +Let's build a better antd together. -We welcome all contributions. Please read our [CONTRIBUTING.md](https://github.com/ant-design/ant-design/blob/master/.github/CONTRIBUTING.md) first. You can submit any ideas as [pull requests](https://github.com/ant-design/ant-design/pulls) or as [GitHub issues](https://github.com/ant-design/ant-design/issues). If you'd like to improve code, check out the [Development Instructions](https://github.com/ant-design/ant-design/wiki/Development) and have a good time! :) +We welcome all contributions. Please read our [Contributing Guide](https://ant.design/docs/react/contributing) first. You can submit any ideas as [Pull Requests](https://github.com/ant-design/ant-design/pulls) or as [GitHub Issues](https://github.com/ant-design/ant-design/issues). If you'd like to improve code, check out the [Development Instructions](https://github.com/ant-design/ant-design/wiki/Development) and have a good time! :) -If you are a collaborator, please follow our [Pull Request principle](https://github.com/ant-design/ant-design/wiki/PR-principle) to create a Pull Request with [collaborator template](https://github.com/ant-design/ant-design/compare?expand=1&template=collaborator.md). +If you are a collaborator, please follow our [Pull Request Principle](https://github.com/ant-design/ant-design/wiki/PR-principle) to create a Pull Request with our [Pull Request Template](https://github.com/ant-design/ant-design/wiki/PR-principle#pull-request-template). [![Let's fund issues in this repository](https://raw.githubusercontent.com/BoostIO/issuehunt-materials/master/v1/issuehunt-button-v1.svg)](https://issuehunt.io/repos/34526884) diff --git a/alias/cssinjs.js b/alias/cssinjs.js new file mode 100644 index 000000000000..ab46a110abff --- /dev/null +++ b/alias/cssinjs.js @@ -0,0 +1,19 @@ +/* eslint-disable global-require, import/no-unresolved */ + +// This is a alias proxy, which will use global `@ant-design/cssinjs` first. +// Use local if global not found. +let cssinjs; + +if (typeof window !== 'undefined' && window.antdCssinjs) { + // Use window UMD version + cssinjs = window.antdCssinjs; +} else if (typeof global !== 'undefined' && global.antdCssinjs) { + // Use global UMD version + cssinjs = global.antdCssinjs; +} else { + // Use local version. + // Use relative path since webpack will also replace module here. + cssinjs = require('../node_modules/@ant-design/cssinjs'); +} + +module.exports = cssinjs; diff --git a/components/_util/__tests__/useZIndex.test.tsx b/components/_util/__tests__/useZIndex.test.tsx new file mode 100644 index 000000000000..be5da90d1305 --- /dev/null +++ b/components/_util/__tests__/useZIndex.test.tsx @@ -0,0 +1,374 @@ +import type { PropsWithChildren } from 'react'; +import React, { useEffect } from 'react'; +import { render } from '@testing-library/react'; +import type { ImageProps, MenuProps } from 'antd'; +import { + AutoComplete, + Cascader, + ColorPicker, + DatePicker, + Drawer, + Dropdown, + Image, + Menu, + Modal, + Popconfirm, + Popover, + Select, + Tooltip, + Tour, + TreeSelect, +} from 'antd'; + +import { waitFakeTimer } from '../../../tests/utils'; +import type { ZIndexConsumer, ZIndexContainer } from '../hooks/useZIndex'; +import { consumerBaseZIndexOffset, containerBaseZIndexOffset, useZIndex } from '../hooks/useZIndex'; +import zIndexContext from '../zindexContext'; + +const WrapWithProvider: React.FC> = ({ + children, + containerType, +}) => { + const [, contextZIndex] = useZIndex(containerType); + return {children}; +}; + +const containerComponent: Record< + ZIndexContainer, + React.FC> +> = { + Modal: ({ children, ...restProps }) => ( + + {children} + + ), + Drawer: ({ children, ...restProps }) => ( + + {children} + + ), + Popover: ({ children, ...restProps }) => ( + + {children} + + ), + Popconfirm: ({ children, ...restProps }) => ( + + {children} + + ), + Tooltip: ({ children, ...restProps }) => ( + + {children} + + ), + Tour: ({ children, ...restProps }) => ( + + ), +}; + +const options = [ + { + label: 'Option 1', + value: '1', + }, + { + label: 'Option 2', + value: '2', + }, +]; + +const items: MenuProps['items'] = [ + { + label: 'Test', + key: 'SubMenu', + children: [ + { + type: 'group', + label: 'Item 1', + children: [ + { + label: 'Option 1', + key: 'setting:1', + }, + { + label: 'Option 2', + key: 'setting:2', + }, + ], + }, + { + type: 'group', + label: 'Item 2', + children: [ + { + label: 'Option 3', + key: 'setting:3', + }, + { + label: 'Option 4', + key: 'setting:4', + }, + ], + }, + ], + }, +]; + +const consumerComponent: Record> = { + SelectLike: ({ rootClassName, ...props }) => ( + <> + , + }); + + await waitFakeTimer(); + + expect(document.querySelector('.ant-modal-wrap')).toHaveStyle({ + zIndex: '2000', + }); + + expect(document.querySelector('.ant-select-dropdown')).toHaveStyle({ + zIndex: '2050', + }); + + instance.destroy(); + + await waitFakeTimer(); + + // Clean up for static method + document.body.innerHTML = ''; + + jest.useRealTimers(); + }); +}); diff --git a/components/_util/hooks/useMultipleSelect.ts b/components/_util/hooks/useMultipleSelect.ts new file mode 100644 index 000000000000..2fd9ff464612 --- /dev/null +++ b/components/_util/hooks/useMultipleSelect.ts @@ -0,0 +1,47 @@ +import { useCallback, useState } from 'react'; + +export type PrevSelectedIndex = null | number; + +/** + * @title multipleSelect hooks + * @description multipleSelect by hold down shift key + */ +export default function useMultipleSelect(getKey: (item: T) => K) { + const [prevSelectedIndex, setPrevSelectedIndex] = useState(null); + + const multipleSelect = useCallback( + (currentSelectedIndex: number, data: T[], selectedKeys: Set) => { + const configPrevSelectedIndex = prevSelectedIndex ?? currentSelectedIndex; + + // 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 shouldSelected = rangeKeys.some((rangeKey) => !selectedKeys.has(rangeKey)); + const changedKeys: K[] = []; + + rangeKeys.forEach((item) => { + if (shouldSelected) { + if (!selectedKeys.has(item)) { + changedKeys.push(item); + } + selectedKeys.add(item); + } else { + selectedKeys.delete(item); + changedKeys.push(item); + } + }); + + setPrevSelectedIndex(shouldSelected ? endIndex : null); + + return changedKeys; + }, + [prevSelectedIndex], + ); + + const updatePrevSelectedIndex = (val: PrevSelectedIndex) => { + setPrevSelectedIndex(val); + }; + + return [multipleSelect, updatePrevSelectedIndex] as const; +} diff --git a/components/_util/hooks/useProxyImperativeHandle.ts b/components/_util/hooks/useProxyImperativeHandle.ts new file mode 100644 index 000000000000..849630cbcfef --- /dev/null +++ b/components/_util/hooks/useProxyImperativeHandle.ts @@ -0,0 +1,47 @@ +// Proxy the dom ref with `{ nativeElement, otherFn }` type +// ref: https://github.com/ant-design/ant-design/discussions/45242 + +import { useImperativeHandle, type Ref } from 'react'; + +function fillProxy( + element: HTMLElement & { _antProxy?: Record }, + handler: Record, +) { + element._antProxy = element._antProxy || {}; + + Object.keys(handler).forEach((key) => { + if (!(key in element._antProxy!)) { + const ori = (element as any)[key]; + element._antProxy![key] = ori; + + (element as any)[key] = handler[key]; + } + }); + + return element; +} + +export default function useProxyImperativeHandle< + NativeELementType extends HTMLElement, + ReturnRefType extends { nativeElement: NativeELementType }, +>(ref: Ref | undefined, init: () => ReturnRefType) { + return useImperativeHandle(ref, () => { + const refObj = init(); + const { nativeElement } = refObj; + + if (typeof Proxy !== 'undefined') { + return new Proxy(nativeElement, { + get(obj: any, prop: any) { + if ((refObj as any)[prop]) { + return (refObj as any)[prop]; + } + + return Reflect.get(obj, prop); + }, + }); + } + + // Fallback of IE + return fillProxy(nativeElement, refObj); + }); +} diff --git a/components/_util/hooks/useZIndex.tsx b/components/_util/hooks/useZIndex.tsx new file mode 100644 index 000000000000..786c3fd7405e --- /dev/null +++ b/components/_util/hooks/useZIndex.tsx @@ -0,0 +1,66 @@ +import React from 'react'; + +import useToken from '../../theme/useToken'; +import zIndexContext from '../zindexContext'; + +export type ZIndexContainer = 'Modal' | 'Drawer' | 'Popover' | 'Popconfirm' | 'Tooltip' | 'Tour'; + +export type ZIndexConsumer = 'SelectLike' | 'Dropdown' | 'DatePicker' | 'Menu' | 'ImagePreview'; + +// Z-Index control range +// Container: 1000 + offset 100 (max base + 10 * offset = 2000) +// Popover: offset 50 +// Notification: Container Max zIndex + componentOffset + +const CONTAINER_OFFSET = 100; +const CONTAINER_OFFSET_MAX_COUNT = 10; + +export const CONTAINER_MAX_OFFSET = CONTAINER_OFFSET * CONTAINER_OFFSET_MAX_COUNT; + +export const containerBaseZIndexOffset: Record = { + Modal: CONTAINER_OFFSET, + Drawer: CONTAINER_OFFSET, + Popover: CONTAINER_OFFSET, + Popconfirm: CONTAINER_OFFSET, + Tooltip: CONTAINER_OFFSET, + Tour: CONTAINER_OFFSET, +}; +export const consumerBaseZIndexOffset: Record = { + SelectLike: 50, + Dropdown: 50, + DatePicker: 50, + Menu: 50, + ImagePreview: 1, +}; + +function isContainerType(type: ZIndexContainer | ZIndexConsumer): type is ZIndexContainer { + return type in containerBaseZIndexOffset; +} + +export function useZIndex( + componentType: ZIndexContainer | ZIndexConsumer, + customZIndex?: number, +): [zIndex: number | undefined, contextZIndex: number] { + const [, token] = useToken(); + const parentZIndex = React.useContext(zIndexContext); + const isContainer = isContainerType(componentType); + + if (customZIndex !== undefined) { + return [customZIndex, customZIndex]; + } + + let zIndex = parentZIndex ?? 0; + + if (isContainer) { + zIndex += + // Use preset token zIndex by default but not stack when has parent container + (parentZIndex ? 0 : token.zIndexPopupBase) + + // Container offset + containerBaseZIndexOffset[componentType]; + + zIndex = Math.min(zIndex, token.zIndexPopupBase + CONTAINER_MAX_OFFSET); + } else { + zIndex += consumerBaseZIndexOffset[componentType]; + } + return [parentZIndex === undefined ? customZIndex : zIndex, zIndex]; +} diff --git a/components/_util/type.ts b/components/_util/type.ts index 02f9aaaca969..25115ca42007 100644 --- a/components/_util/type.ts +++ b/components/_util/type.ts @@ -2,3 +2,5 @@ export type LiteralUnion = T | (string & {}); export type AnyObject = Record; + +export type CustomComponent

= React.ComponentType

| string; diff --git a/components/_util/zindexContext.ts b/components/_util/zindexContext.ts new file mode 100644 index 000000000000..39df635c168b --- /dev/null +++ b/components/_util/zindexContext.ts @@ -0,0 +1,9 @@ +import React from 'react'; + +const zIndexContext = React.createContext(undefined); + +if (process.env.NODE_ENV !== 'production') { + zIndexContext.displayName = 'zIndexContext'; +} + +export default zIndexContext; diff --git a/components/app/__tests__/index.test.tsx b/components/app/__tests__/index.test.tsx index c67fed6ce686..aafcac03eafb 100644 --- a/components/app/__tests__/index.test.tsx +++ b/components/app/__tests__/index.test.tsx @@ -1,6 +1,7 @@ -import { SmileOutlined } from '@ant-design/icons'; import React, { useEffect } from 'react'; +import { SmileOutlined } from '@ant-design/icons'; import type { NotificationConfig } from 'antd/es/notification/interface'; + import App from '..'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; @@ -208,4 +209,28 @@ describe('App', () => { ).toBeTruthy(); }); }); + + describe('component', () => { + it('replace', () => { + const { container } = render( + +

+ , + ); + + expect(container.querySelector('section.ant-app')).toBeTruthy(); + }); + + it('to false', () => { + const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + const { container } = render( + +

+ , + ); + expect(warnSpy).not.toHaveBeenCalled(); + expect(container.querySelector('.ant-app')).toBeFalsy(); + warnSpy.mockRestore(); + }); + }); }); diff --git a/components/app/context.ts b/components/app/context.ts index 23f73aa1446b..4b3220a3da7d 100644 --- a/components/app/context.ts +++ b/components/app/context.ts @@ -1,12 +1,13 @@ import React from 'react'; -import type { MessageInstance, ConfigOptions as MessageConfig } from '../message/interface'; -import type { NotificationInstance, NotificationConfig } from '../notification/interface'; + +import type { ConfigOptions as MessageConfig, MessageInstance } from '../message/interface'; import type { HookAPI as ModalHookAPI } from '../modal/useModal'; +import type { NotificationConfig, NotificationInstance } from '../notification/interface'; -export type AppConfig = { +export interface AppConfig { message?: MessageConfig; notification?: NotificationConfig; -}; +} export const AppConfigContext = React.createContext({}); diff --git a/components/app/index.en-US.md b/components/app/index.en-US.md index 155e82a30649..ddbd04af366e 100644 --- a/components/app/index.en-US.md +++ b/components/app/index.en-US.md @@ -29,8 +29,8 @@ Application wrapper for some global usages. App provides upstream and downstream method calls through `Context`, because useApp needs to be used as a subcomponent, we recommend encapsulating App at the top level in the application. ```tsx -import { App } from 'antd'; import React from 'react'; +import { App } from 'antd'; const MyPage: React.FC = () => { const { message, notification, modal } = App.useApp(); @@ -102,8 +102,9 @@ export { message, modal, notification }; ```tsx // sub page -import { Button, Space } from 'antd'; import React from 'react'; +import { Button, Space } from 'antd'; + import { message } from './store'; export default () => { @@ -129,6 +130,7 @@ Common props ref:[Common props](/docs/react/common-props) | Property | Description | Type | Default | Version | | --- | --- | --- | --- | --- | +| component | Config render element, if `false` will not create DOM node | ComponentType | div | 5.11.0 | | message | Global config for Message | [MessageConfig](/components/message/#messageconfig) | - | 5.3.0 | | notification | Global config for Notification | [NotificationConfig](/components/notification/#notificationconfig) | - | 5.3.0 | diff --git a/components/app/index.tsx b/components/app/index.tsx index 56df12b953a8..03692525280e 100644 --- a/components/app/index.tsx +++ b/components/app/index.tsx @@ -1,6 +1,8 @@ -import classNames from 'classnames'; import type { ReactNode } from 'react'; import React, { useContext } from 'react'; +import classNames from 'classnames'; + +import type { AnyObject, CustomComponent } from '../_util/type'; import type { ConfigConsumerProps } from '../config-provider'; import { ConfigContext } from '../config-provider'; import useMessage from '../message/useMessage'; @@ -10,17 +12,18 @@ import type { AppConfig, useAppProps } from './context'; import AppContext, { AppConfigContext } from './context'; import useStyle from './style'; -export interface AppProps extends AppConfig { +export interface AppProps

extends AppConfig { style?: React.CSSProperties; className?: string; rootClassName?: string; prefixCls?: string; children?: ReactNode; + component?: CustomComponent

| false; } const useApp = () => React.useContext(AppContext); -const App: React.FC & { useApp: typeof useApp } = (props) => { +const App: React.FC & { useApp: () => useAppProps } = (props) => { const { prefixCls: customizePrefixCls, children, @@ -29,6 +32,7 @@ const App: React.FC & { useApp: typeof useApp } = (props) => { message, notification, style, + component = 'div', } = props; const { getPrefixCls } = useContext(ConfigContext); const prefixCls = getPrefixCls('app', customizePrefixCls); @@ -60,15 +64,22 @@ const App: React.FC & { useApp: typeof useApp } = (props) => { [messageApi, notificationApi, ModalApi], ); + // ============================ Render ============================ + const Component = component === false ? React.Fragment : component; + const rootProps: AppProps = { + className: customClassName, + style, + }; + return wrapSSR( -

+ {ModalContextHolder} {messageContextHolder} {notificationContextHolder} {children} -
+ , ); diff --git a/components/app/index.zh-CN.md b/components/app/index.zh-CN.md index 7d6ee0c9704f..056c54716058 100644 --- a/components/app/index.zh-CN.md +++ b/components/app/index.zh-CN.md @@ -131,6 +131,7 @@ export default () => { | 参数 | 说明 | 类型 | 默认值 | 版本 | | --- | --- | --- | --- | --- | +| component | 设置渲染元素,为 `false` 则不创建 DOM 节点 | ComponentType | div | 5.11.0 | | message | App 内 Message 的全局配置 | [MessageConfig](/components/message-cn/#messageconfig) | - | 5.3.0 | | notification | App 内 Notification 的全局配置 | [NotificationConfig](/components/notification-cn/#notificationconfig) | - | 5.3.0 | diff --git a/components/auto-complete/index.tsx b/components/auto-complete/index.tsx index 30a62f50170d..7870b73a4c01 100755 --- a/components/auto-complete/index.tsx +++ b/components/auto-complete/index.tsx @@ -18,6 +18,7 @@ import type { SelectProps, } from '../select'; import Select from '../select'; +import { useZIndex } from '../_util/hooks/useZIndex'; const { Option } = Select; @@ -128,6 +129,9 @@ const AutoComplete: React.ForwardRefRenderFunction
Href Primary @@ -1079,7 +1081,7 @@ exports[`renders components/button/demo/disabled.tsx extend context correctly 1` Href Primary(disabled) @@ -1550,6 +1552,7 @@ exports[`renders components/button/demo/icon.tsx extend context correctly 1`] = Href Primary @@ -984,7 +986,7 @@ exports[`renders components/button/demo/disabled.tsx correctly 1`] = ` Href Primary(disabled) @@ -1375,6 +1377,7 @@ exports[`renders components/button/demo/icon.tsx correctly 1`] = ` diff --git a/components/button/button.tsx b/components/button/button.tsx index d224167f0906..fa4a3ff8f1a5 100644 --- a/components/button/button.tsx +++ b/components/button/button.tsx @@ -260,9 +260,11 @@ const InternalButton: React.ForwardRefRenderFunction< className={classNames(classes, { [`${prefixCls}-disabled`]: mergedDisabled, })} + href={mergedDisabled ? undefined : linkButtonRestProps.href} style={fullStyle} onClick={handleClick} ref={buttonRef as React.Ref} + tabIndex={mergedDisabled ? -1 : 0} > {iconNode} {kids} diff --git a/components/card/Card.tsx b/components/card/Card.tsx index 5521e360bc2e..cfe959eee71c 100644 --- a/components/card/Card.tsx +++ b/components/card/Card.tsx @@ -1,7 +1,8 @@ +import * as React from 'react'; import classNames from 'classnames'; import type { Tab } from 'rc-tabs/lib/interface'; import omit from 'rc-util/lib/omit'; -import * as React from 'react'; + import { ConfigContext } from '../config-provider'; import useSize from '../config-provider/hooks/useSize'; import Skeleton from '../skeleton'; @@ -46,14 +47,24 @@ export interface CardProps extends Omit, 't tabProps?: TabsProps; } -function getAction(actions: React.ReactNode[]): React.ReactNode[] { - return actions.map((action, index) => ( - // eslint-disable-next-line react/no-array-index-key -
  • - {action} -
  • - )); -} +const ActionNode: React.FC<{ prefixCls: string; actions: React.ReactNode[] }> = (props) => { + const { prefixCls, actions = [] } = props; + return ( +
      + {actions.map((action, index) => { + // Move this out since eslint not allow index key + // And eslint-disable makes conflict with rollup + // ref https://github.com/ant-design/ant-design/issues/46022 + const key = `action-${index}`; + return ( +
    • + {action} +
    • + ); + })} +
    + ); +}; const Card = React.forwardRef((props, ref) => { const { @@ -144,10 +155,9 @@ const Card = React.forwardRef((props, ref) => { {loading ? loadingBlock : children}
    ); + const actionDom = - actions && actions.length ? ( -
      {getAction(actions)}
    - ) : null; + actions && actions.length ? : null; const divProps = omit(others, ['onTabChange']); diff --git a/components/carousel/index.en-US.md b/components/carousel/index.en-US.md index 392b1a81e523..484a1d0db581 100644 --- a/components/carousel/index.en-US.md +++ b/components/carousel/index.en-US.md @@ -32,13 +32,17 @@ Common props ref:[Common props](/docs/react/common-props) | Property | Description | Type | Default | Version | | --- | --- | --- | --- | --- | | autoplay | Whether to scroll automatically | boolean | false | | +| autoplaySpeed | Delay between each auto scroll (in milliseconds) | number | 3000 | | | dotPosition | The position of the dots, which can be one of `top` `bottom` `left` `right` | string | `bottom` | | | dots | Whether to show the dots at the bottom of the gallery, `object` for `dotsClass` and any others | boolean \| { className?: string } | true | | -| waitForAnimate | Whether to wait for the animation when switching | boolean | false | | +| fade | Whether to use fade transition | boolean | false | | +| infinite | Infinitely wrap around contents | boolean | true | | +| speed | Animation speed in milliseconds | number | 500 | | | easing | Transition interpolation function name | string | `linear` | | | effect | Transition effect | `scrollx` \| `fade` | `scrollx` | | | afterChange | Callback function called after the current index changes | (current: number) => void | - | | | beforeChange | Callback function called before the current index changes | (current: number, next: number) => void | - | | +| waitForAnimate | Whether to wait for the animation when switching | boolean | false | | ## Methods diff --git a/components/carousel/index.zh-CN.md b/components/carousel/index.zh-CN.md index 4b53c62f128a..20958ef57b44 100644 --- a/components/carousel/index.zh-CN.md +++ b/components/carousel/index.zh-CN.md @@ -33,13 +33,17 @@ demo: | 参数 | 说明 | 类型 | 默认值 | 版本 | | --- | --- | --- | --- | --- | | autoplay | 是否自动切换 | boolean | false | | +| autoplaySpeed | 自动切换的间隔(毫秒) | number | 3000 | | | dotPosition | 面板指示点位置,可选 `top` `bottom` `left` `right` | string | `bottom` | | | dots | 是否显示面板指示点,如果为 `object` 则同时可以指定 `dotsClass` 或者 | boolean \| { className?: string } | true | | -| waitForAnimate | 是否等待切换动画 | boolean | false | | +| fade | 使用渐变切换动效 | boolean | false | | +| infinite | 是否无限循环切换(实现方式是复制两份 children 元素,如果子元素有副作用则可能会引发 bug) | boolean | true | | +| speed | 切换动效的时间(毫秒) | number | 500 | | | easing | 动画效果 | string | `linear` | | | effect | 动画效果函数 | `scrollx` \| `fade` | `scrollx` | | | afterChange | 切换面板的回调 | (current: number) => void | - | | | beforeChange | 切换面板的回调 | (current: number, next: number) => void | - | | +| waitForAnimate | 是否等待切换动画 | boolean | false | | ## 方法 diff --git a/components/carousel/style/index.ts b/components/carousel/style/index.ts index 391df4f58954..e783f4a615e8 100644 --- a/components/carousel/style/index.ts +++ b/components/carousel/style/index.ts @@ -230,7 +230,7 @@ const genCarouselStyle: GenerateStyle = (token) => { fontSize: 0, background: token.colorBgContainer, border: 0, - borderRadius: 1, + borderRadius: token.dotHeight, outline: 'none', cursor: 'pointer', opacity: 0.3, diff --git a/components/cascader/index.tsx b/components/cascader/index.tsx index 50b680400c5f..98c3d69b7150 100644 --- a/components/cascader/index.tsx +++ b/components/cascader/index.tsx @@ -34,6 +34,7 @@ import useCheckable from './hooks/useCheckable'; import useColumnIcons from './hooks/useColumnIcons'; import CascaderPanel from './Panel'; import useStyle from './style'; +import { useZIndex } from '../_util/hooks/useZIndex'; // Align the design since we use `rc-select` in root. This help: // - List search content will show all content @@ -288,6 +289,9 @@ const Cascader = React.forwardRef>((props, ref) const mergedAllowClear = allowClear === true ? { clearIcon } : allowClear; + // ============================ zIndex ============================ + const [zIndex] = useZIndex('SelectLike', restProps.dropdownStyle?.zIndex as number); + // ==================== Render ===================== const renderNode = ( >((props, ref) checkable={checkable} dropdownClassName={mergedDropdownClassName} dropdownPrefixCls={customizePrefixCls || cascaderPrefixCls} + dropdownStyle={{ + ...restProps.dropdownStyle, + zIndex, + }} choiceTransitionName={getTransitionName(rootPrefixCls, '', choiceTransitionName)} transitionName={getTransitionName(rootPrefixCls, 'slide-up', transitionName)} getPopupContainer={getPopupContainer || getContextPopupContainer} diff --git a/components/checkbox/Checkbox.tsx b/components/checkbox/Checkbox.tsx index 6e790d4f6197..b4f351a01089 100644 --- a/components/checkbox/Checkbox.tsx +++ b/components/checkbox/Checkbox.tsx @@ -35,6 +35,7 @@ export interface AbstractCheckboxProps { autoFocus?: boolean; type?: string; skipGroup?: boolean; + required?: boolean; } export interface CheckboxChangeEventTarget extends CheckboxProps { diff --git a/components/checkbox/Group.tsx b/components/checkbox/Group.tsx index 94dba906651e..0e22569430ea 100644 --- a/components/checkbox/Group.tsx +++ b/components/checkbox/Group.tsx @@ -18,6 +18,7 @@ export interface CheckboxOptionType { title?: string; id?: string; onChange?: (e: CheckboxChangeEvent) => void; + required?: boolean; } export interface AbstractCheckboxGroupProps { @@ -126,6 +127,7 @@ const InternalGroup: React.ForwardRefRenderFunction {option.label} diff --git a/components/collapse/style/index.ts b/components/collapse/style/index.ts index 18630323b9f5..3af31b0d7408 100644 --- a/components/collapse/style/index.ts +++ b/components/collapse/style/index.ts @@ -130,17 +130,8 @@ export const genBaseStyle: GenerateStyle = (token) => { }, }, - [`${componentCls}-header-collapsible-only`]: { - cursor: 'default', - - [`${componentCls}-header-text`]: { - flex: 'none', - cursor: 'pointer', - }, - }, - [`${componentCls}-icon-collapsible-only`]: { - cursor: 'default', + cursor: 'unset', [`${componentCls}-expand-icon`]: { cursor: 'pointer', diff --git a/components/color-picker/ColorPicker.tsx b/components/color-picker/ColorPicker.tsx index 3f8f4d183b20..2fcb54ed0520 100644 --- a/components/color-picker/ColorPicker.tsx +++ b/components/color-picker/ColorPicker.tsx @@ -12,6 +12,7 @@ import { getStatusClassNames } from '../_util/statusUtils'; import { devUseWarning } from '../_util/warning'; import type { ConfigConsumerProps } from '../config-provider/context'; import { ConfigContext } from '../config-provider/context'; +import DisabledContext from '../config-provider/DisabledContext'; import useSize from '../config-provider/hooks/useSize'; import type { SizeType } from '../config-provider/SizeContext'; import { FormItemInputContext, NoFormStyle } from '../form/context'; @@ -104,7 +105,8 @@ const ColorPicker: CompoundedComponent = (props) => { } = props; const { getPrefixCls, direction, colorPicker } = useContext(ConfigContext); - + const contextDisabled = useContext(DisabledContext); + const mergedDisabled = disabled ?? contextDisabled; const [, token] = useToken(); const [colorValue, setColorValue] = useColorState(token.colorPrimary, { @@ -113,7 +115,7 @@ const ColorPicker: CompoundedComponent = (props) => { }); const [popupOpen, setPopupOpen] = useMergedState(false, { value: open, - postState: (openData) => !disabled && openData, + postState: (openData) => !mergedDisabled && openData, onChange: onOpenChange, }); const [formatValue, setFormatValue] = useMergedState(format, { @@ -219,7 +221,7 @@ const ColorPicker: CompoundedComponent = (props) => { color: colorValue, allowClear, colorCleared, - disabled, + disabled: mergedDisabled, disabledAlpha, presets, panelRender, @@ -230,12 +232,14 @@ const ColorPicker: CompoundedComponent = (props) => { const mergedStyle: React.CSSProperties = { ...colorPicker?.style, ...style }; + // ============================ zIndex ============================ + return wrapSSR( { - if (popupAllowCloseRef.current && !disabled) { + if (popupAllowCloseRef.current && !mergedDisabled) { setPopupOpen(visible); } }} @@ -259,7 +263,7 @@ const ColorPicker: CompoundedComponent = (props) => { style={mergedStyle} color={value ? generateColor(value) : colorValue} prefixCls={prefixCls} - disabled={disabled} + disabled={mergedDisabled} colorCleared={colorCleared} showText={showText} format={formatValue} diff --git a/components/color-picker/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/color-picker/__tests__/__snapshots__/demo-extend.test.ts.snap index 5b6d1e5a9849..02bf8b6337be 100644 --- a/components/color-picker/__tests__/__snapshots__/demo-extend.test.ts.snap +++ b/components/color-picker/__tests__/__snapshots__/demo-extend.test.ts.snap @@ -159,7 +159,7 @@ Array [
    { expect(handleColorChange).toHaveBeenCalledTimes(2); }); + describe('preset collapsed', () => { + const recommendedPreset = { + label: 'Recommended', + colors: ['#f00', '#0f0', '#00f'], + }; + + const selector = '.ant-color-picker-presets .ant-collapse-item.ant-collapse-item-active'; + + it('Should default collapsed work', async () => { + const { container } = render(); + + expect(container.querySelectorAll(selector)).toHaveLength(1); + }); + + it('Should collapsed work', async () => { + const { container } = render( + , + ); + + expect(container.querySelectorAll(selector)).toHaveLength(1); + }); + }); + it('Should format change work', async () => { const { container } = render(); fireEvent.click(container.querySelector('.ant-color-picker-trigger')!); diff --git a/components/color-picker/components/ColorPresets.tsx b/components/color-picker/components/ColorPresets.tsx index 0bcadbef074c..adbc137f1889 100644 --- a/components/color-picker/components/ColorPresets.tsx +++ b/components/color-picker/components/ColorPresets.tsx @@ -34,6 +34,8 @@ const isBright = (value: Color, bgColorToken: string) => { return r * 0.299 + g * 0.587 + b * 0.114 > 192; }; +const genCollapsePanelKey = ({ label }: PresetsItem) => `panel-${label}`; + const ColorPresets: FC = ({ prefixCls, presets, value: color, onChange }) => { const [locale] = useLocale('ColorPicker'); const [, token] = useToken(); @@ -43,8 +45,13 @@ const ColorPresets: FC = ({ prefixCls, presets, value: color, }); const colorPresetsPrefixCls = `${prefixCls}-presets`; - const activeKeys = useMemo( - () => presetsValue.map((preset) => `panel-${preset.label}`), + const activeKeys = useMemo( + () => + presetsValue.reduce((acc, preset) => { + const { defaultOpen = true } = preset; + if (defaultOpen) acc.push(genCollapsePanelKey(preset)); + return acc; + }, []), [presetsValue], ); @@ -53,7 +60,7 @@ const ColorPresets: FC = ({ prefixCls, presets, value: color, }; const items: CollapseProps['items'] = presetsValue.map((preset) => ({ - key: `panel-${preset.label}`, + key: genCollapsePanelKey(preset), label:
    {preset?.label}
    , children: (
    diff --git a/components/color-picker/index.en-US.md b/components/color-picker/index.en-US.md index b340ba2d6742..a9ca6338a45d 100644 --- a/components/color-picker/index.en-US.md +++ b/components/color-picker/index.en-US.md @@ -53,7 +53,7 @@ Common props ref:[Common props](/docs/react/common-props) | destroyTooltipOnHide | Whether destroy popover when hidden | `boolean` | false | 5.7.0 | | format | Format of color | `rgb` \| `hex` \| `hsb` | `hex` | | | open | Whether to show popup | boolean | - | | -| presets | Preset colors | `{ label: ReactNode, colors: Array }[]` | - | | +| presets | Preset colors | `{ label: ReactNode, colors: Array, defaultOpen?: boolean }[]` | - | `defaultOpen: 5.11.0` | | placement | Placement of popup | `top` \| `topLeft` \| `topRight` \| `bottom` \| `bottomLeft` \| `bottomRight` | `bottomLeft` | | | panelRender | Custom Render Panel | `(panel: React.ReactNode, extra: { components: { Picker: FC; Presets: FC } }) => React.ReactNode` | - | 5.7.0 | | showText | Show color text | boolean \| `(color: Color) => React.ReactNode` | - | 5.7.0 | diff --git a/components/color-picker/index.zh-CN.md b/components/color-picker/index.zh-CN.md index 782611c38533..867481239fee 100644 --- a/components/color-picker/index.zh-CN.md +++ b/components/color-picker/index.zh-CN.md @@ -54,7 +54,7 @@ group: | destroyTooltipOnHide | 关闭后是否销毁弹窗 | `boolean` | false | 5.7.0 | | format | 颜色格式 | `rgb` \| `hex` \| `hsb` | `hex` | | | open | 是否显示弹出窗口 | boolean | - | | -| presets | 预设的颜色 | `{ label: ReactNode, colors: Array }[]` | - | | +| presets | 预设的颜色 | `{ label: ReactNode, colors: Array, defaultOpen?: boolean }[]` | - | `defaultOpen: 5.11.0` | | placement | 弹出窗口的位置 | `top` \| `topLeft` \| `topRight` \| `bottom` \| `bottomLeft` \| `bottomRight` | `bottomLeft` | | | panelRender | 自定义渲染面板 | `(panel: React.ReactNode, extra: { components: { Picker: FC; Presets: FC } }) => React.ReactNode` | - | 5.7.0 | | showText | 显示颜色文本 | boolean \| `(color: Color) => React.ReactNode` | - | 5.7.0 | diff --git a/components/color-picker/interface.ts b/components/color-picker/interface.ts index f0c4c3e93565..f56f5eb69396 100644 --- a/components/color-picker/interface.ts +++ b/components/color-picker/interface.ts @@ -11,6 +11,12 @@ export enum ColorFormat { export interface PresetsItem { label: ReactNode; colors: (string | Color)[]; + /** + * Whether the initial state is collapsed + * @since 5.11.0 + * @default true + */ + defaultOpen?: boolean; } export type TriggerType = 'click' | 'hover'; diff --git a/components/config-provider/__tests__/style.test.tsx b/components/config-provider/__tests__/style.test.tsx index 23f588b2c67a..355fad352407 100644 --- a/components/config-provider/__tests__/style.test.tsx +++ b/components/config-provider/__tests__/style.test.tsx @@ -18,6 +18,7 @@ import DatePicker from '../../date-picker'; import Descriptions from '../../descriptions'; import Divider from '../../divider'; import Drawer from '../../drawer'; +import Dropdown from '../../dropdown'; import Empty from '../../empty'; import Flex from '../../flex'; import Form from '../../form'; @@ -1045,6 +1046,34 @@ describe('ConfigProvider support style and className props', () => { expect(container.querySelector('.ant-picker')).toHaveStyle('color: red; font-size: 16px;'); }); + it('Should RangePicker className works', () => { + const { RangePicker } = TimePicker; + const { container } = render( + + + , + ); + expect(container.querySelector('.ant-picker')).toHaveClass('test-class'); + }); + + it('Should RangePicker style works', () => { + const { RangePicker } = TimePicker; + const { container } = render( + + + , + ); + expect(container.querySelector('.ant-picker')).toHaveStyle('color: red; font-size: 16px;'); + }); + it('Should message className & style works', () => { const Demo: React.FC = () => { const [messageApi, contextHolder] = message.useMessage(); @@ -1279,4 +1308,17 @@ describe('ConfigProvider support style and className props', () => { expect(element).toHaveClass('cp-flex'); expect(element).toHaveStyle({ backgroundColor: 'blue' }); }); + + it('Should Dropdown className & style works', () => { + const { container } = render( + + + test + + , + ); + const element = container.querySelector('.ant-dropdown'); + expect(element).toHaveClass('cp-dropdown'); + expect(element).toHaveStyle({ backgroundColor: 'red' }); + }); }); diff --git a/components/config-provider/__tests__/theme.test.tsx b/components/config-provider/__tests__/theme.test.tsx index d3c14df61c0b..dc691224beb5 100644 --- a/components/config-provider/__tests__/theme.test.tsx +++ b/components/config-provider/__tests__/theme.test.tsx @@ -1,10 +1,11 @@ -import { kebabCase } from 'lodash'; -import canUseDom from 'rc-util/lib/Dom/canUseDom'; import React from 'react'; +import kebabCase from 'lodash/kebabCase'; +import canUseDom from 'rc-util/lib/Dom/canUseDom'; + import ConfigProvider from '..'; import { InputNumber } from '../..'; -import { render } from '../../../tests/utils'; import { resetWarned } from '../../_util/warning'; +import { render } from '../../../tests/utils'; import theme from '../../theme'; import { useToken } from '../../theme/internal'; diff --git a/components/config-provider/context.ts b/components/config-provider/context.ts index 2ecf8152247c..c7abb8a7fda1 100644 --- a/components/config-provider/context.ts +++ b/components/config-provider/context.ts @@ -5,18 +5,18 @@ import type { Options } from 'scroll-into-view-if-needed'; import type { WarningContextProps } from '../_util/warning'; import type { ShowWaveEffect } from '../_util/wave/interface'; import type { BadgeProps } from '../badge'; -import type { ModalProps } from '../modal'; import type { ButtonProps } from '../button'; +import type { DrawerProps } from '../drawer'; import type { FlexProps } from '../flex/interface'; import type { RequiredMark } from '../form/Form'; import type { InputProps } from '../input'; import type { Locale } from '../locale'; +import type { ModalProps } from '../modal'; import type { SpaceProps } from '../space'; import type { TabsProps } from '../tabs'; import type { AliasToken, MappingAlgorithm, OverrideToken } from '../theme/interface'; import type { RenderEmptyHandler } from './defaultRenderEmpty'; import type { SizeType } from './SizeContext'; -import type { DrawerProps } from '../drawer'; export const defaultIconPrefixCls = 'anticon'; @@ -171,6 +171,8 @@ export interface ConfigConsumerProps { tree?: ComponentStyleConfig; colorPicker?: ComponentStyleConfig; datePicker?: ComponentStyleConfig; + rangePicker?: ComponentStyleConfig; + dropdown?: ComponentStyleConfig; flex?: FlexConfig; wave?: WaveConfig; warning?: WarningContextProps; diff --git a/components/config-provider/index.en-US.md b/components/config-provider/index.en-US.md index 33f41f761032..548ac8a38bc4 100644 --- a/components/config-provider/index.en-US.md +++ b/components/config-provider/index.en-US.md @@ -118,9 +118,11 @@ const { | collapse | Set Collapse common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | colorPicker | Set ColorPicker common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | datePicker | Set datePicker common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | +| rangePicker | Set rangePicker common props | { className?: string, style?: React.CSSProperties } | - | 5.11.0 | | descriptions | Set Descriptions common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | divider | Set Divider common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | drawer | Set Drawer common props | { className?: string, style?: React.CSSProperties, classNames?: [DrawerProps\["classNames"\]](/components/drawer-cn#api), styles?: [DrawerProps\["styles"\]](/components/drawer-cn#api) } | - | 5.7.0, `classNames` and `styles`: 5.10.0 | +| dropdown | Set Dropdown common props | { className?: string, style?: React.CSSProperties } | - | 5.11.0 | | empty | Set Empty common props | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | flex | Set Flex common props | { className?: string, style?: React.CSSProperties, vertical?: boolean } | - | 5.10.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: 5.7.0; style: 5.7.0 | diff --git a/components/config-provider/index.tsx b/components/config-provider/index.tsx index ba2056fb8525..e7e612bc2c58 100644 --- a/components/config-provider/index.tsx +++ b/components/config-provider/index.tsx @@ -198,6 +198,8 @@ export interface ConfigProviderProps { tree?: ComponentStyleConfig; colorPicker?: ComponentStyleConfig; datePicker?: ComponentStyleConfig; + rangePicker?: ComponentStyleConfig; + dropdown?: ComponentStyleConfig; flex?: FlexConfig; /** * Wave is special component which only patch on the effect of component interaction. @@ -339,8 +341,10 @@ const ProviderChildren: React.FC = (props) => { tree, colorPicker, datePicker, + rangePicker, flex, wave, + dropdown, warning: warningConfig, } = props; @@ -430,8 +434,10 @@ const ProviderChildren: React.FC = (props) => { tree, colorPicker, datePicker, + rangePicker, flex, wave, + dropdown, warning: warningConfig, }; diff --git a/components/config-provider/index.zh-CN.md b/components/config-provider/index.zh-CN.md index a5b53faa4d3a..f10b2a2439b4 100644 --- a/components/config-provider/index.zh-CN.md +++ b/components/config-provider/index.zh-CN.md @@ -120,9 +120,11 @@ const { | collapse | 设置 Collapse 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | colorPicker | 设置 ColorPicker 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | datePicker | 设置 DatePicker 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | +| rangePicker | 设置 RangePicker 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.11.0 | | descriptions | 设置 Descriptions 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | divider | 设置 Divider 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | drawer | 设置 Drawer 组件的通用属性 | { className?: string, style?: React.CSSProperties, classNames?: [DrawerProps\["classNames"\]](/components/drawer-cn#api), styles?: [DrawerProps\["styles"\]](/components/drawer-cn#api) } | - | 5.7.0, `classNames` 和 `styles`: 5.10.0 | +| dropdown | 设置 Dropdown 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.11.0 | | empty | 设置 Empty 组件的通用属性 | { className?: string, style?: React.CSSProperties } | - | 5.7.0 | | flex | 设置 Flex 组件的通用属性 | { className?: string, style?: React.CSSProperties, vertical?: boolean } | - | 5.10.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: 5.7.0; style: 5.7.0 | diff --git a/components/date-picker/generatePicker/generateRangePicker.tsx b/components/date-picker/generatePicker/generateRangePicker.tsx index 7eb6c49a81a9..5c779fd870ab 100644 --- a/components/date-picker/generatePicker/generateRangePicker.tsx +++ b/components/date-picker/generatePicker/generateRangePicker.tsx @@ -27,6 +27,7 @@ import { } from '../util'; import Components from './Components'; import type { CommonPickerMethods, PickerComponentClass } from './interface'; +import { useZIndex } from '../../_util/hooks/useZIndex'; export default function generateRangePicker(generateConfig: GenerateConfig) { type InternalRangePickerProps = RangePickerProps & {}; @@ -48,6 +49,7 @@ export default function generateRangePicker(generateConfig: GenerateCo prefixCls: customizePrefixCls, getPopupContainer: customGetPopupContainer, className, + style, placement, size: customizeSize, disabled: customDisabled, @@ -63,7 +65,7 @@ export default function generateRangePicker(generateConfig: GenerateCo } = props; const innerRef = React.useRef>(null); - const { getPrefixCls, direction, getPopupContainer } = useContext(ConfigContext); + const { getPrefixCls, direction, getPopupContainer, rangePicker } = useContext(ConfigContext); const prefixCls = getPrefixCls('picker', customizePrefixCls); const { compactSize, compactItemClassnames } = useCompactItemContext(prefixCls, direction); const { format, showTime, picker } = props as any; @@ -110,6 +112,9 @@ export default function generateRangePicker(generateConfig: GenerateCo const locale = { ...contextLocale, ...props.locale! }; + // ============================ zIndex ============================ + const [zIndex] = useZIndex('DatePicker', props.popupStyle?.zIndex as number); + return wrapSSR( separator={ @@ -138,8 +143,10 @@ export default function generateRangePicker(generateConfig: GenerateCo hashId, compactItemClassnames, className, + rangePicker?.className, rootClassName, )} + style={{ ...rangePicker?.style, ...style }} locale={locale.lang} prefixCls={prefixCls} getPopupContainer={customGetPopupContainer || getPopupContainer} @@ -147,6 +154,10 @@ export default function generateRangePicker(generateConfig: GenerateCo components={Components} direction={direction} dropdownClassName={classNames(hashId, popupClassName || dropdownClassName, rootClassName)} + popupStyle={{ + ...props.popupStyle, + zIndex, + }} allowClear={mergeAllowClear(allowClear, clearIcon, )} />, ); diff --git a/components/date-picker/generatePicker/generateSinglePicker.tsx b/components/date-picker/generatePicker/generateSinglePicker.tsx index 5039f2733ff0..c79979b2b5d0 100644 --- a/components/date-picker/generatePicker/generateSinglePicker.tsx +++ b/components/date-picker/generatePicker/generateSinglePicker.tsx @@ -28,6 +28,7 @@ import { } from '../util'; import Components from './Components'; import type { CommonPickerMethods, DatePickRef, PickerComponentClass } from './interface'; +import { useZIndex } from '../../_util/hooks/useZIndex'; export default function generatePicker(generateConfig: GenerateConfig) { type CustomPickerProps = { @@ -138,6 +139,8 @@ export default function generatePicker(generateConfig: GenerateConfig< const [contextLocale] = useLocale('DatePicker', enUS); const locale = { ...contextLocale, ...props.locale! }; + // ============================ zIndex ============================ + const [zIndex] = useZIndex('DatePicker', props.popupStyle?.zIndex as number); return wrapSSR( @@ -182,6 +185,10 @@ export default function generatePicker(generateConfig: GenerateConfig< rootClassName, popupClassName || dropdownClassName, )} + popupStyle={{ + ...props.popupStyle, + zIndex, + }} allowClear={mergeAllowClear(allowClear, clearIcon, )} />, ); diff --git a/components/date-picker/index.en-US.md b/components/date-picker/index.en-US.md index 2801d8cb719e..43d008ec6101 100644 --- a/components/date-picker/index.en-US.md +++ b/components/date-picker/index.en-US.md @@ -56,6 +56,12 @@ The default locale is en-US, if you need to use other languages, recommend to us If there are special needs (only modifying single component language), Please use the property: local. Example: [default](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json). + +:::warning +When use with Nextjs App Router, make sure to add `'use client'` before import locale file of dayjs. +It's because all components of Ant Design only works in client, importing locale in RSC will not work. +::: + ```jsx import locale from 'antd/es/date-picker/locale/zh_CN'; diff --git a/components/date-picker/index.zh-CN.md b/components/date-picker/index.zh-CN.md index 7ed5483b3d16..c1fe46aa019d 100644 --- a/components/date-picker/index.zh-CN.md +++ b/components/date-picker/index.zh-CN.md @@ -57,6 +57,12 @@ demo: 如有特殊需求(仅修改单一组件的语言),请使用 locale 参数,参考:[默认配置](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json)。 + +:::warning +在搭配 Nextjs 的 App Router 使用时,注意在引入 dayjs 的 locale 文件时加上 `'use client'`。 +这是由于 Ant Design 的组件都是客户端组件,在 RSC 中引入 dayjs 的 locale 文件将不会在客户端生效。 +::: + ```jsx import locale from 'antd/es/date-picker/locale/zh_CN'; diff --git a/components/descriptions/__tests__/hooks.test.tsx b/components/descriptions/__tests__/hooks.test.tsx new file mode 100644 index 000000000000..5f3fd2175791 --- /dev/null +++ b/components/descriptions/__tests__/hooks.test.tsx @@ -0,0 +1,26 @@ +import React from 'react'; + +import Descriptions from '..'; +import { render } from '../../../tests/utils'; +import useBreakpoint from '../../grid/hooks/useBreakpoint'; +import useItems from '../hooks/useItems'; + +describe('Descriptions.Hooks', () => { + it('Should Descriptions not throw react key prop error in jsx mode', () => { + const Demo = () => { + const screens = useBreakpoint(); + const items = useItems( + screens, + undefined, + + Bamboo + , + ); + + return

    {(items[0] as any).key}

    ; + }; + + const { container } = render(); + expect(container.querySelector('p')?.textContent).toBe('bamboo'); + }); +}); diff --git a/components/descriptions/hooks/useItems.ts b/components/descriptions/hooks/useItems.ts index 357385bde1a5..db0917772a93 100644 --- a/components/descriptions/hooks/useItems.ts +++ b/components/descriptions/hooks/useItems.ts @@ -6,7 +6,7 @@ import { matchScreen, type ScreenMap } from '../../_util/responsiveObserver'; // Convert children into items const transChildren2Items = (childNodes?: React.ReactNode) => - toArray(childNodes).map((node) => ({ ...node?.props })); + toArray(childNodes).map((node) => ({ ...node?.props, key: node.key })); export default function useItems( screens: ScreenMap, diff --git a/components/drawer/__tests__/__snapshots__/demo-extend.test.tsx.snap b/components/drawer/__tests__/__snapshots__/demo-extend.test.tsx.snap index 8917bb43c791..ad975b99342c 100644 --- a/components/drawer/__tests__/__snapshots__/demo-extend.test.tsx.snap +++ b/components/drawer/__tests__/__snapshots__/demo-extend.test.tsx.snap @@ -1049,7 +1049,7 @@ Array [
    -
    -
    -
    -
    - -`; - -exports[`renders components/form/demo/control-ref.tsx extend context correctly 2`] = `[]`; - exports[`renders components/form/demo/custom-feedback-icons.tsx extend context correctly 1`] = `
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + , ] `; @@ -9551,6 +9678,7 @@ exports[`renders components/form/demo/register.tsx extend context correctly 1`] aria-required="true" class="ant-input" id="register_intro" + maxlength="100" />
    `; -exports[`renders components/form/demo/control-ref.tsx correctly 1`] = ` -
    -
    -
    -
    - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - - - - - Select a option and change input text above - -
    - -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - - - -
    -
    -
    -
    -
    -
    -`; - exports[`renders components/form/demo/custom-feedback-icons.tsx correctly 1`] = `
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    , ] `; @@ -6504,6 +6363,7 @@ exports[`renders components/form/demo/register.tsx correctly 1`] = ` aria-required="true" class="ant-input" id="register_intro" + maxlength="100" />
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    `; diff --git a/components/form/__tests__/index.test.tsx b/components/form/__tests__/index.test.tsx index 45dce79324d2..387bdf586c7f 100644 --- a/components/form/__tests__/index.test.tsx +++ b/components/form/__tests__/index.test.tsx @@ -1,19 +1,20 @@ import type { ChangeEventHandler } from 'react'; import React, { version as ReactVersion, useEffect, useRef, useState } from 'react'; +import { AlertFilled } from '@ant-design/icons'; import type { ColProps } from 'antd/es/grid'; import classNames from 'classnames'; import scrollIntoView from 'scroll-into-view-if-needed'; -import { AlertFilled } from '@ant-design/icons'; import type { FormInstance } from '..'; import Form from '..'; import { resetWarned } from '../../_util/warning'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; -import { fireEvent, pureRender, render, screen, waitFakeTimer } from '../../../tests/utils'; +import { act, fireEvent, pureRender, render, screen, waitFakeTimer } from '../../../tests/utils'; import Button from '../../button'; import Cascader from '../../cascader'; import Checkbox from '../../checkbox'; +import ColorPicker from '../../color-picker'; import ConfigProvider from '../../config-provider'; import DatePicker from '../../date-picker'; import Drawer from '../../drawer'; @@ -1166,6 +1167,9 @@ describe('Form', () => { + + + ); const { container } = render(); @@ -1692,6 +1696,7 @@ describe('Form', () => { { label: 'female', value: 1 }, ]} />, + , , , - - - - - prevValues.gender !== currentValues.gender} - > - {({ getFieldValue }) => - getFieldValue('gender') === 'other' ? ( - - - - ) : null - } - - - - - - - - ); -}; - -export default App; diff --git a/components/form/demo/custom-feedback-icons.tsx b/components/form/demo/custom-feedback-icons.tsx index 7af3c276a33d..4719749dae81 100644 --- a/components/form/demo/custom-feedback-icons.tsx +++ b/components/form/demo/custom-feedback-icons.tsx @@ -1,9 +1,8 @@ import React from 'react'; -import { uniqueId } from 'lodash'; - -import { createStyles, css } from 'antd-style'; import { AlertFilled, CloseSquareFilled } from '@ant-design/icons'; import { Button, Form, Input, Tooltip } from 'antd'; +import { createStyles, css } from 'antd-style'; +import uniqueId from 'lodash/uniqueId'; const useStyle = createStyles(() => ({ 'custom-feedback-icons': css` diff --git a/components/form/demo/disabled.tsx b/components/form/demo/disabled.tsx index d2373cfdd657..060b157f48ed 100644 --- a/components/form/demo/disabled.tsx +++ b/components/form/demo/disabled.tsx @@ -1,9 +1,10 @@ -import { PlusOutlined } from '@ant-design/icons'; import React, { useState } from 'react'; +import { PlusOutlined } from '@ant-design/icons'; import { Button, Cascader, Checkbox, + ColorPicker, DatePicker, Form, Input, @@ -113,6 +114,9 @@ const FormDisabledDemo: React.FC = () => { + + + ); diff --git a/components/form/index.en-US.md b/components/form/index.en-US.md index 8da3eb2e670d..f63847bd0bc3 100644 --- a/components/form/index.en-US.md +++ b/components/form/index.en-US.md @@ -18,7 +18,6 @@ High performance Form component with data scope management. Including data colle Basic Usage Form methods -Form methods (Class component) Form Layout Form disabled Required style @@ -308,9 +307,23 @@ Provide linkage between forms. If a sub form with `name` prop update, it will au | setFieldValue | Set fields value(Will directly pass to form store and **reset validation message**. If you do not want to modify passed object, please clone first) | (name: [NamePath](#namepath), value: any) => void | 4.22.0 | | setFieldsValue | Set fields value(Will directly pass to form store and **reset validation message**. If you do not want to modify passed object, please clone first). Use `setFieldValue` instead if you want to only config single value in Form.List | (values) => void | | | submit | Submit the form. It's same as click `submit` button | () => void | | -| validateFields | Validate fields. Use `recursive` to validate all the field in the path | (nameList?: [NamePath](#namepath)\[], { validateOnly?: boolean }) => Promise | `validateOnly`: 5.5.0, `recursive`: 5.9.0 | +| validateFields | Validate fields. Use `recursive` to validate all the field in the path | (nameList?: [NamePath](#namepath)\[], config?: [ValidateConfig](#validateFields)) => Promise | | -#### validateFields return sample +#### validateFields + +```tsx +export interface ValidateConfig { + // New in 5.5.0. Only validate content and not show error message on UI. + validateOnly?: boolean; + // New in 5.9.0. Recursively validate the provided `nameList` and its sub-paths. + recursive?: boolean; + // New in 5.11.0. Validate dirty fields (touched + validated). + // It's useful to validate fields only when they are touched or validated. + dirty?: boolean; +} +``` + +return sample: ```jsx validateFields() diff --git a/components/form/index.zh-CN.md b/components/form/index.zh-CN.md index 5424cbe33f75..f5fbfd6e39db 100644 --- a/components/form/index.zh-CN.md +++ b/components/form/index.zh-CN.md @@ -19,7 +19,6 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*ylFATY6w-ygAAA 基本使用 表单方法调用 -表单方法调用(Class component) 表单布局 表单禁用 必选样式 @@ -307,9 +306,23 @@ Form.List 渲染表单相关操作函数。 | setFieldValue | 设置表单的值(该值将直接传入 form store 中并且**重置错误信息**。如果你不希望传入对象被修改,请克隆后传入) | (name: [NamePath](#namepath), value: any) => void | 4.22.0 | | setFieldsValue | 设置表单的值(该值将直接传入 form store 中并且**重置错误信息**。如果你不希望传入对象被修改,请克隆后传入)。如果你只想修改 Form.List 中单项值,请通过 `setFieldValue` 进行指定 | (values) => void | | | submit | 提交表单,与点击 `submit` 按钮效果相同 | () => void | | -| validateFields | 触发表单验证,设置 `recursive` 时会递归校验所有包含的路径 | (nameList?: [NamePath](#namepath)\[], { validateOnly?: boolean, recursive?: boolean }) => Promise | `validateOnly`: 5.5.0, `recursive`: 5.9.0 | +| validateFields | 触发表单验证,设置 `recursive` 时会递归校验所有包含的路径 | (nameList?: [NamePath](#namepath)\[], config?: [ValidateConfig](#validateFields)) => Promise | | -#### validateFields 返回示例 +#### validateFields + +```tsx +export interface ValidateConfig { + // 5.5.0 新增。仅校验内容而不会将错误信息展示到 UI 上。 + validateOnly?: boolean; + // 5.9.0 新增。对提供的 `nameList` 与其子路径进行递归校验。 + recursive?: boolean; + // 5.11.0 新增。校验 dirty 的字段(touched + validated)。 + // 使用 `dirty` 可以很方便的仅校验用户操作过和被校验过的字段。 + dirty?: boolean; +} +``` + +返回示例: ```jsx validateFields() diff --git a/components/image/index.en-US.md b/components/image/index.en-US.md index d9233d884a5a..04f1265766d5 100644 --- a/components/image/index.en-US.md +++ b/components/image/index.en-US.md @@ -51,7 +51,7 @@ Other attributes [<img>](https://developer.mozilla.org/en-US/docs/Web/HTML/El ### PreviewType -| 参数 | 说明 | 类型 | 默认值 | 版本 | +| Property | Description | Type | Default | Version | | --- | --- | --- | --- | --- | | visible | Whether the preview dialog is visible or not | boolean | - | - | | src | Custom preview src | string | - | 4.10.0 | @@ -72,7 +72,7 @@ Other attributes [<img>](https://developer.mozilla.org/en-US/docs/Web/HTML/El ## PreviewGroup -| 参数 | 说明 | 类型 | 默认值 | 版本 | +| Property | Description | Type | Default | Version | | --- | --- | --- | --- | --- | | preview | Preview config, `disabled` when false | boolean \| [PreviewGroupType](#previewgrouptype) | true | 4.6.0 [PreviewGroupType](#previewgrouptype):4.7.0 | | items | Preview items | string[] \| { src: string, crossOrigin: string, ... }[] | - | 5.7.0 | @@ -80,7 +80,7 @@ Other attributes [<img>](https://developer.mozilla.org/en-US/docs/Web/HTML/El ### PreviewGroupType -| 参数 | 说明 | 类型 | 默认值 | 版本 | +| Property | Description | Type | Default | Version | | --- | --- | --- | --- | --- | | visible | Whether the preview dialog is visible or not | boolean | - | - | | getContainer | The mounted node for preview dialog but still display at fullScreen | string \| HTMLElement \| (() => HTMLElement) \| false | - | 4.8.0 | @@ -99,7 +99,7 @@ Other attributes [<img>](https://developer.mozilla.org/en-US/docs/Web/HTML/El | imageRender | Custom preview content | (originalNode: React.ReactElement, info: { transform: [TransformType](#transformtype), current: number }) => React.ReactNode | - | 5.7.0 | | onTransform | Callback when the transform of image changed | { transform: [TransformType](#transformtype), action: [TransformAction](#transformaction) } | - | 5.7.0 | | onChange | Callback when switch preview image | (current: number, prevCurrent: number) => void | - | 5.3.0 | -| onVisibleChange | Callback when `visible` changed | (visible: boolean, prevVisible: boolean, current: number) => void | - | current 参数 5.3.0 | +| onVisibleChange | Callback when `visible` changed | (visible: boolean, prevVisible: boolean, current: number) => void | - | current Property 5.3.0 | ## Interface diff --git a/components/image/index.tsx b/components/image/index.tsx index 3d60dcfb85a0..61cedf51182c 100644 --- a/components/image/index.tsx +++ b/components/image/index.tsx @@ -4,6 +4,7 @@ import classNames from 'classnames'; import RcImage from 'rc-image'; import type { ImageProps } from 'rc-image'; +import { useZIndex } from '../_util/hooks/useZIndex'; import { getTransitionName } from '../_util/motion'; import { ConfigContext } from '../config-provider'; import defaultLocale from '../locale/en_US'; @@ -42,6 +43,11 @@ const Image: CompositionImage = (props) => { const mergedClassName = classNames(className, hashId, image?.className); + const [zIndex] = useZIndex( + 'ImagePreview', + typeof preview === 'object' ? preview.zIndex : undefined, + ); + const mergedPreview = React.useMemo(() => { if (preview === false) { return preview; @@ -60,6 +66,7 @@ const Image: CompositionImage = (props) => { getContainer: getContainer || getContextPopupContainer, transitionName: getTransitionName(rootPrefixCls, 'zoom', _preview.transitionName), maskTransitionName: getTransitionName(rootPrefixCls, 'fade', _preview.maskTransitionName), + zIndex, }; }, [preview, imageLocale]); diff --git a/components/input-number/index.en-US.md b/components/input-number/index.en-US.md index 836f3582f8ed..3d259bf4781b 100644 --- a/components/input-number/index.en-US.md +++ b/components/input-number/index.en-US.md @@ -42,8 +42,10 @@ Common props ref:[Common props](/docs/react/common-props) | addonBefore | The label text displayed before (on the left side of) the input field | ReactNode | - | | | autoFocus | If get focus when component mounted | boolean | false | - | | bordered | Whether has border style | boolean | true | 4.12.0 | +| changeOnBlur | Trigger `onChange` when blur. e.g. reset value in range by blur | boolean | true | 5.11.0 | | controls | Whether to show `+-` controls, or set custom arrows icon | boolean \| { upIcon?: React.ReactNode; downIcon?: React.ReactNode; } | - | 4.19.0 | | decimalSeparator | Decimal separator | string | - | - | +| placeholder | placeholder | string | - | | | defaultValue | The initial value | number | - | - | | disabled | If disable the input | boolean | false | - | | formatter | Specifies the format of the value presented | function(value: number \| string, info: { userTyping: boolean, input: string }): string | - | info: 4.17.0 | diff --git a/components/input-number/index.tsx b/components/input-number/index.tsx index 1c928728e860..218c5bc99e4c 100644 --- a/components/input-number/index.tsx +++ b/components/input-number/index.tsx @@ -103,6 +103,9 @@ const InputNumber = React.forwardRef((props, ); const wrapperClassName = `${prefixCls}-group`; + // eslint-disable-next-line react/jsx-no-useless-fragment + const suffixNode = hasFeedback && <>{feedbackIcon}; + const element = ( ((props, readOnly={readOnly} controls={controlsTemp} prefix={prefix} - suffix={hasFeedback && feedbackIcon} + suffix={suffixNode} addonAfter={ addonAfter && ( diff --git a/components/input-number/index.zh-CN.md b/components/input-number/index.zh-CN.md index 7f6b2c5382ce..81458d22a6ca 100644 --- a/components/input-number/index.zh-CN.md +++ b/components/input-number/index.zh-CN.md @@ -43,8 +43,10 @@ demo: | addonBefore | 带标签的 input,设置前置标签 | ReactNode | - | 4.17.0 | | autoFocus | 自动获取焦点 | boolean | false | - | | bordered | 是否有边框 | boolean | true | 4.12.0 | +| changeOnBlur | 是否在失去焦点时,触发 `onChange` 事件(例如值超出范围时,重新限制回范围并触发事件) | boolean | true | 5.11.0 | | controls | 是否显示增减按钮,也可设置自定义箭头图标 | boolean \| { upIcon?: React.ReactNode; downIcon?: React.ReactNode; } | - | 4.19.0 | | decimalSeparator | 小数点 | string | - | - | +| placeholder | 占位符 | string | - | | | defaultValue | 初始值 | number | - | - | | disabled | 禁用 | boolean | false | - | | formatter | 指定输入框展示值的格式 | function(value: number \| string, info: { userTyping: boolean, input: string }): string | - | info: 4.17.0 | diff --git a/components/input/TextArea.tsx b/components/input/TextArea.tsx index 21a44e6dbd7a..fc492694f992 100644 --- a/components/input/TextArea.tsx +++ b/components/input/TextArea.tsx @@ -1,17 +1,18 @@ +import * as React from 'react'; +import { forwardRef } from 'react'; import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled'; import classNames from 'classnames'; import type { BaseInputProps } from 'rc-input/lib/interface'; import type { TextAreaRef as RcTextAreaRef } from 'rc-textarea'; import RcTextArea from 'rc-textarea'; import type { TextAreaProps as RcTextAreaProps } from 'rc-textarea/lib/interface'; -import * as React from 'react'; -import { forwardRef } from 'react'; + import type { InputStatus } from '../_util/statusUtils'; import { getMergedStatus, getStatusClassNames } from '../_util/statusUtils'; import { ConfigContext } from '../config-provider'; import DisabledContext from '../config-provider/DisabledContext'; -import type { SizeType } from '../config-provider/SizeContext'; import useSize from '../config-provider/hooks/useSize'; +import type { SizeType } from '../config-provider/SizeContext'; import { FormItemInputContext } from '../form/context'; import type { InputFocusOptions } from './Input'; import { triggerFocus } from './Input'; @@ -38,7 +39,6 @@ const TextArea = forwardRef((props, ref) => { disabled: customDisabled, status: customStatus, allowClear, - showCount, classNames: classes, rootClassName, className, @@ -99,7 +99,7 @@ const TextArea = forwardRef((props, ref) => { [`${prefixCls}-affix-wrapper-borderless`]: !bordered, [`${prefixCls}-affix-wrapper-sm`]: mergedSize === 'small', [`${prefixCls}-affix-wrapper-lg`]: mergedSize === 'large', - [`${prefixCls}-textarea-show-count`]: showCount, + [`${prefixCls}-textarea-show-count`]: props.showCount || props.count?.show, }, getStatusClassNames(`${prefixCls}-affix-wrapper`, mergedStatus), hashId, @@ -120,7 +120,6 @@ const TextArea = forwardRef((props, ref) => { }} prefixCls={prefixCls} suffix={hasFeedback && {feedbackIcon}} - showCount={showCount} ref={innerRef} />, ); diff --git a/components/input/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/input/__tests__/__snapshots__/demo-extend.test.ts.snap index e52987c7c3fc..d0245ed32aa5 100644 --- a/components/input/__tests__/__snapshots__/demo-extend.test.ts.snap +++ b/components/input/__tests__/__snapshots__/demo-extend.test.ts.snap @@ -599,6 +599,91 @@ exports[`renders components/input/demo/addon.tsx extend context correctly 1`] = exports[`renders components/input/demo/addon.tsx extend context correctly 2`] = `[]`; +exports[`renders components/input/demo/advance-count.tsx extend context correctly 1`] = ` +
    +
    +
    + Exceed Max +
    + + + + + 12 / 10 + + + +
    +
    +
    + Emoji count as length 1 +
    + + + + + 3 + + + +
    +
    +
    + Not exceed max +
    + + + + + 6 / 6 + + + +
    +
    +`; + +exports[`renders components/input/demo/advance-count.tsx extend context correctly 2`] = `[]`; + exports[`renders components/input/demo/align.tsx extend context correctly 1`] = ` Array [
    @@ -10347,15 +10435,15 @@ Array [ 0 / 20 - , -
    , -
    , +