diff --git a/.dumi/pages/theme-editor/index.tsx b/.dumi/pages/theme-editor/index.tsx index 5d11f141ba..e0df502b38 100644 --- a/.dumi/pages/theme-editor/index.tsx +++ b/.dumi/pages/theme-editor/index.tsx @@ -183,6 +183,10 @@ const CustomTheme = () => { style={{ height: 'calc(100vh - 64px - 56px)' }} onThemeChange={(newTheme) => { setTheme(newTheme.config); + setThemeConfigContent({ + json: newTheme.config, + text: undefined, + }); }} locale={lang === 'cn' ? zhCN : enUS} /> diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index 29372905d1..69aa3d8b8b 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -15,6 +15,25 @@ timeline: true --- +## 5.6.4 + +`2023-07-03` + +- Form + - 🐞 Fix `onFieldsChange` event will still be triggered incorrectly when the field is not configured with `rules` when the Form is submitted. [#43290](https://github.com/ant-design/ant-design/pull/43290) + - 🐞 Fix the problem that the warning message that `name` is empty is falsely reported when the `name` of Form.List is 0. [#43199](https://github.com/ant-design/ant-design/pull/43199) [@Yuiai01](https://github.com/Yuiai01) +- 🐞 Fix the Badge `color` attribute does not take effect. [#43304](https://github.com/ant-design/ant-design/pull/43304) +- 🐞 Fix the position of Select clear icon when FormItem sets `hasFeedback`. [#43302](https://github.com/ant-design/ant-design/pull/43302) [@tinyfind](https://github.com/tinyfind) +- 🐞 Fix Transfer paging drop-down button is hidden and `showSizeChanger` method is invalid. [#41906](https://github.com/ant-design/ant-design/pull/41906) [@Yuiai01](https://github.com/Yuiai01) +- 🐞 Fix the invalid modification of `colorText` and `fontSize` of Popconfirm component. [#43212](https://github.com/ant-design/ant-design/pull/43212) [@MadCcc](https://github.com/MadCcc) +- 🐞 Fix the problem that deleting files after Upload configures `maxCount` will not trigger `onChange`. [#43193](https://github.com/ant-design/ant-design/pull/43193) +- 💄 Fix Button disabled style error when it has `link` or `href` attribute. [#43091](https://github.com/ant-design/ant-design/pull/43091) [@BoyYangzai](https://github.com/BoyYangzai) +- TypeScript + - 🤖 Optimize Breadcrumb `params` type and support generics. [#43211](https://github.com/ant-design/ant-design/pull/43211) + - 🤖 Optimize Breadcrumb `params` type and support generics. [#43257](https://github.com/ant-design/ant-design/pull/43257) [@thinkasany](https://github.com/thinkasany) + - 🤖 Remove redundant number type from Button `loading`. [#43256](https://github.com/ant-design/ant-design/pull/43256) [@thinkasany](https://github.com/thinkasany) + - 🤖 Transparently pass Cascader `optionType` generic. [#43231](https://github.com/ant-design/ant-design/pull/43231) [@ZWkang](https://github.com/ZWkang) + ## 5.6.3 `2023-06-25` diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index 7f4268fb35..20822b1013 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -15,6 +15,25 @@ timeline: true --- +## 5.6.4 + +`2023-07-03` + +- Form + - 🐞 修复 Form 在提交时,字段没有配置 `rules` 时仍会错误触发 `onFieldsChange` 事件的问题。[#43290](https://github.com/ant-design/ant-design/pull/43290) + - 🐞 修复 Form.List 的 `name` 为 0 时误报 `name` 为空的警告信息的问题。[#43199](https://github.com/ant-design/ant-design/pull/43199) [@Yuiai01](https://github.com/Yuiai01) +- 🐞 修复 Badge `color` 属性不生效的问题。[#43304](https://github.com/ant-design/ant-design/pull/43304) +- 🐞 修复 Select 组件的消除图标在 FormItem 设置 `hasFeedback` 时的位置问题。[#43302](https://github.com/ant-design/ant-design/pull/43302) [@tinyfind](https://github.com/tinyfind) +- 🐞 修复 Transfer 分页下拉按钮被隐藏以及 `showSizeChanger` 方法无效。[#41906](https://github.com/ant-design/ant-design/pull/41906) [@Yuiai01](https://github.com/Yuiai01) +- 🐞 修复 Popconfirm 组件 `colorText` 和 `fontSize` 修改无效的问题。[#43212](https://github.com/ant-design/ant-design/pull/43212) [@MadCcc](https://github.com/MadCcc) +- 🐞 修复 Upload 配置 `maxCount` 后删除文件不会触发 `onChange` 的问题。[#43193](https://github.com/ant-design/ant-design/pull/43193) +- 💄 修复 Button 在有 `link` 或 `href` 属性时禁用样式错误。[#43091](https://github.com/ant-design/ant-design/pull/43091) [@BoyYangzai](https://github.com/BoyYangzai) +- TypeScript + - 🤖 优化 Breadcrumb `params` 类型,支持泛型。[#43211](https://github.com/ant-design/ant-design/pull/43211) + - 🤖 优化 Typography `copyIdRef` 类型。[#43257](https://github.com/ant-design/ant-design/pull/43257) [@thinkasany](https://github.com/thinkasany) + - 🤖 移除 Button `loading` 多余 number 类型。[#43256](https://github.com/ant-design/ant-design/pull/43256) [@thinkasany](https://github.com/thinkasany) + - 🤖 透传 Cascader `optionType` 泛型。[#43231](https://github.com/ant-design/ant-design/pull/43231) [@ZWkang](https://github.com/ZWkang) + ## 5.6.3 `2023-06-25` diff --git a/components/app/index.en-US.md b/components/app/index.en-US.md index e7cd528e8f..eda1014f72 100644 --- a/components/app/index.en-US.md +++ b/components/app/index.en-US.md @@ -13,7 +13,7 @@ Application wrapper for some global usages. ## When To Use - Provide reset styles based on `.ant-app` element. -- You could use static methods of `message/notification/Modal` form `useApp` without put `contextHolder` mannully. +- You could use static methods of `message/notification/Modal` form `useApp` without writing `contextHolder` manually. ## Examples @@ -95,7 +95,7 @@ export default () => { return null; }; -export { message, notification, modal }; +export { message, modal, notification }; ``` ```tsx diff --git a/components/app/index.tsx b/components/app/index.tsx index 1ece36064a..56df12b953 100644 --- a/components/app/index.tsx +++ b/components/app/index.tsx @@ -42,7 +42,7 @@ const App: React.FC & { useApp: typeof useApp } = (props) => { message: { ...appConfig.message, ...message }, notification: { ...appConfig.notification, ...notification }, }), - [message, notification, appConfig.message, appConfig.message], + [message, notification, appConfig.message, appConfig.notification], ); const [messageApi, messageContextHolder] = useMessage(mergedAppConfig.message); diff --git a/components/badge/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/badge/__tests__/__snapshots__/demo-extend.test.ts.snap index e5231453e9..88077d5007 100644 --- a/components/badge/__tests__/__snapshots__/demo-extend.test.ts.snap +++ b/components/badge/__tests__/__snapshots__/demo-extend.test.ts.snap @@ -627,531 +627,759 @@ Array [ `; exports[`renders components/badge/demo/colorful-with-count-debug.tsx extend context correctly 1`] = ` -
+Array [
- -
- pink -
- - + pink +
+ - 4 + + 4 + - - - 4 + + 4 + - - - -
-
- + +
+
-
- red -
- - + red +
+ - 4 + + 4 + - - - 4 + + 4 + - - - - -
- + +
+
-
- yellow -
- - + yellow +
+ - 4 + + 4 + - - - 4 + + 4 + - - - - -
- + +
+
-
- orange -
- - + orange +
+ - 4 + + 4 + - - - 4 + + 4 + - - - - -
- + +
+
-
- cyan -
- + cyan +
+ + + + 4 + + + + + 4 + + + + + +
+ - + green +
+ - 4 + + 4 + - - + + 4 + + + + + +
+ +
+ blue +
+ - 4 + + 4 + -
- - -
-
- + + 4 + + + + +
+
-
- green -
- + purple +
+ + + + 4 + + + + + 4 + + + + + +
+ - + geekblue +
+ - 4 + + 4 + - - + + 4 + + + + + +
+ +
+ magenta +
+ - 4 + + 4 + -
- - -
-
- + + 4 + + + + +
+
-
- blue -
- + volcano +
+ + + + 4 + + + + + 4 + + + + + +
+ - + gold +
+ - 4 + + 4 + - - + + 4 + + + + + +
+ +
+ lime +
+ - 4 + + 4 + -
- - -
+ + + 4 + + + + + + ,
- -
- purple -
- + + loading + +
+
+
+ + + + loading + + +
+
+ - - 4 - - + class="ant-badge-status-dot ant-badge-status-processing ant-badge-color-yellow" + /> - - 4 - + loading - - -
-
- +
+
-
- geekblue -
- + - - 4 - + loading + +
+
+ + - - 4 - + loading - - -
-
- +
+
-
- magenta -
- + - - 4 - + loading + +
+
+ + - - 4 - + loading - - -
-
- +
+
-
- volcano -
- + - - 4 - + loading + +
+
+ + - - 4 - + loading - - -
-
- +
+
-
- gold -
- + - - 4 - + loading + +
+
+ + - - 4 - + loading - - -
-
- +
+
-
- lime -
- + - - 4 - + loading + +
+
+ + - - 4 - + loading - - -
- + + + , +] `; exports[`renders components/badge/demo/dot.tsx extend context correctly 1`] = ` @@ -1976,11 +2204,7 @@ exports[`renders components/badge/demo/ribbon.tsx extend context correctly 1`] = -
- Hippies -
- Happy -
+ Hippies
+Array [
- -
- pink -
- - + pink +
+ - 4 + + 4 + - - - 4 + + 4 + - - - -
-
- + +
+
-
- red -
- - + red +
+ - 4 + + 4 + - - - 4 + + 4 + - - - - -
- + +
+
-
- yellow -
- - + yellow +
+ - 4 + + 4 + - - - 4 + + 4 + - - - - -
- + +
+
-
- orange -
- - + orange +
+ - 4 + + 4 + - - - 4 + + 4 + - - - - -
- + +
+
-
- cyan -
- + cyan +
+ + + + 4 + + + + + 4 + + + + + +
+ - + green +
+ - 4 + + 4 + - - + + 4 + + + + + +
+ +
+ blue +
+ - 4 + + 4 + -
- - -
-
- + + 4 + + + + +
+
-
- green -
- + purple +
+ + + + 4 + + + + + 4 + + + + + +
+ - + geekblue +
+ - 4 + + 4 + - - + + 4 + + + + + +
+ +
+ magenta +
+ - 4 + + 4 + -
- - -
-
- + + 4 + + + + +
+
-
- blue -
- + volcano +
+ + + + 4 + + + + + 4 + + + + + +
+ - + gold +
+ - 4 + + 4 + - - + + 4 + + + + + +
+ +
+ lime +
+ - 4 + + 4 + -
- - -
+ + + 4 + + + + + + ,
- -
- purple -
- + + loading + +
+
+
+ + + + loading + + +
+
+ - - 4 - - + class="ant-badge-status-dot ant-badge-status-processing ant-badge-color-yellow" + /> - - 4 - + loading - - -
-
- +
+
-
- geekblue -
- + - - 4 - + loading + +
+
+ + - - 4 - + loading - - -
-
- +
+
-
- magenta -
- + - - 4 - + loading + +
+
+ + - - 4 - + loading - - -
-
- +
+
-
- volcano -
- + - - 4 - + loading + +
+
+ + - - 4 - + loading - - -
-
- +
+
-
- gold -
- + - - 4 - + loading + +
+
+ + - - 4 - + loading - - -
-
- +
+
-
- lime -
- + - - 4 - + loading + +
+
+ + - - 4 - + loading - - -
- + + + , +] `; exports[`renders components/badge/demo/dot.tsx correctly 1`] = ` @@ -1977,11 +2205,7 @@ exports[`renders components/badge/demo/ribbon.tsx correctly 1`] = ` -
- Hippies -
- Happy -
+ Hippies
( +
+ {color} +
+); + const App: React.FC = () => ( - - {colors.map((color) => ( - -
- {color} -
-
- ))} -
+ <> + + {colors.map((color) => ( + + + + ))} + + + {colors.map((color) => ( + + ))} + + ); export default App; diff --git a/components/badge/demo/ribbon.tsx b/components/badge/demo/ribbon.tsx index 4770cd9bfa..a58e16f09e 100644 --- a/components/badge/demo/ribbon.tsx +++ b/components/badge/demo/ribbon.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { Badge, Card, Space } from 'antd'; +import React from 'react'; const App: React.FC = () => ( @@ -8,12 +8,7 @@ const App: React.FC = () => ( and raises the spyglass. - - Hippies
- Happy -
- } color="pink"> + and raises the spyglass. diff --git a/components/badge/style/index.ts b/components/badge/style/index.ts index f474ee2da9..3c1a276039 100644 --- a/components/badge/style/index.ts +++ b/components/badge/style/index.ts @@ -74,8 +74,11 @@ const genSharedBadgeStyle: GenerateStyle = (token: BadgeToken): CSSO const ribbonWrapperPrefixCls = `${antCls}-ribbon-wrapper`; const colorPreset = genPresetColor(token, (colorKey, { darkColor }) => ({ - [`${componentCls}-color-${colorKey}`]: { + [`&${componentCls} ${componentCls}-color-${colorKey}`]: { background: darkColor, + [`&:not(${componentCls}-count)`]: { + color: darkColor, + }, }, })); diff --git a/components/breadcrumb/Breadcrumb.tsx b/components/breadcrumb/Breadcrumb.tsx index 4b084f805f..8bdb0f12a8 100755 --- a/components/breadcrumb/Breadcrumb.tsx +++ b/components/breadcrumb/Breadcrumb.tsx @@ -46,9 +46,9 @@ export type ItemType = Partial; export type InternalRouteType = Partial; -export interface BreadcrumbProps { +export interface BreadcrumbProps = any> { prefixCls?: string; - params?: any; + params?: T; separator?: React.ReactNode; style?: React.CSSProperties; className?: string; @@ -60,19 +60,13 @@ export interface BreadcrumbProps { items?: ItemType[]; - itemRender?: ( - route: ItemType, - params: any, - routes: ItemType[], - paths: string[], - ) => React.ReactNode; + itemRender?: (route: ItemType, params: T, routes: ItemType[], paths: string[]) => React.ReactNode; } -const getPath = (params: any, path?: string) => { +const getPath = = any>(params: T, path?: string) => { if (path === undefined) { return path; } - let mergedPath = (path || '').replace(/^\//, ''); Object.keys(params).forEach((key) => { mergedPath = mergedPath.replace(`:${key}`, params[key]!); @@ -80,7 +74,7 @@ const getPath = (params: any, path?: string) => { return mergedPath; }; -const Breadcrumb = (props: BreadcrumbProps) => { +const Breadcrumb = = any>(props: BreadcrumbProps) => { const { prefixCls: customizePrefixCls, separator = '/', @@ -113,7 +107,7 @@ const Breadcrumb = (props: BreadcrumbProps) => { // generated by route const paths: string[] = []; - const itemRenderRoutes: any = items || legacyRoutes; + const itemRenderRoutes = items || legacyRoutes; crumbs = mergedItems.map((item, index) => { const { @@ -168,7 +162,7 @@ const Breadcrumb = (props: BreadcrumbProps) => { onClick={onClick} prefixCls={prefixCls} > - {mergedItemRender(item as BreadcrumbItemType, params, itemRenderRoutes, paths, href)} + {mergedItemRender(item, params, itemRenderRoutes!, paths, href)} ); }); diff --git a/components/breadcrumb/BreadcrumbItem.tsx b/components/breadcrumb/BreadcrumbItem.tsx index 0cb432e1b8..820d409ba0 100644 --- a/components/breadcrumb/BreadcrumbItem.tsx +++ b/components/breadcrumb/BreadcrumbItem.tsx @@ -37,7 +37,7 @@ export interface BreadcrumbItemProps extends SeparatorType { overlay?: DropdownProps['overlay']; } -export const InternalBreadcrumbItem = (props: BreadcrumbItemProps) => { +export const InternalBreadcrumbItem: React.FC = (props) => { const { prefixCls, separator = '/', children, menu, overlay, dropdownProps, href } = props; // Warning for deprecated usage @@ -103,11 +103,15 @@ export const InternalBreadcrumbItem = (props: BreadcrumbItemProps) => { return null; }; -const BreadcrumbItem = (props: BreadcrumbItemProps) => { +type CompoundedComponent = React.FC & { + /** @internal */ + __ANT_BREADCRUMB_ITEM: boolean; +}; + +const BreadcrumbItem: CompoundedComponent = (props) => { const { prefixCls: customizePrefixCls, children, href, ...restProps } = props; const { getPrefixCls } = React.useContext(ConfigContext); const prefixCls = getPrefixCls('breadcrumb', customizePrefixCls); - return ( {renderItem(prefixCls, restProps as ItemType, children, href)} diff --git a/components/breadcrumb/__tests__/Breadcrumb.test.tsx b/components/breadcrumb/__tests__/Breadcrumb.test.tsx index eb00b0f6ed..ccebb91521 100644 --- a/components/breadcrumb/__tests__/Breadcrumb.test.tsx +++ b/components/breadcrumb/__tests__/Breadcrumb.test.tsx @@ -384,4 +384,19 @@ describe('Breadcrumb', () => { ); expect(document.querySelector('.ant-dropdown')).toBeTruthy(); }); + + it('Breadcrumb params type test', () => { + interface Params { + key1?: number; + key2?: string; + } + expect( + + params={{ + key1: 1, + key2: 'test', + }} + />, + ).toBeTruthy(); + }); }); diff --git a/components/button/button.tsx b/components/button/button.tsx index 90b0f990f6..868b60186e 100644 --- a/components/button/button.tsx +++ b/components/button/button.tsx @@ -76,8 +76,6 @@ type CompoundedComponent = React.ForwardRefExoticComponent< __ANT_BUTTON: boolean; }; -type Loading = number | boolean; - type LoadingConfigType = { loading: boolean; delay: number; @@ -137,7 +135,7 @@ const InternalButton: React.ForwardRefRenderFunction< const loadingOrDelay = useMemo(() => getLoadingConfig(loading), [loading]); - const [innerLoading, setLoading] = useState(loadingOrDelay.loading); + const [innerLoading, setLoading] = useState(loadingOrDelay.loading); const [hasTwoCNChar, setHasTwoCNChar] = useState(false); @@ -218,8 +216,6 @@ const InternalButton: React.ForwardRefRenderFunction< const linkButtonRestProps = omit(rest as ButtonProps & { navigate: any }, ['navigate']); - const hrefAndDisabled = linkButtonRestProps.href !== undefined && mergedDisabled; - const classes = classNames( prefixCls, hashId, @@ -234,7 +230,6 @@ const InternalButton: React.ForwardRefRenderFunction< [`${prefixCls}-block`]: block, [`${prefixCls}-dangerous`]: !!danger, [`${prefixCls}-rtl`]: direction === 'rtl', - [`${prefixCls}-disabled`]: hrefAndDisabled, }, compactItemClassnames, className, @@ -263,7 +258,9 @@ const InternalButton: React.ForwardRefRenderFunction< return wrapSSR( } diff --git a/components/button/style/index.ts b/components/button/style/index.ts index 23df848cad..3737efe86c 100644 --- a/components/button/style/index.ts +++ b/components/button/style/index.ts @@ -115,8 +115,12 @@ const genSharedButtonStyle: GenerateStyle = (token): CSS }; }; -const genHoverActiveButtonStyle = (hoverStyle: CSSObject, activeStyle: CSSObject): CSSObject => ({ - '&:not(:disabled)': { +const genHoverActiveButtonStyle = ( + btnCls: string, + hoverStyle: CSSObject, + activeStyle: CSSObject, +): CSSObject => ({ + [`&:not(:disabled):not(${btnCls}-disabled)`]: { '&:hover': hoverStyle, '&:active': activeStyle, }, @@ -161,6 +165,7 @@ const genGhostButtonStyle = ( boxShadow: 'none', ...genHoverActiveButtonStyle( + btnCls, { backgroundColor: 'transparent', ...hoverStyle, @@ -180,7 +185,7 @@ const genGhostButtonStyle = ( }); const genSolidDisabledButtonStyle: GenerateStyle = (token) => ({ - '&:disabled': { + [`&:disabled, &${token.componentCls}-disabled`]: { ...genDisabledStyle(token), }, }); @@ -190,7 +195,7 @@ const genSolidButtonStyle: GenerateStyle = (token) => ({ }); const genPureDisabledButtonStyle: GenerateStyle = (token) => ({ - '&:disabled': { + [`&:disabled, &${token.componentCls}-disabled`]: { cursor: 'not-allowed', color: token.colorTextDisabled, }, @@ -206,6 +211,7 @@ const genDefaultButtonStyle: GenerateStyle = (token) => boxShadow: `0 ${token.controlOutlineWidth}px 0 ${token.controlTmpOutline}`, ...genHoverActiveButtonStyle( + token.componentCls, { color: token.colorPrimaryHover, borderColor: token.colorPrimaryHover, @@ -229,6 +235,7 @@ const genDefaultButtonStyle: GenerateStyle = (token) => borderColor: token.colorError, ...genHoverActiveButtonStyle( + token.componentCls, { color: token.colorErrorHover, borderColor: token.colorErrorBorderHover, @@ -260,6 +267,7 @@ const genPrimaryButtonStyle: GenerateStyle = (token) => boxShadow: `0 ${token.controlOutlineWidth}px 0 ${token.controlOutline}`, ...genHoverActiveButtonStyle( + token.componentCls, { color: token.colorTextLightSolid, backgroundColor: token.colorPrimaryHover, @@ -291,6 +299,7 @@ const genPrimaryButtonStyle: GenerateStyle = (token) => boxShadow: `0 ${token.controlOutlineWidth}px 0 ${token.colorErrorOutline}`, ...genHoverActiveButtonStyle( + token.componentCls, { backgroundColor: token.colorErrorHover, }, @@ -329,6 +338,7 @@ const genLinkButtonStyle: GenerateStyle = (token) => ({ color: token.colorLink, ...genHoverActiveButtonStyle( + token.componentCls, { color: token.colorLinkHover, }, @@ -343,6 +353,7 @@ const genLinkButtonStyle: GenerateStyle = (token) => ({ color: token.colorError, ...genHoverActiveButtonStyle( + token.componentCls, { color: token.colorErrorHover, }, @@ -358,6 +369,7 @@ const genLinkButtonStyle: GenerateStyle = (token) => ({ // Type: Text const genTextButtonStyle: GenerateStyle = (token) => ({ ...genHoverActiveButtonStyle( + token.componentCls, { color: token.colorText, backgroundColor: token.colorBgTextHover, @@ -375,6 +387,7 @@ const genTextButtonStyle: GenerateStyle = (token) => ({ ...genPureDisabledButtonStyle(token), ...genHoverActiveButtonStyle( + token.componentCls, { color: token.colorErrorHover, backgroundColor: token.colorErrorBg, @@ -387,14 +400,6 @@ const genTextButtonStyle: GenerateStyle = (token) => ({ }, }); -// Href and Disabled -const genDisabledButtonStyle: GenerateStyle = (token) => ({ - ...genDisabledStyle(token), - [`&${token.componentCls}:hover`]: { - ...genDisabledStyle(token), - }, -}); - const genTypeButtonStyle: GenerateStyle = (token) => { const { componentCls } = token; @@ -404,7 +409,6 @@ const genTypeButtonStyle: GenerateStyle = (token) => { [`${componentCls}-dashed`]: genDashedButtonStyle(token), [`${componentCls}-link`]: genLinkButtonStyle(token), [`${componentCls}-text`]: genTextButtonStyle(token), - [`${componentCls}-disabled`]: genDisabledButtonStyle(token), }; }; @@ -528,7 +532,7 @@ export default genComponentStyleHook('Button', (token) => { // Block genBlockButtonStyle(buttonToken), - // Group (type, ghost, danger, disabled, loading) + // Group (type, ghost, danger, loading) genTypeButtonStyle(buttonToken), // Button Group diff --git a/components/cascader/index.tsx b/components/cascader/index.tsx index 0118133525..5fe66a369f 100644 --- a/components/cascader/index.tsx +++ b/components/cascader/index.tsx @@ -96,30 +96,39 @@ const defaultSearchRender: ShowSearchType['render'] = (inputValue, path, prefixC return optionList; }; -type SingleCascaderProps = Omit & { +type SingleCascaderProps = Omit< + RcSingleCascaderProps, + 'checkable' | 'options' +> & { multiple?: false; }; -type MultipleCascaderProps = Omit & { +type MultipleCascaderProps = Omit< + RcMultipleCascaderProps, + 'checkable' | 'options' +> & { multiple: true; }; -type UnionCascaderProps = SingleCascaderProps | MultipleCascaderProps; - -export type CascaderProps = UnionCascaderProps & { - multiple?: boolean; - size?: SizeType; - disabled?: boolean; - bordered?: boolean; - placement?: SelectCommonPlacement; - suffixIcon?: React.ReactNode; - options?: DataNodeType[]; - status?: InputStatus; - - rootClassName?: string; - popupClassName?: string; - /** @deprecated Please use `popupClassName` instead */ - dropdownClassName?: string; -}; +type UnionCascaderProps = + | SingleCascaderProps + | MultipleCascaderProps; + +export type CascaderProps = + UnionCascaderProps & { + multiple?: boolean; + size?: SizeType; + disabled?: boolean; + bordered?: boolean; + placement?: SelectCommonPlacement; + suffixIcon?: React.ReactNode; + options?: DataNodeType[]; + status?: InputStatus; + + rootClassName?: string; + popupClassName?: string; + /** @deprecated Please use `popupClassName` instead */ + dropdownClassName?: string; + }; export interface CascaderRef { focus: () => void; diff --git a/components/date-picker/index.en-US.md b/components/date-picker/index.en-US.md index 4b71f5eb4a..e8360aaff0 100644 --- a/components/date-picker/index.en-US.md +++ b/components/date-picker/index.en-US.md @@ -83,7 +83,7 @@ The following APIs are shared by DatePicker, RangePicker. | className | The picker className | string | - | | | dateRender | Custom rendering function for date cells, >= 5.4.0 use `cellRender` instead. | function(currentDate: dayjs, today: dayjs) => React.ReactNode | - | < 5.4.0 | | changeOnBlur | Trigger `change` when blur. e.g. datetime picker no need click confirm button | boolean | false | 5.5.0 | -| cellRender | Custom rendering function for picker cells | function(current: dayjs, today: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 | +| cellRender | Custom rendering function for picker cells | (current: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 | | disabled | Determine whether the DatePicker is disabled | boolean | false | | | disabledDate | Specify the date that cannot be selected | (currentDate: dayjs) => boolean | - | | | format | To set the date format, support multi-format matching when it is an array, display the first one shall prevail. refer to [dayjs#format](https://day.js.org/docs/en/display/format). for example: [Custom Format](#components-date-picker-demo-format) | [formatType](#formattype) | [rc-picker](https://github.com/react-component/picker/blob/f512f18ed59d6791280d1c3d7d37abbb9867eb0b/src/utils/uiUtil.ts#L155-L177) | | @@ -187,7 +187,7 @@ Added in `4.1.0`. | --- | --- | --- | --- | --- | | allowEmpty | Allow start or end input leave empty | \[boolean, boolean] | \[false, false] | | | dateRender | Custom rendering function for date cells, >= 5.4.0 use `cellRender` instead. | function(currentDate: dayjs, today: dayjs) => React.ReactNode | - | < 5.4.0 | -| cellRender | Custom rendering function for picker cells | function(current: dayjs, today: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 | +| cellRender | Custom rendering function for picker cells | (current: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 | | defaultPickerValue | To set default picker date | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | - | | | defaultValue | To set default date | \[[dayjs](https://day.js.org/), [dayjs](https://day.js.org/)] | - | | | disabled | If disable start or end | \[boolean, boolean] | - | | @@ -248,8 +248,9 @@ Please use correct [language](/docs/react/i18n) ([#5605](https://github.com/ant- ```js import dayjs from 'dayjs'; import 'dayjs/locale/zh-cn'; -import 'dayjs/plugin/updateLocale'; +import updateLocale from 'dayjs/plugin/updateLocale'; +dayjs.extend(updateLocale); dayjs.updateLocale('zh-cn', { weekStart: 0, }); diff --git a/components/date-picker/index.zh-CN.md b/components/date-picker/index.zh-CN.md index 7977e5c2b1..0d5eda09a1 100644 --- a/components/date-picker/index.zh-CN.md +++ b/components/date-picker/index.zh-CN.md @@ -84,7 +84,7 @@ import locale from 'antd/locale/zh_CN'; | className | 选择器 className | string | - | | | dateRender | 自定义日期单元格的内容,5.4.0 起用 `cellRender` 代替 | function(currentDate: dayjs, today: dayjs) => React.ReactNode | - | < 5.4.0 | | changeOnBlur | 失去焦点时触发 `change` 事件,例如 datetime 下不再需要点击确认按钮 | boolean | false | 5.5.0 | -| cellRender | 自定义单元格的内容 | function(current: dayjs, today: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 | +| cellRender | 自定义单元格的内容 | (current: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 | | disabled | 禁用 | boolean | false | | | disabledDate | 不可选择的日期 | (currentDate: dayjs) => boolean | - | | | format | 设置日期格式,为数组时支持多格式匹配,展示以第一个为准。配置参考 [dayjs#format](https://day.js.org/docs/zh-CN/display/format#%E6%94%AF%E6%8C%81%E7%9A%84%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%8D%A0%E4%BD%8D%E7%AC%A6%E5%88%97%E8%A1%A8)。示例:[自定义格式](#components-date-picker-demo-format) | [formatType](#formattype) | [rc-picker](https://github.com/react-component/picker/blob/f512f18ed59d6791280d1c3d7d37abbb9867eb0b/src/utils/uiUtil.ts#L155-L177) | | @@ -188,7 +188,7 @@ import locale from 'antd/locale/zh_CN'; | --- | --- | --- | --- | --- | | allowEmpty | 允许起始项部分为空 | \[boolean, boolean] | \[false, false] | | | dateRender | 自定义日期单元格的内容,5.4.0 起用 `cellRender` 代替 | function(currentDate: dayjs, today: dayjs) => React.ReactNode | - | < 5.4.0 | -| cellRender | 自定义单元格的内容。 | function(current: dayjs, today: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 | +| cellRender | 自定义单元格的内容。 | (current: dayjs, info: { originNode: React.ReactElement,today: DateType, range?: 'start' \| 'end', type: PanelMode, locale?: Locale, subType?: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 | | defaultPickerValue | 默认面板日期 | [dayjs](https://day.js.org/)\[] | - | | | defaultValue | 默认日期 | [dayjs](https://day.js.org/)\[] | - | | | disabled | 禁用起始项 | \[boolean, boolean] | - | | @@ -243,8 +243,10 @@ export type FormatType = Generic | GenericFn | Array; ```js import dayjs from 'dayjs'; import 'dayjs/locale/zh-cn'; -import 'dayjs/plugin/updateLocale'; +import updateLocale from 'dayjs/plugin/updateLocale'; + +dayjs.extend(updateLocale); dayjs.updateLocale('zh-cn', { weekStart: 0, }); diff --git a/components/form/FormList.tsx b/components/form/FormList.tsx index eaff6f5520..55160ca9ea 100644 --- a/components/form/FormList.tsx +++ b/components/form/FormList.tsx @@ -1,8 +1,8 @@ import { List } from 'rc-field-form'; import type { StoreValue, ValidatorRule } from 'rc-field-form/lib/interface'; import * as React from 'react'; -import { ConfigContext } from '../config-provider'; import warning from '../_util/warning'; +import { ConfigContext } from '../config-provider'; import { FormItemPrefixContext } from './context'; export interface FormListFieldData { @@ -35,7 +35,12 @@ const FormList: React.FC = ({ children, ...props }) => { - warning(!!props.name, 'Form.List', 'Miss `name` prop.'); + warning( + typeof props.name === 'number' || + (Array.isArray(props.name) ? !!props.name.length : !!props.name), + 'Form.List', + 'Miss `name` prop.', + ); const { getPrefixCls } = React.useContext(ConfigContext); const prefixCls = getPrefixCls('form', customizePrefixCls); diff --git a/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap index 2491e6a522..15e28e5f15 100644 --- a/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap +++ b/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap @@ -7591,9 +7591,9 @@ exports[`renders components/form/demo/layout-can-wrap.tsx extend context correct
- 超长标签文案超长标签文案 + A super long label text
- 正常标签文案 + Normal label
- 超长标签文案超长标签文案 + A super long label text
{ errorSpy.mockRestore(); }); + + it('no warning when name is 0', () => { + const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + + render( +
+ + {(fields) => + fields.map((field) => ( + + + + )) + } + +
, + ); + + expect(errorSpy).not.toHaveBeenCalled(); + + errorSpy.mockRestore(); + }); + + it('warning when name is empty array', () => { + const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + + render( +
+ + {(fields) => + fields.map((field) => ( + + + + )) + } + +
, + ); + + expect(errorSpy).toHaveBeenCalled(); + + errorSpy.mockRestore(); + }); + + it('warning when name is null', () => { + const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + + render( +
+ + {(fields) => + fields.map((field) => ( + + + + )) + } + +
, + ); + + expect(errorSpy).toHaveBeenCalled(); + + errorSpy.mockRestore(); + }); }); diff --git a/components/form/demo/layout-can-wrap.tsx b/components/form/demo/layout-can-wrap.tsx index d41cb0686f..1829995b3c 100644 --- a/components/form/demo/layout-can-wrap.tsx +++ b/components/form/demo/layout-can-wrap.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { Button, Form, Input } from 'antd'; +import React from 'react'; const App: React.FC = () => (
( colon={false} style={{ maxWidth: 600 }} > - + - + diff --git a/components/popconfirm/style/index.tsx b/components/popconfirm/style/index.tsx index 0f77bd6fee..11a5c3ae5a 100644 --- a/components/popconfirm/style/index.tsx +++ b/components/popconfirm/style/index.tsx @@ -12,6 +12,7 @@ const genBaseStyle: GenerateStyle = (token) => { const { componentCls, iconCls, + antCls, zIndexPopup, colorText, colorWarning, @@ -25,7 +26,10 @@ const genBaseStyle: GenerateStyle = (token) => { return { [componentCls]: { zIndex: zIndexPopup, - color: colorText, + + [`&${antCls}-popover`]: { + fontSize, + }, [`${componentCls}-message`]: { marginBottom: marginXS, @@ -51,6 +55,7 @@ const genBaseStyle: GenerateStyle = (token) => { [`${componentCls}-description`]: { marginTop: marginXXS, + color: colorText, }, }, diff --git a/components/progress/style/index.tsx b/components/progress/style/index.tsx index 2a5275d3ef..b68ae667c0 100644 --- a/components/progress/style/index.tsx +++ b/components/progress/style/index.tsx @@ -1,8 +1,8 @@ import type { CSSObject } from '@ant-design/cssinjs'; import { Keyframes } from '@ant-design/cssinjs'; +import { resetComponent } from '../../style'; import type { FullToken, GenerateStyle } from '../../theme/internal'; import { genComponentStyleHook, mergeToken } from '../../theme/internal'; -import { resetComponent } from '../../style'; export interface ComponentToken {} @@ -16,20 +16,23 @@ interface ProgressToken extends FullToken<'Progress'> { progressActiveMotionDuration: string; } -const antProgressActive = new Keyframes('antProgressActive', { - '0%': { - transform: 'translateX(-100%) scaleX(0)', - opacity: 0.1, - }, - '20%': { - transform: 'translateX(-100%) scaleX(0)', - opacity: 0.5, - }, - to: { - transform: 'translateX(0) scaleX(1)', - opacity: 0, - }, -}); +const genAntProgressActive = (isRtl?: boolean) => { + const direction = isRtl ? '100%' : '-100%'; + return new Keyframes(`antProgress${isRtl ? 'RTL' : 'LTR'}Active`, { + '0%': { + transform: `translateX(${direction}) scaleX(0)`, + opacity: 0.1, + }, + '20%': { + transform: `translateX(${direction}) scaleX(0)`, + opacity: 0.5, + }, + to: { + transform: 'translateX(0) scaleX(1)', + opacity: 0, + }, + }); +}; const genBaseStyle: GenerateStyle = (token) => { const { componentCls: progressCls, iconCls: iconPrefixCls } = token; @@ -116,7 +119,7 @@ const genBaseStyle: GenerateStyle = (token) => { backgroundColor: token.colorBgContainer, borderRadius: token.progressLineRadius, opacity: 0, - animationName: antProgressActive, + animationName: genAntProgressActive(), animationDuration: token.progressActiveMotionDuration, animationTimingFunction: token.motionEaseOutQuint, animationIterationCount: 'infinite', @@ -124,6 +127,12 @@ const genBaseStyle: GenerateStyle = (token) => { }, }, + [`&${progressCls}-rtl${progressCls}-status-active`]: { + [`${progressCls}-bg::before`]: { + animationName: genAntProgressActive(true), + }, + }, + [`&${progressCls}-status-exception`]: { [`${progressCls}-bg`]: { backgroundColor: token.colorError, diff --git a/components/select/style/index.tsx b/components/select/style/index.tsx index 202be12803..45bb9c94ba 100644 --- a/components/select/style/index.tsx +++ b/components/select/style/index.tsx @@ -235,7 +235,7 @@ const genBaseStyle: GenerateStyle = (token) => { // ========================= Feedback ========================== [`${componentCls}-has-feedback`]: { [`${componentCls}-clear`]: { - insetInlineEnd: inputPaddingHorizontalBase + token.fontSize + token.paddingXXS, + insetInlineEnd: inputPaddingHorizontalBase + token.fontSize + token.paddingXS, }, }, }; diff --git a/components/spin/index.tsx b/components/spin/index.tsx index 93d148dd3b..33708204ab 100644 --- a/components/spin/index.tsx +++ b/components/spin/index.tsx @@ -61,10 +61,10 @@ function renderIndicator(prefixCls: string, props: SpinClassProps): React.ReactN return ( - - - - + + + + ); } diff --git a/components/table/demo/drag-sorting.tsx b/components/table/demo/drag-sorting.tsx index f6d9269759..e5e11ce1d1 100644 --- a/components/table/demo/drag-sorting.tsx +++ b/components/table/demo/drag-sorting.tsx @@ -1,9 +1,9 @@ import type { DragEndEvent } from '@dnd-kit/core'; -import { DndContext } from '@dnd-kit/core'; +import { DndContext, PointerSensor, useSensor, useSensors } from '@dnd-kit/core'; import { restrictToVerticalAxis } from '@dnd-kit/modifiers'; import { - arrayMove, SortableContext, + arrayMove, useSortable, verticalListSortingStrategy, } from '@dnd-kit/sortable'; @@ -77,6 +77,15 @@ const App: React.FC = () => { }, ]); + const sensors = useSensors( + useSensor(PointerSensor, { + activationConstraint: { + // https://docs.dndkit.com/api-documentation/sensors/pointer#activation-constraints + distance: 1, + }, + }), + ); + const onDragEnd = ({ active, over }: DragEndEvent) => { if (active.id !== over?.id) { setDataSource((prev) => { @@ -88,7 +97,7 @@ const App: React.FC = () => { }; return ( - + i.key)} diff --git a/components/tag/demo/draggable.tsx b/components/tag/demo/draggable.tsx index 9e8820b96c..d3c3dc0450 100644 --- a/components/tag/demo/draggable.tsx +++ b/components/tag/demo/draggable.tsx @@ -1,14 +1,14 @@ -import React, { useState } from 'react'; -import { Tag } from 'antd'; -import { DndContext, PointerSensor, useSensor, useSensors, closestCenter } from '@dnd-kit/core'; +import { DndContext, PointerSensor, closestCenter, useSensor, useSensors } from '@dnd-kit/core'; +import type { DragEndEvent } from '@dnd-kit/core/dist/types/index'; import { - arrayMove, - useSortable, SortableContext, + arrayMove, horizontalListSortingStrategy, + useSortable, } from '@dnd-kit/sortable'; +import { Tag } from 'antd'; import type { FC } from 'react'; -import type { DragEndEvent } from '@dnd-kit/core/dist/types/index'; +import React, { useState } from 'react'; type Item = { id: number; @@ -25,14 +25,14 @@ const DraggableTag: FC = (props) => { const commonStyle = { cursor: 'move', - transition: 'unset', // 防止拖拽完毕之后元素抖动 + transition: 'unset', // Prevent element from shaking after drag }; const style = transform ? { ...commonStyle, transform: `translate3d(${transform.x}px, ${transform.y}px, 0)`, - transition: isDragging ? 'unset' : transition, // 处理拖拽中的元素不跟手的问题 + transition: isDragging ? 'unset' : transition, // Improve performance/visual effect when dragging } : commonStyle; diff --git a/components/time-picker/index.en-US.md b/components/time-picker/index.en-US.md index 80fa4cd1e1..8e12f977f1 100644 --- a/components/time-picker/index.en-US.md +++ b/components/time-picker/index.en-US.md @@ -50,6 +50,7 @@ dayjs.extend(customParseFormat) | allowClear | Whether allow clearing text | boolean | true | | | autoFocus | If get focus when component mounted | boolean | false | | | bordered | Whether has border style | boolean | true | | +| cellRender | Custom rendering function for picker cells | (current: number, info: { originNode: React.ReactElement, today: dayjs, range?: 'start' \| 'end', subType: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 | | changeOnBlur | Trigger `change` when blur. e.g. datetime picker no need click confirm button | boolean | false | 5.5.0 | | className | The className of picker | string | - | | | clearIcon | The custom clear icon | ReactNode | - | | diff --git a/components/time-picker/index.zh-CN.md b/components/time-picker/index.zh-CN.md index e0d01aca9b..eba10140d6 100644 --- a/components/time-picker/index.zh-CN.md +++ b/components/time-picker/index.zh-CN.md @@ -50,6 +50,7 @@ dayjs.extend(customParseFormat) | allowClear | 是否展示清除按钮 | boolean | true | | | autoFocus | 自动获取焦点 | boolean | false | | | bordered | 是否有边框 | boolean | true | | +| cellRender | 自定义单元格的内容 | (current: number, info: { originNode: React.ReactNode, today: dayjs, range?: 'start' \| 'end', subType: 'hour' \| 'minute' \| 'second' \| 'meridiem' }) => React.ReactNode | - | 5.4.0 | | changeOnBlur | 失去焦点时触发 `change` 事件,例如 datetime 下不再需要点击确认按钮 | boolean | false | 5.5.0 | | className | 选择器类名 | string | - | | | clearIcon | 自定义的清除图标 | ReactNode | - | | diff --git a/components/transfer/ListBody.tsx b/components/transfer/ListBody.tsx index e57c60c075..5708422f12 100644 --- a/components/transfer/ListBody.tsx +++ b/components/transfer/ListBody.tsx @@ -1,14 +1,17 @@ import classNames from 'classnames'; import * as React from 'react'; + +import useMergedState from 'rc-util/lib/hooks/useMergedState'; import type { KeyWiseTransferItem } from '.'; -import type { PaginationType } from './interface'; -import type { RenderedItem, TransferListProps } from './list'; import Pagination from '../pagination'; import ListItem from './ListItem'; +import type { PaginationType } from './interface'; +import type { RenderedItem, TransferListProps } from './list'; export const OmitProps = ['handleFilter', 'handleClear', 'checkedKeys'] as const; -export type OmitProp = typeof OmitProps[number]; +export type OmitProp = (typeof OmitProps)[number]; type PartialTransferListProps = Omit, OmitProp>; +type ExistPagination = Exclude; export interface TransferListBodyProps extends PartialTransferListProps { filteredItems: RecordType[]; @@ -16,25 +19,15 @@ export interface TransferListBodyProps extends PartialTransferListPr selectedKeys: string[]; } -const parsePagination = (pagination?: PaginationType) => { - if (!pagination) { - return null; - } - +const parsePagination = (pagination?: ExistPagination) => { const defaultPagination: PaginationType = { - pageSize: 10, simple: true, showSizeChanger: false, showLessItems: false, }; - if (typeof pagination === 'object') { - return { ...defaultPagination, ...pagination }; - } - - return defaultPagination; + return { ...defaultPagination, ...pagination }; }; - export interface ListBodyRef { items?: RenderedItem[]; } @@ -57,16 +50,28 @@ const TransferListBody: React.ForwardRefRenderFunction< onItemSelect, onItemRemove, } = props; - const [current, setCurrent] = React.useState(1); + const mergedPagination = React.useMemo(() => { + if (!pagination) { + return null; + } + + const convertPagination = typeof pagination === 'object' ? pagination : {}; + + return parsePagination(convertPagination); + }, [pagination]); + + const [pageSize, setPageSize] = useMergedState(10, { + value: mergedPagination?.pageSize, + }); + React.useEffect(() => { - const mergedPagination = parsePagination(pagination); if (mergedPagination) { - const maxPageCount = Math.ceil(filteredRenderItems.length / mergedPagination.pageSize!); + const maxPageCount = Math.ceil(filteredRenderItems.length / pageSize!); setCurrent(Math.min(current, maxPageCount)); } - }, [filteredRenderItems, pagination]); + }, [filteredRenderItems, mergedPagination, pageSize]); const onClick = (item: RecordType) => { onItemSelect?.(item.key, !selectedKeys.includes(item.key)); @@ -80,33 +85,33 @@ const TransferListBody: React.ForwardRefRenderFunction< setCurrent(cur); }; + const onSizeChange = (cur: number, size: number) => { + setCurrent(cur); + setPageSize(size); + }; + const memoizedItems = React.useMemo[]>(() => { - const mergedPagination = parsePagination(pagination); const displayItems = mergedPagination - ? filteredRenderItems.slice( - (current - 1) * mergedPagination.pageSize!, - current * mergedPagination.pageSize!, - ) + ? filteredRenderItems.slice((current - 1) * pageSize!, current * pageSize!) : filteredRenderItems; return displayItems; - }, [current, filteredRenderItems, pagination]); + }, [current, filteredRenderItems, mergedPagination, pageSize]); React.useImperativeHandle(ref, () => ({ items: memoizedItems })); - const mergedPagination = parsePagination(pagination); - const paginationNode: React.ReactNode = mergedPagination ? ( ) : null; diff --git a/components/transfer/__tests__/index.test.tsx b/components/transfer/__tests__/index.test.tsx index 6920c8bb83..764df524d2 100644 --- a/components/transfer/__tests__/index.test.tsx +++ b/components/transfer/__tests__/index.test.tsx @@ -73,6 +73,19 @@ const searchTransferProps = { targetKeys: ['3', '4'], }; +const generateData = (n = 20) => { + const data = []; + for (let i = 0; i < n; i++) { + data.push({ + key: `${i}`, + title: `content${i}`, + description: `description of content${i}`, + chosen: false, + }); + } + return data; +}; + describe('Transfer', () => { mountTest(Transfer); rtlTest(Transfer); @@ -595,6 +608,32 @@ describe('Transfer', () => { ); await waitFor(() => expect(getAllByTitle('1/1')).toHaveLength(2)); }); + + it('should support change pageSize', () => { + const dataSource = generateData(); + const { container } = render( + , + ); + + fireEvent.mouseDown(container.querySelector('.ant-select-selector')!); + fireEvent.click(container.querySelectorAll('.ant-select-item-option')[1]); + expect(container.querySelectorAll('.ant-transfer-list-content-item').length).toBe(20); + }); + + it('should be used first when pagination has pagesize', () => { + const dataSource = generateData(30); + + const { container } = render( + , + ); + + fireEvent.mouseDown(container.querySelector('.ant-select-selector')!); + fireEvent.click(container.querySelectorAll('.ant-select-item-option')[2]); + expect(container.querySelectorAll('.ant-transfer-list-content-item').length).toBe(20); + }); }); it('remove by click icon', () => { diff --git a/components/transfer/list.tsx b/components/transfer/list.tsx index e10facd00b..7661e5b808 100644 --- a/components/transfer/list.tsx +++ b/components/transfer/list.tsx @@ -110,7 +110,6 @@ const TransferList = ( } = props; const [filterValue, setFilterValue] = useState(''); - const listBodyRef = useRef>({}); const internalHandleFilter = (e: React.ChangeEvent) => { diff --git a/components/transfer/style/index.ts b/components/transfer/style/index.ts index 5e050aed1e..96f18573ad 100644 --- a/components/transfer/style/index.ts +++ b/components/transfer/style/index.ts @@ -101,6 +101,7 @@ const genTransferListStyle: GenerateStyle = (token: TransferToken marginXS, paddingSM, lineType, + antCls, iconCls, motionDurationSlow, controlItemBgHover, @@ -174,8 +175,9 @@ const genTransferListStyle: GenerateStyle = (token: TransferToken display: 'flex', flex: 'auto', flexDirection: 'column', - overflow: 'hidden', fontSize: token.fontSize, + // https://blog.csdn.net/qq449245884/article/details/107373672/ + minHeight: 0, '&-search-wrapper': { position: 'relative', @@ -262,6 +264,10 @@ const genTransferListStyle: GenerateStyle = (token: TransferToken padding: `${token.paddingXS}px 0`, textAlign: 'end', borderTop: `${lineWidth}px ${lineType} ${colorSplit}`, + + [`${antCls}-pagination-options`]: { + paddingInlineEnd: token.paddingXS, + }, }, '&-body-not-found': { diff --git a/components/tree/demo/drag-debug.tsx b/components/tree/demo/drag-debug.tsx index 3442009846..44ac6849cd 100644 --- a/components/tree/demo/drag-debug.tsx +++ b/components/tree/demo/drag-debug.tsx @@ -1,9 +1,9 @@ /* eslint-disable @typescript-eslint/no-shadow */ -import React from 'react'; -import type { TreeProps } from 'antd'; -import { Tree, Switch } from 'antd'; import { CarryOutOutlined } from '@ant-design/icons'; +import type { TreeProps } from 'antd'; +import { Switch, Tree } from 'antd'; import type { DataNode } from 'rc-tree/lib/interface'; +import React from 'react'; const x = 3; const y = 2; @@ -40,7 +40,7 @@ const App: React.FC = () => { const onDragEnter: TreeProps['onDragEnter'] = (info) => { console.log(info); - // expandedKeys 需要受控时设置 + // expandedKeys, set it when controlled is needed setExpandedKeys(info.expandedKeys); }; @@ -79,7 +79,7 @@ const App: React.FC = () => { // Drop on the content loop(data, dropKey, (item) => { item.children = item.children || []; - // where to insert 示例添加到尾部,可以是随意位置 + // where to insert. New item was inserted to the end of the array in this example, but can be anywhere item.children.push(dragObj); }); } else if ( @@ -89,7 +89,7 @@ const App: React.FC = () => { ) { loop(data, dropKey, (item) => { item.children = item.children || []; - // where to insert 示例添加到头部,可以是随意位置 + // where to insert. New item was inserted to the start of the array in this example, but can be anywhere item.children.unshift(dragObj); }); } else { diff --git a/components/tree/demo/draggable.tsx b/components/tree/demo/draggable.tsx index 6c4bb62049..cd3bd4ed2d 100644 --- a/components/tree/demo/draggable.tsx +++ b/components/tree/demo/draggable.tsx @@ -1,6 +1,6 @@ -import React, { useState } from 'react'; import { Tree } from 'antd'; import type { DataNode, TreeProps } from 'antd/es/tree'; +import React, { useState } from 'react'; const x = 3; const y = 2; @@ -36,7 +36,7 @@ const App: React.FC = () => { const onDragEnter: TreeProps['onDragEnter'] = (info) => { console.log(info); - // expandedKeys 需要受控时设置 + // expandedKeys, set it when controlled is needed // setExpandedKeys(info.expandedKeys) }; @@ -74,7 +74,7 @@ const App: React.FC = () => { // Drop on the content loop(data, dropKey, (item) => { item.children = item.children || []; - // where to insert 示例添加到头部,可以是随意位置 + // where to insert. New item was inserted to the start of the array in this example, but can be anywhere item.children.unshift(dragObj); }); } else if ( @@ -84,7 +84,7 @@ const App: React.FC = () => { ) { loop(data, dropKey, (item) => { item.children = item.children || []; - // where to insert 示例添加到头部,可以是随意位置 + // where to insert. New item was inserted to the start of the array in this example, but can be anywhere item.children.unshift(dragObj); // in previous version, we use item.children.push(dragObj) to insert the // item to the tail of the children diff --git a/components/typography/Base/index.tsx b/components/typography/Base/index.tsx index 9c712fc529..56cef15b47 100644 --- a/components/typography/Base/index.tsx +++ b/components/typography/Base/index.tsx @@ -11,17 +11,17 @@ import useMergedState from 'rc-util/lib/hooks/useMergedState'; import omit from 'rc-util/lib/omit'; import { composeRef } from 'rc-util/lib/ref'; import * as React from 'react'; +import { isStyleSupport } from '../../_util/styleChecker'; +import TransButton from '../../_util/transButton'; import { ConfigContext } from '../../config-provider'; import useLocale from '../../locale/useLocale'; import type { TooltipProps } from '../../tooltip'; import Tooltip from '../../tooltip'; -import { isStyleSupport } from '../../_util/styleChecker'; -import TransButton from '../../_util/transButton'; import Editable from '../Editable'; -import useMergedConfig from '../hooks/useMergedConfig'; -import useUpdatedEffect from '../hooks/useUpdatedEffect'; import type { TypographyProps } from '../Typography'; import Typography from '../Typography'; +import useMergedConfig from '../hooks/useMergedConfig'; +import useUpdatedEffect from '../hooks/useUpdatedEffect'; import Ellipsis from './Ellipsis'; import EllipsisTooltip from './EllipsisTooltip'; @@ -193,7 +193,7 @@ const Base = React.forwardRef((props, ref) => { // ========================== Copyable ========================== const [enableCopy, copyConfig] = useMergedConfig(copyable); const [copied, setCopied] = React.useState(false); - const copyIdRef = React.useRef(); + const copyIdRef = React.useRef(null); const copyOptions: Pick = {}; if (copyConfig.format) { @@ -201,7 +201,9 @@ const Base = React.forwardRef((props, ref) => { } const cleanCopyId = () => { - window.clearTimeout(copyIdRef.current!); + if (copyIdRef.current) { + clearTimeout(copyIdRef.current); + } }; const onCopyClick = (e?: React.MouseEvent) => { @@ -214,7 +216,7 @@ const Base = React.forwardRef((props, ref) => { // Trigger tips update cleanCopyId(); - copyIdRef.current = window.setTimeout(() => { + copyIdRef.current = setTimeout(() => { setCopied(false); }, 3000); diff --git a/docs/react/faq.en-US.md b/docs/react/faq.en-US.md index 67feb46644..865845e137 100644 --- a/docs/react/faq.en-US.md +++ b/docs/react/faq.en-US.md @@ -234,3 +234,34 @@ Here are some typical wrong examples: ## Do you guys have any channel or website for submitting monetary donations, like through PayPal or Alipay? [https://opencollective.com/ant-design](https://opencollective.com/ant-design) + +## Use Form's `setFieldsValue` method to report an error if the object type contains `null` + +When we try to set the form value using the `setFieldsValue` method in the form instance of the form component, if the passed object contains the type null, such as: + +```tsx +// This is not real world code, just for explain +import { Form } from 'antd'; + +type Test = { + value: string[] | null; +}; + +export default () => { + const [form] = Form.useForm(); + + form.setFieldsValue({ + value: null, // Error: Type "null" cannot be assigned to type "string[] | undefined". + }); +}; +``` + +If you encounter the above error, please check the current project `tsconfig.json` contains the following configuration: + +```json +{ + "strictNullChecks": true +} +``` + +The above problem occurs if `strictNullChecks` is set to `true`, If you can determine the project don't need this configuration (see [strictNullChecks](https://www.typescriptlang.org/zh/tsconfig#strictNullChecks) to judge whether need the configuration). You can try changing to `false` to turn off the control strict check. However, if you do need to enable this feature, you can avoid this situation by using other types instead of `null` when designing types diff --git a/docs/react/faq.zh-CN.md b/docs/react/faq.zh-CN.md index 631bbe82ba..35973d24f7 100644 --- a/docs/react/faq.zh-CN.md +++ b/docs/react/faq.zh-CN.md @@ -256,3 +256,34 @@ import { ConfigProvider } from 'antd'; ## 你们有接受捐助的渠道吗,比如支付宝或者微信支付? [https://opencollective.com/ant-design](https://opencollective.com/ant-design) + +## 使用表单组件的 `setFieldsValue` 方法如果对象类型中含有 `null` 时 TS 类型报错 + +当我们尝试使用表单组件的表单实例当中的 `setFieldsValue` 方法设置表单值时,如果在传入的对象中包含有 `null` 类型,如: + +```tsx +// This is not real world code, just for explain +import { Form } from 'antd'; + +type Test = { + value: string[] | null; +}; + +export default () => { + const [form] = Form.useForm(); + + form.setFieldsValue({ + value: null, // Error: 不能将类型“null”分配给类型“string[] | undefined”。 + }); +}; +``` + +如果你遇到上述报错,请检查当前项目的 `tsconfig.json` 中是否包含如下配置: + +```json +{ + "strictNullChecks": true +} +``` + +如果 `strictNullChecks` 的值被设置为 `true` 就会出现上述问题,如果你确定项目中可以不需要这个检测配置(查看[strictNullChecks](https://www.typescriptlang.org/zh/tsconfig#strictNullChecks)判断是否需要该配置),可以尝试改为 `false` 关闭控制严格检查功能。但如果你确实需要开启这个功能,那么,你可以在设计类型时,使用其他类型替代 `null` 以避免出现这种情况。 diff --git a/docs/spec/data-format.zh-CN.md b/docs/spec/data-format.zh-CN.md index d7fecf891c..7456a57cd8 100644 --- a/docs/spec/data-format.zh-CN.md +++ b/docs/spec/data-format.zh-CN.md @@ -66,7 +66,7 @@ title: 数据格式 不推荐示例 -**大额计量:** 如果一个金额很大,那么数值中的“万”“亿”单位可采用汉字。如果一个数值很大,那么数值中的“万”“亿”单位可采用汉字。 +**大额计量:** 如果一个数值很大,那么数值中的“万”“亿”单位可采用汉字。 ### 日期时间 diff --git a/docs/spec/transition.en-US.md b/docs/spec/transition.en-US.md index 00847dfa8c..d3ad0d31ac 100644 --- a/docs/spec/transition.en-US.md +++ b/docs/spec/transition.en-US.md @@ -16,19 +16,19 @@ Our Gray Matter are wired to react to dynamic things like movement,shape change ## Maintain Context While Changing Views Slide In and Slide Out: Create an illusion of virtual space.
-