Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 21 additions & 18 deletions docs/examples/debug.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export default () => {
const singleRef = React.useRef<PickerRef>(null);

const [value, setValue] = React.useState<Dayjs>(null);
const [rangeValue, setRangeValue] = React.useState<[Dayjs?, Dayjs?]>(
const [rangeValue, setRangeValue] = React.useState<[Dayjs, Dayjs]>(

Check notice

Code scanning / CodeQL

Unused variable, import, function or class

Unused variable rangeValue.

Check notice

Code scanning / CodeQL

Unused variable, import, function or class

Unused variable setRangeValue.
// [dayjs('2000-12-15'), dayjs('2020-12-22')],
// null,
undefined,
Expand All @@ -149,24 +149,27 @@ export default () => {
<SinglePicker
// Shared
{...sharedLocale}
// picker="week"
// multiple
format="YYYY-MM-DD"
showTime
// format="YYYY-MM-DD"
// showTime={{
// defaultValue: dayjs('2000-01-01 03:05:08'),
// }}
// autoFocus
defaultValue={[
dayjs(),
// dayjs('2000-01-01'),
// dayjs('2000-01-03'),
// dayjs('2000-01-05'),
// dayjs('2000-01-07'),
// dayjs('2000-01-09'),
]}
// defaultValue={[
// dayjs(),
// // dayjs('2000-01-01'),
// // dayjs('2000-01-03'),
// // dayjs('2000-01-05'),
// // dayjs('2000-01-07'),
// // dayjs('2000-01-09'),
// ]}
// disabledDate={(date) => date.date() >= 5}
getPopupContainer={(node) => {
console.log('Popup!', node);
return node.parentElement!;
}}
// getPopupContainer={(node) => {
// console.log('Popup!', node);
// return node.parentElement!;
// }}
picker="time"
defaultPickerValue={dayjs('2000-01-01 03:05:08')}
presets={[
{
label: 'Good',
Expand All @@ -193,7 +196,7 @@ export default () => {
}}
/>
<br />
<RangePicker
{/* <RangePicker
{...sharedLocale}
value={rangeValue}
separator="~~~~~"
Expand Down Expand Up @@ -235,7 +238,7 @@ export default () => {
start: 'inputStart',
end: 'inputEnd',
}}
/>
/> */}
<br />

<button
Expand Down
12 changes: 1 addition & 11 deletions src/PickerInput/Popup/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@ export interface FooterProps<DateType extends object = any> {
onSubmit: (date?: DateType) => void;
needConfirm: boolean;

// OK
onOk: VoidFunction;

// Now
onNow: (now: DateType) => void;
}
Expand All @@ -43,7 +40,6 @@ export default function Footer(props: FooterProps) {
showNow,
showTime,
onSubmit,
onOk,
onNow,
invalid,
needConfirm,
Expand Down Expand Up @@ -91,13 +87,7 @@ export default function Footer(props: FooterProps) {
// >>> OK
const okNode = needConfirm && (
<li className={`${prefixCls}-ok`}>
<Button
disabled={invalid}
onClick={() => {
onOk();
onSubmit();
}}
>
<Button disabled={invalid} onClick={onSubmit}>
{locale.ok}
</Button>
</li>
Expand Down
46 changes: 40 additions & 6 deletions src/PickerInput/Popup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface PopupProps<DateType extends object = any, PresetValue = DateTyp
// Change
needConfirm: boolean;
isInvalid: (date: DateType | DateType[]) => boolean;
onOk: VoidFunction;
}

export default function Popup<DateType extends object = any>(props: PopupProps<DateType>) {
Expand Down Expand Up @@ -56,7 +57,11 @@ export default function Popup<DateType extends object = any>(props: PopupProps<D

// Change
value,
onSelect,
isInvalid,
pickerValue,
onOk,
onSubmit,
} = props;

const { prefixCls } = React.useContext(PickerContext);
Expand Down Expand Up @@ -90,16 +95,40 @@ export default function Popup<DateType extends object = any>(props: PopupProps<D
}, [containerWidth, activeOffset, range]);

// ======================== Custom ========================
const disableSubmit = React.useMemo(() => {
const valueList = toArray(value).filter((val) => val);
function filterEmpty<T>(list: T[]) {
return list.filter((item) => item);
}

const valueList = React.useMemo(() => filterEmpty(toArray(value)), [value]);

const isTimePicker = picker === 'time';
const isEmptyValue = !valueList.length;

const footerSubmitValue = React.useMemo(() => {
if (isTimePicker && isEmptyValue) {
return filterEmpty([pickerValue]);
}
return valueList;
}, [isTimePicker, valueList, isEmptyValue, pickerValue]);

const disableSubmit = React.useMemo(() => {
// Empty is invalid
if (!valueList.length) {
if (!footerSubmitValue.length) {
return true;
}

return valueList.some((val) => isInvalid(val));
}, [value, isInvalid]);
return footerSubmitValue.some((val) => isInvalid(val));
}, [footerSubmitValue, isInvalid]);

const onFooterSubmit = () => {
// For TimePicker, we will additional trigger the value update
if (isTimePicker && isEmptyValue) {
onSelect(pickerValue);
}

onOk();
onSubmit();
};

let mergedNodes: React.ReactNode = (
<div className={`${prefixCls}-panel-layout`}>
Expand All @@ -112,7 +141,12 @@ export default function Popup<DateType extends object = any>(props: PopupProps<D
/>
<div>
<PopupPanel {...props} />
<Footer {...props} showNow={multiple ? false : showNow} invalid={disableSubmit} />
<Footer
{...props}
showNow={multiple ? false : showNow}
invalid={disableSubmit}
onSubmit={onFooterSubmit}
/>
</div>
</div>
);
Expand Down
4 changes: 2 additions & 2 deletions src/PickerInput/RangePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ export interface BaseRangePickerProps<DateType extends object>
*
* Note: `defaultPickerValue` priority is higher than `value` for the first open.
*/
defaultPickerValue?: [DateType, DateType] | null;
defaultPickerValue?: [DateType, DateType] | DateType | null;
/**
* Config each start & end field popup panel date.
* When config `pickerValue`, you must also provide `onPickerValueChange` to handle changes.
*/
pickerValue?: [DateType, DateType] | null;
pickerValue?: [DateType, DateType] | DateType | null;
/**
* Each popup panel `pickerValue` includes `mode` change will trigger the callback.
* @param date The changed picker value
Expand Down
38 changes: 27 additions & 11 deletions src/PickerInput/hooks/useFilledProps.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { warning } from 'rc-util';
import * as React from 'react';
import { toArray } from '../../utils/miscUtil';
import { fillLocale } from '../../hooks/useLocale';
import { getTimeConfig } from '../../hooks/useTimeConfig';
import type { FormatType, InternalMode } from '../../interface';
import { toArray } from '../../utils/miscUtil';
import type { RangePickerProps } from '../RangePicker';
import { fillClearIcon } from '../Selector/hooks/useClearIcon';
import useDisabledBoundary from './useDisabledBoundary';
Expand Down Expand Up @@ -32,6 +32,7 @@ type PickedProps<DateType extends object = any> = Pick<
| 'disabledDate'
| 'minDate'
| 'maxDate'
| 'defaultOpenValue'
> & {
multiple?: boolean;
// RangePicker showTime definition is different with Picker
Expand All @@ -48,8 +49,16 @@ type GetGeneric<T> = T extends PickedProps<infer U> ? U : never;

type ToArrayType<T, DateType> = T extends any[] ? T : DateType[];

function useList<T>(value: T | T[]) {
const values = React.useMemo(() => (value ? toArray(value) : value), [value]);
function useList<T>(value: T | T[], fillMode = false) {
const values = React.useMemo(() => {
const list = value ? toArray(value) : value;

if (fillMode && list) {
list[1] = list[1] || list[0];
}

return list;
}, [value, fillMode]);
return values;
}

Expand Down Expand Up @@ -105,25 +114,32 @@ export default function useFilledProps<
defaultValue,
pickerValue,
defaultPickerValue,
defaultOpenValue,
} = props;

const values = useList(value);
const defaultValues = useList(defaultValue);
const defaultOpenValues = useList(defaultOpenValue, true);
const pickerValues = useList(pickerValue);
const defaultPickerValues = useList(defaultPickerValue);
const defaultPickerValues = useList(defaultPickerValue) || defaultOpenValues;

const mergedLocale = fillLocale(locale);
const mergedShowTime = getTimeConfig(props);

// ======================= Warning ========================
if (
process.env.NODE_ENV !== 'production' &&
picker === 'time' &&
['disabledHours', 'disabledMinutes', 'disabledSeconds'].some((key) => (props as any)[key])
) {
if (process.env.NODE_ENV !== 'production' && picker === 'time') {
if (
['disabledHours', 'disabledMinutes', 'disabledSeconds'].some((key) => (props as any)[key])
) {
warning(
false,
`'disabledHours', 'disabledMinutes', 'disabledSeconds' will be removed in the next major version, please use 'disabledTime' instead.`,
);
}

warning(
false,
`'disabledHours', 'disabledMinutes', 'disabledSeconds' will be removed in the next major version, please use 'disabledTime' instead.`,
!defaultOpenValue,
`'defaultOpenValue' is deprecated which merged into 'defaultPickerValue' instead.`,
);
}

Expand Down
31 changes: 15 additions & 16 deletions src/PickerInput/hooks/useRangePickerValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,22 +76,21 @@ export default function useRangePickerValue<DateType extends object, ValueType e
});

// Current PickerValue
const currentPickerValue = React.useMemo(
() =>
// Merge the `showTime.defaultValue` into `pickerValue`
fillTime(
generateConfig,
[mergedStartPickerValue, mergedEndPickerValue][mergedActiveIndex],
timeDefaultValue[mergedActiveIndex],
),
[
mergedStartPickerValue,
mergedEndPickerValue,
mergedActiveIndex,
generateConfig,
timeDefaultValue,
],
);
const currentPickerValue = React.useMemo(() => {
const current = [mergedStartPickerValue, mergedEndPickerValue][mergedActiveIndex];

// Merge the `showTime.defaultValue` into `pickerValue`
return pickerMode === 'time'
? current
: fillTime(generateConfig, current, timeDefaultValue[mergedActiveIndex]);
}, [
pickerMode,
mergedStartPickerValue,
mergedEndPickerValue,
mergedActiveIndex,
generateConfig,
timeDefaultValue,
]);

const setCurrentPickerValue = (
nextPickerValue: DateType,
Expand Down
2 changes: 2 additions & 0 deletions src/interface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,8 @@ export interface SharedPickerProps<DateType extends object = any>
maxDate?: DateType;

// Open
/** @deprecated Please use `defaultPickerValue` instead */
defaultOpenValue?: DateType;
defaultOpen?: boolean;
open?: boolean;
onOpenChange?: (open: boolean) => void;
Expand Down
43 changes: 19 additions & 24 deletions tests/picker.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -777,11 +777,9 @@ describe('Picker.Basic', () => {

it('not open when disabled', () => {
const { rerender } = render(<DayPicker disabled />);
// document.querySelector('.rc-picker').simulate('click');
fireEvent.click(document.querySelector('.rc-picker'));
expect(isOpen()).toBeFalsy();

// wrapper.setProps({ disabled: false });
rerender(<DayPicker disabled={false} />);
expect(isOpen()).toBeFalsy();
});
Expand All @@ -791,38 +789,35 @@ describe('Picker.Basic', () => {
const inputElement = document.querySelector('input');
inputElement.focus = jest.fn();

// document.querySelector('.rc-picker').simulate('mouseup');
fireEvent.mouseUp(document.querySelector('.rc-picker'));
expect(inputElement.focus).toHaveBeenCalledTimes(0);
expect(isOpen()).toBeFalsy();
});

// Removed `defaultOpenValue`
// it('defaultOpenValue in timePicker', () => {
// resetWarned();
// const onChange = jest.fn();
// const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
it('defaultOpenValue in timePicker', () => {
resetWarned();
const onChange = jest.fn();
const errSpy = jest.spyOn(console, 'error').mockImplementation(() => {});

// const { container } = render(
// <DayPicker
// picker="time"
// defaultOpenValue={getDay('2000-01-01 00:10:23')}
// onChange={onChange}
// />,
// );
const { container } = render(
<DayPicker
picker="time"
defaultOpenValue={getDay('2000-01-01 00:10:23')}
onChange={onChange}
/>,
);

// expect(errSpy).toHaveBeenCalledWith(
// 'Warning: `defaultOpenValue` may confuse user for the current value status. Please use `defaultValue` instead.',
// );
expect(errSpy).toHaveBeenCalledWith(
"Warning: 'defaultOpenValue' is deprecated which merged into 'defaultPickerValue' instead.",
);

// openPicker(container);
// // document.querySelector('.rc-picker-ok button').simulate('click');
// fireEvent.click(document.querySelector('.rc-picker-ok button'));
openPicker(container);
fireEvent.click(document.querySelector('.rc-picker-ok button'));

// expect(isSame(onChange.mock.calls[0][0], '2000-01-01 00:10:23')).toBeTruthy();
expect(isSame(onChange.mock.calls[0][0], '2000-01-01 00:10:23')).toBeTruthy();

// errSpy.mockRestore();
// });
errSpy.mockRestore();
});

it('close to reset', () => {
const { container } = render(<DayPicker defaultValue={getDay('2000-01-01')} />);
Expand Down