diff --git a/README.md b/README.md
index 16cb3e7f4..9d66c2562 100644
--- a/README.md
+++ b/README.md
@@ -54,6 +54,7 @@ render(, 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 |
@@ -102,7 +103,7 @@ render(, 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 |
@@ -112,6 +113,7 @@ render(, 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 |
diff --git a/docs/examples/basic.tsx b/docs/examples/basic.tsx
index 08d747111..acff81877 100644
--- a/docs/examples/basic.tsx
+++ b/docs/examples/basic.tsx
@@ -154,6 +154,10 @@ export default () => {
Keyboard event with prevent default behaviors
{...sharedProps} locale={enUS} onKeyDown={keyDown} />
+
+
PreviewValue is false
+
{...sharedProps} locale={enUS} onKeyDown={keyDown} previewValue={false} />
+
);
diff --git a/docs/examples/range.tsx b/docs/examples/range.tsx
index 1b137c8b0..23f50ea00 100644
--- a/docs/examples/range.tsx
+++ b/docs/examples/range.tsx
@@ -202,6 +202,17 @@ export default () => {
disabledDate={disabledDate}
/>
+
+
PreviewValue is false
+
+ {...sharedProps}
+ previewValue={false}
+ value={undefined}
+ locale={zhCN}
+ placeholder={['start...', 'end...']}
+ disabledDate={disabledDate}
+ />
+
);
diff --git a/docs/examples/time.tsx b/docs/examples/time.tsx
index d1332b99c..419b519c8 100644
--- a/docs/examples/time.tsx
+++ b/docs/examples/time.tsx
@@ -12,7 +12,7 @@ const testClassNames = {
suffix: 'test-suffix',
popupContent: 'test-popup-content',
popupItem: 'test-popup-item',
-}
+};
export default () => {
return (
@@ -53,6 +53,18 @@ export default () => {
disabledHours: () => (type === 'start' ? [now.hours()] : [now.hours() - 5]),
})}
/>
+
+ PreviewValue is false
+ ({
+ disabledHours: () => (type === 'start' ? [now.hours()] : [now.hours() - 5]),
+ })}
+ />
);
};
diff --git a/src/PickerInput/RangePicker.tsx b/src/PickerInput/RangePicker.tsx
index 7a0b57839..97d4f335b 100644
--- a/src/PickerInput/RangePicker.tsx
+++ b/src/PickerInput/RangePicker.tsx
@@ -164,6 +164,7 @@ function RangePicker(
styles: propStyles,
classNames: propClassNames,
+ previewValue,
// Value
defaultValue,
value,
@@ -483,12 +484,19 @@ function RangePicker(
[activeInputLeft: number, activeInputRight: number, selectorWidth: number]
>([0, 0, 0]);
+ const onSetHover = (date: RangeValueType | null, source: 'cell' | 'preset') => {
+ if (previewValue !== 'hover') {
+ return;
+ }
+ setInternalHoverValues(date);
+ setHoverSource(source);
+ };
+
// ======================= Presets ========================
const presetList = usePresets(presets, ranges);
const onPresetHover = (nextValues: RangeValueType | null) => {
- setInternalHoverValues(nextValues);
- setHoverSource('preset');
+ onSetHover(nextValues, 'preset');
};
const onPresetSubmit = (nextValues: RangeValueType) => {
@@ -505,8 +513,7 @@ function RangePicker(
// ======================== Panel =========================
const onPanelHover = (date: DateType) => {
- setInternalHoverValues(date ? fillCalendarValue(date, activeIndex) : null);
- setHoverSource('cell');
+ onSetHover(date ? fillCalendarValue(date, activeIndex) : null, 'cell');
};
// >>> Focus
diff --git a/src/PickerInput/SinglePicker.tsx b/src/PickerInput/SinglePicker.tsx
index c773fbd09..09e5ca32e 100644
--- a/src/PickerInput/SinglePicker.tsx
+++ b/src/PickerInput/SinglePicker.tsx
@@ -128,6 +128,8 @@ function Picker(
styles: propStyles,
classNames: propClassNames,
+ previewValue,
+
// Value
order,
defaultValue,
@@ -406,6 +408,14 @@ function Picker(
}
}, [mergedOpen]);
+ const onSetHover = (date: DateType | null, source: 'cell' | 'preset') => {
+ if (previewValue !== 'hover') {
+ return;
+ }
+ setInternalHoverValue(date);
+ setHoverSource(source);
+ };
+
// ========================================================
// == Panels ==
// ========================================================
@@ -413,8 +423,7 @@ function Picker(
const presetList = usePresets(presets);
const onPresetHover = (nextValue: DateType | null) => {
- setInternalHoverValue(nextValue);
- setHoverSource('preset');
+ onSetHover(nextValue, 'preset');
};
// TODO: handle this
@@ -433,8 +442,7 @@ function Picker(
// ======================== Panel =========================
const onPanelHover = (date: DateType | null) => {
- setInternalHoverValue(date);
- setHoverSource('cell');
+ onSetHover(date, 'cell');
};
// >>> Focus
diff --git a/src/PickerInput/hooks/useFilledProps.ts b/src/PickerInput/hooks/useFilledProps.ts
index 26178c967..8cdd895cd 100644
--- a/src/PickerInput/hooks/useFilledProps.ts
+++ b/src/PickerInput/hooks/useFilledProps.ts
@@ -33,6 +33,7 @@ type PickedProps = Pick<
| 'minDate'
| 'maxDate'
| 'defaultOpenValue'
+ | 'previewValue'
> & {
multiple?: boolean;
// RangePicker showTime definition is different with Picker
@@ -96,6 +97,7 @@ export default function useFilledProps<
locale,
picker = 'date',
prefixCls = 'rc-picker',
+ previewValue = 'hover',
styles = {},
classNames = {},
order = true,
@@ -161,6 +163,7 @@ export default function useFilledProps<
const filledProps = React.useMemo(
() => ({
...props,
+ previewValue,
prefixCls,
locale: mergedLocale,
picker,
diff --git a/src/interface.tsx b/src/interface.tsx
index 2fe3dae7d..99f9b6767 100644
--- a/src/interface.tsx
+++ b/src/interface.tsx
@@ -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
@@ -425,6 +427,13 @@ export interface SharedPickerProps
*/
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;
diff --git a/tests/range.spec.tsx b/tests/range.spec.tsx
index e584b75fc..b5173a656 100644
--- a/tests/range.spec.tsx
+++ b/tests/range.spec.tsx
@@ -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(
+ ,
+ );
+
+ // 找到第一个输入框并保存初始值
+ const inputStart = container.querySelectorAll('.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);
+ });
});
diff --git a/tests/time.spec.tsx b/tests/time.spec.tsx
index e19837d0d..afcd4841c 100644
--- a/tests/time.spec.tsx
+++ b/tests/time.spec.tsx
@@ -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(() => {
@@ -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(
+ ,
+ );
+ 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');
+ });
});