Skip to content

Commit

Permalink
feat: preset value support callback function (#654)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
Wxh16144 and zombieJ authored Jul 11, 2023
1 parent 6663e26 commit 98556b2
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 33 deletions.
4 changes: 4 additions & 0 deletions docs/examples/basic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ export default () => {
label: 'Hello World!',
value: moment(),
},
{
label: 'Now',
value: () => moment(),
}
],
};

Expand Down
10 changes: 10 additions & 0 deletions docs/examples/range.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,16 @@ export default () => {
defaultValue={[moment('1990-09-03'), moment('1989-11-28')]}
clearIcon={<span>X</span>}
suffixIcon={<span>O</span>}
presets={[
{
label: 'Last week',
value: [moment().subtract(1, 'week'), moment()],
},
{
label: 'Last 3 days',
value: () => [moment().subtract(3, 'days'), moment().add(3, 'days')],
},
]}
/>
<RangePicker<Moment>
{...sharedProps}
Expand Down
15 changes: 5 additions & 10 deletions src/PresetPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import type { PresetDate } from './interface';
import { executeValue } from './utils/miscUtil';

export interface PresetPanelProps<T> {
prefixCls: string;
Expand All @@ -21,20 +22,14 @@ export default function PresetPanel<T>(props: PresetPanelProps<T>) {
{presets.map(({ label, value }, index) => (
<li
key={index}
onClick={() => {
onClick(value);
}}
onMouseEnter={() => {
onHover?.(value);
}}
onMouseLeave={() => {
onHover?.(null);
}}
onClick={() => onClick?.(executeValue(value))}
onMouseEnter={() => onHover?.(executeValue(value))}
onMouseLeave={() => onHover?.(null)}
>
{label}
</li>
))}
</ul>
</div>
</div >
);
}
15 changes: 4 additions & 11 deletions src/hooks/usePresets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,10 @@ export default function usePresets<T>(
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 [];
Expand Down
2 changes: 1 addition & 1 deletion src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export type CustomFormat<DateType> = (value: DateType) => string;

export interface PresetDate<T> {
label: React.ReactNode;
value: T;
value: T | (() => T);
}

// https://stackoverflow.com/a/39495173; need TypeScript >= 4.5
Expand Down
4 changes: 4 additions & 0 deletions src/utils/miscUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,7 @@ export function updateValues<T, R = [T | null, T | null] | null>(

return (newValues as unknown) as R;
}

export function executeValue<T>(value: T | (() => T)): T {
return typeof value === 'function' ? (value as () => T)() : value;
}
35 changes: 35 additions & 0 deletions tests/picker.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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(
<MomentPicker
onChange={onChange}
open
presets={[
{
label: 'Bamboo',
value: mockPresetValue,
},
]}
/>,
);

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');
});
});
49 changes: 38 additions & 11 deletions tests/range.spec.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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) {
Expand Down Expand Up @@ -331,15 +333,32 @@ describe('Picker.Range', () => {
});
});

describe('ranges', () => {
it('work', () => {
function testRangePickerPresetRange(propsType: 'ranges' | 'presets') {

const genProps = (ranges: Record<string, any>) => {
const props: Partial<RangePickerProps<Moment>> = {};
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<Moment>;
}

it(`${propsType} work`, () => {
const onChange = jest.fn();
const { container } = render(
<MomentRangePicker
ranges={{
test: [getMoment('1989-11-28'), getMoment('1990-09-03')],
func: () => [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}
/>,
);
Expand Down Expand Up @@ -371,12 +390,14 @@ describe('Picker.Range', () => {
expect(isOpen()).toBeFalsy();
});

it('hover className', () => {
it(`${propsType} hover className`, () => {
const { container } = render(
<MomentRangePicker
ranges={{
now: [getMoment('1990-09-11'), getMoment('1990-09-13')],
}}
{...genProps(
{
now: [getMoment('1990-09-11'), getMoment('1990-09-13')],
}
)}
/>,
);

Expand All @@ -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', () => {
Expand Down

1 comment on commit 98556b2

@vercel
Copy link

@vercel vercel bot commented on 98556b2 Jul 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.