Skip to content

Commit bf91819

Browse files
[pickers] Always use props.value as the source of truth when defined
1 parent 7dfca29 commit bf91819

File tree

11 files changed

+56
-79
lines changed

11 files changed

+56
-79
lines changed

packages/x-date-pickers/src/DateCalendar/DateCalendar.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import { PickerViewRoot } from '../internals/components/PickerViewRoot';
2727
import { useReduceAnimations } from '../internals/hooks/useReduceAnimations';
2828
import { DateCalendarClasses, getDateCalendarUtilityClass } from './dateCalendarClasses';
2929
import { BaseDateValidationProps } from '../internals/models/validation';
30-
import { useControlledValueWithTimezone } from '../internals/hooks/useValueWithTimezone';
30+
import { useControlledValue } from '../internals/hooks/useControlledValue';
3131
import { singleItemValueManager } from '../internals/utils/valueManagers';
3232
import { VIEW_HEIGHT } from '../internals/constants/dimensions';
3333
import { PickerOwnerState, PickerValidDate } from '../models';
@@ -151,7 +151,7 @@ export const DateCalendar = React.forwardRef(function DateCalendar(
151151
...other
152152
} = props;
153153

154-
const { value, handleValueChange, timezone } = useControlledValueWithTimezone({
154+
const { value, handleValueChange, timezone } = useControlledValue({
155155
name: 'DateCalendar',
156156
timezone: timezoneProp,
157157
value: valueProp,

packages/x-date-pickers/src/DigitalClock/DigitalClock.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { DigitalClockOwnerState, DigitalClockProps } from './DigitalClock.types'
1818
import { useViews } from '../internals/hooks/useViews';
1919
import { PickerValidDate } from '../models';
2020
import { DIGITAL_CLOCK_VIEW_HEIGHT } from '../internals/constants/dimensions';
21-
import { useControlledValueWithTimezone } from '../internals/hooks/useValueWithTimezone';
21+
import { useControlledValue } from '../internals/hooks/useControlledValue';
2222
import { singleItemValueManager } from '../internals/utils/valueManagers';
2323
import { useClockReferenceDate } from '../internals/hooks/useClockReferenceDate';
2424
import { getFocusedListItemIndex } from '../internals/utils/utils';
@@ -159,7 +159,7 @@ export const DigitalClock = React.forwardRef(function DigitalClock(
159159
value,
160160
handleValueChange: handleRawValueChange,
161161
timezone,
162-
} = useControlledValueWithTimezone({
162+
} = useControlledValue({
163163
name: 'DigitalClock',
164164
timezone: timezoneProp,
165165
value: valueProp,

packages/x-date-pickers/src/MonthCalendar/MonthCalendar.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { applyDefaultDate, getMonthsInYear } from '../internals/utils/date-utils
1818
import { MonthCalendarProps } from './MonthCalendar.types';
1919
import { singleItemValueManager } from '../internals/utils/valueManagers';
2020
import { SECTION_TYPE_GRANULARITY } from '../internals/utils/getDefaultReferenceDate';
21-
import { useControlledValueWithTimezone } from '../internals/hooks/useValueWithTimezone';
21+
import { useControlledValue } from '../internals/hooks/useControlledValue';
2222
import { DIALOG_WIDTH } from '../internals/constants/dimensions';
2323
import { PickerOwnerState, PickerValidDate } from '../models';
2424
import { usePickerPrivateContext } from '../internals/hooks/usePickerPrivateContext';
@@ -126,7 +126,7 @@ export const MonthCalendar = React.forwardRef(function MonthCalendar(
126126
...other
127127
} = props;
128128

129-
const { value, handleValueChange, timezone } = useControlledValueWithTimezone({
129+
const { value, handleValueChange, timezone } = useControlledValue({
130130
name: 'MonthCalendar',
131131
timezone: timezoneProp,
132132
value: valueProp,

packages/x-date-pickers/src/MultiSectionDigitalClock/MultiSectionDigitalClock.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
import { getHourSectionOptions, getTimeSectionOptions } from './MultiSectionDigitalClock.utils';
2626
import { PickerOwnerState, PickerValidDate, TimeStepOptions, TimeView } from '../models';
2727
import { TimeViewWithMeridiem } from '../internals/models';
28-
import { useControlledValueWithTimezone } from '../internals/hooks/useValueWithTimezone';
28+
import { useControlledValue } from '../internals/hooks/useControlledValue';
2929
import { singleItemValueManager } from '../internals/utils/valueManagers';
3030
import { useClockReferenceDate } from '../internals/hooks/useClockReferenceDate';
3131
import { formatMeridiem } from '../internals/utils/date-utils';
@@ -112,7 +112,7 @@ export const MultiSectionDigitalClock = React.forwardRef(function MultiSectionDi
112112
value,
113113
handleValueChange: handleRawValueChange,
114114
timezone,
115-
} = useControlledValueWithTimezone({
115+
} = useControlledValue({
116116
name: 'MultiSectionDigitalClock',
117117
timezone: timezoneProp,
118118
value: valueProp,

packages/x-date-pickers/src/TimeClock/TimeClock.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { getTimeClockUtilityClass, TimeClockClasses } from './timeClockClasses';
1717
import { Clock, ClockProps } from './Clock';
1818
import { TimeClockProps } from './TimeClock.types';
1919
import { getHourNumbers, getMinutesNumbers } from './ClockNumbers';
20-
import { useControlledValueWithTimezone } from '../internals/hooks/useValueWithTimezone';
20+
import { useControlledValue } from '../internals/hooks/useControlledValue';
2121
import { singleItemValueManager } from '../internals/utils/valueManagers';
2222
import { useClockReferenceDate } from '../internals/hooks/useClockReferenceDate';
2323
import { usePickerPrivateContext } from '../internals/hooks/usePickerPrivateContext';
@@ -110,7 +110,7 @@ export const TimeClock = React.forwardRef(function TimeClock(
110110
...other
111111
} = props;
112112

113-
const { value, handleValueChange, timezone } = useControlledValueWithTimezone({
113+
const { value, handleValueChange, timezone } = useControlledValue({
114114
name: 'TimeClock',
115115
timezone: timezoneProp,
116116
value: valueProp,

packages/x-date-pickers/src/YearCalendar/YearCalendar.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { applyDefaultDate } from '../internals/utils/date-utils';
1919
import { YearCalendarProps } from './YearCalendar.types';
2020
import { singleItemValueManager } from '../internals/utils/valueManagers';
2121
import { SECTION_TYPE_GRANULARITY } from '../internals/utils/getDefaultReferenceDate';
22-
import { useControlledValueWithTimezone } from '../internals/hooks/useValueWithTimezone';
22+
import { useControlledValue } from '../internals/hooks/useControlledValue';
2323
import { DIALOG_WIDTH, MAX_CALENDAR_HEIGHT } from '../internals/constants/dimensions';
2424
import { PickerOwnerState, PickerValidDate } from '../models';
2525
import { usePickerPrivateContext } from '../internals/hooks/usePickerPrivateContext';
@@ -140,7 +140,7 @@ export const YearCalendar = React.forwardRef(function YearCalendar(
140140
...other
141141
} = props;
142142

143-
const { value, handleValueChange, timezone } = useControlledValueWithTimezone({
143+
const { value, handleValueChange, timezone } = useControlledValue({
144144
name: 'YearCalendar',
145145
timezone: timezoneProp,
146146
value: valueProp,

packages/x-date-pickers/src/internals/hooks/useValueWithTimezone.test.tsx renamed to packages/x-date-pickers/src/internals/hooks/useControlledValue.test.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { expect } from 'chai';
33
import { screen } from '@mui/internal-test-utils';
44
import { PickersTimezone, PickerValidDate } from '@mui/x-date-pickers/models';
55
import { createPickerRenderer } from 'test/utils/pickers';
6-
import { useValueWithTimezone } from './useValueWithTimezone';
6+
import { useControlledValue } from './useControlledValue';
77
import { singleItemValueManager } from '../utils/valueManagers';
88

99
describe('useValueWithTimezone', () => {
@@ -22,10 +22,11 @@ describe('useValueWithTimezone', () => {
2222
const { expectedTimezone, ...other } = params;
2323

2424
function TestComponent(props: typeof other) {
25-
const { timezone } = useValueWithTimezone({
25+
const { timezone } = useControlledValue({
26+
name: 'test',
2627
...props,
2728
valueManager: singleItemValueManager,
28-
onChange: () => {},
29+
onChange: undefined,
2930
});
3031

3132
return <div data-testid="result">{timezone}</div>;

packages/x-date-pickers/src/internals/hooks/useValueWithTimezone.ts renamed to packages/x-date-pickers/src/internals/hooks/useControlledValue.ts

Lines changed: 34 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,34 @@ import { PickersTimezone, PickerValidDate } from '../../models';
77
import { PickerValidValue } from '../models';
88

99
/**
10-
* Hooks making sure that:
10+
* Hooks controlling the value while making sure that:
1111
* - The value returned by `onChange` always have the timezone of `props.value` or `props.defaultValue` if defined
1212
* - The value rendered is always the one from `props.timezone` if defined
1313
*/
14-
export const useValueWithTimezone = <
14+
export const useControlledValue = <
1515
TValue extends PickerValidValue,
1616
TChange extends (...params: any[]) => void,
1717
>({
18+
name,
1819
timezone: timezoneProp,
1920
value: valueProp,
2021
defaultValue,
2122
referenceDate,
22-
onChange,
23+
onChange: onChangeProp,
2324
valueManager,
24-
}: UseValueWithTimezoneParameters<TValue, TChange>) => {
25+
}: UseControlledValueWithTimezoneParameters<TValue, TChange>) => {
2526
const utils = useUtils();
2627

27-
const firstDefaultValue = React.useRef(defaultValue);
28-
const inputValue = valueProp ?? firstDefaultValue.current ?? valueManager.emptyValue;
28+
const [valueWithInputTimezone, setValue] = useControlled({
29+
name,
30+
state: 'value',
31+
controlled: valueProp,
32+
default: defaultValue ?? valueManager.emptyValue,
33+
});
2934

3035
const inputTimezone = React.useMemo(
31-
() => valueManager.getTimezone(utils, inputValue),
32-
[utils, valueManager, inputValue],
36+
() => valueManager.getTimezone(utils, valueWithInputTimezone),
37+
[utils, valueManager, valueWithInputTimezone],
3338
);
3439

3540
const setInputTimezone = useEventCallback((newValue: TValue) => {
@@ -40,65 +45,35 @@ export const useValueWithTimezone = <
4045
return valueManager.setTimezone(utils, inputTimezone, newValue);
4146
});
4247

43-
let timezoneToRender: PickersTimezone;
44-
if (timezoneProp) {
45-
timezoneToRender = timezoneProp;
46-
} else if (inputTimezone) {
47-
timezoneToRender = inputTimezone;
48-
} else if (referenceDate) {
49-
timezoneToRender = utils.getTimezone(referenceDate);
50-
} else {
51-
timezoneToRender = 'default';
52-
}
48+
const timezoneToRender = React.useMemo(() => {
49+
if (timezoneProp) {
50+
return timezoneProp;
51+
}
52+
if (inputTimezone) {
53+
return inputTimezone;
54+
}
55+
if (referenceDate) {
56+
return utils.getTimezone(referenceDate);
57+
}
58+
return 'default';
59+
}, [timezoneProp, inputTimezone, referenceDate, utils]);
5360

5461
const valueWithTimezoneToRender = React.useMemo(
55-
() => valueManager.setTimezone(utils, timezoneToRender, inputValue),
56-
[valueManager, utils, timezoneToRender, inputValue],
62+
() => valueManager.setTimezone(utils, timezoneToRender, valueWithInputTimezone),
63+
[valueManager, utils, timezoneToRender, valueWithInputTimezone],
5764
);
5865

5966
const handleValueChange = useEventCallback((newValue: TValue, ...otherParams: any[]) => {
6067
const newValueWithInputTimezone = setInputTimezone(newValue);
61-
onChange?.(newValueWithInputTimezone, ...otherParams);
68+
setValue(newValueWithInputTimezone);
69+
onChangeProp?.(newValueWithInputTimezone, ...otherParams);
6270
}) as TChange;
6371

64-
return { value: valueWithTimezoneToRender, handleValueChange, timezone: timezoneToRender };
65-
};
66-
67-
/**
68-
* Wrapper around `useControlled` and `useValueWithTimezone`
69-
*/
70-
export const useControlledValueWithTimezone = <
71-
TValue extends PickerValidValue,
72-
TChange extends (...params: any[]) => void,
73-
>({
74-
name,
75-
timezone: timezoneProp,
76-
value: valueProp,
77-
defaultValue,
78-
referenceDate,
79-
onChange: onChangeProp,
80-
valueManager,
81-
}: UseControlledValueWithTimezoneParameters<TValue, TChange>) => {
82-
const [valueWithInputTimezone, setValue] = useControlled({
83-
name,
84-
state: 'value',
85-
controlled: valueProp,
86-
default: defaultValue ?? valueManager.emptyValue,
87-
});
88-
89-
const onChange = useEventCallback((newValue: TValue, ...otherParams: any[]) => {
90-
setValue(newValue);
91-
onChangeProp?.(newValue, ...otherParams);
92-
}) as TChange;
93-
94-
return useValueWithTimezone({
95-
timezone: timezoneProp,
96-
value: valueWithInputTimezone,
97-
defaultValue: undefined,
98-
referenceDate,
99-
onChange,
100-
valueManager,
101-
});
72+
return {
73+
value: valueWithTimezoneToRender,
74+
handleValueChange,
75+
timezone: timezoneToRender,
76+
};
10277
};
10378

10479
interface UseValueWithTimezoneParameters<

packages/x-date-pickers/src/internals/hooks/useField/useFieldState.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import {
2929
InferError,
3030
InferFieldSection,
3131
} from '../../../models';
32-
import { useControlledValueWithTimezone } from '../useValueWithTimezone';
32+
import { useControlledValue } from '../useControlledValue';
3333
import {
3434
GetDefaultReferenceDateProps,
3535
getSectionTypeGranularity,
@@ -110,7 +110,7 @@ export const useFieldState = <
110110
},
111111
} = params;
112112

113-
const { value, handleValueChange, timezone } = useControlledValueWithTimezone({
113+
const { value, handleValueChange, timezone } = useControlledValue({
114114
name: 'a field component',
115115
timezone: timezoneProp,
116116
value: valueProp,

packages/x-date-pickers/src/internals/hooks/usePicker/hooks/useValueAndOpenStates.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { warnOnce } from '@mui/x-internals/warning';
33
import useEventCallback from '@mui/utils/useEventCallback';
44
import { DateOrTimeViewWithMeridiem, PickerValidValue, PickerValueManager } from '../../../models';
55
import { PickerSelectionState, UsePickerProps, UsePickerState } from '../usePicker.types';
6-
import { useValueWithTimezone } from '../../useValueWithTimezone';
6+
import { useControlledValue } from '../../useControlledValue';
77
import { useUtils } from '../../useUtils';
88
import { InferError, PickerChangeHandlerContext } from '../../../../models';
99
import { SetValueActionOptions } from '../../../components/PickerProvider';
@@ -82,7 +82,8 @@ export function useValueAndOpenStates<
8282
timezone,
8383
value: valuePropWithTimezoneToRender,
8484
handleValueChange,
85-
} = useValueWithTimezone({
85+
} = useControlledValue({
86+
name: 'a picker component',
8687
timezone: timezoneProp,
8788
value: valueProp,
8889
defaultValue,

packages/x-date-pickers/src/internals/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export { PickersToolbarButton } from './components/PickersToolbarButton';
6262

6363
export { DAY_MARGIN, DIALOG_WIDTH, VIEW_HEIGHT } from './constants/dimensions';
6464

65-
export { useControlledValueWithTimezone } from './hooks/useValueWithTimezone';
65+
export { useControlledValue as useControlledValueWithTimezone } from './hooks/useControlledValue';
6666
export type { DesktopOnlyPickerProps } from './hooks/useDesktopPicker';
6767
export {
6868
useField,

0 commit comments

Comments
 (0)