@mui/x-date-pickers 6.0.2 → 6.0.3

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 (129) hide show
  1. package/AdapterDateFns/index.js +1 -0
  2. package/AdapterDateFnsJalali/index.js +1 -0
  3. package/AdapterDayjs/index.js +5 -0
  4. package/AdapterLuxon/index.js +1 -0
  5. package/AdapterMoment/index.js +5 -0
  6. package/AdapterMomentHijri/index.js +5 -0
  7. package/AdapterMomentJalaali/index.js +5 -0
  8. package/CHANGELOG.md +58 -5
  9. package/DateField/DateField.js +4 -0
  10. package/DateField/DateField.types.d.ts +2 -2
  11. package/DateField/useDateField.js +5 -3
  12. package/DateTimeField/DateTimeField.js +4 -0
  13. package/DateTimeField/DateTimeField.types.d.ts +2 -2
  14. package/DateTimeField/useDateTimeField.js +5 -3
  15. package/PickersDay/PickersDay.js +4 -4
  16. package/TimeField/TimeField.js +4 -0
  17. package/TimeField/TimeField.types.d.ts +2 -2
  18. package/TimeField/useTimeField.js +5 -3
  19. package/index.d.ts +1 -6
  20. package/index.js +4 -2
  21. package/internals/hooks/useDesktopPicker/useDesktopPicker.types.d.ts +5 -4
  22. package/internals/hooks/useField/index.d.ts +2 -2
  23. package/internals/hooks/useField/index.js +1 -1
  24. package/internals/hooks/useField/useField.d.ts +1 -1
  25. package/internals/hooks/useField/useField.js +54 -25
  26. package/internals/hooks/useField/useField.types.d.ts +24 -12
  27. package/internals/hooks/useField/useFieldState.d.ts +1 -2
  28. package/internals/hooks/useField/useFieldState.js +1 -6
  29. package/internals/hooks/useMobilePicker/useMobilePicker.types.d.ts +5 -4
  30. package/internals/hooks/usePicker/usePicker.d.ts +2 -1
  31. package/internals/hooks/usePicker/usePicker.types.d.ts +4 -3
  32. package/internals/hooks/usePicker/usePickerValue.d.ts +8 -8
  33. package/internals/hooks/usePicker/usePickerValue.js +7 -11
  34. package/internals/hooks/useStaticPicker/useStaticPicker.types.d.ts +2 -1
  35. package/internals/index.d.ts +2 -2
  36. package/internals/index.js +2 -2
  37. package/internals/models/fields.d.ts +3 -3
  38. package/internals/utils/date-utils.d.ts +1 -0
  39. package/internals/utils/date-utils.js +6 -0
  40. package/internals/utils/valueManagers.js +4 -5
  41. package/legacy/AdapterDateFns/index.js +1 -0
  42. package/legacy/AdapterDateFnsJalali/index.js +1 -0
  43. package/legacy/AdapterDayjs/index.js +5 -0
  44. package/legacy/AdapterLuxon/index.js +1 -0
  45. package/legacy/AdapterMoment/index.js +5 -0
  46. package/legacy/AdapterMomentHijri/index.js +5 -0
  47. package/legacy/AdapterMomentJalaali/index.js +5 -0
  48. package/legacy/DateField/DateField.js +4 -0
  49. package/legacy/DateField/useDateField.js +4 -2
  50. package/legacy/DateTimeField/DateTimeField.js +4 -0
  51. package/legacy/DateTimeField/useDateTimeField.js +4 -2
  52. package/legacy/PickersDay/PickersDay.js +4 -4
  53. package/legacy/TimeField/TimeField.js +4 -0
  54. package/legacy/TimeField/useTimeField.js +4 -2
  55. package/legacy/index.js +4 -2
  56. package/legacy/internals/hooks/useField/index.js +1 -1
  57. package/legacy/internals/hooks/useField/useField.js +79 -39
  58. package/legacy/internals/hooks/useField/useFieldState.js +1 -8
  59. package/legacy/internals/hooks/usePicker/usePickerValue.js +9 -13
  60. package/legacy/internals/index.js +2 -2
  61. package/legacy/internals/utils/date-utils.js +6 -0
  62. package/legacy/internals/utils/valueManagers.js +3 -8
  63. package/legacy/locales/faIR.js +33 -16
  64. package/legacy/locales/nlNL.js +12 -10
  65. package/legacy/locales/plPL.js +12 -10
  66. package/legacy/models/index.js +1 -0
  67. package/legacy/tests/describeValue/testPickerOpenCloseLifeCycle.js +2 -3
  68. package/locales/faIR.js +13 -16
  69. package/locales/nlNL.js +8 -10
  70. package/locales/plPL.js +8 -10
  71. package/models/index.d.ts +6 -0
  72. package/models/index.js +1 -0
  73. package/models/package.json +6 -0
  74. package/modern/AdapterDateFns/index.js +1 -0
  75. package/modern/AdapterDateFnsJalali/index.js +1 -0
  76. package/modern/AdapterDayjs/index.js +5 -0
  77. package/modern/AdapterLuxon/index.js +1 -0
  78. package/modern/AdapterMoment/index.js +5 -0
  79. package/modern/AdapterMomentHijri/index.js +5 -0
  80. package/modern/AdapterMomentJalaali/index.js +5 -0
  81. package/modern/DateField/DateField.js +4 -0
  82. package/modern/DateField/useDateField.js +5 -3
  83. package/modern/DateTimeField/DateTimeField.js +4 -0
  84. package/modern/DateTimeField/useDateTimeField.js +5 -3
  85. package/modern/PickersDay/PickersDay.js +4 -4
  86. package/modern/TimeField/TimeField.js +4 -0
  87. package/modern/TimeField/useTimeField.js +5 -3
  88. package/modern/index.js +4 -2
  89. package/modern/internals/hooks/useField/index.js +1 -1
  90. package/modern/internals/hooks/useField/useField.js +53 -25
  91. package/modern/internals/hooks/useField/useFieldState.js +1 -6
  92. package/modern/internals/hooks/usePicker/usePickerValue.js +7 -11
  93. package/modern/internals/index.js +2 -2
  94. package/modern/internals/utils/date-utils.js +6 -0
  95. package/modern/internals/utils/valueManagers.js +4 -5
  96. package/modern/locales/faIR.js +13 -16
  97. package/modern/locales/nlNL.js +8 -10
  98. package/modern/locales/plPL.js +8 -10
  99. package/modern/models/index.js +1 -0
  100. package/modern/tests/describeValue/testPickerOpenCloseLifeCycle.js +2 -3
  101. package/node/AdapterDateFns/index.js +1 -0
  102. package/node/AdapterDateFnsJalali/index.js +1 -0
  103. package/node/AdapterDayjs/index.js +5 -0
  104. package/node/AdapterLuxon/index.js +1 -0
  105. package/node/AdapterMoment/index.js +5 -0
  106. package/node/AdapterMomentHijri/index.js +5 -0
  107. package/node/AdapterMomentJalaali/index.js +5 -0
  108. package/node/DateField/DateField.js +4 -0
  109. package/node/DateField/useDateField.js +5 -3
  110. package/node/DateTimeField/DateTimeField.js +4 -0
  111. package/node/DateTimeField/useDateTimeField.js +5 -3
  112. package/node/PickersDay/PickersDay.js +4 -4
  113. package/node/TimeField/TimeField.js +4 -0
  114. package/node/TimeField/useTimeField.js +5 -3
  115. package/node/index.js +14 -2
  116. package/node/internals/hooks/useField/index.js +0 -6
  117. package/node/internals/hooks/useField/useField.js +52 -24
  118. package/node/internals/hooks/useField/useFieldState.js +1 -6
  119. package/node/internals/hooks/usePicker/usePickerValue.js +7 -11
  120. package/node/internals/index.js +6 -6
  121. package/node/internals/utils/date-utils.js +9 -2
  122. package/node/internals/utils/valueManagers.js +2 -3
  123. package/node/locales/faIR.js +13 -16
  124. package/node/locales/nlNL.js +8 -10
  125. package/node/locales/plPL.js +8 -10
  126. package/node/models/index.js +5 -0
  127. package/node/tests/describeValue/testPickerOpenCloseLifeCycle.js +2 -3
  128. package/package.json +2 -2
  129. package/tests/describeValue/testPickerOpenCloseLifeCycle.js +2 -3
@@ -5,9 +5,10 @@ import * as React from 'react';
5
5
  import useEnhancedEffect from '@mui/utils/useEnhancedEffect';
6
6
  import useEventCallback from '@mui/utils/useEventCallback';
7
7
  import useForkRef from '@mui/utils/useForkRef';
8
+ import { useTheme } from '@mui/material/styles';
8
9
  import { useValidation } from '../validation/useValidation';
9
10
  import { useUtils } from '../useUtils';
10
- import { adjustSectionValue, isAndroid, cleanString } from './useField.utils';
11
+ import { adjustSectionValue, isAndroid, cleanString, getSectionOrder } from './useField.utils';
11
12
  import { useFieldState } from './useFieldState';
12
13
  import { useFieldCharacterEditing } from './useFieldCharacterEditing';
13
14
  import { getActiveElement } from '../../utils/utils';
@@ -22,7 +23,6 @@ export const useField = params => {
22
23
  updateSectionValue,
23
24
  updateValueFromValueStr,
24
25
  setTempAndroidValueStr,
25
- sectionOrder,
26
26
  sectionsValueBoundaries
27
27
  } = useFieldState(params);
28
28
  const {
@@ -38,7 +38,8 @@ export const useField = params => {
38
38
  inputRef: inputRefProp,
39
39
  internalProps,
40
40
  internalProps: {
41
- readOnly = false
41
+ readOnly = false,
42
+ unstableFieldRef
42
43
  },
43
44
  forwardedProps: {
44
45
  onClick,
@@ -57,6 +58,8 @@ export const useField = params => {
57
58
  const inputRef = React.useRef(null);
58
59
  const handleRef = useForkRef(inputRefProp, inputRef);
59
60
  const focusTimeoutRef = React.useRef(undefined);
61
+ const theme = useTheme();
62
+ const sectionOrder = React.useMemo(() => getSectionOrder(state.sections, theme.direction === 'rtl'), [theme.direction, state.sections]);
60
63
  const syncSelectionFromDOM = () => {
61
64
  if (readOnly) {
62
65
  setSelectedSections(null);
@@ -143,27 +146,32 @@ export const useField = params => {
143
146
  updateValueFromValueStr(cleanValueStr);
144
147
  return;
145
148
  }
146
- const prevValueStr = cleanString(fieldValueManager.getValueStrFromSections(state.sections));
147
- let startOfDiffIndex = -1;
148
- let endOfDiffIndex = -1;
149
- for (let i = 0; i < prevValueStr.length; i += 1) {
150
- if (startOfDiffIndex === -1 && prevValueStr[i] !== cleanValueStr[i]) {
151
- startOfDiffIndex = i;
149
+ let keyPressed;
150
+ if (selectedSectionIndexes.startIndex === 0 && selectedSectionIndexes.endIndex === state.sections.length - 1) {
151
+ keyPressed = cleanValueStr;
152
+ } else {
153
+ const prevValueStr = cleanString(fieldValueManager.getValueStrFromSections(state.sections));
154
+ let startOfDiffIndex = -1;
155
+ let endOfDiffIndex = -1;
156
+ for (let i = 0; i < prevValueStr.length; i += 1) {
157
+ if (startOfDiffIndex === -1 && prevValueStr[i] !== cleanValueStr[i]) {
158
+ startOfDiffIndex = i;
159
+ }
160
+ if (endOfDiffIndex === -1 && prevValueStr[prevValueStr.length - i - 1] !== cleanValueStr[cleanValueStr.length - i - 1]) {
161
+ endOfDiffIndex = i;
162
+ }
152
163
  }
153
- if (endOfDiffIndex === -1 && prevValueStr[prevValueStr.length - i - 1] !== cleanValueStr[cleanValueStr.length - i - 1]) {
154
- endOfDiffIndex = i;
164
+ const activeSection = state.sections[selectedSectionIndexes.startIndex];
165
+ const hasDiffOutsideOfActiveSection = startOfDiffIndex < activeSection.start || prevValueStr.length - endOfDiffIndex - 1 > activeSection.end;
166
+ if (hasDiffOutsideOfActiveSection) {
167
+ // TODO: Support if the new date is valid
168
+ return;
155
169
  }
156
- }
157
- const activeSection = state.sections[selectedSectionIndexes.startIndex];
158
- const hasDiffOutsideOfActiveSection = startOfDiffIndex < activeSection.start || prevValueStr.length - endOfDiffIndex - 1 > activeSection.end;
159
- if (hasDiffOutsideOfActiveSection) {
160
- // TODO: Support if the new date is valid
161
- return;
162
- }
163
170
 
164
- // The active section being selected, the browser has replaced its value with the key pressed by the user.
165
- const activeSectionEndRelativeToNewValue = cleanValueStr.length - prevValueStr.length + activeSection.end - cleanString(activeSection.endSeparator || '').length;
166
- const keyPressed = cleanValueStr.slice(activeSection.start, activeSectionEndRelativeToNewValue);
171
+ // The active section being selected, the browser has replaced its value with the key pressed by the user.
172
+ const activeSectionEndRelativeToNewValue = cleanValueStr.length - prevValueStr.length + activeSection.end - cleanString(activeSection.endSeparator || '').length;
173
+ keyPressed = cleanValueStr.slice(activeSection.start, activeSectionEndRelativeToNewValue);
174
+ }
167
175
  if (isAndroid() && keyPressed.length === 0) {
168
176
  setTempAndroidValueStr(valueStr);
169
177
  return;
@@ -259,9 +267,11 @@ export const useField = params => {
259
267
  });
260
268
  useEnhancedEffect(() => {
261
269
  if (selectedSectionIndexes == null) {
262
- if (inputRef.current.selectionStart !== 0 || inputRef.current.selectionEnd !== 0) {
263
- // Ensure input selection range is in sync with component selection indexes
264
- inputRef.current.setSelectionRange(0, 0);
270
+ if (inputRef.current.scrollLeft) {
271
+ // Ensure that input content is not marked as selected.
272
+ // setting selection range to 0 causes issues in Safari.
273
+ // https://bugs.webkit.org/show_bug.cgi?id=224425
274
+ inputRef.current.scrollLeft = 0;
265
275
  }
266
276
  return;
267
277
  }
@@ -274,7 +284,11 @@ export const useField = params => {
274
284
  selectionEnd += lastSelectedSection.endSeparator.length;
275
285
  }
276
286
  if (selectionStart !== inputRef.current.selectionStart || selectionEnd !== inputRef.current.selectionEnd) {
287
+ // Fix scroll jumping on iOS browser: https://github.com/mui/mui-x/issues/8321
288
+ const currentScrollTop = inputRef.current.scrollTop;
277
289
  inputRef.current.setSelectionRange(selectionStart, selectionEnd);
290
+ // Even reading this variable seems to do the trick, but also setting it just to make use of it
291
+ inputRef.current.scrollTop = currentScrollTop;
278
292
  }
279
293
  });
280
294
  const validationError = useValidation(_extends({}, internalProps, {
@@ -318,7 +332,21 @@ export const useField = params => {
318
332
  return 'tel';
319
333
  }, [selectedSectionIndexes, state.sections]);
320
334
  const inputHasFocus = inputRef.current && inputRef.current === getActiveElement(document);
321
- const shouldShowPlaceholder = !inputHasFocus && (!state.value || valueManager.areValuesEqual(utils, state.value, valueManager.emptyValue));
335
+ const shouldShowPlaceholder = !inputHasFocus && valueManager.areValuesEqual(utils, state.value, valueManager.emptyValue);
336
+ React.useImperativeHandle(unstableFieldRef, () => ({
337
+ getSections: () => state.sections,
338
+ getActiveSectionIndex: () => {
339
+ const browserStartIndex = inputRef.current.selectionStart ?? 0;
340
+ const browserEndIndex = inputRef.current.selectionEnd ?? 0;
341
+ if (browserStartIndex === 0 && browserEndIndex === 0) {
342
+ return null;
343
+ }
344
+ const nextSectionIndex = browserStartIndex <= state.sections[0].startInInput ? 1 // Special case if browser index is in invisible characters at the beginning.
345
+ : state.sections.findIndex(section => section.startInInput - section.startSeparator.length > browserStartIndex);
346
+ return nextSectionIndex === -1 ? state.sections.length - 1 : nextSectionIndex - 1;
347
+ },
348
+ setSelectedSections: activeSectionIndex => setSelectedSections(activeSectionIndex)
349
+ }));
322
350
  return _extends({
323
351
  placeholder: state.placeholder,
324
352
  autoComplete: 'off'
@@ -1,6 +1,5 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import * as React from 'react';
3
- import { useTheme } from '@mui/material/styles';
4
3
  import useControlled from '@mui/utils/useControlled';
5
4
  import { useUtils, useLocaleText, useLocalizationContext } from '../useUtils';
6
5
  import { addPositionPropertiesToSections, splitFormatIntoSections, clampDaySection, mergeDateIntoReferenceDate, getSectionsBoundaries, validateSections, getDateFromDateSections } from './useField.utils';
@@ -8,8 +7,6 @@ export const useFieldState = params => {
8
7
  const utils = useUtils();
9
8
  const localeText = useLocaleText();
10
9
  const adapter = useLocalizationContext();
11
- const theme = useTheme();
12
- const isRTL = theme.direction === 'rtl';
13
10
  const {
14
11
  valueManager,
15
12
  fieldValueManager,
@@ -28,7 +25,6 @@ export const useFieldState = params => {
28
25
  const firstDefaultValue = React.useRef(defaultValue);
29
26
  const valueFromTheOutside = valueProp ?? firstDefaultValue.current ?? valueManager.emptyValue;
30
27
  const sectionsValueBoundaries = React.useMemo(() => getSectionsBoundaries(utils), [utils]);
31
- const sectionOrder = React.useMemo(() => fieldValueManager.getSectionOrder(utils, localeText, format, isRTL), [fieldValueManager, format, isRTL, localeText, utils]);
32
28
  const placeholder = React.useMemo(() => fieldValueManager.getValueStrFromSections(fieldValueManager.getSectionsFromValue(utils, localeText, null, valueManager.emptyValue, format)), [fieldValueManager, format, localeText, utils, valueManager.emptyValue]);
33
29
  const [state, setState] = React.useState(() => {
34
30
  const sections = fieldValueManager.getSectionsFromValue(utils, localeText, null, valueFromTheOutside, format);
@@ -216,7 +212,7 @@ export const useFieldState = params => {
216
212
  }));
217
213
  React.useEffect(() => {
218
214
  if (!valueManager.areValuesEqual(utils, state.value, valueFromTheOutside)) {
219
- const sections = fieldValueManager.getSectionsFromValue(utils, localeText, state.sections, valueFromTheOutside, format);
215
+ const sections = fieldValueManager.getSectionsFromValue(utils, localeText, null, valueFromTheOutside, format);
220
216
  setState(prevState => _extends({}, prevState, {
221
217
  value: valueFromTheOutside,
222
218
  referenceValue: fieldValueManager.updateReferenceValue(utils, valueFromTheOutside, prevState.referenceValue),
@@ -243,7 +239,6 @@ export const useFieldState = params => {
243
239
  updateSectionValue,
244
240
  updateValueFromValueStr,
245
241
  setTempAndroidValueStr,
246
- sectionOrder,
247
242
  sectionsValueBoundaries
248
243
  };
249
244
  };
@@ -25,13 +25,12 @@ export const usePickerValue = ({
25
25
  } = props;
26
26
  const utils = useUtils();
27
27
  const adapter = useLocalizationContext();
28
- const [rawValue, setValue] = useControlled({
28
+ const [value, setValue] = useControlled({
29
29
  controlled: inValue,
30
30
  default: defaultValue ?? valueManager.emptyValue,
31
31
  name: 'usePickerValue',
32
32
  state: 'value'
33
33
  });
34
- const value = React.useMemo(() => valueManager.cleanValue(utils, rawValue), [valueManager, utils, rawValue]);
35
34
  const [selectedSections, setSelectedSections] = useControlled({
36
35
  controlled: selectedSectionsProp,
37
36
  default: null,
@@ -81,7 +80,7 @@ export const usePickerValue = ({
81
80
  }
82
81
  }
83
82
  });
84
- if (params.forceOnChangeCall || !params.skipOnChangeCall && !valueManager.areValuesEqual(utils, dateState.committed, params.value)) {
83
+ if (!params.skipOnChangeCall && !valueManager.areValuesEqual(utils, dateState.committed, params.value)) {
85
84
  setValue(params.value);
86
85
  if (onChange) {
87
86
  const context = {
@@ -126,18 +125,14 @@ export const usePickerValue = ({
126
125
  // Reset all date in state to the empty value and close picker.
127
126
  setDate({
128
127
  value: valueManager.emptyValue,
129
- action: 'acceptAndClose',
130
- // force `onChange` in cases like input (value) === `Invalid date`
131
- forceOnChangeCall: !valueManager.areValuesEqual(utils, value, valueManager.emptyValue)
128
+ action: 'acceptAndClose'
132
129
  });
133
130
  });
134
131
  const handleAccept = useEventCallback(() => {
135
132
  // Set all date in state to equal the current draft value and close picker.
136
133
  setDate({
137
134
  value: dateState.draft,
138
- action: 'acceptAndClose',
139
- // force `onChange` in cases like input (value) === `Invalid date`
140
- forceOnChangeCall: !valueManager.areValuesEqual(utils, dateState.committed, dateState.draft)
135
+ action: 'acceptAndClose'
141
136
  });
142
137
  });
143
138
  const handleDismiss = useEventCallback(() => {
@@ -230,8 +225,9 @@ export const usePickerValue = ({
230
225
  selectedSections,
231
226
  onSelectedSectionsChange: handleFieldSelectedSectionsChange
232
227
  };
228
+ const viewValue = React.useMemo(() => valueManager.cleanValue(utils, dateState.draft), [utils, valueManager, dateState.draft]);
233
229
  const viewResponse = {
234
- value: dateState.draft,
230
+ value: viewValue,
235
231
  onChange: handleChange,
236
232
  onClose: handleClose,
237
233
  open: isOpen,
@@ -248,7 +244,7 @@ export const usePickerValue = ({
248
244
  return Array.isArray(testedValue) ? validationResponse.every(v => v === null) : validationResponse === null;
249
245
  };
250
246
  const layoutResponse = _extends({}, actions, {
251
- value: dateState.draft,
247
+ value: viewValue,
252
248
  onChange: handleChangeAndCommit,
253
249
  isValid
254
250
  });
@@ -9,7 +9,7 @@ export { pickersArrowSwitcherClasses } from './components/PickersArrowSwitcher/p
9
9
  export { pickersPopperClasses } from './components/pickersPopperClasses';
10
10
  export { PickersToolbarButton } from './components/PickersToolbarButton';
11
11
  export { DAY_MARGIN, DIALOG_WIDTH } from './constants/dimensions';
12
- export { useField, createDateStrForInputFromSections, addPositionPropertiesToSections, splitFormatIntoSections, getSectionOrder } from './hooks/useField';
12
+ export { useField, createDateStrForInputFromSections, addPositionPropertiesToSections, splitFormatIntoSections } from './hooks/useField';
13
13
  export { usePicker } from './hooks/usePicker';
14
14
  export { useStaticPicker } from './hooks/useStaticPicker';
15
15
  export { useLocalizationContext, useDefaultDates, useUtils, useLocaleText, useNow } from './hooks/useUtils';
@@ -18,7 +18,7 @@ export { validateDate } from './hooks/validation/useDateValidation';
18
18
  export { validateTime } from './hooks/validation/useTimeValidation';
19
19
  export { validateDateTime } from './hooks/validation/useDateTimeValidation';
20
20
  export { usePreviousMonthDisabled, useNextMonthDisabled } from './hooks/date-helpers-hooks';
21
- export { applyDefaultDate, replaceInvalidDateByNull } from './utils/date-utils';
21
+ export { applyDefaultDate, replaceInvalidDateByNull, areDatesEqual } from './utils/date-utils';
22
22
  export { executeInTheNextEventLoopTick, getActiveElement, onSpaceOrEnter, DEFAULT_DESKTOP_MODE_MEDIA_QUERY } from './utils/utils';
23
23
  export { defaultReduceAnimations } from './utils/defaultReduceAnimations';
24
24
  export { extractValidationProps } from './utils/validation';
@@ -63,4 +63,10 @@ export const applyDefaultDate = (utils, value, defaultValue) => {
63
63
  return defaultValue;
64
64
  }
65
65
  return value;
66
+ };
67
+ export const areDatesEqual = (utils, a, b) => {
68
+ if (!utils.isValid(a) && a != null && !utils.isValid(b) && b != null) {
69
+ return true;
70
+ }
71
+ return utils.isEqual(a, b);
66
72
  };
@@ -1,10 +1,10 @@
1
- import { replaceInvalidDateByNull } from './date-utils';
2
- import { addPositionPropertiesToSections, createDateStrForInputFromSections, splitFormatIntoSections, getSectionOrder } from '../hooks/useField/useField.utils';
1
+ import { areDatesEqual, replaceInvalidDateByNull } from './date-utils';
2
+ import { addPositionPropertiesToSections, createDateStrForInputFromSections, splitFormatIntoSections } from '../hooks/useField/useField.utils';
3
3
  export const singleItemValueManager = {
4
4
  emptyValue: null,
5
5
  getTodayValue: utils => utils.date(),
6
6
  cleanValue: replaceInvalidDateByNull,
7
- areValuesEqual: (utils, a, b) => utils.isEqual(a, b),
7
+ areValuesEqual: areDatesEqual,
8
8
  isSameError: (a, b) => a === b,
9
9
  defaultErrorState: null
10
10
  };
@@ -28,6 +28,5 @@ export const singleItemFieldValueManager = {
28
28
  })
29
29
  }),
30
30
  parseValueStr: (valueStr, referenceValue, parseDate) => parseDate(valueStr.trim(), referenceValue),
31
- hasError: error => error != null,
32
- getSectionOrder: (utils, localeText, format, isRTL) => getSectionOrder(splitFormatIntoSections(utils, localeText, format, null), isRTL)
31
+ hasError: error => error != null
33
32
  };
@@ -26,27 +26,24 @@ const faIRPickers = {
26
26
  minutesClockNumberText: minutes => `${minutes} دقیقه ها`,
27
27
  secondsClockNumberText: seconds => `${seconds} ثانیه ها`,
28
28
  // Calendar labels
29
- // calendarWeekNumberHeaderLabel: 'Week number',
30
- // calendarWeekNumberHeaderText: '#',
31
- // calendarWeekNumberAriaLabelText: weekNumber => `Week ${weekNumber}`,
32
- // calendarWeekNumberText: weekNumber => `${weekNumber}`,
33
-
29
+ calendarWeekNumberHeaderLabel: 'عدد هفته',
30
+ calendarWeekNumberHeaderText: '#',
31
+ calendarWeekNumberAriaLabelText: weekNumber => `هفته ${weekNumber}`,
32
+ calendarWeekNumberText: weekNumber => `${weekNumber}`,
34
33
  // Open picker labels
35
34
  openDatePickerDialogue: (value, utils) => value !== null && utils.isValid(value) ? `تاریخ را انتخاب کنید، تاریخ انتخاب شده ${utils.format(value, 'fullDate')} می باشد` : 'تاریخ را انتخاب کنید',
36
35
  openTimePickerDialogue: (value, utils) => value !== null && utils.isValid(value) ? `ساعت را انتخاب کنید، ساعت انتخاب شده ${utils.format(value, 'fullTime')} می باشد` : 'ساعت را انتخاب کنید',
37
36
  // Table labels
38
37
  timeTableLabel: 'انتخاب تاریخ',
39
- dateTableLabel: 'انتخاب ساعت'
40
-
38
+ dateTableLabel: 'انتخاب ساعت',
41
39
  // Field section placeholders
42
- // fieldYearPlaceholder: params => 'Y'.repeat(params.digitAmount),
43
- // fieldMonthPlaceholder: params => params.contentType === 'letter' ? 'MMMM' : 'MM',
44
- // fieldDayPlaceholder: () => 'DD',
45
- // fieldWeekDayPlaceholder: params => params.contentType === 'letter' ? 'EEEE' : 'EE',
46
- // fieldHoursPlaceholder: () => 'hh',
47
- // fieldMinutesPlaceholder: () => 'mm',
48
- // fieldSecondsPlaceholder: () => 'ss',
49
- // fieldMeridiemPlaceholder: () => 'aa',
40
+ fieldYearPlaceholder: params => 'Y'.repeat(params.digitAmount),
41
+ fieldMonthPlaceholder: params => params.contentType === 'letter' ? 'MMMM' : 'MM',
42
+ fieldDayPlaceholder: () => 'DD',
43
+ fieldWeekDayPlaceholder: params => params.contentType === 'letter' ? 'EEEE' : 'EE',
44
+ fieldHoursPlaceholder: () => 'hh',
45
+ fieldMinutesPlaceholder: () => 'mm',
46
+ fieldSecondsPlaceholder: () => 'ss',
47
+ fieldMeridiemPlaceholder: () => 'aa'
50
48
  };
51
-
52
49
  export const faIR = getPickersLocalization(faIRPickers);
@@ -16,22 +16,20 @@ const nlNLPickers = {
16
16
  okButtonLabel: 'OK',
17
17
  todayButtonLabel: 'Vandaag',
18
18
  // Toolbar titles
19
- // datePickerToolbarTitle: 'Select date',
20
- // dateTimePickerToolbarTitle: 'Select date & time',
21
- // timePickerToolbarTitle: 'Select time',
22
- // dateRangePickerToolbarTitle: 'Select date range',
23
-
19
+ datePickerToolbarTitle: 'Selecteer datum',
20
+ dateTimePickerToolbarTitle: 'Selecteer datum & tijd',
21
+ timePickerToolbarTitle: 'Selecteer tijd',
22
+ dateRangePickerToolbarTitle: 'Selecteer datumbereik',
24
23
  // Clock labels
25
24
  clockLabelText: (view, time, adapter) => `Selecteer ${view}. ${time === null ? 'Geen tijd geselecteerd' : `Geselecteerde tijd is ${adapter.format(time, 'fullTime')}`}`,
26
25
  hoursClockNumberText: hours => `${hours} uren`,
27
26
  minutesClockNumberText: minutes => `${minutes} minuten`,
28
27
  secondsClockNumberText: seconds => `${seconds} seconden`,
29
28
  // Calendar labels
30
- // calendarWeekNumberHeaderLabel: 'Week number',
31
- // calendarWeekNumberHeaderText: '#',
32
- // calendarWeekNumberAriaLabelText: weekNumber => `Week ${weekNumber}`,
33
- // calendarWeekNumberText: weekNumber => `${weekNumber}`,
34
-
29
+ calendarWeekNumberHeaderLabel: 'Weeknummer',
30
+ calendarWeekNumberHeaderText: '#',
31
+ calendarWeekNumberAriaLabelText: weekNumber => `Week ${weekNumber}`,
32
+ calendarWeekNumberText: weekNumber => `${weekNumber}`,
35
33
  // Open picker labels
36
34
  openDatePickerDialogue: (value, utils) => value !== null && utils.isValid(value) ? `Kies datum, geselecteerde datum is ${utils.format(value, 'fullDate')}` : 'Kies datum',
37
35
  openTimePickerDialogue: (value, utils) => value !== null && utils.isValid(value) ? `Kies tijd, geselecteerde tijd is ${utils.format(value, 'fullTime')}` : 'Kies tijd',
@@ -16,22 +16,20 @@ const plPLPickers = {
16
16
  okButtonLabel: 'Zatwierdź',
17
17
  todayButtonLabel: 'Dzisiaj',
18
18
  // Toolbar titles
19
- // datePickerToolbarTitle: 'Select date',
20
- // dateTimePickerToolbarTitle: 'Select date & time',
21
- // timePickerToolbarTitle: 'Select time',
22
- // dateRangePickerToolbarTitle: 'Select date range',
23
-
19
+ datePickerToolbarTitle: 'Wybierz datę',
20
+ dateTimePickerToolbarTitle: 'Wybierz datę i czas',
21
+ timePickerToolbarTitle: 'Wybierz czas',
22
+ dateRangePickerToolbarTitle: 'Wybierz zakres dat',
24
23
  // Clock labels
25
24
  clockLabelText: (view, time, adapter) => `Select ${view}. ${time === null ? 'Nie wybrano czasu' : `Wybrany czas to ${adapter.format(time, 'fullTime')}`}`,
26
25
  hoursClockNumberText: hours => `${hours} godzin`,
27
26
  minutesClockNumberText: minutes => `${minutes} minut`,
28
27
  secondsClockNumberText: seconds => `${seconds} sekund`,
29
28
  // Calendar labels
30
- // calendarWeekNumberHeaderLabel: 'Week number',
31
- // calendarWeekNumberHeaderText: '#',
32
- // calendarWeekNumberAriaLabelText: weekNumber => `Week ${weekNumber}`,
33
- // calendarWeekNumberText: weekNumber => `${weekNumber}`,
34
-
29
+ calendarWeekNumberHeaderLabel: 'Numer tygodnia',
30
+ calendarWeekNumberHeaderText: '#',
31
+ calendarWeekNumberAriaLabelText: weekNumber => `Tydzień ${weekNumber}`,
32
+ calendarWeekNumberText: weekNumber => `${weekNumber}`,
35
33
  // Open picker labels
36
34
  openDatePickerDialogue: (value, utils) => value != null && utils.isValid(value) ? `Wybierz datę, obecnie wybrana data to ${utils.format(value, 'fullDate')}` : 'Wybierz datę',
37
35
  openTimePickerDialogue: (value, utils) => value !== null && utils.isValid(value) ? `Wybierz czas, obecnie wybrany czas to ${utils.format(value, 'fullTime')}` : 'Wybierz czas',
@@ -0,0 +1 @@
1
+ export {};
@@ -87,7 +87,7 @@ export const testPickerOpenCloseLifeCycle = (ElementToTest, getOptions) => {
87
87
  expect(onAccept.callCount).to.equal(pickerParams.variant === 'mobile' ? 0 : 1);
88
88
  expect(onClose.callCount).to.equal(pickerParams.variant === 'mobile' ? 0 : 1);
89
89
  });
90
- it('should not select any field section after closing on mobile', () => {
90
+ it('should not select input content after closing on mobile', () => {
91
91
  if (pickerParams.variant !== 'mobile') {
92
92
  return;
93
93
  }
@@ -103,8 +103,7 @@ export const testPickerOpenCloseLifeCycle = (ElementToTest, getOptions) => {
103
103
  } else {
104
104
  textbox = getTextbox();
105
105
  }
106
- expect(textbox.selectionStart).to.be.equal(0);
107
- expect(textbox.selectionEnd).to.be.equal(0);
106
+ expect(textbox.scrollLeft).to.be.equal(0);
108
107
  });
109
108
  it('should call onChange, onClose and onAccept when selecting a value and `props.closeOnSelect` is true', () => {
110
109
  const onChange = spy();
@@ -144,6 +144,7 @@ class AdapterDateFns extends _dateFns.default {
144
144
  return token;
145
145
  }).join('');
146
146
  };
147
+ // Redefined here just to show how it can be written using expandFormat
147
148
  this.getFormatHelperText = format => {
148
149
  return this.expandFormat(format).replace(/(aaa|aa|a)/g, '(a|p)m').toLocaleLowerCase();
149
150
  };
@@ -75,6 +75,7 @@ class AdapterDateFnsJalali extends _dateFnsJalali.default {
75
75
  return token;
76
76
  }).join('');
77
77
  };
78
+ // Redefined here just to show how it can be written using expandFormat
78
79
  this.getFormatHelperText = format => {
79
80
  return this.expandFormat(format).replace(/(aaa|aa|a)/g, '(a|p)m').toLocaleLowerCase();
80
81
  };
@@ -83,6 +83,10 @@ class AdapterDayjs extends _dayjs2.default {
83
83
  /* istanbul ignore next */
84
84
  return /A|a/.test(this.getLocaleFormats().LT || '');
85
85
  };
86
+ /**
87
+ * The current getFormatHelperText method uses an outdated format parsing logic.
88
+ * We should use this one in the future to support all localized formats.
89
+ */
86
90
  this.expandFormat = format => {
87
91
  const localeFormats = this.getLocaleFormats();
88
92
 
@@ -93,6 +97,7 @@ class AdapterDayjs extends _dayjs2.default {
93
97
  return a || localeFormats[b] || t(localeFormats[B]);
94
98
  });
95
99
  };
100
+ // Redefined here just to show how it can be written using expandFormat
96
101
  this.getFormatHelperText = format => {
97
102
  return this.expandFormat(format).replace(/a/gi, '(a|p)m').toLocaleLowerCase();
98
103
  };
@@ -99,6 +99,7 @@ class AdapterLuxon extends _luxon2.default {
99
99
  locale: this.locale
100
100
  }).replace('yyyyy', 'yyyy');
101
101
  };
102
+ // Redefined here just to show how it can be written using expandFormat
102
103
  this.getFormatHelperText = format => {
103
104
  return this.expandFormat(format).replace(/(a)/g, '(a|p)m').toLocaleLowerCase();
104
105
  };
@@ -72,6 +72,10 @@ class AdapterMoment extends _moment2.default {
72
72
  start: '[',
73
73
  end: ']'
74
74
  };
75
+ /**
76
+ * The current getFormatHelperText method uses an outdated format parsing logic.
77
+ * We should use this one in the future to support all localized formats.
78
+ */
75
79
  this.expandFormat = format => {
76
80
  // @see https://github.com/moment/moment/blob/develop/src/lib/format/format.js#L6
77
81
  const localFormattingTokens = /(\[[^[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})|./g;
@@ -86,6 +90,7 @@ class AdapterMoment extends _moment2.default {
86
90
  this.getCurrentLocaleCode = () => {
87
91
  return this.locale || _moment.default.locale();
88
92
  };
93
+ // Redefined here just to show how it can be written using expandFormat
89
94
  this.getFormatHelperText = format => {
90
95
  return this.expandFormat(format).replace(/a/gi, '(a|p)m').toLocaleLowerCase();
91
96
  };
@@ -54,6 +54,10 @@ class AdapterMomentHijri extends _hijri.default {
54
54
  start: '[',
55
55
  end: ']'
56
56
  };
57
+ /**
58
+ * The current getFormatHelperText method uses an outdated format parsing logic.
59
+ * We should use this one in the future to support all localized formats.
60
+ */
57
61
  this.expandFormat = format => {
58
62
  // @see https://github.com/moment/moment/blob/develop/src/lib/format/format.js#L6
59
63
  const localFormattingTokens = /(\[[^[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})|./g;
@@ -65,6 +69,7 @@ class AdapterMomentHijri extends _hijri.default {
65
69
  return token;
66
70
  }).join('').replace('dd', 'iDD'); // Fix for https://github.com/dmtrKovalenko/date-io/pull/632
67
71
  };
72
+ // Redefined here just to show how it can be written using expandFormat
68
73
  this.getFormatHelperText = format => {
69
74
  return this.expandFormat(format).replace(/a/gi, '(a|p)m').replace('iY', 'Y').replace('iM', 'M').replace('iD', 'D').toLocaleLowerCase();
70
75
  };
@@ -53,6 +53,10 @@ class AdapterMomentJalaali extends _jalaali.default {
53
53
  start: '[',
54
54
  end: ']'
55
55
  };
56
+ /**
57
+ * The current getFormatHelperText method uses an outdated format parsing logic.
58
+ * We should use this one in the future to support all localized formats.
59
+ */
56
60
  this.expandFormat = format => {
57
61
  // @see https://github.com/moment/moment/blob/develop/src/lib/format/format.js#L6
58
62
  const localFormattingTokens = /(\[[^[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})|./g;
@@ -64,6 +68,7 @@ class AdapterMomentJalaali extends _jalaali.default {
64
68
  return token;
65
69
  }).join('').replace('dd', 'jDD'); // Fix for https://github.com/dmtrKovalenko/date-io/pull/632;
66
70
  };
71
+ // Redefined here just to show how it can be written using expandFormat
67
72
  this.getFormatHelperText = format => {
68
73
  return this.expandFormat(format).replace(/a/gi, '(a|p)m').replace('jY', 'Y').replace('jM', 'M').replace('jD', 'D').toLocaleLowerCase();
69
74
  };
@@ -278,6 +278,10 @@ process.env.NODE_ENV !== "production" ? DateField.propTypes = {
278
278
  * The system prop that allows defining system overrides as well as additional CSS styles.
279
279
  */
280
280
  sx: _propTypes.default.oneOfType([_propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.object, _propTypes.default.bool])), _propTypes.default.func, _propTypes.default.object]),
281
+ /**
282
+ * The ref object used to imperatively interact with the field.
283
+ */
284
+ unstableFieldRef: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.object]),
281
285
  /**
282
286
  * The selected value.
283
287
  * Used when the component is controlled.
@@ -12,7 +12,7 @@ var _useField = require("../internals/hooks/useField");
12
12
  var _useDateValidation = require("../internals/hooks/validation/useDateValidation");
13
13
  var _dateUtils = require("../internals/utils/date-utils");
14
14
  var _useUtils = require("../internals/hooks/useUtils");
15
- const _excluded = ["value", "defaultValue", "format", "onChange", "readOnly", "onError", "shouldDisableDate", "shouldDisableMonth", "shouldDisableYear", "minDate", "maxDate", "disableFuture", "disablePast", "selectedSections", "onSelectedSectionsChange"];
15
+ const _excluded = ["value", "defaultValue", "format", "onChange", "readOnly", "onError", "shouldDisableDate", "shouldDisableMonth", "shouldDisableYear", "minDate", "maxDate", "disableFuture", "disablePast", "selectedSections", "onSelectedSectionsChange", "unstableFieldRef"];
16
16
  const useDefaultizedDateField = props => {
17
17
  const utils = (0, _useUtils.useUtils)();
18
18
  const defaultDates = (0, _useUtils.useDefaultDates)();
@@ -44,7 +44,8 @@ const useDateField = ({
44
44
  disableFuture,
45
45
  disablePast,
46
46
  selectedSections,
47
- onSelectedSectionsChange
47
+ onSelectedSectionsChange,
48
+ unstableFieldRef
48
49
  } = _useDefaultizedDateFi,
49
50
  other = (0, _objectWithoutPropertiesLoose2.default)(_useDefaultizedDateFi, _excluded);
50
51
  return (0, _useField.useField)({
@@ -65,7 +66,8 @@ const useDateField = ({
65
66
  disableFuture,
66
67
  disablePast,
67
68
  selectedSections,
68
- onSelectedSectionsChange
69
+ onSelectedSectionsChange,
70
+ unstableFieldRef
69
71
  },
70
72
  valueManager: _valueManagers.singleItemValueManager,
71
73
  fieldValueManager: _valueManagers.singleItemFieldValueManager,
@@ -326,6 +326,10 @@ process.env.NODE_ENV !== "production" ? DateTimeField.propTypes = {
326
326
  * The system prop that allows defining system overrides as well as additional CSS styles.
327
327
  */
328
328
  sx: _propTypes.default.oneOfType([_propTypes.default.arrayOf(_propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.object, _propTypes.default.bool])), _propTypes.default.func, _propTypes.default.object]),
329
+ /**
330
+ * The ref object used to imperatively interact with the field.
331
+ */
332
+ unstableFieldRef: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.object]),
329
333
  /**
330
334
  * The selected value.
331
335
  * Used when the component is controlled.
@@ -12,7 +12,7 @@ var _useField = require("../internals/hooks/useField");
12
12
  var _useDateTimeValidation = require("../internals/hooks/validation/useDateTimeValidation");
13
13
  var _dateUtils = require("../internals/utils/date-utils");
14
14
  var _useUtils = require("../internals/hooks/useUtils");
15
- const _excluded = ["value", "defaultValue", "format", "onChange", "readOnly", "onError", "shouldDisableDate", "shouldDisableMonth", "shouldDisableYear", "minDate", "maxDate", "disableFuture", "disablePast", "minTime", "maxTime", "minDateTime", "maxDateTime", "minutesStep", "disableIgnoringDatePartForTimeValidation", "shouldDisableClock", "shouldDisableTime", "selectedSections", "onSelectedSectionsChange", "ampm"];
15
+ const _excluded = ["value", "defaultValue", "format", "onChange", "readOnly", "onError", "shouldDisableDate", "shouldDisableMonth", "shouldDisableYear", "minDate", "maxDate", "disableFuture", "disablePast", "minTime", "maxTime", "minDateTime", "maxDateTime", "minutesStep", "disableIgnoringDatePartForTimeValidation", "shouldDisableClock", "shouldDisableTime", "selectedSections", "onSelectedSectionsChange", "ampm", "unstableFieldRef"];
16
16
  const useDefaultizedDateTimeField = props => {
17
17
  const utils = (0, _useUtils.useUtils)();
18
18
  const defaultDates = (0, _useUtils.useDefaultDates)();
@@ -56,7 +56,8 @@ const useDateTimeField = ({
56
56
  shouldDisableTime,
57
57
  selectedSections,
58
58
  onSelectedSectionsChange,
59
- ampm
59
+ ampm,
60
+ unstableFieldRef
60
61
  } = _useDefaultizedDateTi,
61
62
  other = (0, _objectWithoutPropertiesLoose2.default)(_useDefaultizedDateTi, _excluded);
62
63
  return (0, _useField.useField)({
@@ -84,7 +85,8 @@ const useDateTimeField = ({
84
85
  disableIgnoringDatePartForTimeValidation,
85
86
  selectedSections,
86
87
  onSelectedSectionsChange,
87
- ampm
88
+ ampm,
89
+ unstableFieldRef
88
90
  },
89
91
  valueManager: _valueManagers.singleItemValueManager,
90
92
  fieldValueManager: _valueManagers.singleItemFieldValueManager,