Skip to content

Commit 98556b2

Browse files
Wxh16144zombieJ
andauthored
feat: preset value support callback function (#654)
* feat: preset value support callback function * test: add case * chore: update demo * Update docs/examples/basic.tsx Co-authored-by: zombieJ <[email protected]> * test: add rangePicker presets case * style: format code * chore: update case * refactor: optimize value execution logic --------- Co-authored-by: zombieJ <[email protected]>
1 parent 6663e26 commit 98556b2

File tree

8 files changed

+101
-33
lines changed

8 files changed

+101
-33
lines changed

docs/examples/basic.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ export default () => {
3333
label: 'Hello World!',
3434
value: moment(),
3535
},
36+
{
37+
label: 'Now',
38+
value: () => moment(),
39+
}
3640
],
3741
};
3842

docs/examples/range.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,16 @@ export default () => {
6262
defaultValue={[moment('1990-09-03'), moment('1989-11-28')]}
6363
clearIcon={<span>X</span>}
6464
suffixIcon={<span>O</span>}
65+
presets={[
66+
{
67+
label: 'Last week',
68+
value: [moment().subtract(1, 'week'), moment()],
69+
},
70+
{
71+
label: 'Last 3 days',
72+
value: () => [moment().subtract(3, 'days'), moment().add(3, 'days')],
73+
},
74+
]}
6575
/>
6676
<RangePicker<Moment>
6777
{...sharedProps}

src/PresetPanel.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as React from 'react';
22
import type { PresetDate } from './interface';
3+
import { executeValue } from './utils/miscUtil';
34

45
export interface PresetPanelProps<T> {
56
prefixCls: string;
@@ -21,20 +22,14 @@ export default function PresetPanel<T>(props: PresetPanelProps<T>) {
2122
{presets.map(({ label, value }, index) => (
2223
<li
2324
key={index}
24-
onClick={() => {
25-
onClick(value);
26-
}}
27-
onMouseEnter={() => {
28-
onHover?.(value);
29-
}}
30-
onMouseLeave={() => {
31-
onHover?.(null);
32-
}}
25+
onClick={() => onClick?.(executeValue(value))}
26+
onMouseEnter={() => onHover?.(executeValue(value))}
27+
onMouseLeave={() => onHover?.(null)}
3328
>
3429
{label}
3530
</li>
3631
))}
3732
</ul>
38-
</div>
33+
</div >
3934
);
4035
}

src/hooks/usePresets.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,10 @@ export default function usePresets<T>(
1414
if (legacyRanges) {
1515
warning(false, '`ranges` is deprecated. Please use `presets` instead.');
1616

17-
const rangeLabels = Object.keys(legacyRanges);
18-
19-
return rangeLabels.map((label) => {
20-
const range = legacyRanges[label];
21-
const newValues = typeof range === 'function' ? (range as any)() : range;
22-
23-
return {
24-
label,
25-
value: newValues,
26-
};
27-
});
17+
return Object.entries(legacyRanges).map(([label, value]) => ({
18+
label,
19+
value,
20+
}));
2821
}
2922

3023
return [];

src/interface.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ export type CustomFormat<DateType> = (value: DateType) => string;
123123

124124
export interface PresetDate<T> {
125125
label: React.ReactNode;
126-
value: T;
126+
value: T | (() => T);
127127
}
128128

129129
// https://stackoverflow.com/a/39495173; need TypeScript >= 4.5

src/utils/miscUtil.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,7 @@ export function updateValues<T, R = [T | null, T | null] | null>(
5050

5151
return (newValues as unknown) as R;
5252
}
53+
54+
export function executeValue<T>(value: T | (() => T)): T {
55+
return typeof value === 'function' ? (value as () => T)() : value;
56+
}

tests/picker.spec.tsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,4 +1030,39 @@ describe('Picker.Basic', () => {
10301030

10311031
expect(onChange.mock.calls[0][0].format('YYYY-MM-DD')).toEqual('2000-09-03');
10321032
});
1033+
1034+
it('presets support callback', () => {
1035+
const onChange = jest.fn();
1036+
const mockPresetValue = jest.fn().mockImplementationOnce(() => moment('2000-09-03'));
1037+
1038+
render(
1039+
<MomentPicker
1040+
onChange={onChange}
1041+
open
1042+
presets={[
1043+
{
1044+
label: 'Bamboo',
1045+
value: mockPresetValue,
1046+
},
1047+
]}
1048+
/>,
1049+
);
1050+
1051+
const firstPreset = document.querySelector('.rc-picker-presets li');
1052+
expect(firstPreset.textContent).toBe('Bamboo');
1053+
1054+
fireEvent.click(firstPreset);
1055+
1056+
expect(mockPresetValue).toHaveBeenCalled();
1057+
expect(onChange.mock.calls[0][0].format('YYYY-MM-DD')).toEqual('2000-09-03');
1058+
1059+
mockPresetValue.mockImplementationOnce(() => moment('2023-05-01 12:34:56'));
1060+
1061+
fireEvent.click(firstPreset);
1062+
1063+
expect(mockPresetValue).toBeCalledTimes(2);
1064+
expect(onChange).toBeCalledTimes(2);
1065+
1066+
expect(onChange.mock.calls[1][0].format('YYYY-MM-DD HH:mm:ss')).toEqual('2023-05-01 12:34:56');
1067+
});
10331068
});

tests/range.spec.tsx

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { act, createEvent, fireEvent, render } from '@testing-library/react';
2-
import moment, { Moment } from 'moment';
2+
import type { Moment } from 'moment';
3+
import moment from 'moment';
34
import KeyCode from 'rc-util/lib/KeyCode';
45
import { spyElementPrototypes } from 'rc-util/lib/test/domHook';
56
import React from 'react';
@@ -18,6 +19,7 @@ import {
1819
openPicker,
1920
selectCell,
2021
} from './util/commonUtil';
22+
import type { RangePickerProps } from '../src/RangePicker';
2123

2224
describe('Picker.Range', () => {
2325
function matchValues(container: HTMLElement, value1: string, value2: string) {
@@ -331,15 +333,32 @@ describe('Picker.Range', () => {
331333
});
332334
});
333335

334-
describe('ranges', () => {
335-
it('work', () => {
336+
function testRangePickerPresetRange(propsType: 'ranges' | 'presets') {
337+
338+
const genProps = (ranges: Record<string, any>) => {
339+
const props: Partial<RangePickerProps<Moment>> = {};
340+
if (propsType === 'ranges') {
341+
// ranges is deprecated, but the case needs to be retained for a while
342+
props.ranges = ranges;
343+
} else if (propsType === 'presets') {
344+
props.presets = [];
345+
Object.entries(ranges).forEach(([label, value]) => {
346+
props.presets.push({ label, value });
347+
})
348+
}
349+
return props as RangePickerProps<Moment>;
350+
}
351+
352+
it(`${propsType} work`, () => {
336353
const onChange = jest.fn();
337354
const { container } = render(
338355
<MomentRangePicker
339-
ranges={{
340-
test: [getMoment('1989-11-28'), getMoment('1990-09-03')],
341-
func: () => [getMoment('2000-01-01'), getMoment('2010-11-11')],
342-
}}
356+
{...genProps(
357+
{
358+
test: [getMoment('1989-11-28'), getMoment('1990-09-03')],
359+
func: () => [getMoment('2000-01-01'), getMoment('2010-11-11')],
360+
}
361+
)}
343362
onChange={onChange}
344363
/>,
345364
);
@@ -371,12 +390,14 @@ describe('Picker.Range', () => {
371390
expect(isOpen()).toBeFalsy();
372391
});
373392

374-
it('hover className', () => {
393+
it(`${propsType} hover className`, () => {
375394
const { container } = render(
376395
<MomentRangePicker
377-
ranges={{
378-
now: [getMoment('1990-09-11'), getMoment('1990-09-13')],
379-
}}
396+
{...genProps(
397+
{
398+
now: [getMoment('1990-09-11'), getMoment('1990-09-13')],
399+
}
400+
)}
380401
/>,
381402
);
382403

@@ -391,6 +412,12 @@ describe('Picker.Range', () => {
391412
expect(findCell(12)).not.toHaveClass('rc-picker-cell-in-range');
392413
expect(findCell(13)).not.toHaveClass('rc-picker-cell-range-end');
393414
});
415+
416+
}
417+
418+
describe('ranges or presets', () => {
419+
testRangePickerPresetRange('ranges');
420+
testRangePickerPresetRange('presets');
394421
});
395422

396423
it('placeholder', () => {

0 commit comments

Comments
 (0)