Skip to content
Open
Show file tree
Hide file tree
Changes from 6 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
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ render(<Picker />, mountNode);
| autoFocus | boolean | false | whether auto focus |
| showTime | boolean \| Object | [showTime options](#showTime-options) | to provide an additional time selection |
| picker | time \| date \| week \| month \| year | | control which kind of panel should be shown |
| previewValue | false \| hover | hover | When the user selects the date hover option, the value of the input field undergoes a temporary change |
| format | String \| String[] | depends on whether you set timePicker and your locale | use to format/parse date(without time) value to/from input. When an array is provided, all values are used for parsing and first value for display |
| use12Hours | boolean | false | 12 hours display mode |
| value | moment | | current value like input's value |
Expand Down Expand Up @@ -102,7 +103,7 @@ render(<Picker />, mountNode);
### RangePicker

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| --- | --- | --- | --- | --- |
| prefixCls | String | rc-picker | prefixCls of this component |
| className | String | '' | additional css class of root dom |
| style | React.CSSProperties | | additional style of root dom node |
Expand All @@ -112,6 +113,7 @@ render(<Picker />, mountNode);
| defaultPickerValue | moment | | Set default display picker view date |
| separator | String | '~' | set separator between inputs |
| picker | time \| date \| week \| month \| year | | control which kind of panel |
| previewValue | false \| hover | hover | When the user selects the date hover option, the value of the input field undergoes a temporary change |
| placeholder | [String, String] | | placeholder of date input |
| showTime | boolean \| Object | [showTime options](#showTime-options) | to provide an additional time selection |
| showTime.defaultValue | [moment, moment] | | to set default time of selected date |
Expand Down
4 changes: 4 additions & 0 deletions docs/examples/basic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ export default () => {
<h3>Keyboard event with prevent default behaviors</h3>
<Picker<Moment> {...sharedProps} locale={enUS} onKeyDown={keyDown} />
</div>
<div style={{ margin: '0 8px' }}>
<h3>PreviewValue is false</h3>
<Picker<Moment> {...sharedProps} locale={enUS} onKeyDown={keyDown} previewValue={false} />
</div>
</div>
</div>
);
Expand Down
11 changes: 11 additions & 0 deletions docs/examples/range.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,17 @@ export default () => {
disabledDate={disabledDate}
/>
</div>
<div style={{ margin: '0 8px' }}>
<h3>PreviewValue is false</h3>
<RangePicker<Moment>
{...sharedProps}
previewValue={false}
value={undefined}
locale={zhCN}
placeholder={['start...', 'end...']}
disabledDate={disabledDate}
/>
</div>
</div>
</div>
);
Expand Down
14 changes: 13 additions & 1 deletion docs/examples/time.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const testClassNames = {
suffix: 'test-suffix',
popupContent: 'test-popup-content',
popupItem: 'test-popup-item',
}
};

export default () => {
return (
Expand Down Expand Up @@ -53,6 +53,18 @@ export default () => {
disabledHours: () => (type === 'start' ? [now.hours()] : [now.hours() - 5]),
})}
/>

<h3>PreviewValue is false</h3>
<RangePicker
defaultValue={[defaultValue, defaultValue]}
picker="time"
locale={zhCN}
previewValue={false}
generateConfig={momentGenerateConfig}
disabledTime={(now, type) => ({
disabledHours: () => (type === 'start' ? [now.hours()] : [now.hours() - 5]),
})}
/>
</div>
);
};
9 changes: 7 additions & 2 deletions src/PickerInput/RangePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ function RangePicker<DateType extends object = any>(
styles: propStyles,
classNames: propClassNames,

previewValue,
// Value
defaultValue,
value,
Expand Down Expand Up @@ -487,7 +488,9 @@ function RangePicker<DateType extends object = any>(
const presetList = usePresets(presets, ranges);

const onPresetHover = (nextValues: RangeValueType<DateType> | null) => {
setInternalHoverValues(nextValues);
if (previewValue === 'hover') {
setInternalHoverValues(nextValues);
}
setHoverSource('preset');
};

Expand All @@ -505,7 +508,9 @@ function RangePicker<DateType extends object = any>(

// ======================== Panel =========================
const onPanelHover = (date: DateType) => {
setInternalHoverValues(date ? fillCalendarValue(date, activeIndex) : null);
if (previewValue === 'hover') {
setInternalHoverValues(date ? fillCalendarValue(date, activeIndex) : null);
}
setHoverSource('cell');
Copy link
Member

Choose a reason for hiding this comment

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

setHoverSource 是否也不需要运行。

};

Expand Down
10 changes: 8 additions & 2 deletions src/PickerInput/SinglePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,8 @@ function Picker<DateType extends object = any>(
styles: propStyles,
classNames: propClassNames,

previewValue,

// Value
order,
defaultValue,
Expand Down Expand Up @@ -413,7 +415,9 @@ function Picker<DateType extends object = any>(
const presetList = usePresets(presets);

const onPresetHover = (nextValue: DateType | null) => {
setInternalHoverValue(nextValue);
if (previewValue === 'hover') {
Copy link
Member

Choose a reason for hiding this comment

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

反过来,不等于的时候提前 return

setInternalHoverValue(nextValue);
}
setHoverSource('preset');
};

Expand All @@ -433,7 +437,9 @@ function Picker<DateType extends object = any>(

// ======================== Panel =========================
const onPanelHover = (date: DateType | null) => {
setInternalHoverValue(date);
if (previewValue === 'hover') {
setInternalHoverValue(date);
}
setHoverSource('cell');
};
Copy link
Member

Choose a reason for hiding this comment

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

onPresetHover 和 onPanelHover 内容几乎一样,是否要合并一下?


Expand Down
3 changes: 3 additions & 0 deletions src/PickerInput/hooks/useFilledProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type PickedProps<DateType extends object = any> = Pick<
| 'minDate'
| 'maxDate'
| 'defaultOpenValue'
| 'previewValue'
> & {
multiple?: boolean;
// RangePicker showTime definition is different with Picker
Expand Down Expand Up @@ -96,6 +97,7 @@ export default function useFilledProps<
locale,
picker = 'date',
prefixCls = 'rc-picker',
previewValue = 'hover',
styles = {},
classNames = {},
order = true,
Expand Down Expand Up @@ -161,6 +163,7 @@ export default function useFilledProps<
const filledProps = React.useMemo(
() => ({
...props,
previewValue,
prefixCls,
locale: mergedLocale,
picker,
Expand Down
9 changes: 9 additions & 0 deletions src/interface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,8 @@ export type LegacyOnKeyDown = (

export type SemanticName = 'root' | 'prefix' | 'input' | 'suffix';

export type PreviewValueType = 'hover';

export type PanelSemanticName = 'root' | 'header' | 'body' | 'content' | 'item' | 'footer';

export interface SharedPickerProps<DateType extends object = any>
Expand Down Expand Up @@ -425,6 +427,13 @@ export interface SharedPickerProps<DateType extends object = any>
*/
preserveInvalidOnBlur?: boolean;

/**
* When the user selects the date hover option, the value of the input field undergoes a temporary change.
* `false` will not preview value.
* `hover` will preview value when hover.
*/
previewValue?: false | PreviewValueType;

// Motion
transitionName?: string;

Expand Down
12 changes: 11 additions & 1 deletion tests/generateWithTZ.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ describe('dayjs: getNow', () => {
const M_now = moment().tz(JP);

expect(D_now.format()).toEqual(M_now.format());
expect(D_now.get('hour') - D_now.utc().get('hour')).toEqual(9);

const expectedOffset = M_now.utcOffset() / 60;
const actualOffset = D_now.get('hour') - D_now.utc().get('hour');

let normalizedOffset = actualOffset;
if (actualOffset > 12) {
normalizedOffset = actualOffset - 24;
} else if (actualOffset < -12) {
normalizedOffset = actualOffset + 24;
}
expect(normalizedOffset).toEqual(expectedOffset);
Copy link
Member

Choose a reason for hiding this comment

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

preview 里为啥要改这个测试用例?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

这个单测写的有问题

Copy link
Member

Choose a reason for hiding this comment

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

可以单独给 PR,不混在一起。

});
});
28 changes: 28 additions & 0 deletions tests/range.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2120,4 +2120,32 @@ describe('Picker.Range', () => {
openPicker(container, 1);
expect(container.querySelectorAll('.rc-picker-input')[0]).toHaveClass('rc-picker-input-active');
});

it('should not update preview value in input when previewValue is false', () => {
const { container } = render(
<DayRangePicker
minDate={dayjs('2024')}
open
mode={['year', 'year']}
showTime
previewValue={false}
needConfirm
value={[dayjs('2024-01-01'), dayjs('2025-01-01')]}
/>,
);

// 找到第一个输入框并保存初始值
const inputStart = container.querySelectorAll<HTMLInputElement>('.rc-picker-input input')[0];
const initialValueStart = inputStart.value;

// 打开第一个面板并 hover 一个新值(例如 2028 年)
const targetCell = document.querySelector('[title="2028"]') as HTMLElement;
expect(targetCell).toBeTruthy(); // 确保存在

// 2. 模拟鼠标移入(hover)
fireEvent.mouseEnter(targetCell);

// 确保值未更新(仍为原值)
expect(inputStart.value).toBe(initialValueStart);
});
});
48 changes: 47 additions & 1 deletion tests/time.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { fireEvent, render } from '@testing-library/react';
import { resetWarned } from '@rc-component/util/lib/warning';
import React from 'react';
import { DayPicker, getDay, openPicker, selectCell, findCell } from './util/commonUtil';
import dayjs from 'dayjs';
import { DayPicker, getDay, openPicker, selectCell } from './util/commonUtil';

describe('Picker.Time', () => {
beforeEach(() => {
Expand Down Expand Up @@ -68,4 +69,49 @@ describe('Picker.Time', () => {
fireEvent.mouseEnter(getColCell(4, 1));
expect(container.querySelector('input')).toHaveValue('1990-09-03 12:00:00.000 PM');
});

it('hover should not update preview value in input when previewValue is false', async () => {
const { container } = render(
<DayPicker
showTime={{
showMillisecond: true,
use12Hours: true,
}}
previewValue={false}
defaultValue={dayjs('1990-09-03 01:02:03')}
/>,
);
openPicker(container);

const getColCell = (colIndex: number, cellIndex: number) => {
const column = document.querySelectorAll('.rc-picker-time-panel-column')[colIndex];
const cell = column.querySelectorAll('.rc-picker-time-panel-cell-inner')[cellIndex];

return cell;
};

// Hour
fireEvent.mouseEnter(getColCell(0, 3));
expect(container.querySelector('input')).toHaveValue('1990-09-03 01:02:03.000 AM');

// Let test for mouse leave
fireEvent.mouseLeave(getColCell(0, 3));
expect(container.querySelector('input')).toHaveValue('1990-09-03 01:02:03.000 AM');

// Minute
fireEvent.mouseEnter(getColCell(1, 2));
expect(container.querySelector('input')).toHaveValue('1990-09-03 01:02:03.000 AM');

// Second
fireEvent.mouseEnter(getColCell(2, 1));
expect(container.querySelector('input')).toHaveValue('1990-09-03 01:02:03.000 AM');

// Millisecond
fireEvent.mouseEnter(getColCell(3, 1));
expect(container.querySelector('input')).toHaveValue('1990-09-03 01:02:03.000 AM');

// Meridiem
fireEvent.mouseEnter(getColCell(4, 1));
expect(container.querySelector('input')).toHaveValue('1990-09-03 01:02:03.000 AM');
});
});