From 78b2c531b17042875924e6d6364e3a9bb9d0ceff Mon Sep 17 00:00:00 2001 From: Pareder Date: Wed, 1 Jul 2026 10:16:47 +0300 Subject: [PATCH 1/2] feat: refactor Footer component to be accessible --- assets/index.less | 5 ----- src/PickerInput/Popup/Footer.tsx | 35 +++++++++++++------------------ src/PickerInput/RangePicker.tsx | 6 ++++-- src/PickerInput/SinglePicker.tsx | 6 ++++-- src/PickerInput/context.tsx | 3 ++- src/interface.tsx | 11 +++------- tests/components.spec.tsx | 2 +- tests/multiple.spec.tsx | 8 +++---- tests/new-range.spec.tsx | 36 ++++++++++++++++---------------- tests/picker.spec.tsx | 28 ++++++++++++------------- tests/range.spec.tsx | 34 +++++++++++++++--------------- tests/util/commonUtil.tsx | 2 +- 12 files changed, 82 insertions(+), 94 deletions(-) diff --git a/assets/index.less b/assets/index.less index 48522d422..ae3b20dec 100644 --- a/assets/index.less +++ b/assets/index.less @@ -191,11 +191,6 @@ margin: 0; padding: 0; overflow: hidden; - list-style: none; - - > li { - display: inline-block; - } } &-ok { diff --git a/src/PickerInput/Popup/Footer.tsx b/src/PickerInput/Popup/Footer.tsx index ba15dba3d..e7a8d58f2 100644 --- a/src/PickerInput/Popup/Footer.tsx +++ b/src/PickerInput/Popup/Footer.tsx @@ -45,7 +45,8 @@ export default function Footer(props: FooterProps) { const { prefixCls, locale, - button: Button = 'button', + nowButton: NowButton = 'button', + okButton: OkButton = 'button', classNames, styles, } = React.useContext(PickerContext); @@ -70,35 +71,29 @@ export default function Footer(props: FooterProps) { } }; - const nowPrefixCls = `${prefixCls}-now`; - const nowBtnPrefixCls = `${nowPrefixCls}-btn`; - const presetNode = showNow && ( -
  • - - {internalMode === 'date' ? locale.today : locale.now} - -
  • + + {internalMode === 'date' ? locale.today : locale.now} + ); // >>> OK const okNode = needConfirm && ( -
  • - -
  • + + {locale.ok} + ); const rangeNode = (presetNode || okNode) && ( - + ); // ======================== Render ======================== diff --git a/src/PickerInput/RangePicker.tsx b/src/PickerInput/RangePicker.tsx index 8bf7d9e76..84e3a1bba 100644 --- a/src/PickerInput/RangePicker.tsx +++ b/src/PickerInput/RangePicker.tsx @@ -717,7 +717,8 @@ function RangePicker( prefixCls, locale, generateConfig, - button: components.button, + nowButton: components.nowButton, + okButton: components.okButton, input: components.input, classNames: mergedClassNames, styles: mergedStyles, @@ -726,7 +727,8 @@ function RangePicker( prefixCls, locale, generateConfig, - components.button, + components.nowButton, + components.okButton, components.input, mergedClassNames, mergedStyles, diff --git a/src/PickerInput/SinglePicker.tsx b/src/PickerInput/SinglePicker.tsx index 6cdf6be3c..d171f36e7 100644 --- a/src/PickerInput/SinglePicker.tsx +++ b/src/PickerInput/SinglePicker.tsx @@ -604,7 +604,8 @@ function Picker( prefixCls, locale, generateConfig, - button: components.button, + nowButton: components.nowButton, + okButton: components.okButton, input: components.input, classNames: mergedClassNames, styles: mergedStyles, @@ -613,7 +614,8 @@ function Picker( prefixCls, locale, generateConfig, - components.button, + components.nowButton, + components.okButton, components.input, mergedClassNames, mergedStyles, diff --git a/src/PickerInput/context.tsx b/src/PickerInput/context.tsx index 6f3c66aab..7591c2e8d 100644 --- a/src/PickerInput/context.tsx +++ b/src/PickerInput/context.tsx @@ -8,7 +8,8 @@ export interface PickerContextProps { locale: Locale; generateConfig: GenerateConfig; /** Customize button component */ - button?: Components['button']; + nowButton?: Components['nowButton']; + okButton?: Components['okButton']; input?: Components['input']; classNames: FilledClassNames; styles: FilledStyles; diff --git a/src/interface.tsx b/src/interface.tsx index 63a690d06..96984ead0 100644 --- a/src/interface.tsx +++ b/src/interface.tsx @@ -275,7 +275,8 @@ export interface SharedPanelProps { export type Components = Partial< Record>> & { - button?: React.ComponentType | string; + nowButton?: React.ComponentType | string; + okButton?: React.ComponentType | string; input?: React.ComponentType | string; } >; @@ -316,13 +317,7 @@ export type SemanticName = 'root' | 'prefix' | 'input' | 'suffix'; export type PreviewValueType = 'hover'; export type PanelSemanticName = - | 'root' - | 'header' - | 'body' - | 'content' - | 'item' - | 'footer' - | 'container'; + 'root' | 'header' | 'body' | 'content' | 'item' | 'footer' | 'container'; export interface SharedPickerProps extends diff --git a/tests/components.spec.tsx b/tests/components.spec.tsx index f53965554..84e087c31 100644 --- a/tests/components.spec.tsx +++ b/tests/components.spec.tsx @@ -26,7 +26,7 @@ describe('Picker.Components', () => { good: [null, null], }} components={{ - button: Button, + okButton: Button, }} picker="time" open diff --git a/tests/multiple.spec.tsx b/tests/multiple.spec.tsx index fee0cd103..866d35cba 100644 --- a/tests/multiple.spec.tsx +++ b/tests/multiple.spec.tsx @@ -49,7 +49,7 @@ describe('Picker.Multiple', () => { expect(isOpen()).toBeTruthy(); // Confirm - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); expect(onChange).toHaveBeenCalledWith(expect.anything(), [ '1990-09-01', '1990-09-03', @@ -72,7 +72,7 @@ describe('Picker.Multiple', () => { selectCell(3); // Confirm - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); expect(onChange).toHaveBeenCalledWith(expect.anything(), ['1990-09-01', '1990-09-05']); }); @@ -112,7 +112,7 @@ describe('Picker.Multiple', () => { expect(container.querySelectorAll('.rc-picker-selection-item')).toHaveLength(1); // Confirm - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); expect(onChange).toHaveBeenCalledWith(expect.anything(), ['2000-01-28']); }); @@ -247,7 +247,7 @@ describe('Picker.Multiple', () => { ); // Confirm - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); expect(onChange).toHaveBeenCalledWith(expect.anything(), ['1998-10-23']); }); }); diff --git a/tests/new-range.spec.tsx b/tests/new-range.spec.tsx index 85a4dd07c..27e33f76f 100644 --- a/tests/new-range.spec.tsx +++ b/tests/new-range.spec.tsx @@ -391,7 +391,7 @@ describe('NewPicker.Range', () => { expect(onCalendarChange).toHaveBeenCalled(); // Check button disabled - expect(document.querySelector('.rc-picker-ok button')).toBeDisabled(); + expect(document.querySelector('.rc-picker-ok')).toBeDisabled(); }); it('not trigger on disabled all hours', () => { @@ -413,7 +413,7 @@ describe('NewPicker.Range', () => { expect(onCalendarChange).toHaveBeenCalled(); // Check button disabled - expect(document.querySelector('.rc-picker-ok button')).toBeDisabled(); + expect(document.querySelector('.rc-picker-ok')).toBeDisabled(); }); it('not trigger onChange if presets is invalidate', () => { @@ -454,10 +454,10 @@ describe('NewPicker.Range', () => { ); openPicker(container); - fireEvent.click(document.querySelector('.rc-picker-now-btn')); - fireEvent.click(document.querySelector('.rc-picker-now-btn')); + fireEvent.click(document.querySelector('.rc-picker-now')); + fireEvent.click(document.querySelector('.rc-picker-now')); - expect(document.querySelector('.rc-picker-now-btn-disabled')).toBeTruthy(); + expect(document.querySelector('.rc-picker-now')).toBeDisabled(); expect(onChange).not.toHaveBeenCalled(); expect(onCalendarChange).not.toHaveBeenCalled(); @@ -546,7 +546,7 @@ describe('NewPicker.Range', () => { value: '01:00:00', }, }); - expect(document.querySelector('.rc-picker-ok button')).not.toBeDisabled(); + expect(document.querySelector('.rc-picker-ok')).not.toBeDisabled(); // Disabled fireEvent.change(input, { @@ -554,7 +554,7 @@ describe('NewPicker.Range', () => { value: '00:00:00', }, }); - expect(document.querySelector('.rc-picker-ok button')).toBeDisabled(); + expect(document.querySelector('.rc-picker-ok')).toBeDisabled(); }); it('disabledDate provides info.type', () => { @@ -602,7 +602,7 @@ describe('NewPicker.Range', () => { onCalendarChange.mockReset(); // End field - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); selectCell(7); expect(onCalendarChange).toHaveBeenCalledWith( expect.anything(), @@ -655,14 +655,14 @@ describe('NewPicker.Range', () => { // Changed by click OK openPicker(container); selectCell(10); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); expect(container.querySelectorAll('input')[0]).toHaveValue('1990-09-10'); // End time selectCell(15, 1); expect(onChange).not.toHaveBeenCalled(); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); expect(onChange).toHaveBeenCalledWith(expect.anything(), ['1990-09-10', '1990-10-15']); }); @@ -721,10 +721,10 @@ describe('NewPicker.Range', () => { const { container } = render(); openPicker(container); selectCell(15); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); selectCell(16); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); expect(onChange).toHaveBeenCalledWith(expect.anything(), [ '1990-09-15 00:00:00', @@ -738,11 +738,11 @@ describe('NewPicker.Range', () => { expect(container.querySelectorAll('input')[0]).toHaveFocus(); expect(container.querySelectorAll('input')[1]).not.toHaveFocus(); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); openPicker(container, 1); expect(container.querySelectorAll('input')[1]).toHaveFocus(); selectCell(2); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); expect(onChange).toHaveBeenCalledWith(expect.anything(), [ '1990-09-01 00:00:00', '1990-09-02 00:00:00', @@ -1381,8 +1381,8 @@ describe('NewPicker.Range', () => { const { container } = render(); openPicker(container); - fireEvent.click(document.querySelector('.rc-picker-now-btn')); - fireEvent.click(document.querySelector('.rc-picker-now-btn')); + fireEvent.click(document.querySelector('.rc-picker-now')); + fireEvent.click(document.querySelector('.rc-picker-now')); expect(onChange).toHaveBeenCalledWith(expect.anything(), ['1990-09-03', '1990-09-03']); }); @@ -1412,12 +1412,12 @@ describe('NewPicker.Range', () => { // Start fireEvent.click(document.querySelectorAll('li.rc-picker-time-panel-cell')[2]); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); await waitFakeTimer(); // End fireEvent.click(document.querySelectorAll('li.rc-picker-time-panel-cell')[2]); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); await waitFakeTimer(); expect(onChange).toHaveBeenCalledWith(expect.anything(), [ diff --git a/tests/picker.spec.tsx b/tests/picker.spec.tsx index 15b964ede..fa6ab1064 100644 --- a/tests/picker.spec.tsx +++ b/tests/picker.spec.tsx @@ -553,7 +553,7 @@ describe('Picker.Basic', () => { const onCalendarChange = jest.fn(); const { container } = render(); openPicker(container); - fireEvent.click(document.querySelector('.rc-picker-now-btn')); + fireEvent.click(document.querySelector('.rc-picker-now')); expect(isSame(onCalendarChange.mock.calls[0][0], '1990-09-03')).toBeTruthy(); }); @@ -563,10 +563,8 @@ describe('Picker.Basic', () => { true} showToday />, ); openPicker(container); - expect(document.querySelector('.rc-picker-now-btn')).toHaveClass( - 'rc-picker-now-btn-disabled', - ); - fireEvent.click(document.querySelector('.rc-picker-now-btn')); + expect(document.querySelector('.rc-picker-now')).toBeDisabled(); + fireEvent.click(document.querySelector('.rc-picker-now')); expect(onCalendarChange).not.toHaveBeenCalled(); }); @@ -574,7 +572,7 @@ describe('Picker.Basic', () => { it(`not works on ${name}`, () => { const { container } = render(); openPicker(container); - expect(document.querySelector('.rc-picker-now-btn')).toBeFalsy(); + expect(document.querySelector('.rc-picker-now')).toBeFalsy(); }); }); }); @@ -611,7 +609,7 @@ describe('Picker.Basic', () => { const onCalendarChange = jest.fn(); const { container } = render(); openPicker(container); - fireEvent.click(document.querySelector('.rc-picker-now > a')); + fireEvent.click(document.querySelector('.rc-picker-now')); expect( isSame(onCalendarChange.mock.calls[0][0], '1990-09-03 00:00:00', 'second'), @@ -624,7 +622,7 @@ describe('Picker.Basic', () => { , ); openPicker(container); - expect(document.querySelector('.rc-picker-now > a')).toBeFalsy(); + expect(document.querySelector('.rc-picker-now')).toBeFalsy(); }); it('datetime close showNow', () => { @@ -633,7 +631,7 @@ describe('Picker.Basic', () => { , ); openPicker(container); - expect(document.querySelector('.rc-picker-now > a')).toBeFalsy(); + expect(document.querySelector('.rc-picker-now')).toBeFalsy(); }); it('time should display now', () => { @@ -643,7 +641,7 @@ describe('Picker.Basic', () => { openPicker(container); expect(document.querySelector('.rc-picker-header')).toBeFalsy(); - fireEvent.click(document.querySelector('.rc-picker-now > a')); + fireEvent.click(document.querySelector('.rc-picker-now')); expect( isSame(onCalendarChange.mock.calls[0][0], '1990-09-03 00:00:00', 'second'), @@ -656,7 +654,7 @@ describe('Picker.Basic', () => { , ); openPicker(container); - expect(document.querySelector('.rc-picker-now > a')).toBeFalsy(); + expect(document.querySelector('.rc-picker-now')).toBeFalsy(); }); }); @@ -669,7 +667,7 @@ describe('Picker.Basic', () => { ); openPicker(container); - fireEvent.click(document.querySelector('.rc-picker-now > a')); + fireEvent.click(document.querySelector('.rc-picker-now')); expect( isSame(onCalendarChange.mock.calls[0][0], '1990-09-03 00:10:00', 'second'), @@ -847,7 +845,7 @@ describe('Picker.Basic', () => { ); openPicker(container); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); expect(isSame(onChange.mock.calls[0][0], '2000-01-01 00:10:23')).toBeTruthy(); @@ -1634,7 +1632,7 @@ describe('Picker.Basic', () => { const onCalendarChange = jest.fn(); render(); - const submitBtn = document.querySelector('.rc-picker-ok button'); + const submitBtn = document.querySelector('.rc-picker-ok'); expect(submitBtn).toHaveAttribute('disabled'); selectCell('00'); @@ -1646,7 +1644,7 @@ describe('Picker.Basic', () => { ); onCalendarChange.mockReset(); - fireEvent.click(document.querySelector('.rc-picker-now-btn')); + fireEvent.click(document.querySelector('.rc-picker-now')); expect(submitBtn).not.toHaveAttribute('disabled'); expect(onCalendarChange).toHaveBeenCalledWith( expect.anything(), diff --git a/tests/range.spec.tsx b/tests/range.spec.tsx index 174a1d64a..9eebebc8f 100644 --- a/tests/range.spec.tsx +++ b/tests/range.spec.tsx @@ -281,7 +281,7 @@ describe('Picker.Range', () => { fireEvent.click(baseElement.querySelectorAll('.rc-picker-input')[0]); expect(baseElement.querySelector('.rc-picker-dropdown-hidden')).toBeFalsy(); fireEvent.click(baseElement.querySelector('.rc-picker-cell-inner')); - fireEvent.click(baseElement.querySelector('.rc-picker-ok button')); + fireEvent.click(baseElement.querySelector('.rc-picker-ok')); act(() => { jest.runAllTimers(); @@ -296,7 +296,7 @@ describe('Picker.Range', () => { fireEvent.click(baseElement.querySelectorAll('.rc-picker-input')[1]); expect(baseElement.querySelector('.rc-picker-dropdown-hidden')).toBeFalsy(); selectCell(11); - fireEvent.click(baseElement.querySelector('.rc-picker-ok button')); + fireEvent.click(baseElement.querySelector('.rc-picker-ok')); act(() => { jest.runAllTimers(); @@ -576,7 +576,7 @@ describe('Picker.Range', () => { openPicker(container); selectCell(13); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); selectCell(23); matchValues(container, '1990-09-13 01:02:03', '1990-09-23 05:06:07'); @@ -850,7 +850,7 @@ describe('Picker.Range', () => { openPicker(container); // Not trigger when not value - expect(document.querySelector('.rc-picker-ok button').disabled).toBeTruthy(); + expect(document.querySelector('.rc-picker-ok').disabled).toBeTruthy(); expect(onCalendarChange).not.toHaveBeenCalled(); // Trigger when start Ok'd @@ -859,7 +859,7 @@ describe('Picker.Range', () => { expect(onCalendarChange).toHaveBeenCalledWith(expect.anything(), ['1990-09-11 00:00:00', ''], { range: 'start', }); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); expect(onCalendarChange).toHaveBeenCalledWith( [expect.anything(), null], ['1990-09-11 00:00:00', ''], @@ -876,7 +876,7 @@ describe('Picker.Range', () => { ['1990-09-11 00:00:00', '1990-09-23 00:00:00'], { range: 'end' }, ); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); expect(onOk).toHaveBeenCalledWith([expect.anything(), expect.anything()]); }); @@ -1031,11 +1031,11 @@ describe('Picker.Range', () => { openPicker(container); selectCell(15); fireEvent.click(findLast(document.querySelector('ul'), 'li')); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); selectCell(15); fireEvent.click(document.querySelector('ul').querySelector('li')); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); expect(onChange).toHaveBeenCalledWith(expect.anything(), [ '1990-09-15 00:00:00', @@ -1055,10 +1055,10 @@ describe('Picker.Range', () => { ); openPicker(container); fireEvent.click(findLast(document.querySelector('ul'), 'li')); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); fireEvent.click(document.querySelector('ul').querySelectorAll('li')[2]); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); expect(onChange).toHaveBeenCalledWith(expect.anything(), [start, end]); @@ -1591,14 +1591,14 @@ describe('Picker.Range', () => { openPicker(container); - expect(document.querySelector('.rc-picker-ok button').disabled).toBeTruthy(); + expect(document.querySelector('.rc-picker-ok').disabled).toBeTruthy(); fireEvent.click( document.querySelector('.rc-picker-time-panel-column').querySelectorAll('li')[6], ); expect(document.querySelectorAll('input')[0].value).toEqual('2020-07-24 06:00:00'); - expect(document.querySelector('.rc-picker-ok button').disabled).toBeTruthy(); + expect(document.querySelector('.rc-picker-ok').disabled).toBeTruthy(); }); // https://github.com/ant-design/ant-design/issues/26024 @@ -1639,10 +1639,10 @@ describe('Picker.Range', () => { openPicker(container); selectCell(24); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); fireEvent.click(document.querySelector('ul').querySelector('li')); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); matchValues(container, '1990-09-24 00:00:00', '1990-09-24 00:00:00'); }); @@ -1652,10 +1652,10 @@ describe('Picker.Range', () => { openPicker(container, 1); selectCell(24); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); fireEvent.click(document.querySelector('ul').querySelector('li')); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); matchValues(container, '1990-09-24 00:00:00', '1990-09-24 00:00:00'); }); @@ -2024,7 +2024,7 @@ describe('Picker.Range', () => { for (let i = 0; i < 2; i++) { selectCell(24); - fireEvent.click(document.querySelector('.rc-picker-ok button')); + fireEvent.click(document.querySelector('.rc-picker-ok')); await waitFakeTimer(); } diff --git a/tests/util/commonUtil.tsx b/tests/util/commonUtil.tsx index 17ca5c113..dd3fbcbdf 100644 --- a/tests/util/commonUtil.tsx +++ b/tests/util/commonUtil.tsx @@ -150,7 +150,7 @@ export function clickButton(type: string) { } export function confirmOK() { - fireEvent.click(document.querySelector('.rc-picker-ok > *')); + fireEvent.click(document.querySelector('.rc-picker-ok')); } export function clearValue() { From 60f6f81f866a9b8dd8e11b4cbca85e9933777582 Mon Sep 17 00:00:00 2001 From: Pareder Date: Fri, 21 Aug 2026 16:34:30 +0300 Subject: [PATCH 2/2] Fix after review --- src/PickerInput/Popup/Footer.tsx | 25 ++++++++-- src/PickerInput/RangePicker.tsx | 2 + src/PickerInput/SinglePicker.tsx | 2 + src/PickerInput/context.tsx | 8 +++- src/PickerInput/hooks/useFilledProps.ts | 8 +++- src/interface.tsx | 10 +++- tests/components.spec.tsx | 64 +++++++++++++++++++++++++ 7 files changed, 112 insertions(+), 7 deletions(-) diff --git a/src/PickerInput/Popup/Footer.tsx b/src/PickerInput/Popup/Footer.tsx index e7a8d58f2..677c3ea78 100644 --- a/src/PickerInput/Popup/Footer.tsx +++ b/src/PickerInput/Popup/Footer.tsx @@ -27,6 +27,14 @@ export interface FooterProps { onNow: (now: DateType) => void; } +/** + * `type` is a native `button` attribute. Custom components (e.g. `antd` Button) use `type` + * as their own variant prop, so only pass it when the intrinsic element is rendered. + */ +function getNativeTypeProps(Component: React.ComponentType | string) { + return Component === 'button' ? ({ type: 'button' } as const) : null; +} + export default function Footer(props: FooterProps) { const { mode, @@ -45,8 +53,9 @@ export default function Footer(props: FooterProps) { const { prefixCls, locale, - nowButton: NowButton = 'button', - okButton: OkButton = 'button', + button = 'button', + nowButton, + okButton, classNames, styles, } = React.useContext(PickerContext); @@ -71,9 +80,12 @@ export default function Footer(props: FooterProps) { } }; + const NowButton = nowButton || button; + const OkButton = okButton || button; + const presetNode = showNow && ( >> OK const okNode = needConfirm && ( - + {locale.ok} ); diff --git a/src/PickerInput/RangePicker.tsx b/src/PickerInput/RangePicker.tsx index 84e3a1bba..f66888b3c 100644 --- a/src/PickerInput/RangePicker.tsx +++ b/src/PickerInput/RangePicker.tsx @@ -717,6 +717,7 @@ function RangePicker( prefixCls, locale, generateConfig, + button: components.button, nowButton: components.nowButton, okButton: components.okButton, input: components.input, @@ -727,6 +728,7 @@ function RangePicker( prefixCls, locale, generateConfig, + components.button, components.nowButton, components.okButton, components.input, diff --git a/src/PickerInput/SinglePicker.tsx b/src/PickerInput/SinglePicker.tsx index d171f36e7..91ec3decd 100644 --- a/src/PickerInput/SinglePicker.tsx +++ b/src/PickerInput/SinglePicker.tsx @@ -604,6 +604,7 @@ function Picker( prefixCls, locale, generateConfig, + button: components.button, nowButton: components.nowButton, okButton: components.okButton, input: components.input, @@ -614,6 +615,7 @@ function Picker( prefixCls, locale, generateConfig, + components.button, components.nowButton, components.okButton, components.input, diff --git a/src/PickerInput/context.tsx b/src/PickerInput/context.tsx index 7591c2e8d..d3dc9fb56 100644 --- a/src/PickerInput/context.tsx +++ b/src/PickerInput/context.tsx @@ -7,8 +7,14 @@ export interface PickerContextProps { prefixCls: string; locale: Locale; generateConfig: GenerateConfig; - /** Customize button component */ + /** + * Customize button component. + * @deprecated Please use `nowButton` and `okButton` instead. + */ + button?: Components['button']; + /** Customize the `now` / `today` button component */ nowButton?: Components['nowButton']; + /** Customize the `ok` button component */ okButton?: Components['okButton']; input?: Components['input']; classNames: FilledClassNames; diff --git a/src/PickerInput/hooks/useFilledProps.ts b/src/PickerInput/hooks/useFilledProps.ts index 8cdd895cd..52ba0eb59 100644 --- a/src/PickerInput/hooks/useFilledProps.ts +++ b/src/PickerInput/hooks/useFilledProps.ts @@ -148,8 +148,9 @@ export default function useFilledProps< ); // ======================= Warning ======================== - if (process.env.NODE_ENV !== 'production' && picker === 'time') { + if (process.env.NODE_ENV !== 'production') { if ( + picker === 'time' && ['disabledHours', 'disabledMinutes', 'disabledSeconds'].some((key) => (props as any)[key]) ) { warning( @@ -157,6 +158,11 @@ export default function useFilledProps< `'disabledHours', 'disabledMinutes', 'disabledSeconds' will be removed in the next major version, please use 'disabledTime' instead.`, ); } + + warning( + !components.button, + `'components.button' is deprecated. Please use 'components.nowButton' and 'components.okButton' instead.`, + ); } // ======================== Props ========================= diff --git a/src/interface.tsx b/src/interface.tsx index 96984ead0..7bdf69506 100644 --- a/src/interface.tsx +++ b/src/interface.tsx @@ -275,6 +275,8 @@ export interface SharedPanelProps { export type Components = Partial< Record>> & { + /** @deprecated Please use `nowButton` and `okButton` instead. Fallback for both when set. */ + button?: React.ComponentType | string; nowButton?: React.ComponentType | string; okButton?: React.ComponentType | string; input?: React.ComponentType | string; @@ -317,7 +319,13 @@ export type SemanticName = 'root' | 'prefix' | 'input' | 'suffix'; export type PreviewValueType = 'hover'; export type PanelSemanticName = - 'root' | 'header' | 'body' | 'content' | 'item' | 'footer' | 'container'; + | 'root' + | 'header' + | 'body' + | 'content' + | 'item' + | 'footer' + | 'container'; export interface SharedPickerProps extends diff --git a/tests/components.spec.tsx b/tests/components.spec.tsx index 84e087c31..b113cda28 100644 --- a/tests/components.spec.tsx +++ b/tests/components.spec.tsx @@ -1,9 +1,15 @@ +import { resetWarned } from '@rc-component/util'; import { render } from '@testing-library/react'; import MockDate from 'mockdate'; import React from 'react'; import { DayPicker, DayRangePicker, getDay } from './util/commonUtil'; describe('Picker.Components', () => { + beforeEach(() => { + resetWarned(); + jest.clearAllMocks(); + }); + beforeAll(() => { MockDate.set(getDay('1990-09-03 00:00:00').toDate()); }); @@ -35,5 +41,63 @@ describe('Picker.Components', () => { expect(document.querySelector('.rc-picker-footer').querySelectorAll('h1')).toHaveLength(1); }); + + it(`${name} legacy 'button'`, () => { + const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + const Component = component as any; + const Button: React.FC = (props) =>

    ; + + render( + , + ); + + // Fallback for both 'nowButton' and 'okButton' + expect(document.querySelector('.rc-picker-footer').querySelectorAll('h1')).toHaveLength(2); + expect(document.querySelector('.rc-picker-now').tagName).toBe('H1'); + expect(document.querySelector('.rc-picker-ok').tagName).toBe('H1'); + + // Legacy 'button' should not receive the native 'type' attribute + expect(document.querySelector('.rc-picker-ok')).not.toHaveAttribute('type'); + + expect(errorSpy).toHaveBeenCalledWith( + "Warning: 'components.button' is deprecated. Please use 'components.nowButton' and 'components.okButton' instead.", + ); + + errorSpy.mockRestore(); + }); + + it(`${name} 'nowButton' and 'okButton' override legacy 'button'`, () => { + const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + const Component = component as any; + const Legacy: React.FC = (props) =>

    ; + const NowButton: React.FC = (props) =>

    ; + const OkButton: React.FC = (props) =>

    ; + + render( + , + ); + + expect(document.querySelector('.rc-picker-footer').querySelectorAll('h1')).toHaveLength(0); + expect(document.querySelector('.rc-picker-now').tagName).toBe('H2'); + expect(document.querySelector('.rc-picker-ok').tagName).toBe('H3'); + + errorSpy.mockRestore(); + }); }); });