diff --git a/docs/examples/basic.tsx b/docs/examples/basic.tsx index e1357e44d..6076e2c23 100644 --- a/docs/examples/basic.tsx +++ b/docs/examples/basic.tsx @@ -33,6 +33,10 @@ export default () => { label: 'Hello World!', value: moment(), }, + { + label: 'Now', + value: () => moment(), + } ], }; diff --git a/docs/examples/range.tsx b/docs/examples/range.tsx index 3cb68d413..688fd24f5 100644 --- a/docs/examples/range.tsx +++ b/docs/examples/range.tsx @@ -62,6 +62,16 @@ export default () => { defaultValue={[moment('1990-09-03'), moment('1989-11-28')]} clearIcon={X} suffixIcon={O} + presets={[ + { + label: 'Last week', + value: [moment().subtract(1, 'week'), moment()], + }, + { + label: 'Last 3 days', + value: () => [moment().subtract(3, 'days'), moment().add(3, 'days')], + }, + ]} /> {...sharedProps} diff --git a/src/PresetPanel.tsx b/src/PresetPanel.tsx index 3459803b8..8665aa837 100644 --- a/src/PresetPanel.tsx +++ b/src/PresetPanel.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import type { PresetDate } from './interface'; +import { executeValue } from './utils/miscUtil'; export interface PresetPanelProps { prefixCls: string; @@ -21,20 +22,14 @@ export default function PresetPanel(props: PresetPanelProps) { {presets.map(({ label, value }, index) => (
  • { - onClick(value); - }} - onMouseEnter={() => { - onHover?.(value); - }} - onMouseLeave={() => { - onHover?.(null); - }} + onClick={() => onClick?.(executeValue(value))} + onMouseEnter={() => onHover?.(executeValue(value))} + onMouseLeave={() => onHover?.(null)} > {label}
  • ))} - + ); } diff --git a/src/hooks/usePresets.ts b/src/hooks/usePresets.ts index 506ed2f91..cacc08b2a 100644 --- a/src/hooks/usePresets.ts +++ b/src/hooks/usePresets.ts @@ -14,17 +14,10 @@ export default function usePresets( if (legacyRanges) { warning(false, '`ranges` is deprecated. Please use `presets` instead.'); - const rangeLabels = Object.keys(legacyRanges); - - return rangeLabels.map((label) => { - const range = legacyRanges[label]; - const newValues = typeof range === 'function' ? (range as any)() : range; - - return { - label, - value: newValues, - }; - }); + return Object.entries(legacyRanges).map(([label, value]) => ({ + label, + value, + })); } return []; diff --git a/src/interface.ts b/src/interface.ts index 0e167d655..4d74ff074 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -123,7 +123,7 @@ export type CustomFormat = (value: DateType) => string; export interface PresetDate { label: React.ReactNode; - value: T; + value: T | (() => T); } // https://stackoverflow.com/a/39495173; need TypeScript >= 4.5 diff --git a/src/utils/miscUtil.ts b/src/utils/miscUtil.ts index f0f0081bc..68db23632 100644 --- a/src/utils/miscUtil.ts +++ b/src/utils/miscUtil.ts @@ -50,3 +50,7 @@ export function updateValues( return (newValues as unknown) as R; } + +export function executeValue(value: T | (() => T)): T { + return typeof value === 'function' ? (value as () => T)() : value; +} diff --git a/tests/picker.spec.tsx b/tests/picker.spec.tsx index fe286df6d..dff905fbb 100644 --- a/tests/picker.spec.tsx +++ b/tests/picker.spec.tsx @@ -1030,4 +1030,39 @@ describe('Picker.Basic', () => { expect(onChange.mock.calls[0][0].format('YYYY-MM-DD')).toEqual('2000-09-03'); }); + + it('presets support callback', () => { + const onChange = jest.fn(); + const mockPresetValue = jest.fn().mockImplementationOnce(() => moment('2000-09-03')); + + render( + , + ); + + const firstPreset = document.querySelector('.rc-picker-presets li'); + expect(firstPreset.textContent).toBe('Bamboo'); + + fireEvent.click(firstPreset); + + expect(mockPresetValue).toHaveBeenCalled(); + expect(onChange.mock.calls[0][0].format('YYYY-MM-DD')).toEqual('2000-09-03'); + + mockPresetValue.mockImplementationOnce(() => moment('2023-05-01 12:34:56')); + + fireEvent.click(firstPreset); + + expect(mockPresetValue).toBeCalledTimes(2); + expect(onChange).toBeCalledTimes(2); + + expect(onChange.mock.calls[1][0].format('YYYY-MM-DD HH:mm:ss')).toEqual('2023-05-01 12:34:56'); + }); }); diff --git a/tests/range.spec.tsx b/tests/range.spec.tsx index 786adca4f..3ebcb0c44 100644 --- a/tests/range.spec.tsx +++ b/tests/range.spec.tsx @@ -1,5 +1,6 @@ import { act, createEvent, fireEvent, render } from '@testing-library/react'; -import moment, { Moment } from 'moment'; +import type { Moment } from 'moment'; +import moment from 'moment'; import KeyCode from 'rc-util/lib/KeyCode'; import { spyElementPrototypes } from 'rc-util/lib/test/domHook'; import React from 'react'; @@ -18,6 +19,7 @@ import { openPicker, selectCell, } from './util/commonUtil'; +import type { RangePickerProps } from '../src/RangePicker'; describe('Picker.Range', () => { function matchValues(container: HTMLElement, value1: string, value2: string) { @@ -331,15 +333,32 @@ describe('Picker.Range', () => { }); }); - describe('ranges', () => { - it('work', () => { + function testRangePickerPresetRange(propsType: 'ranges' | 'presets') { + + const genProps = (ranges: Record) => { + const props: Partial> = {}; + if (propsType === 'ranges') { + // ranges is deprecated, but the case needs to be retained for a while + props.ranges = ranges; + } else if (propsType === 'presets') { + props.presets = []; + Object.entries(ranges).forEach(([label, value]) => { + props.presets.push({ label, value }); + }) + } + return props as RangePickerProps; + } + + it(`${propsType} work`, () => { const onChange = jest.fn(); const { container } = render( [getMoment('2000-01-01'), getMoment('2010-11-11')], - }} + {...genProps( + { + test: [getMoment('1989-11-28'), getMoment('1990-09-03')], + func: () => [getMoment('2000-01-01'), getMoment('2010-11-11')], + } + )} onChange={onChange} />, ); @@ -371,12 +390,14 @@ describe('Picker.Range', () => { expect(isOpen()).toBeFalsy(); }); - it('hover className', () => { + it(`${propsType} hover className`, () => { const { container } = render( , ); @@ -391,6 +412,12 @@ describe('Picker.Range', () => { expect(findCell(12)).not.toHaveClass('rc-picker-cell-in-range'); expect(findCell(13)).not.toHaveClass('rc-picker-cell-range-end'); }); + + } + + describe('ranges or presets', () => { + testRangePickerPresetRange('ranges'); + testRangePickerPresetRange('presets'); }); it('placeholder', () => {