From 61f779a8aa0d984fa2ec3470a1b350bf4857f836 Mon Sep 17 00:00:00 2001 From: Flavien DELANGLE Date: Wed, 20 Nov 2024 10:09:27 +0100 Subject: [PATCH] [pickers] Always use `props.value` when it changes (#15490) --- .../tests/field.DesktopDatePicker.test.tsx | 42 +++++++++++++++++++ .../hooks/usePicker/usePickerValue.ts | 14 ++----- .../hooks/usePicker/usePickerValue.types.ts | 2 +- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/packages/x-date-pickers/src/DesktopDatePicker/tests/field.DesktopDatePicker.test.tsx b/packages/x-date-pickers/src/DesktopDatePicker/tests/field.DesktopDatePicker.test.tsx index 4ef2b7327fab..9ecd7d09a43f 100644 --- a/packages/x-date-pickers/src/DesktopDatePicker/tests/field.DesktopDatePicker.test.tsx +++ b/packages/x-date-pickers/src/DesktopDatePicker/tests/field.DesktopDatePicker.test.tsx @@ -1,5 +1,6 @@ import { fireEvent } from '@mui/internal-test-utils'; import { DesktopDatePicker, DesktopDatePickerProps } from '@mui/x-date-pickers/DesktopDatePicker'; +import { fireUserEvent } from 'test/utils/fireUserEvent'; import { createPickerRenderer, buildFieldInteractions, @@ -98,6 +99,47 @@ describe(' - Field', () => { testFormat({ views: ['year', 'month', 'day'] }, 'MM/DD/YYYY'); testFormat({ views: ['year', 'day'] }, 'MM/DD/YYYY'); }); + + it('should allow to set the value to its previous valid value using props.value', () => { + // Test with accessible DOM structure + let view = renderWithProps( + { + enableAccessibleFieldDOMStructure: true as const, + value: adapterToUse.date('2022-10-31'), + }, + { componentFamily: 'picker' }, + ); + + view.selectSection('month'); + expectFieldValueV7(view.getSectionsContainer(), '10/31/2022'); + + view.pressKey(0, 'ArrowUp'); + expectFieldValueV7(view.getSectionsContainer(), '11/31/2022'); + + view.setProps({ value: adapterToUse.date('2022-10-31') }); + expectFieldValueV7(view.getSectionsContainer(), '10/31/2022'); + + view.unmount(); + + // Test with non-accessible DOM structure + view = renderWithProps( + { + enableAccessibleFieldDOMStructure: false as const, + value: adapterToUse.date('2022-10-31'), + }, + { componentFamily: 'picker' }, + ); + + const input = getTextbox(); + view.selectSection('month'); + expectFieldValueV6(input, '10/31/2022'); + + fireUserEvent.keyPress(input, { key: 'ArrowUp' }); + expectFieldValueV6(input, '11/31/2022'); + + view.setProps({ value: adapterToUse.date('2022-10-31') }); + expectFieldValueV6(input, '10/31/2022'); + }); }); describe('slots: field', () => { diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts index 96c71b62a82c..5c22920d367d 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.ts @@ -243,7 +243,7 @@ export const usePickerValue = < draft: initialValue, lastPublishedValue: initialValue, lastCommittedValue: initialValue, - lastControlledValue: inValueWithTimezoneToRender, + lastControlledValue: inValueWithoutRenderTimezone, hasBeenModifiedSinceMount: false, }; }); @@ -322,15 +322,7 @@ export const usePickerValue = < } }); - if ( - inValueWithTimezoneToRender !== undefined && - (dateState.lastControlledValue === undefined || - !valueManager.areValuesEqual( - utils, - dateState.lastControlledValue, - inValueWithTimezoneToRender, - )) - ) { + if (dateState.lastControlledValue !== inValueWithoutRenderTimezone) { const isUpdateComingFromPicker = valueManager.areValuesEqual( utils, dateState.draft, @@ -339,7 +331,7 @@ export const usePickerValue = < setDateState((prev) => ({ ...prev, - lastControlledValue: inValueWithTimezoneToRender, + lastControlledValue: inValueWithoutRenderTimezone, ...(isUpdateComingFromPicker ? {} : { diff --git a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts index 5b5952a1d3d0..c01be0eaefd3 100644 --- a/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts +++ b/packages/x-date-pickers/src/internals/hooks/usePicker/usePickerValue.types.ts @@ -155,7 +155,7 @@ export interface UsePickerValueState { */ lastCommittedValue: TValue; /** - * Last value passed with `props.value`. + * Last value passed to `props.value`. * Used to update the `draft` value whenever the `value` prop changes. */ lastControlledValue: TValue | undefined;