From 4303e5e28a2da425bf83136cea0416b4f80d961a Mon Sep 17 00:00:00 2001 From: afc163 Date: Sun, 29 Sep 2024 13:26:05 +0800 Subject: [PATCH 01/22] feat: Tree add indentSize token (#51010) --- components/tree/demo/component-token.tsx | 1 + components/tree/style/index.ts | 27 ++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/components/tree/demo/component-token.tsx b/components/tree/demo/component-token.tsx index 2bd5341f6e..4a12065b63 100644 --- a/components/tree/demo/component-token.tsx +++ b/components/tree/demo/component-token.tsx @@ -48,6 +48,7 @@ const App: React.FC = () => { Tree: { nodeHoverBg: '#fff2f0', nodeSelectedBg: '#ffa39e', + indentSize: 80, }, }, }} diff --git a/components/tree/style/index.ts b/components/tree/style/index.ts index af4091265f..7a241a0ec0 100644 --- a/components/tree/style/index.ts +++ b/components/tree/style/index.ts @@ -13,6 +13,11 @@ export interface TreeSharedToken { * @descEN Node title height */ titleHeight: number; + /** + * @desc 缩进宽度 + * @descEN Indent width of tree + */ + indentSize?: number; /** * @desc 节点悬浮态背景色 * @descEN Background color of hovered node @@ -94,7 +99,15 @@ type TreeToken = FullToken<'Tree'> & { }; export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject => { - const { treeCls, treeNodeCls, treeNodePadding, titleHeight, nodeSelectedBg, nodeHoverBg } = token; + const { + treeCls, + treeNodeCls, + treeNodePadding, + titleHeight, + indentSize, + nodeSelectedBg, + nodeHoverBg, + } = token; const treeCheckBoxMarginHorizontal = token.paddingXS; return { @@ -223,7 +236,7 @@ export const genBaseStyle = (prefixCls: string, token: TreeToken): CSSObject => userSelect: 'none', '&-unit': { display: 'inline-block', - width: titleHeight, + width: indentSize, }, }, @@ -534,12 +547,14 @@ export const genTreeStyle = ( }; export const initComponentToken = (token: AliasToken): TreeSharedToken => { - const { controlHeightSM } = token; + const { controlHeightSM, controlItemBgHover, controlItemBgActive } = token; + const titleHeight = controlHeightSM; return { - titleHeight: controlHeightSM, - nodeHoverBg: token.controlItemBgHover, - nodeSelectedBg: token.controlItemBgActive, + titleHeight, + indentSize: titleHeight, + nodeHoverBg: controlItemBgHover, + nodeSelectedBg: controlItemBgActive, }; }; From 91754fb16040619c4bfdea351b7835f0e6de33c4 Mon Sep 17 00:00:00 2001 From: lijianan <574980606@qq.com> Date: Sun, 29 Sep 2024 13:28:53 +0800 Subject: [PATCH 02/22] feat: expandedRowClassName should support string (#51067) --- components/table/index.en-US.md | 2 +- components/table/index.zh-CN.md | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/table/index.en-US.md b/components/table/index.en-US.md index ea1168a346..222de43768 100644 --- a/components/table/index.en-US.md +++ b/components/table/index.en-US.md @@ -248,7 +248,7 @@ Properties for expandable. | columnWidth | Set the width of the expand column | string \| number | - | | | defaultExpandAllRows | Expand all rows initially | boolean | false | | | defaultExpandedRowKeys | Initial expanded row keys | string\[] | - | | -| expandedRowClassName | Expanded row's className | function(record, index, indent): string | - | | +| expandedRowClassName | Expanded row's className | string \| (record, index, indent) => string | - | string: 5.22.0 | | expandedRowKeys | Current expanded row keys | string\[] | - | | | expandedRowRender | Expanded container render for each row | function(record, index, indent, expanded): ReactNode | - | | | expandIcon | Customize row expand Icon. Ref [example](https://codesandbox.io/s/fervent-bird-nuzpr) | function(props): ReactNode | - | | diff --git a/components/table/index.zh-CN.md b/components/table/index.zh-CN.md index 63c4d0102c..37e041868f 100644 --- a/components/table/index.zh-CN.md +++ b/components/table/index.zh-CN.md @@ -250,7 +250,7 @@ const columns = [ | columnWidth | 自定义展开列宽度 | string \| number | - | | | defaultExpandAllRows | 初始时,是否展开所有行 | boolean | false | | | defaultExpandedRowKeys | 默认展开的行 | string\[] | - | | -| expandedRowClassName | 展开行的 className | function(record, index, indent): string | - | | +| expandedRowClassName | 展开行的 className | string \| (record, index, indent) => string | - | string: 5.22.0 | | expandedRowKeys | 展开的行,控制属性 | string\[] | - | | | expandedRowRender | 额外的展开行 | function(record, index, indent, expanded): ReactNode | - | | | expandIcon | 自定义展开图标,参考[示例](https://codesandbox.io/s/fervent-bird-nuzpr) | function(props): ReactNode | - | | diff --git a/package.json b/package.json index 3fed96b62e..70ade9c9b7 100644 --- a/package.json +++ b/package.json @@ -140,7 +140,7 @@ "rc-slider": "~11.1.6", "rc-steps": "~6.0.1", "rc-switch": "~4.1.0", - "rc-table": "~7.47.5", + "rc-table": "~7.48.0", "rc-tabs": "~15.2.0", "rc-textarea": "~1.8.2", "rc-tooltip": "~6.2.1", From 7e5c67e69f643a8d2f0e75691ad574f6f352a579 Mon Sep 17 00:00:00 2001 From: afc163 Date: Tue, 15 Oct 2024 13:51:42 +0800 Subject: [PATCH 03/22] chore: update snapshot --- components/table/__tests__/__snapshots__/empty.test.tsx.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/table/__tests__/__snapshots__/empty.test.tsx.snap b/components/table/__tests__/__snapshots__/empty.test.tsx.snap index 3a06957340..a5f52d2f3e 100644 --- a/components/table/__tests__/__snapshots__/empty.test.tsx.snap +++ b/components/table/__tests__/__snapshots__/empty.test.tsx.snap @@ -356,7 +356,7 @@ exports[`Table renders empty table with fixed columns should work 1`] = ` class="ant-spin-container" >
Date: Tue, 15 Oct 2024 01:24:27 -0700 Subject: [PATCH 04/22] feat: focus on the first field with error in form validation (#51231) Co-authored-by: afc163 --- components/form/Form.tsx | 15 ++++++--- components/form/__tests__/index.test.tsx | 32 +++++++++++++++++++ .../form/demo/validate-scroll-to-field.tsx | 2 +- components/form/hooks/useForm.ts | 8 +++++ components/form/index.en-US.md | 2 +- components/form/index.zh-CN.md | 2 +- 6 files changed, 54 insertions(+), 7 deletions(-) diff --git a/components/form/Form.tsx b/components/form/Form.tsx index 5b59bbfc1e..b2941245b6 100644 --- a/components/form/Form.tsx +++ b/components/form/Form.tsx @@ -31,6 +31,10 @@ export type RequiredMark = export type FormLayout = 'horizontal' | 'inline' | 'vertical'; export type FormItemLayout = 'horizontal' | 'vertical'; +export type ScrollFocusOptions = Options & { + focus?: boolean; +}; + export interface FormProps extends Omit, 'form'> { prefixCls?: string; colon?: boolean; @@ -44,7 +48,7 @@ export interface FormProps extends Omit, 'form feedbackIcons?: FeedbackIcons; size?: SizeType; disabled?: boolean; - scrollToFirstError?: Options | boolean; + scrollToFirstError?: ScrollFocusOptions | boolean; requiredMark?: RequiredMark; /** @deprecated Will warning in future branch. Pls use `requiredMark` instead. */ hideRequiredMark?: boolean; @@ -166,13 +170,16 @@ const InternalForm: React.ForwardRefRenderFunction = (props, nativeElement: nativeElementRef.current?.nativeElement, })); - const scrollToField = (options: boolean | Options, fieldName: InternalNamePath) => { + const scrollToField = (options: ScrollFocusOptions | boolean, fieldName: InternalNamePath) => { if (options) { - let defaultScrollToFirstError: Options = { block: 'nearest' }; + let defaultScrollToFirstError: ScrollFocusOptions = { block: 'nearest' }; if (typeof options === 'object') { - defaultScrollToFirstError = options; + defaultScrollToFirstError = { ...defaultScrollToFirstError, ...options }; } wrapForm.scrollToField(fieldName, defaultScrollToFirstError); + if (defaultScrollToFirstError.focus) { + wrapForm.focusField(fieldName); + } } }; diff --git a/components/form/__tests__/index.test.tsx b/components/form/__tests__/index.test.tsx index 5c070458a4..08d76ab1f0 100644 --- a/components/form/__tests__/index.test.tsx +++ b/components/form/__tests__/index.test.tsx @@ -534,6 +534,38 @@ describe('Form', () => { expect(scrollIntoView).toHaveBeenCalledTimes(3); }); + it('should scrollToFirstError work with focus', async () => { + const onFinishFailed = jest.fn(); + const focusSpy = jest.spyOn(HTMLElement.prototype, 'focus'); + + const { container } = render( +
+ + + + + + +
, + ); + + expect(scrollIntoView).not.toHaveBeenCalled(); + expect(focusSpy).not.toHaveBeenCalled(); + + fireEvent.submit(container.querySelector('form')!); + await waitFakeTimer(); + + const inputNode = document.getElementById('test'); + expect(focusSpy).toHaveBeenCalledWith(); + expect(scrollIntoView).toHaveBeenCalledWith(inputNode, { + block: 'center', + focus: true, + scrollMode: 'if-needed', + }); + + focusSpy.mockRestore(); + }); + // https://github.com/ant-design/ant-design/issues/28869 it('should work with Upload', async () => { const uploadRef = React.createRef(); diff --git a/components/form/demo/validate-scroll-to-field.tsx b/components/form/demo/validate-scroll-to-field.tsx index 53209679df..b483c7a562 100644 --- a/components/form/demo/validate-scroll-to-field.tsx +++ b/components/form/demo/validate-scroll-to-field.tsx @@ -7,7 +7,7 @@ const App = () => { return (
extends RcFormInstance { scrollToField: (name: NamePath, options?: ScrollOptions) => void; + focusField: (name: NamePath) => void; /** @internal: This is an internal usage. Do not use in your prod */ __INTERNAL__: { /** No! Do not use this in your code! */ @@ -67,6 +68,13 @@ export default function useForm(form?: FormInstance): [For } as any); } }, + focusField: (name: NamePath) => { + const node = getFieldDOMNode(name, wrapForm); + + if (node) { + node.focus?.(); + } + }, getFieldInstance: (name: NamePath) => { const namePathStr = toNamePathStr(name); return itemsRef.current[namePathStr]; diff --git a/components/form/index.en-US.md b/components/form/index.en-US.md index b06ed00baf..6899392d5c 100644 --- a/components/form/index.en-US.md +++ b/components/form/index.en-US.md @@ -80,7 +80,7 @@ Common props ref:[Common props](/docs/react/common-props) | name | Form name. Will be the prefix of Field `id` | string | - | | | preserve | Keep field value even when field removed. You can get the preserve field value by `getFieldsValue(true)` | boolean | true | 4.4.0 | | requiredMark | Required mark style. Can use required mark or optional mark. You can not config to single Form.Item since this is a Form level config | boolean \| `optional` \| ((label: ReactNode, info: { required: boolean }) => ReactNode) | true | `renderProps`: 5.9.0 | -| scrollToFirstError | Auto scroll to first failed field when submit | boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options) | false | | +| scrollToFirstError | Auto scroll to first failed field when submit | boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options) \| { focus: boolean } | false | | | size | Set field component size (antd components only) | `small` \| `middle` \| `large` | - | | | validateMessages | Validation prompt template, description [see below](#validatemessages) | [ValidateMessages](https://github.com/ant-design/ant-design/blob/6234509d18bac1ac60fbb3f92a5b2c6a6361295a/components/locale/en_US.ts#L88-L134) | - | | | validateTrigger | Config field validate trigger | string \| string\[] | `onChange` | 4.3.0 | diff --git a/components/form/index.zh-CN.md b/components/form/index.zh-CN.md index c2fd3ef2d9..81d5ea50d9 100644 --- a/components/form/index.zh-CN.md +++ b/components/form/index.zh-CN.md @@ -81,7 +81,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*ylFATY6w-ygAAA | name | 表单名称,会作为表单字段 `id` 前缀使用 | string | - | | | preserve | 当字段被删除时保留字段值。你可以通过 `getFieldsValue(true)` 来获取保留字段值 | boolean | true | 4.4.0 | | requiredMark | 必选样式,可以切换为必选或者可选展示样式。此为 Form 配置,Form.Item 无法单独配置 | boolean \| `optional` \| ((label: ReactNode, info: { required: boolean }) => ReactNode) | true | `renderProps`: 5.9.0 | -| scrollToFirstError | 提交失败自动滚动到第一个错误字段 | boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options) | false | | +| scrollToFirstError | 提交失败自动滚动到第一个错误字段 | boolean \| [Options](https://github.com/stipsan/scroll-into-view-if-needed/tree/ece40bd9143f48caf4b99503425ecb16b0ad8249#options) \| { focus: boolean } | false | | | size | 设置字段组件的尺寸(仅限 antd 组件) | `small` \| `middle` \| `large` | - | | | validateMessages | 验证提示模板,说明[见下](#validatemessages) | [ValidateMessages](https://github.com/ant-design/ant-design/blob/6234509d18bac1ac60fbb3f92a5b2c6a6361295a/components/locale/en_US.ts#L88-L134) | - | | | validateTrigger | 统一设置字段触发验证的时机 | string \| string\[] | `onChange` | 4.3.0 | From 015740d1eb40497170b9a002e0651871e7dd33cc Mon Sep 17 00:00:00 2001 From: Guo Yunhe Date: Wed, 16 Oct 2024 18:04:38 +0800 Subject: [PATCH 05/22] feat(Select): Select supports prefix prop (#51186) --- .../__snapshots__/demo-extend.test.ts.snap | 1094 +- .../__snapshots__/demo.test.tsx.snap | 1050 +- .../__snapshots__/index.test.tsx.snap | 36 +- .../__snapshots__/demo-extend.test.ts.snap | 700 +- .../__tests__/__snapshots__/demo.test.ts.snap | 672 +- .../__snapshots__/index.test.tsx.snap | 400 +- .../__snapshots__/demo-extend.test.ts.snap | 50 +- .../__tests__/__snapshots__/demo.test.ts.snap | 48 +- .../__snapshots__/demo-extend.test.ts.snap | 1300 +- .../__snapshots__/index.test.tsx.snap | 100 +- .../__snapshots__/components.test.tsx.snap | 2266 +-- .../__snapshots__/popup.test.tsx.snap | 132 +- .../__snapshots__/demo-extend.test.ts.snap | 50 +- .../__snapshots__/demo.test.tsx.snap | 48 +- .../__snapshots__/demo-extend.test.tsx.snap | 150 +- .../__snapshots__/demo-extend.test.ts.snap | 42 +- .../__tests__/__snapshots__/demo.test.ts.snap | 40 +- .../__snapshots__/demo-extend.test.ts.snap | 1106 +- .../__snapshots__/demo.test.tsx.snap | 996 +- .../__snapshots__/index.test.tsx.snap | 44 +- .../__snapshots__/demo-extend.test.ts.snap | 100 +- .../__snapshots__/demo.test.tsx.snap | 96 +- .../__snapshots__/demo-extend.test.ts.snap | 720 +- .../__snapshots__/demo.test.tsx.snap | 690 +- .../__snapshots__/pagination.test.tsx.snap | 140 +- .../__snapshots__/index.test.tsx.snap | 12740 +++++++++------- .../__snapshots__/demo-extend.test.ts.snap | 794 +- .../__tests__/__snapshots__/demo.test.ts.snap | 760 +- .../__snapshots__/index.test.tsx.snap | 46 +- .../__snapshots__/demo-extend.test.ts.snap | 50 +- .../__tests__/__snapshots__/demo.test.ts.snap | 48 +- .../__snapshots__/demo-extend.test.ts.snap | 5739 ++++--- .../__snapshots__/demo.test.tsx.snap | 6992 +++++---- .../__snapshots__/index.test.tsx.snap | 126 +- components/select/demo/suffix.md | 4 +- components/select/demo/suffix.tsx | 49 +- components/select/index.en-US.md | 3 +- components/select/index.tsx | 3 + components/select/index.zh-CN.md | 3 +- components/select/style/index.ts | 2 +- components/select/style/multiple.ts | 10 +- components/select/style/single.ts | 34 +- components/select/style/token.ts | 2 + .../__snapshots__/demo-extend.test.ts.snap | 772 +- .../__snapshots__/demo.test.tsx.snap | 656 +- .../__snapshots__/demo-extend.test.ts.snap | 184 +- .../__tests__/__snapshots__/demo.test.ts.snap | 264 +- .../__snapshots__/demo-extend.test.ts.snap | 168 +- .../__tests__/__snapshots__/demo.test.ts.snap | 160 +- .../__snapshots__/demo-extend.test.ts.snap | 44 +- .../__snapshots__/demo.test.tsx.snap | 42 +- .../__snapshots__/demo-extend.test.ts.snap | 50 +- .../__tests__/__snapshots__/demo.test.ts.snap | 48 +- .../__snapshots__/demo-extend.test.ts.snap | 50 +- package.json | 2 +- 55 files changed, 23060 insertions(+), 18855 deletions(-) diff --git a/components/auto-complete/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/auto-complete/__tests__/__snapshots__/demo-extend.test.ts.snap index 7b464beb55..2518e7d3e2 100644 --- a/components/auto-complete/__tests__/__snapshots__/demo-extend.test.ts.snap +++ b/components/auto-complete/__tests__/__snapshots__/demo-extend.test.ts.snap @@ -10,26 +10,30 @@ Array [ class="ant-select-selector" > - - - - UnClearable + + + + + UnClearable +
- - - - Customized clear icon + + + + + Customized clear icon +
- - - - input here + + + + + input here +
- - - - control mode + + + + + control mode +
- - + + + -
-