@mui/x-date-pickers 8.0.0-beta.0 → 8.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/CHANGELOG.md +77 -0
  2. package/DateCalendar/DayCalendar.d.ts +3 -7
  3. package/DateCalendar/DayCalendar.js +16 -8
  4. package/DateCalendar/index.d.ts +0 -1
  5. package/DateField/useDateField.d.ts +1 -1
  6. package/DateField/useDateField.js +2 -16
  7. package/DatePicker/DatePicker.js +1 -0
  8. package/DateTimeField/useDateTimeField.d.ts +1 -1
  9. package/DateTimeField/useDateTimeField.js +2 -16
  10. package/DateTimePicker/DateTimePicker.js +1 -0
  11. package/DesktopDatePicker/DesktopDatePicker.js +1 -0
  12. package/DesktopDateTimePicker/DesktopDateTimePicker.js +1 -0
  13. package/DesktopTimePicker/DesktopTimePicker.js +1 -0
  14. package/MobileDatePicker/MobileDatePicker.js +1 -0
  15. package/MobileDateTimePicker/MobileDateTimePicker.js +1 -0
  16. package/MobileTimePicker/MobileTimePicker.js +1 -0
  17. package/PickersDay/PickersDay.d.ts +1 -72
  18. package/PickersDay/PickersDay.js +30 -28
  19. package/PickersDay/PickersDay.types.d.ts +114 -0
  20. package/PickersDay/PickersDay.types.js +5 -0
  21. package/PickersDay/index.d.ts +1 -1
  22. package/PickersDay/usePickerDayOwnerState.d.ts +14 -0
  23. package/PickersDay/usePickerDayOwnerState.js +40 -0
  24. package/TimeField/useTimeField.d.ts +1 -1
  25. package/TimeField/useTimeField.js +2 -16
  26. package/TimePicker/TimePicker.js +1 -0
  27. package/esm/DateCalendar/DayCalendar.d.ts +3 -7
  28. package/esm/DateCalendar/DayCalendar.js +16 -8
  29. package/esm/DateCalendar/index.d.ts +0 -1
  30. package/esm/DateField/useDateField.d.ts +1 -1
  31. package/esm/DateField/useDateField.js +3 -17
  32. package/esm/DatePicker/DatePicker.js +1 -0
  33. package/esm/DateTimeField/useDateTimeField.d.ts +1 -1
  34. package/esm/DateTimeField/useDateTimeField.js +3 -17
  35. package/esm/DateTimePicker/DateTimePicker.js +1 -0
  36. package/esm/DesktopDatePicker/DesktopDatePicker.js +1 -0
  37. package/esm/DesktopDateTimePicker/DesktopDateTimePicker.js +1 -0
  38. package/esm/DesktopTimePicker/DesktopTimePicker.js +1 -0
  39. package/esm/MobileDatePicker/MobileDatePicker.js +1 -0
  40. package/esm/MobileDateTimePicker/MobileDateTimePicker.js +1 -0
  41. package/esm/MobileTimePicker/MobileTimePicker.js +1 -0
  42. package/esm/PickersDay/PickersDay.d.ts +1 -72
  43. package/esm/PickersDay/PickersDay.js +30 -28
  44. package/esm/PickersDay/PickersDay.types.d.ts +114 -0
  45. package/esm/PickersDay/PickersDay.types.js +1 -0
  46. package/esm/PickersDay/index.d.ts +1 -1
  47. package/esm/PickersDay/usePickerDayOwnerState.d.ts +14 -0
  48. package/esm/PickersDay/usePickerDayOwnerState.js +32 -0
  49. package/esm/TimeField/useTimeField.d.ts +1 -1
  50. package/esm/TimeField/useTimeField.js +3 -17
  51. package/esm/TimePicker/TimePicker.js +1 -0
  52. package/esm/hooks/useSplitFieldProps.d.ts +1 -1
  53. package/esm/index.js +1 -1
  54. package/esm/internals/components/PickerFieldUI.d.ts +5 -5
  55. package/esm/internals/hooks/useField/buildSectionsFromFormat.d.ts +2 -2
  56. package/esm/internals/hooks/useField/buildSectionsFromFormat.js +9 -9
  57. package/esm/internals/hooks/useField/index.d.ts +1 -1
  58. package/esm/internals/hooks/useField/useField.d.ts +2 -4
  59. package/esm/internals/hooks/useField/useField.js +5 -229
  60. package/esm/internals/hooks/useField/useField.types.d.ts +48 -68
  61. package/esm/internals/hooks/useField/useField.utils.d.ts +2 -5
  62. package/esm/internals/hooks/useField/useField.utils.js +7 -92
  63. package/esm/internals/hooks/useField/useFieldCharacterEditing.d.ts +19 -26
  64. package/esm/internals/hooks/useField/useFieldCharacterEditing.js +42 -60
  65. package/esm/internals/hooks/useField/useFieldRootHandleKeyDown.d.ts +16 -0
  66. package/esm/internals/hooks/useField/useFieldRootHandleKeyDown.js +204 -0
  67. package/esm/internals/hooks/useField/useFieldState.d.ts +23 -13
  68. package/esm/internals/hooks/useField/useFieldState.js +103 -30
  69. package/esm/internals/hooks/useField/useFieldV6TextField.d.ts +3 -3
  70. package/esm/internals/hooks/useField/useFieldV6TextField.js +202 -135
  71. package/esm/internals/hooks/useField/useFieldV7TextField.d.ts +3 -2
  72. package/esm/internals/hooks/useField/useFieldV7TextField.js +217 -153
  73. package/esm/internals/hooks/usePicker/usePicker.types.d.ts +1 -0
  74. package/esm/internals/index.d.ts +2 -1
  75. package/esm/internals/index.js +1 -0
  76. package/esm/managers/useDateManager.js +3 -3
  77. package/esm/managers/useDateTimeManager.js +3 -3
  78. package/esm/managers/useTimeManager.js +3 -3
  79. package/esm/models/fields.d.ts +2 -2
  80. package/esm/models/manager.d.ts +3 -2
  81. package/hooks/useSplitFieldProps.d.ts +1 -1
  82. package/index.js +1 -1
  83. package/internals/components/PickerFieldUI.d.ts +5 -5
  84. package/internals/hooks/useField/buildSectionsFromFormat.d.ts +2 -2
  85. package/internals/hooks/useField/buildSectionsFromFormat.js +9 -9
  86. package/internals/hooks/useField/index.d.ts +1 -1
  87. package/internals/hooks/useField/useField.d.ts +2 -4
  88. package/internals/hooks/useField/useField.js +5 -231
  89. package/internals/hooks/useField/useField.types.d.ts +48 -68
  90. package/internals/hooks/useField/useField.utils.d.ts +2 -5
  91. package/internals/hooks/useField/useField.utils.js +8 -94
  92. package/internals/hooks/useField/useFieldCharacterEditing.d.ts +19 -26
  93. package/internals/hooks/useField/useFieldCharacterEditing.js +41 -59
  94. package/internals/hooks/useField/useFieldRootHandleKeyDown.d.ts +16 -0
  95. package/internals/hooks/useField/useFieldRootHandleKeyDown.js +210 -0
  96. package/internals/hooks/useField/useFieldState.d.ts +23 -13
  97. package/internals/hooks/useField/useFieldState.js +102 -29
  98. package/internals/hooks/useField/useFieldV6TextField.d.ts +3 -3
  99. package/internals/hooks/useField/useFieldV6TextField.js +202 -135
  100. package/internals/hooks/useField/useFieldV7TextField.d.ts +3 -2
  101. package/internals/hooks/useField/useFieldV7TextField.js +218 -154
  102. package/internals/hooks/usePicker/usePicker.types.d.ts +1 -0
  103. package/internals/index.d.ts +2 -1
  104. package/internals/index.js +7 -0
  105. package/managers/useDateManager.js +3 -3
  106. package/managers/useDateTimeManager.js +3 -3
  107. package/managers/useTimeManager.js +3 -3
  108. package/models/fields.d.ts +2 -2
  109. package/models/manager.d.ts +3 -2
  110. package/modern/DateCalendar/DayCalendar.d.ts +3 -7
  111. package/modern/DateCalendar/DayCalendar.js +16 -8
  112. package/modern/DateCalendar/index.d.ts +0 -1
  113. package/modern/DateField/useDateField.d.ts +1 -1
  114. package/modern/DateField/useDateField.js +3 -17
  115. package/modern/DatePicker/DatePicker.js +1 -0
  116. package/modern/DateTimeField/useDateTimeField.d.ts +1 -1
  117. package/modern/DateTimeField/useDateTimeField.js +3 -17
  118. package/modern/DateTimePicker/DateTimePicker.js +1 -0
  119. package/modern/DesktopDatePicker/DesktopDatePicker.js +1 -0
  120. package/modern/DesktopDateTimePicker/DesktopDateTimePicker.js +1 -0
  121. package/modern/DesktopTimePicker/DesktopTimePicker.js +1 -0
  122. package/modern/MobileDatePicker/MobileDatePicker.js +1 -0
  123. package/modern/MobileDateTimePicker/MobileDateTimePicker.js +1 -0
  124. package/modern/MobileTimePicker/MobileTimePicker.js +1 -0
  125. package/modern/PickersDay/PickersDay.d.ts +1 -72
  126. package/modern/PickersDay/PickersDay.js +30 -28
  127. package/modern/PickersDay/PickersDay.types.d.ts +114 -0
  128. package/modern/PickersDay/PickersDay.types.js +1 -0
  129. package/modern/PickersDay/index.d.ts +1 -1
  130. package/modern/PickersDay/usePickerDayOwnerState.d.ts +14 -0
  131. package/modern/PickersDay/usePickerDayOwnerState.js +32 -0
  132. package/modern/TimeField/useTimeField.d.ts +1 -1
  133. package/modern/TimeField/useTimeField.js +3 -17
  134. package/modern/TimePicker/TimePicker.js +1 -0
  135. package/modern/hooks/useSplitFieldProps.d.ts +1 -1
  136. package/modern/index.js +1 -1
  137. package/modern/internals/components/PickerFieldUI.d.ts +5 -5
  138. package/modern/internals/hooks/useField/buildSectionsFromFormat.d.ts +2 -2
  139. package/modern/internals/hooks/useField/buildSectionsFromFormat.js +9 -9
  140. package/modern/internals/hooks/useField/index.d.ts +1 -1
  141. package/modern/internals/hooks/useField/useField.d.ts +2 -4
  142. package/modern/internals/hooks/useField/useField.js +5 -229
  143. package/modern/internals/hooks/useField/useField.types.d.ts +48 -68
  144. package/modern/internals/hooks/useField/useField.utils.d.ts +2 -5
  145. package/modern/internals/hooks/useField/useField.utils.js +7 -92
  146. package/modern/internals/hooks/useField/useFieldCharacterEditing.d.ts +19 -26
  147. package/modern/internals/hooks/useField/useFieldCharacterEditing.js +42 -60
  148. package/modern/internals/hooks/useField/useFieldRootHandleKeyDown.d.ts +16 -0
  149. package/modern/internals/hooks/useField/useFieldRootHandleKeyDown.js +204 -0
  150. package/modern/internals/hooks/useField/useFieldState.d.ts +23 -13
  151. package/modern/internals/hooks/useField/useFieldState.js +103 -30
  152. package/modern/internals/hooks/useField/useFieldV6TextField.d.ts +3 -3
  153. package/modern/internals/hooks/useField/useFieldV6TextField.js +202 -135
  154. package/modern/internals/hooks/useField/useFieldV7TextField.d.ts +3 -2
  155. package/modern/internals/hooks/useField/useFieldV7TextField.js +217 -153
  156. package/modern/internals/hooks/usePicker/usePicker.types.d.ts +1 -0
  157. package/modern/internals/index.d.ts +2 -1
  158. package/modern/internals/index.js +1 -0
  159. package/modern/managers/useDateManager.js +3 -3
  160. package/modern/managers/useDateTimeManager.js +3 -3
  161. package/modern/managers/useTimeManager.js +3 -3
  162. package/modern/models/fields.d.ts +2 -2
  163. package/modern/models/manager.d.ts +3 -2
  164. package/package.json +1 -1
  165. package/tsconfig.build.tsbuildinfo +1 -1
@@ -17,20 +17,6 @@ export const getDateSectionConfigFromFormatToken = (utils, formatToken) => {
17
17
  maxLength: config.maxLength
18
18
  };
19
19
  };
20
- const getDeltaFromKeyCode = keyCode => {
21
- switch (keyCode) {
22
- case 'ArrowUp':
23
- return 1;
24
- case 'ArrowDown':
25
- return -1;
26
- case 'PageUp':
27
- return 5;
28
- case 'PageDown':
29
- return -5;
30
- default:
31
- return 0;
32
- }
33
- };
34
20
  export const getDaysInWeekStr = (utils, format) => {
35
21
  const elements = [];
36
22
  const now = utils.date(undefined, 'default');
@@ -108,21 +94,13 @@ export const isStringNumber = (valueStr, localizedDigits) => {
108
94
  };
109
95
 
110
96
  /**
111
- * Remove the leading zeroes to a digit section value.
97
+ * Make sure the value of a digit section have the right amount of leading zeros.
112
98
  * E.g.: `03` => `3`
113
99
  * Warning: Should only be called with non-localized digits. Call `removeLocalizedDigits` with your value if needed.
114
100
  */
115
101
  export const cleanLeadingZeros = (valueStr, size) => {
116
- let cleanValueStr = valueStr;
117
-
118
- // Remove the leading zeros
119
- cleanValueStr = Number(cleanValueStr).toString();
120
-
121
- // Add enough leading zeros to fill the section
122
- while (cleanValueStr.length < size) {
123
- cleanValueStr = `0${cleanValueStr}`;
124
- }
125
- return cleanValueStr;
102
+ // Remove the leading zeros and then add back as many as needed.
103
+ return Number(valueStr).toString().padStart(size, '0');
126
104
  };
127
105
  export const cleanDigitSectionValue = (utils, value, sectionBoundaries, localizedDigits, section) => {
128
106
  if (process.env.NODE_ENV !== 'production') {
@@ -143,68 +121,6 @@ export const cleanDigitSectionValue = (utils, value, sectionBoundaries, localize
143
121
  }
144
122
  return applyLocalizedDigits(valueStr, localizedDigits);
145
123
  };
146
- export const adjustSectionValue = (utils, timezone, section, keyCode, sectionsValueBoundaries, localizedDigits, activeDate, stepsAttributes) => {
147
- const delta = getDeltaFromKeyCode(keyCode);
148
- const isStart = keyCode === 'Home';
149
- const isEnd = keyCode === 'End';
150
- const shouldSetAbsolute = section.value === '' || isStart || isEnd;
151
- const adjustDigitSection = () => {
152
- const sectionBoundaries = sectionsValueBoundaries[section.type]({
153
- currentDate: activeDate,
154
- format: section.format,
155
- contentType: section.contentType
156
- });
157
- const getCleanValue = value => cleanDigitSectionValue(utils, value, sectionBoundaries, localizedDigits, section);
158
- const step = section.type === 'minutes' && stepsAttributes?.minutesStep ? stepsAttributes.minutesStep : 1;
159
- const currentSectionValue = parseInt(removeLocalizedDigits(section.value, localizedDigits), 10);
160
- let newSectionValueNumber = currentSectionValue + delta * step;
161
- if (shouldSetAbsolute) {
162
- if (section.type === 'year' && !isEnd && !isStart) {
163
- return utils.formatByString(utils.date(undefined, timezone), section.format);
164
- }
165
- if (delta > 0 || isStart) {
166
- newSectionValueNumber = sectionBoundaries.minimum;
167
- } else {
168
- newSectionValueNumber = sectionBoundaries.maximum;
169
- }
170
- }
171
- if (newSectionValueNumber % step !== 0) {
172
- if (delta < 0 || isStart) {
173
- newSectionValueNumber += step - (step + newSectionValueNumber) % step; // for JS -3 % 5 = -3 (should be 2)
174
- }
175
- if (delta > 0 || isEnd) {
176
- newSectionValueNumber -= newSectionValueNumber % step;
177
- }
178
- }
179
- if (newSectionValueNumber > sectionBoundaries.maximum) {
180
- return getCleanValue(sectionBoundaries.minimum + (newSectionValueNumber - sectionBoundaries.maximum - 1) % (sectionBoundaries.maximum - sectionBoundaries.minimum + 1));
181
- }
182
- if (newSectionValueNumber < sectionBoundaries.minimum) {
183
- return getCleanValue(sectionBoundaries.maximum - (sectionBoundaries.minimum - newSectionValueNumber - 1) % (sectionBoundaries.maximum - sectionBoundaries.minimum + 1));
184
- }
185
- return getCleanValue(newSectionValueNumber);
186
- };
187
- const adjustLetterSection = () => {
188
- const options = getLetterEditingOptions(utils, timezone, section.type, section.format);
189
- if (options.length === 0) {
190
- return section.value;
191
- }
192
- if (shouldSetAbsolute) {
193
- if (delta > 0 || isStart) {
194
- return options[0];
195
- }
196
- return options[options.length - 1];
197
- }
198
- const currentOptionIndex = options.indexOf(section.value);
199
- const newOptionIndex = (currentOptionIndex + delta) % options.length;
200
- const clampedIndex = (newOptionIndex + options.length) % options.length;
201
- return options[clampedIndex];
202
- };
203
- if (section.contentType === 'digit' || section.contentType === 'digit-with-letter') {
204
- return adjustDigitSection();
205
- }
206
- return adjustLetterSection();
207
- };
208
124
  export const getSectionVisibleValue = (section, target, localizedDigits) => {
209
125
  let value = section.value || section.placeholder;
210
126
  const hasLeadingZeros = target === 'non-input' ? section.hasLeadingZerosInFormat : section.hasLeadingZerosInInput;
@@ -244,12 +160,11 @@ export const doesSectionFormatHaveLeadingZeros = (utils, contentType, sectionTyp
244
160
  // We can't use `changeSectionValueFormat`, because `utils.parse('1', 'YYYY')` returns `1971` instead of `1`.
245
161
  case 'year':
246
162
  {
247
- if (isFourDigitYearFormat(utils, format)) {
248
- const formatted0001 = utils.formatByString(utils.setYear(now, 1), format);
249
- return formatted0001 === '0001';
163
+ // Remove once https://github.com/iamkun/dayjs/pull/2847 is merged and bump dayjs version
164
+ if (utils.lib === 'dayjs' && format === 'YY') {
165
+ return true;
250
166
  }
251
- const formatted2001 = utils.formatByString(utils.setYear(now, 2001), format);
252
- return formatted2001 === '01';
167
+ return utils.formatByString(utils.setYear(now, 1), format).startsWith('0');
253
168
  }
254
169
  case 'month':
255
170
  {
@@ -1,23 +1,5 @@
1
- import { PickersTimezone, InferFieldSection } from "../../../models/index.js";
2
- import { FieldSectionsValueBoundaries } from "./useField.types.js";
3
- import { UpdateSectionValueParams } from "./useFieldState.js";
1
+ import { UseFieldStateReturnValue } from "./useFieldState.js";
4
2
  import { PickerValidValue } from "../../models/index.js";
5
- export interface ApplyCharacterEditingParams {
6
- keyPressed: string;
7
- sectionIndex: number;
8
- }
9
- interface UseFieldCharacterEditingParams<TValue extends PickerValidValue> {
10
- sections: InferFieldSection<TValue>[];
11
- updateSectionValue: (params: UpdateSectionValueParams<TValue>) => void;
12
- sectionsValueBoundaries: FieldSectionsValueBoundaries;
13
- localizedDigits: string[];
14
- setTempAndroidValueStr: (newValue: string | null) => void;
15
- timezone: PickersTimezone;
16
- }
17
- export interface UseFieldCharacterEditingResponse {
18
- applyCharacterEditing: (params: ApplyCharacterEditingParams) => void;
19
- resetCharacterQuery: () => void;
20
- }
21
3
  /**
22
4
  * Update the active section value when the user pressed a key that is not a navigation key (arrow key for example).
23
5
  * This hook has two main editing behaviors
@@ -26,11 +8,22 @@ export interface UseFieldCharacterEditingResponse {
26
8
  * 2. The letter editing when the user presses another key
27
9
  */
28
10
  export declare const useFieldCharacterEditing: <TValue extends PickerValidValue>({
29
- sections,
30
- updateSectionValue,
31
- sectionsValueBoundaries,
32
- localizedDigits,
33
- setTempAndroidValueStr,
34
- timezone
35
- }: UseFieldCharacterEditingParams<TValue>) => UseFieldCharacterEditingResponse;
11
+ stateResponse: {
12
+ localizedDigits,
13
+ sectionsValueBoundaries,
14
+ state,
15
+ timezone,
16
+ setCharacterQuery,
17
+ setTempAndroidValueStr,
18
+ updateSectionValue
19
+ }
20
+ }: UseFieldCharacterEditingParameters<TValue>) => UseFieldCharacterEditingReturnValue;
21
+ export interface ApplyCharacterEditingParameters {
22
+ keyPressed: string;
23
+ sectionIndex: number;
24
+ }
25
+ interface UseFieldCharacterEditingParameters<TValue extends PickerValidValue> {
26
+ stateResponse: UseFieldStateReturnValue<TValue>;
27
+ }
28
+ export type UseFieldCharacterEditingReturnValue = (params: ApplyCharacterEditingParameters) => void;
36
29
  export {};
@@ -1,32 +1,7 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
- import * as React from 'react';
3
2
  import useEventCallback from '@mui/utils/useEventCallback';
4
3
  import { useUtils } from "../useUtils.js";
5
4
  import { changeSectionValueFormat, cleanDigitSectionValue, doesSectionFormatHaveLeadingZeros, getDateSectionConfigFromFormatToken, getDaysInWeekStr, getLetterEditingOptions, applyLocalizedDigits, removeLocalizedDigits, isStringNumber } from "./useField.utils.js";
6
-
7
- /**
8
- * The letter editing and the numeric editing each define a `CharacterEditingApplier`.
9
- * This function decides what the new section value should be and if the focus should switch to the next section.
10
- *
11
- * If it returns `null`, then the section value is not updated and the focus does not move.
12
- */
13
-
14
- /**
15
- * Function called by `applyQuery` which decides:
16
- * - what is the new section value ?
17
- * - should the query used to get this value be stored for the next key press ?
18
- *
19
- * If it returns `{ sectionValue: string; shouldGoToNextSection: boolean }`,
20
- * Then we store the query and update the section with the new value.
21
- *
22
- * If it returns `{ saveQuery: true` },
23
- * Then we store the query and don't update the section.
24
- *
25
- * If it returns `{ saveQuery: false },
26
- * Then we do nothing.
27
- */
28
-
29
- const QUERY_LIFE_DURATION_MS = 5000;
30
5
  const isQueryResponseWithoutValue = response => response.saveQuery != null;
31
6
 
32
7
  /**
@@ -37,44 +12,33 @@ const isQueryResponseWithoutValue = response => response.saveQuery != null;
37
12
  * 2. The letter editing when the user presses another key
38
13
  */
39
14
  export const useFieldCharacterEditing = ({
40
- sections,
41
- updateSectionValue,
42
- sectionsValueBoundaries,
43
- localizedDigits,
44
- setTempAndroidValueStr,
45
- timezone
15
+ stateResponse: {
16
+ // States and derived states
17
+ localizedDigits,
18
+ sectionsValueBoundaries,
19
+ state,
20
+ timezone,
21
+ // Methods to update the states
22
+ setCharacterQuery,
23
+ setTempAndroidValueStr,
24
+ updateSectionValue
25
+ }
46
26
  }) => {
47
27
  const utils = useUtils();
48
- const [query, setQuery] = React.useState(null);
49
- const resetQuery = useEventCallback(() => setQuery(null));
50
- React.useEffect(() => {
51
- if (query != null && sections[query.sectionIndex]?.type !== query.sectionType) {
52
- resetQuery();
53
- }
54
- }, [sections, query, resetQuery]);
55
- React.useEffect(() => {
56
- if (query != null) {
57
- const timeout = setTimeout(() => resetQuery(), QUERY_LIFE_DURATION_MS);
58
- return () => {
59
- clearTimeout(timeout);
60
- };
61
- }
62
- return () => {};
63
- }, [query, resetQuery]);
64
28
  const applyQuery = ({
65
29
  keyPressed,
66
30
  sectionIndex
67
31
  }, getFirstSectionValueMatchingWithQuery, isValidQueryValue) => {
68
32
  const cleanKeyPressed = keyPressed.toLowerCase();
69
- const activeSection = sections[sectionIndex];
33
+ const activeSection = state.sections[sectionIndex];
70
34
 
71
35
  // The current query targets the section being editing
72
36
  // We can try to concatenate the value
73
- if (query != null && (!isValidQueryValue || isValidQueryValue(query.value)) && query.sectionIndex === sectionIndex) {
74
- const concatenatedQueryValue = `${query.value}${cleanKeyPressed}`;
37
+ if (state.characterQuery != null && (!isValidQueryValue || isValidQueryValue(state.characterQuery.value)) && state.characterQuery.sectionIndex === sectionIndex) {
38
+ const concatenatedQueryValue = `${state.characterQuery.value}${cleanKeyPressed}`;
75
39
  const queryResponse = getFirstSectionValueMatchingWithQuery(concatenatedQueryValue, activeSection);
76
40
  if (!isQueryResponseWithoutValue(queryResponse)) {
77
- setQuery({
41
+ setCharacterQuery({
78
42
  sectionIndex,
79
43
  value: concatenatedQueryValue,
80
44
  sectionType: activeSection.type
@@ -84,10 +48,10 @@ export const useFieldCharacterEditing = ({
84
48
  }
85
49
  const queryResponse = getFirstSectionValueMatchingWithQuery(cleanKeyPressed, activeSection);
86
50
  if (isQueryResponseWithoutValue(queryResponse) && !queryResponse.saveQuery) {
87
- resetQuery();
51
+ setCharacterQuery(null);
88
52
  return null;
89
53
  }
90
- setQuery({
54
+ setCharacterQuery({
91
55
  sectionIndex,
92
56
  value: cleanKeyPressed,
93
57
  sectionType: activeSection.type
@@ -235,8 +199,8 @@ export const useFieldCharacterEditing = ({
235
199
  };
236
200
  return applyQuery(params, getFirstSectionValueMatchingWithQuery, queryValue => isStringNumber(queryValue, localizedDigits));
237
201
  };
238
- const applyCharacterEditing = useEventCallback(params => {
239
- const section = sections[params.sectionIndex];
202
+ return useEventCallback(params => {
203
+ const section = state.sections[params.sectionIndex];
240
204
  const isNumericEditing = isStringNumber(params.keyPressed, localizedDigits);
241
205
  const response = isNumericEditing ? applyNumericEditing(_extends({}, params, {
242
206
  keyPressed: applyLocalizedDigits(params.keyPressed, localizedDigits)
@@ -251,8 +215,26 @@ export const useFieldCharacterEditing = ({
251
215
  shouldGoToNextSection: response.shouldGoToNextSection
252
216
  });
253
217
  });
254
- return {
255
- applyCharacterEditing,
256
- resetCharacterQuery: resetQuery
257
- };
258
- };
218
+ };
219
+
220
+ /**
221
+ * The letter editing and the numeric editing each define a `CharacterEditingApplier`.
222
+ * This function decides what the new section value should be and if the focus should switch to the next section.
223
+ *
224
+ * If it returns `null`, then the section value is not updated and the focus does not move.
225
+ */
226
+
227
+ /**
228
+ * Function called by `applyQuery` which decides:
229
+ * - what is the new section value ?
230
+ * - should the query used to get this value be stored for the next key press ?
231
+ *
232
+ * If it returns `{ sectionValue: string; shouldGoToNextSection: boolean }`,
233
+ * Then we store the query and update the section with the new value.
234
+ *
235
+ * If it returns `{ saveQuery: true` },
236
+ * Then we store the query and don't update the section.
237
+ *
238
+ * If it returns `{ saveQuery: false },
239
+ * Then we do nothing.
240
+ */
@@ -0,0 +1,16 @@
1
+ import { PickerManager } from "../../../models/index.js";
2
+ import { PickerValidValue } from "../../models/index.js";
3
+ import { UseFieldStateReturnValue } from "./useFieldState.js";
4
+ import { UseFieldInternalProps } from "./useField.types.js";
5
+ /**
6
+ * Returns the `onKeyDown` handler to pass to the root element of the field.
7
+ */
8
+ export declare function useFieldRootHandleKeyDown<TValue extends PickerValidValue>(parameters: UseFieldRootHandleKeyDownParameters<TValue>): (event: React.KeyboardEvent<HTMLSpanElement>) => void;
9
+ interface UseFieldRootHandleKeyDownParameters<TValue extends PickerValidValue> {
10
+ manager: PickerManager<TValue, any, any, any, any>;
11
+ stateResponse: UseFieldStateReturnValue<TValue>;
12
+ internalPropsWithDefaults: UseFieldInternalProps<TValue, any, any> & {
13
+ minutesStep?: number;
14
+ };
15
+ }
16
+ export {};
@@ -0,0 +1,204 @@
1
+ import useEventCallback from '@mui/utils/useEventCallback';
2
+ import { useUtils } from "../useUtils.js";
3
+ import { cleanDigitSectionValue, getLetterEditingOptions, removeLocalizedDigits } from "./useField.utils.js";
4
+
5
+ /**
6
+ * Returns the `onKeyDown` handler to pass to the root element of the field.
7
+ */
8
+ export function useFieldRootHandleKeyDown(parameters) {
9
+ const utils = useUtils();
10
+ const {
11
+ manager: {
12
+ internal_fieldValueManager: fieldValueManager
13
+ },
14
+ internalPropsWithDefaults: {
15
+ minutesStep,
16
+ disabled,
17
+ readOnly
18
+ },
19
+ stateResponse: {
20
+ // States and derived states
21
+ state,
22
+ value,
23
+ activeSectionIndex,
24
+ parsedSelectedSections,
25
+ sectionsValueBoundaries,
26
+ localizedDigits,
27
+ timezone,
28
+ sectionOrder,
29
+ // Methods to update the states
30
+ clearValue,
31
+ clearActiveSection,
32
+ setSelectedSections,
33
+ updateSectionValue
34
+ }
35
+ } = parameters;
36
+ return useEventCallback(event => {
37
+ if (disabled) {
38
+ return;
39
+ }
40
+ // eslint-disable-next-line default-case
41
+ switch (true) {
42
+ // Select all
43
+ case (event.ctrlKey || event.metaKey) && String.fromCharCode(event.keyCode) === 'A' && !event.shiftKey && !event.altKey:
44
+ {
45
+ // prevent default to make sure that the next line "select all" while updating
46
+ // the internal state at the same time.
47
+ event.preventDefault();
48
+ setSelectedSections('all');
49
+ break;
50
+ }
51
+
52
+ // Move selection to next section
53
+ case event.key === 'ArrowRight':
54
+ {
55
+ event.preventDefault();
56
+ if (parsedSelectedSections == null) {
57
+ setSelectedSections(sectionOrder.startIndex);
58
+ } else if (parsedSelectedSections === 'all') {
59
+ setSelectedSections(sectionOrder.endIndex);
60
+ } else {
61
+ const nextSectionIndex = sectionOrder.neighbors[parsedSelectedSections].rightIndex;
62
+ if (nextSectionIndex !== null) {
63
+ setSelectedSections(nextSectionIndex);
64
+ }
65
+ }
66
+ break;
67
+ }
68
+
69
+ // Move selection to previous section
70
+ case event.key === 'ArrowLeft':
71
+ {
72
+ event.preventDefault();
73
+ if (parsedSelectedSections == null) {
74
+ setSelectedSections(sectionOrder.endIndex);
75
+ } else if (parsedSelectedSections === 'all') {
76
+ setSelectedSections(sectionOrder.startIndex);
77
+ } else {
78
+ const nextSectionIndex = sectionOrder.neighbors[parsedSelectedSections].leftIndex;
79
+ if (nextSectionIndex !== null) {
80
+ setSelectedSections(nextSectionIndex);
81
+ }
82
+ }
83
+ break;
84
+ }
85
+
86
+ // Reset the value of the selected section
87
+ case event.key === 'Delete':
88
+ {
89
+ event.preventDefault();
90
+ if (readOnly) {
91
+ break;
92
+ }
93
+ if (parsedSelectedSections == null || parsedSelectedSections === 'all') {
94
+ clearValue();
95
+ } else {
96
+ clearActiveSection();
97
+ }
98
+ break;
99
+ }
100
+
101
+ // Increment / decrement the selected section value
102
+ case ['ArrowUp', 'ArrowDown', 'Home', 'End', 'PageUp', 'PageDown'].includes(event.key):
103
+ {
104
+ event.preventDefault();
105
+ if (readOnly || activeSectionIndex == null) {
106
+ break;
107
+ }
108
+
109
+ // if all sections are selected, mark the currently editing one as selected
110
+ if (parsedSelectedSections === 'all') {
111
+ setSelectedSections(activeSectionIndex);
112
+ }
113
+ const activeSection = state.sections[activeSectionIndex];
114
+ const newSectionValue = adjustSectionValue(utils, timezone, activeSection, event.key, sectionsValueBoundaries, localizedDigits, fieldValueManager.getDateFromSection(value, activeSection), {
115
+ minutesStep
116
+ });
117
+ updateSectionValue({
118
+ section: activeSection,
119
+ newSectionValue,
120
+ shouldGoToNextSection: false
121
+ });
122
+ break;
123
+ }
124
+ }
125
+ });
126
+ }
127
+ function getDeltaFromKeyCode(keyCode) {
128
+ switch (keyCode) {
129
+ case 'ArrowUp':
130
+ return 1;
131
+ case 'ArrowDown':
132
+ return -1;
133
+ case 'PageUp':
134
+ return 5;
135
+ case 'PageDown':
136
+ return -5;
137
+ default:
138
+ return 0;
139
+ }
140
+ }
141
+ function adjustSectionValue(utils, timezone, section, keyCode, sectionsValueBoundaries, localizedDigits, activeDate, stepsAttributes) {
142
+ const delta = getDeltaFromKeyCode(keyCode);
143
+ const isStart = keyCode === 'Home';
144
+ const isEnd = keyCode === 'End';
145
+ const shouldSetAbsolute = section.value === '' || isStart || isEnd;
146
+ const adjustDigitSection = () => {
147
+ const sectionBoundaries = sectionsValueBoundaries[section.type]({
148
+ currentDate: activeDate,
149
+ format: section.format,
150
+ contentType: section.contentType
151
+ });
152
+ const getCleanValue = value => cleanDigitSectionValue(utils, value, sectionBoundaries, localizedDigits, section);
153
+ const step = section.type === 'minutes' && stepsAttributes?.minutesStep ? stepsAttributes.minutesStep : 1;
154
+ let newSectionValueNumber;
155
+ if (shouldSetAbsolute) {
156
+ if (section.type === 'year' && !isEnd && !isStart) {
157
+ return utils.formatByString(utils.date(undefined, timezone), section.format);
158
+ }
159
+ if (delta > 0 || isStart) {
160
+ newSectionValueNumber = sectionBoundaries.minimum;
161
+ } else {
162
+ newSectionValueNumber = sectionBoundaries.maximum;
163
+ }
164
+ } else {
165
+ const currentSectionValue = parseInt(removeLocalizedDigits(section.value, localizedDigits), 10);
166
+ newSectionValueNumber = currentSectionValue + delta * step;
167
+ }
168
+ if (newSectionValueNumber % step !== 0) {
169
+ if (delta < 0 || isStart) {
170
+ newSectionValueNumber += step - (step + newSectionValueNumber) % step; // for JS -3 % 5 = -3 (should be 2)
171
+ }
172
+ if (delta > 0 || isEnd) {
173
+ newSectionValueNumber -= newSectionValueNumber % step;
174
+ }
175
+ }
176
+ if (newSectionValueNumber > sectionBoundaries.maximum) {
177
+ return getCleanValue(sectionBoundaries.minimum + (newSectionValueNumber - sectionBoundaries.maximum - 1) % (sectionBoundaries.maximum - sectionBoundaries.minimum + 1));
178
+ }
179
+ if (newSectionValueNumber < sectionBoundaries.minimum) {
180
+ return getCleanValue(sectionBoundaries.maximum - (sectionBoundaries.minimum - newSectionValueNumber - 1) % (sectionBoundaries.maximum - sectionBoundaries.minimum + 1));
181
+ }
182
+ return getCleanValue(newSectionValueNumber);
183
+ };
184
+ const adjustLetterSection = () => {
185
+ const options = getLetterEditingOptions(utils, timezone, section.type, section.format);
186
+ if (options.length === 0) {
187
+ return section.value;
188
+ }
189
+ if (shouldSetAbsolute) {
190
+ if (delta > 0 || isStart) {
191
+ return options[0];
192
+ }
193
+ return options[options.length - 1];
194
+ }
195
+ const currentOptionIndex = options.indexOf(section.value);
196
+ const newOptionIndex = (currentOptionIndex + delta) % options.length;
197
+ const clampedIndex = (newOptionIndex + options.length) % options.length;
198
+ return options[clampedIndex];
199
+ };
200
+ if (section.contentType === 'digit' || section.contentType === 'digit-with-letter') {
201
+ return adjustDigitSection();
202
+ }
203
+ return adjustLetterSection();
204
+ }
@@ -1,7 +1,13 @@
1
- import { UseFieldInternalProps, UseFieldParams, UseFieldState, FieldParsedSelectedSections, FieldSectionsValueBoundaries, UseFieldForwardedProps } from "./useField.types.js";
2
- import { FieldSelectedSections, PickersTimezone, InferFieldSection } from "../../../models/index.js";
1
+ import { UseFieldInternalProps, UseFieldState, FieldParsedSelectedSections, FieldSectionsValueBoundaries, SectionOrdering, UseFieldForwardedProps, CharacterEditingQuery } from "./useField.types.js";
2
+ import { FieldSelectedSections, PickersTimezone, InferFieldSection, PickerManager } from "../../../models/index.js";
3
3
  import { PickerValidValue } from "../../models/index.js";
4
- export interface UpdateSectionValueParams<TValue extends PickerValidValue> {
4
+ export declare const useFieldState: <TValue extends PickerValidValue, TEnableAccessibleFieldDOMStructure extends boolean, TError, TValidationProps extends {}, TForwardedProps extends UseFieldForwardedProps<TEnableAccessibleFieldDOMStructure>>(parameters: UseFieldStateParameters<TValue, TEnableAccessibleFieldDOMStructure, TError, TValidationProps, TForwardedProps>) => UseFieldStateReturnValue<TValue>;
5
+ interface UseFieldStateParameters<TValue extends PickerValidValue, TEnableAccessibleFieldDOMStructure extends boolean, TError, TValidationProps extends {}, TForwardedProps extends UseFieldForwardedProps<TEnableAccessibleFieldDOMStructure>> {
6
+ manager: PickerManager<TValue, TEnableAccessibleFieldDOMStructure, TError, TValidationProps, any>;
7
+ internalPropsWithDefaults: UseFieldInternalProps<TValue, TEnableAccessibleFieldDOMStructure, TError> & TValidationProps;
8
+ forwardedProps: TForwardedProps;
9
+ }
10
+ export interface UpdateSectionValueParameters<TValue extends PickerValidValue> {
5
11
  /**
6
12
  * The section on which we want to apply the new value.
7
13
  */
@@ -15,20 +21,24 @@ export interface UpdateSectionValueParams<TValue extends PickerValidValue> {
15
21
  */
16
22
  shouldGoToNextSection: boolean;
17
23
  }
18
- export interface UseFieldStateResponse<TValue extends PickerValidValue> {
19
- state: UseFieldState<TValue>;
20
- value: TValue;
24
+ export interface UseFieldStateReturnValue<TValue extends PickerValidValue> {
21
25
  activeSectionIndex: number | null;
26
+ areAllSectionsEmpty: boolean;
27
+ error: boolean;
28
+ localizedDigits: string[];
22
29
  parsedSelectedSections: FieldParsedSelectedSections;
23
- setSelectedSections: (sections: FieldSelectedSections) => void;
30
+ sectionOrder: SectionOrdering;
31
+ sectionsValueBoundaries: FieldSectionsValueBoundaries;
32
+ state: UseFieldState<TValue>;
33
+ timezone: PickersTimezone;
34
+ value: TValue;
24
35
  clearValue: () => void;
25
36
  clearActiveSection: () => void;
26
- updateSectionValue: (params: UpdateSectionValueParams<TValue>) => void;
27
- updateValueFromValueStr: (valueStr: string) => void;
37
+ setCharacterQuery: (characterQuery: CharacterEditingQuery | null) => void;
38
+ setSelectedSections: (sections: FieldSelectedSections) => void;
28
39
  setTempAndroidValueStr: (tempAndroidValueStr: string | null) => void;
29
- sectionsValueBoundaries: FieldSectionsValueBoundaries;
40
+ updateSectionValue: (parameters: UpdateSectionValueParameters<TValue>) => void;
41
+ updateValueFromValueStr: (valueStr: string) => void;
30
42
  getSectionsFromValue: (value: TValue, fallbackSections?: InferFieldSection<TValue>[] | null) => InferFieldSection<TValue>[];
31
- localizedDigits: string[];
32
- timezone: PickersTimezone;
33
43
  }
34
- export declare const useFieldState: <TValue extends PickerValidValue, TEnableAccessibleFieldDOMStructure extends boolean, TForwardedProps extends UseFieldForwardedProps<TEnableAccessibleFieldDOMStructure>, TInternalProps extends UseFieldInternalProps<TValue, TEnableAccessibleFieldDOMStructure, any>>(params: UseFieldParams<TValue, TEnableAccessibleFieldDOMStructure, TForwardedProps, TInternalProps>) => UseFieldStateResponse<TValue>;
44
+ export {};