@mui/x-date-pickers 8.16.0 → 8.18.0

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 (104) hide show
  1. package/CHANGELOG.md +208 -1
  2. package/DateCalendar/DayCalendar.d.ts +1 -1
  3. package/DateCalendar/PickersFadeTransitionGroup.d.ts +1 -1
  4. package/DateCalendar/PickersSlideTransition.d.ts +1 -1
  5. package/DatePicker/DatePicker.js +8 -2
  6. package/DateTimePicker/DateTimePicker.js +8 -2
  7. package/DateTimePicker/DateTimePickerTabs.d.ts +1 -1
  8. package/DateTimePicker/DateTimePickerToolbar.d.ts +1 -1
  9. package/DateTimePicker/DateTimePickerToolbar.js +2 -1
  10. package/DayCalendarSkeleton/DayCalendarSkeleton.d.ts +1 -1
  11. package/DesktopDatePicker/DesktopDatePicker.js +8 -2
  12. package/DesktopDateTimePicker/DesktopDateTimePicker.js +8 -2
  13. package/DesktopTimePicker/DesktopTimePicker.js +8 -2
  14. package/MobileDatePicker/MobileDatePicker.js +8 -2
  15. package/MobileDateTimePicker/MobileDateTimePicker.js +8 -2
  16. package/MobileTimePicker/MobileTimePicker.js +8 -2
  17. package/PickersActionBar/PickersActionBar.d.ts +1 -1
  18. package/PickersShortcuts/PickersShortcuts.d.ts +1 -2
  19. package/PickersShortcuts/PickersShortcuts.js +2 -3
  20. package/PickersTextField/PickersOutlinedInput/Outline.d.ts +1 -1
  21. package/StaticDatePicker/StaticDatePicker.js +8 -2
  22. package/StaticDateTimePicker/StaticDateTimePicker.js +8 -2
  23. package/StaticTimePicker/StaticTimePicker.js +8 -2
  24. package/TimeClock/Clock.d.ts +1 -1
  25. package/TimeClock/ClockNumber.d.ts +1 -1
  26. package/TimeClock/ClockNumbers.d.ts +1 -1
  27. package/TimeClock/ClockPointer.d.ts +1 -1
  28. package/TimePicker/TimePicker.js +8 -2
  29. package/TimePicker/TimePickerToolbar.d.ts +1 -2
  30. package/TimePicker/TimePickerToolbar.js +2 -3
  31. package/dateViewRenderers/dateViewRenderers.d.ts +1 -2
  32. package/dateViewRenderers/dateViewRenderers.js +0 -2
  33. package/esm/DateCalendar/DayCalendar.d.ts +1 -1
  34. package/esm/DateCalendar/PickersFadeTransitionGroup.d.ts +1 -1
  35. package/esm/DateCalendar/PickersSlideTransition.d.ts +1 -1
  36. package/esm/DatePicker/DatePicker.js +8 -2
  37. package/esm/DateTimePicker/DateTimePicker.js +8 -2
  38. package/esm/DateTimePicker/DateTimePickerTabs.d.ts +1 -1
  39. package/esm/DateTimePicker/DateTimePickerToolbar.d.ts +1 -1
  40. package/esm/DateTimePicker/DateTimePickerToolbar.js +2 -1
  41. package/esm/DayCalendarSkeleton/DayCalendarSkeleton.d.ts +1 -1
  42. package/esm/DesktopDatePicker/DesktopDatePicker.js +8 -2
  43. package/esm/DesktopDateTimePicker/DesktopDateTimePicker.js +8 -2
  44. package/esm/DesktopTimePicker/DesktopTimePicker.js +8 -2
  45. package/esm/MobileDatePicker/MobileDatePicker.js +8 -2
  46. package/esm/MobileDateTimePicker/MobileDateTimePicker.js +8 -2
  47. package/esm/MobileTimePicker/MobileTimePicker.js +8 -2
  48. package/esm/PickersActionBar/PickersActionBar.d.ts +1 -1
  49. package/esm/PickersShortcuts/PickersShortcuts.d.ts +1 -2
  50. package/esm/PickersShortcuts/PickersShortcuts.js +2 -2
  51. package/esm/PickersTextField/PickersOutlinedInput/Outline.d.ts +1 -1
  52. package/esm/StaticDatePicker/StaticDatePicker.js +8 -2
  53. package/esm/StaticDateTimePicker/StaticDateTimePicker.js +8 -2
  54. package/esm/StaticTimePicker/StaticTimePicker.js +8 -2
  55. package/esm/TimeClock/Clock.d.ts +1 -1
  56. package/esm/TimeClock/ClockNumber.d.ts +1 -1
  57. package/esm/TimeClock/ClockNumbers.d.ts +1 -1
  58. package/esm/TimeClock/ClockPointer.d.ts +1 -1
  59. package/esm/TimePicker/TimePicker.js +8 -2
  60. package/esm/TimePicker/TimePickerToolbar.d.ts +1 -2
  61. package/esm/TimePicker/TimePickerToolbar.js +2 -2
  62. package/esm/dateViewRenderers/dateViewRenderers.d.ts +1 -2
  63. package/esm/dateViewRenderers/dateViewRenderers.js +0 -1
  64. package/esm/index.js +1 -1
  65. package/esm/internals/components/PickerFieldUI.d.ts +2 -2
  66. package/esm/internals/components/PickerPopper/PickerPopper.d.ts +1 -1
  67. package/esm/internals/components/PickerProvider.d.ts +9 -1
  68. package/esm/internals/components/PickersModalDialog.d.ts +1 -1
  69. package/esm/internals/demo/DemoContainer.d.ts +2 -2
  70. package/esm/internals/hooks/useDesktopPicker/useDesktopPicker.d.ts +1 -2
  71. package/esm/internals/hooks/useDesktopPicker/useDesktopPicker.js +0 -1
  72. package/esm/internals/hooks/useField/useFieldState.js +19 -10
  73. package/esm/internals/hooks/useField/useFieldV6TextField.js +1 -0
  74. package/esm/internals/hooks/useMobilePicker/useMobilePicker.d.ts +1 -2
  75. package/esm/internals/hooks/useMobilePicker/useMobilePicker.js +0 -1
  76. package/esm/internals/hooks/usePicker/hooks/useValueAndOpenStates.js +14 -2
  77. package/esm/internals/hooks/usePicker/usePicker.js +13 -5
  78. package/esm/internals/hooks/usePicker/usePicker.types.d.ts +8 -2
  79. package/esm/internals/hooks/useStaticPicker/useStaticPicker.d.ts +1 -2
  80. package/esm/internals/hooks/useStaticPicker/useStaticPicker.js +0 -1
  81. package/esm/models/pickers.d.ts +8 -0
  82. package/esm/timeViewRenderers/timeViewRenderers.d.ts +3 -4
  83. package/esm/timeViewRenderers/timeViewRenderers.js +0 -1
  84. package/index.js +1 -1
  85. package/internals/components/PickerFieldUI.d.ts +2 -2
  86. package/internals/components/PickerPopper/PickerPopper.d.ts +1 -1
  87. package/internals/components/PickerProvider.d.ts +9 -1
  88. package/internals/components/PickersModalDialog.d.ts +1 -1
  89. package/internals/demo/DemoContainer.d.ts +2 -2
  90. package/internals/hooks/useDesktopPicker/useDesktopPicker.d.ts +1 -2
  91. package/internals/hooks/useDesktopPicker/useDesktopPicker.js +0 -2
  92. package/internals/hooks/useField/useFieldState.js +19 -10
  93. package/internals/hooks/useField/useFieldV6TextField.js +1 -0
  94. package/internals/hooks/useMobilePicker/useMobilePicker.d.ts +1 -2
  95. package/internals/hooks/useMobilePicker/useMobilePicker.js +0 -2
  96. package/internals/hooks/usePicker/hooks/useValueAndOpenStates.js +14 -2
  97. package/internals/hooks/usePicker/usePicker.js +13 -5
  98. package/internals/hooks/usePicker/usePicker.types.d.ts +8 -2
  99. package/internals/hooks/useStaticPicker/useStaticPicker.d.ts +1 -2
  100. package/internals/hooks/useStaticPicker/useStaticPicker.js +0 -2
  101. package/models/pickers.d.ts +8 -0
  102. package/package.json +3 -3
  103. package/timeViewRenderers/timeViewRenderers.d.ts +3 -4
  104. package/timeViewRenderers/timeViewRenderers.js +0 -2
@@ -22,7 +22,7 @@ export declare const PickerFieldUIContext: React.Context<PickerFieldUIContextVal
22
22
  * Adds the button to open the Picker and the button to clear the value of the field.
23
23
  * @ignore - internal component.
24
24
  */
25
- export declare function PickerFieldUI<TEnableAccessibleFieldDOMStructure extends boolean, TProps extends UseFieldProps<TEnableAccessibleFieldDOMStructure>>(props: PickerFieldUIProps<TEnableAccessibleFieldDOMStructure, TProps>): React.JSX.Element;
25
+ export declare function PickerFieldUI<TEnableAccessibleFieldDOMStructure extends boolean, TProps extends UseFieldProps<TEnableAccessibleFieldDOMStructure>>(props: PickerFieldUIProps<TEnableAccessibleFieldDOMStructure, TProps>): import("react/jsx-runtime").JSX.Element;
26
26
  export interface ExportedPickerFieldUIProps {
27
27
  /**
28
28
  * If `true`, a clear button will be shown in the field allowing value clearing.
@@ -123,7 +123,7 @@ interface UseFieldTextFieldPropsParameters {
123
123
  ref: React.Ref<HTMLDivElement>;
124
124
  externalForwardedProps: any;
125
125
  }
126
- export declare function PickerFieldUIContextProvider(props: PickerFieldUIContextProviderProps): React.JSX.Element;
126
+ export declare function PickerFieldUIContextProvider(props: PickerFieldUIContextProviderProps): import("react/jsx-runtime").JSX.Element;
127
127
  interface PickerFieldUIContextProviderProps {
128
128
  children: React.ReactNode;
129
129
  inputRef: React.Ref<HTMLInputElement> | undefined;
@@ -64,4 +64,4 @@ export interface PickerPopperProps extends ExportedPickerPopperProps {
64
64
  slots?: PickerPopperSlots;
65
65
  slotProps?: PickerPopperSlotProps;
66
66
  }
67
- export declare function PickerPopper(inProps: PickerPopperProps): React.JSX.Element;
67
+ export declare function PickerPopper(inProps: PickerPopperProps): import("react/jsx-runtime").JSX.Element;
@@ -16,7 +16,7 @@ export declare const PickerPrivateContext: React.Context<PickerPrivateContextVal
16
16
  *
17
17
  * @ignore - do not document.
18
18
  */
19
- export declare function PickerProvider<TValue extends PickerValidValue>(props: PickerProviderProps<TValue>): React.JSX.Element;
19
+ export declare function PickerProvider<TValue extends PickerValidValue>(props: PickerProviderProps<TValue>): import("react/jsx-runtime").JSX.Element;
20
20
  export interface PickerProviderProps<TValue extends PickerValidValue> {
21
21
  contextValue: PickerContextValue<any, any, any>;
22
22
  actionsContextValue: PickerActionsContextValue<any, any, any>;
@@ -232,6 +232,14 @@ export interface SetValueActionOptions<TError = string | null> {
232
232
  * It should not be defined if the change does not come from a shortcut.
233
233
  */
234
234
  shortcut?: PickersShortcutsItemContext;
235
+ /**
236
+ * Source of the change.
237
+ * Simplified to one of the following values:
238
+ * - 'field' (changes coming from the text field)
239
+ * - 'view' (any interaction inside the picker UI: views, toolbar, action bar, shortcuts, etc.)
240
+ * - 'unknown' (unspecified or third-party triggers)
241
+ */
242
+ source?: 'field' | 'view' | 'unknown';
235
243
  /**
236
244
  * Whether the value should call `onChange` and `onAccept` when the value is not controlled and has never been modified.
237
245
  * If `true`, the `onChange` and `onAccept` callback will only be fired if the value has been modified (and is not equal to the last published value).
@@ -45,4 +45,4 @@ export interface PickersModalDialogProps {
45
45
  */
46
46
  slotProps?: PickersModalDialogSlotProps;
47
47
  }
48
- export declare function PickersModalDialog(props: React.PropsWithChildren<PickersModalDialogProps>): React.JSX.Element;
48
+ export declare function PickersModalDialog(props: React.PropsWithChildren<PickersModalDialogProps>): import("react/jsx-runtime").JSX.Element;
@@ -14,7 +14,7 @@ interface DemoItemProps extends Omit<StackProps, 'component'> {
14
14
  * WARNING: This is an internal component used in documentation to achieve a desired layout.
15
15
  * Please do not use it in your application.
16
16
  */
17
- export declare function DemoItem(props: DemoItemProps): React.JSX.Element;
17
+ export declare function DemoItem(props: DemoItemProps): import("react/jsx-runtime").JSX.Element;
18
18
  export declare namespace DemoItem {
19
19
  var displayName: string;
20
20
  }
@@ -22,5 +22,5 @@ export declare namespace DemoItem {
22
22
  * WARNING: This is an internal component used in documentation to achieve a desired layout.
23
23
  * Please do not use it in your application.
24
24
  */
25
- export declare function DemoContainer(props: DemoGridProps): React.JSX.Element;
25
+ export declare function DemoContainer(props: DemoGridProps): import("react/jsx-runtime").JSX.Element;
26
26
  export {};
@@ -1,4 +1,3 @@
1
- import * as React from 'react';
2
1
  import { UseDesktopPickerParams, UseDesktopPickerProps } from "./useDesktopPicker.types.js";
3
2
  import { DateOrTimeViewWithMeridiem } from "../../models/index.js";
4
3
  /**
@@ -12,5 +11,5 @@ export declare const useDesktopPicker: <TView extends DateOrTimeViewWithMeridiem
12
11
  steps,
13
12
  ...pickerParams
14
13
  }: UseDesktopPickerParams<TView, TEnableAccessibleFieldDOMStructure, TExternalProps>) => {
15
- renderPicker: () => React.JSX.Element;
14
+ renderPicker: () => import("react/jsx-runtime").JSX.Element;
16
15
  };
@@ -2,7 +2,6 @@ import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
3
3
  const _excluded = ["props", "steps"],
4
4
  _excluded2 = ["ownerState"];
5
- import * as React from 'react';
6
5
  import useSlotProps from '@mui/utils/useSlotProps';
7
6
  import { PickerPopper } from "../../components/PickerPopper/PickerPopper.js";
8
7
  import { usePicker } from "../usePicker/index.js";
@@ -68,14 +68,6 @@ export const useFieldState = parameters => {
68
68
  value,
69
69
  onError: internalPropsWithDefaults.onError
70
70
  });
71
- const error = React.useMemo(() => {
72
- // only override when `error` is undefined.
73
- // in case of multi input fields, the `error` value is provided externally and will always be defined.
74
- if (errorProp !== undefined) {
75
- return errorProp;
76
- }
77
- return hasValidationError;
78
- }, [hasValidationError, errorProp]);
79
71
  const localizedDigits = React.useMemo(() => getLocalizedDigits(adapter), [adapter]);
80
72
  const sectionsValueBoundaries = React.useMemo(() => getSectionsBoundaries(adapter, localizedDigits, timezone), [adapter, localizedDigits, timezone]);
81
73
  const getSectionsFromValue = React.useCallback(valueToAnalyze => fieldValueManager.getSectionsFromValue(valueToAnalyze, date => buildSectionsFromFormat({
@@ -130,6 +122,22 @@ export const useFieldState = parameters => {
130
122
  const activeSectionIndex = parsedSelectedSections === 'all' ? 0 : parsedSelectedSections;
131
123
  const sectionOrder = React.useMemo(() => getSectionOrder(state.sections, isRtl && !enableAccessibleFieldDOMStructure), [state.sections, isRtl, enableAccessibleFieldDOMStructure]);
132
124
  const areAllSectionsEmpty = React.useMemo(() => state.sections.every(section => section.value === ''), [state.sections]);
125
+
126
+ // When the field loses focus (no active section), consider partially filled sections as invalid.
127
+ // This enforces that the field must be entirely filled or entirely empty on blur.
128
+ const hasPartiallyFilledSectionsOnBlur = React.useMemo(() => {
129
+ if (activeSectionIndex != null) {
130
+ return false;
131
+ }
132
+ const filledSections = state.sections.filter(s => s.value !== '');
133
+ return filledSections.length > 0 && state.sections.length - filledSections.length > 0;
134
+ }, [state.sections, activeSectionIndex]);
135
+ const error = React.useMemo(() => {
136
+ if (errorProp !== undefined) {
137
+ return errorProp;
138
+ }
139
+ return hasValidationError || hasPartiallyFilledSectionsOnBlur;
140
+ }, [hasValidationError, hasPartiallyFilledSectionsOnBlur, errorProp]);
133
141
  const publishValue = newValue => {
134
142
  const context = {
135
143
  validationError: validator({
@@ -278,11 +286,12 @@ export const useFieldState = parameters => {
278
286
 
279
287
  /**
280
288
  * If the previous date is not null,
281
- * Then we publish the date as `null`.
289
+ * Then we publish the date as `newActiveDate to prevent error state oscillation`.
290
+ * @link: https://github.com/mui/mui-x/issues/17967
282
291
  */
283
292
  if (activeDate != null) {
284
293
  setSectionUpdateToApplyOnNextInvalidDate(newSectionValue);
285
- return publishValue(fieldValueManager.updateDateInValue(value, section, null));
294
+ publishValue(fieldValueManager.updateDateInValue(value, section, newActiveDate));
286
295
  }
287
296
 
288
297
  /**
@@ -384,6 +384,7 @@ export const useFieldV6TextField = parameters => {
384
384
  }));
385
385
  return _extends({}, forwardedProps, {
386
386
  error,
387
+ 'aria-invalid': error,
387
388
  clearable: Boolean(clearable && !areAllSectionsEmpty && !readOnly && !disabled),
388
389
  onBlur: handleContainerBlur,
389
390
  onClick: handleInputClick,
@@ -1,4 +1,3 @@
1
- import * as React from 'react';
2
1
  import { UseMobilePickerParams, UseMobilePickerProps } from "./useMobilePicker.types.js";
3
2
  import { DateOrTimeViewWithMeridiem } from "../../models/index.js";
4
3
  /**
@@ -12,5 +11,5 @@ export declare const useMobilePicker: <TView extends DateOrTimeViewWithMeridiem,
12
11
  steps,
13
12
  ...pickerParams
14
13
  }: UseMobilePickerParams<TView, TEnableAccessibleFieldDOMStructure, TExternalProps>) => {
15
- renderPicker: () => React.JSX.Element;
14
+ renderPicker: () => import("react/jsx-runtime").JSX.Element;
16
15
  };
@@ -2,7 +2,6 @@ import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
3
3
  const _excluded = ["props", "steps"],
4
4
  _excluded2 = ["ownerState"];
5
- import * as React from 'react';
6
5
  import useSlotProps from '@mui/utils/useSlotProps';
7
6
  import { PickersModalDialog } from "../../components/PickersModalDialog.js";
8
7
  import { usePicker } from "../usePicker/index.js";
@@ -105,6 +105,7 @@ export function useValueAndOpenStates(parameters) {
105
105
  skipPublicationIfPristine = false,
106
106
  validationError,
107
107
  shortcut,
108
+ source,
108
109
  shouldClose = changeImportance === 'accept'
109
110
  } = options ?? {};
110
111
  let shouldFireOnChange;
@@ -127,8 +128,18 @@ export function useValueAndOpenStates(parameters) {
127
128
  let cachedContext = null;
128
129
  const getContext = () => {
129
130
  if (!cachedContext) {
131
+ let inferredSource;
132
+ if (source) {
133
+ inferredSource = source;
134
+ } else if (shortcut) {
135
+ inferredSource = 'view';
136
+ } else {
137
+ // Default to unknown when not explicitly tagged by a picker call site
138
+ inferredSource = 'unknown';
139
+ }
130
140
  cachedContext = {
131
- validationError: validationError == null ? getValidationErrorForNewValue(newValue) : validationError
141
+ validationError: validationError == null ? getValidationErrorForNewValue(newValue) : validationError,
142
+ source: inferredSource
132
143
  };
133
144
  if (shortcut) {
134
145
  cachedContext.shortcut = shortcut;
@@ -165,7 +176,8 @@ export function useValueAndOpenStates(parameters) {
165
176
  return;
166
177
  }
167
178
  setValue(newValue, {
168
- changeImportance: selectionState === 'finish' && closeOnSelect ? 'accept' : 'set'
179
+ changeImportance: selectionState === 'finish' && closeOnSelect ? 'accept' : 'set',
180
+ source: 'view'
169
181
  });
170
182
  });
171
183
 
@@ -111,15 +111,23 @@ export const usePicker = ({
111
111
  autoFocus: autoFocusView,
112
112
  getStepNavigation
113
113
  });
114
- const clearValue = useEventCallback(() => setValue(valueManager.emptyValue));
115
- const setValueToToday = useEventCallback(() => setValue(valueManager.getTodayValue(adapter, timezone, valueType)));
116
- const acceptValueChanges = useEventCallback(() => setValue(value));
114
+ const clearValue = useEventCallback(() => setValue(valueManager.emptyValue, {
115
+ source: 'view'
116
+ }));
117
+ const setValueToToday = useEventCallback(() => setValue(valueManager.getTodayValue(adapter, timezone, valueType), {
118
+ source: 'view'
119
+ }));
120
+ const acceptValueChanges = useEventCallback(() => setValue(value, {
121
+ source: 'view'
122
+ }));
117
123
  const cancelValueChanges = useEventCallback(() => setValue(state.lastCommittedValue, {
118
- skipPublicationIfPristine: true
124
+ skipPublicationIfPristine: true,
125
+ source: 'view'
119
126
  }));
120
127
  const dismissViews = useEventCallback(() => {
121
128
  setValue(value, {
122
- skipPublicationIfPristine: true
129
+ skipPublicationIfPristine: true,
130
+ source: 'view'
123
131
  });
124
132
  });
125
133
  const {
@@ -28,7 +28,10 @@ export interface UsePickerBaseProps<TValue extends PickerValidValue, TView exten
28
28
  * @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value.
29
29
  * @template TError The validation error type. It will be either `string` or a `null`. It can be in `[start, end]` format in case of range value.
30
30
  * @param {TValue} value The new value.
31
- * @param {FieldChangeHandlerContext<TError>} context The context containing the validation result of the current value.
31
+ * @param {FieldChangeHandlerContext<TError>} context Context about this change:
32
+ * - `validationError`: validation result of the current value
33
+ * - `source`: source of the change. One of 'field' | 'view' | 'unknown'
34
+ * - `shortcut` (optional): the shortcut metadata if the change was triggered by a shortcut selection
32
35
  */
33
36
  onChange?: (value: TValue, context: PickerChangeHandlerContext<TError>) => void;
34
37
  /**
@@ -36,7 +39,10 @@ export interface UsePickerBaseProps<TValue extends PickerValidValue, TView exten
36
39
  * @template TValue The value type. It will be the same type as `value` or `null`. It can be in `[start, end]` format in case of range value.
37
40
  * @template TError The validation error type. It will be either `string` or a `null`. It can be in `[start, end]` format in case of range value.
38
41
  * @param {TValue} value The value that was just accepted.
39
- * @param {FieldChangeHandlerContext<TError>} context The context containing the validation result of the current value.
42
+ * @param {FieldChangeHandlerContext<TError>} context Context about this acceptance:
43
+ * - `validationError`: validation result of the current value
44
+ * - `source`: source of the acceptance. One of 'field' | 'picker' | 'unknown'
45
+ * - `shortcut` (optional): the shortcut metadata if the value was accepted via a shortcut selection
40
46
  */
41
47
  onAccept?: (value: TValue, context: PickerChangeHandlerContext<TError>) => void;
42
48
  /**
@@ -1,4 +1,3 @@
1
- import * as React from 'react';
2
1
  import { UseStaticPickerParams, UseStaticPickerProps } from "./useStaticPicker.types.js";
3
2
  import { DateOrTimeViewWithMeridiem } from "../../models/index.js";
4
3
  /**
@@ -12,5 +11,5 @@ export declare const useStaticPicker: <TView extends DateOrTimeViewWithMeridiem,
12
11
  steps,
13
12
  ...pickerParams
14
13
  }: UseStaticPickerParams<TView, TExternalProps>) => {
15
- renderPicker: () => React.JSX.Element;
14
+ renderPicker: () => import("react/jsx-runtime").JSX.Element;
16
15
  };
@@ -1,7 +1,6 @@
1
1
  import _extends from "@babel/runtime/helpers/esm/extends";
2
2
  import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
3
3
  const _excluded = ["props", "steps"];
4
- import * as React from 'react';
5
4
  import clsx from 'clsx';
6
5
  import { styled } from '@mui/material/styles';
7
6
  import { usePicker } from "../usePicker/index.js";
@@ -2,6 +2,14 @@ import { PickerOrientation, PickerVariant } from "../internals/models/common.js"
2
2
  import type { PickersShortcutsItemContext } from "../PickersShortcuts/index.js";
3
3
  export interface PickerChangeHandlerContext<TError> {
4
4
  validationError: TError;
5
+ /**
6
+ * Source of the change that triggered `onChange` or `onAccept`.
7
+ * Simplified to one of the following values:
8
+ * - 'field' (changes coming from the text field)
9
+ * - 'view' (any interaction inside the picker UI: views, toolbar, action bar, shortcuts, etc.)
10
+ * - 'unknown' (unspecified or third-party triggers)
11
+ */
12
+ source: 'field' | 'view' | 'unknown';
5
13
  /**
6
14
  * Shortcut causing this `onChange` or `onAccept` call.
7
15
  * If the call has not been caused by a shortcut selection, this property will be `undefined`.
@@ -1,4 +1,3 @@
1
- import * as React from 'react';
2
1
  import { TimeClockProps } from "../TimeClock/index.js";
3
2
  import { TimeView } from "../models/index.js";
4
3
  import { DigitalClockProps } from "../DigitalClock/index.js";
@@ -40,7 +39,7 @@ export declare const renderTimeViewClock: ({
40
39
  showViewSwitcher,
41
40
  disableIgnoringDatePartForTimeValidation,
42
41
  timezone
43
- }: TimeViewRendererProps<TimeView, TimeClockProps<TimeView>>) => React.JSX.Element;
42
+ }: TimeViewRendererProps<TimeView, TimeClockProps<TimeView>>) => import("react/jsx-runtime").JSX.Element;
44
43
  export declare const renderDigitalClockTimeView: ({
45
44
  view,
46
45
  onViewChange,
@@ -70,7 +69,7 @@ export declare const renderDigitalClockTimeView: ({
70
69
  timeSteps,
71
70
  skipDisabled,
72
71
  timezone
73
- }: TimeViewRendererProps<Extract<TimeView, "hours">, Omit<DigitalClockProps, "timeStep"> & Pick<TimePickerProps, "timeSteps">>) => React.JSX.Element;
72
+ }: TimeViewRendererProps<Extract<TimeView, "hours">, Omit<DigitalClockProps, "timeStep"> & Pick<TimePickerProps, "timeSteps">>) => import("react/jsx-runtime").JSX.Element;
74
73
  export declare const renderMultiSectionDigitalClockTimeView: ({
75
74
  view,
76
75
  onViewChange,
@@ -100,4 +99,4 @@ export declare const renderMultiSectionDigitalClockTimeView: ({
100
99
  timeSteps,
101
100
  skipDisabled,
102
101
  timezone
103
- }: TimeViewRendererProps<TimeViewWithMeridiem, MultiSectionDigitalClockProps>) => React.JSX.Element;
102
+ }: TimeViewRendererProps<TimeViewWithMeridiem, MultiSectionDigitalClockProps>) => import("react/jsx-runtime").JSX.Element;
@@ -1,4 +1,3 @@
1
- import * as React from 'react';
2
1
  import { TimeClock } from "../TimeClock/index.js";
3
2
  import { DigitalClock } from "../DigitalClock/index.js";
4
3
  import { MultiSectionDigitalClock } from "../MultiSectionDigitalClock/index.js";
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-date-pickers v8.16.0
2
+ * @mui/x-date-pickers v8.18.0
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -22,7 +22,7 @@ export declare const PickerFieldUIContext: React.Context<PickerFieldUIContextVal
22
22
  * Adds the button to open the Picker and the button to clear the value of the field.
23
23
  * @ignore - internal component.
24
24
  */
25
- export declare function PickerFieldUI<TEnableAccessibleFieldDOMStructure extends boolean, TProps extends UseFieldProps<TEnableAccessibleFieldDOMStructure>>(props: PickerFieldUIProps<TEnableAccessibleFieldDOMStructure, TProps>): React.JSX.Element;
25
+ export declare function PickerFieldUI<TEnableAccessibleFieldDOMStructure extends boolean, TProps extends UseFieldProps<TEnableAccessibleFieldDOMStructure>>(props: PickerFieldUIProps<TEnableAccessibleFieldDOMStructure, TProps>): import("react/jsx-runtime").JSX.Element;
26
26
  export interface ExportedPickerFieldUIProps {
27
27
  /**
28
28
  * If `true`, a clear button will be shown in the field allowing value clearing.
@@ -123,7 +123,7 @@ interface UseFieldTextFieldPropsParameters {
123
123
  ref: React.Ref<HTMLDivElement>;
124
124
  externalForwardedProps: any;
125
125
  }
126
- export declare function PickerFieldUIContextProvider(props: PickerFieldUIContextProviderProps): React.JSX.Element;
126
+ export declare function PickerFieldUIContextProvider(props: PickerFieldUIContextProviderProps): import("react/jsx-runtime").JSX.Element;
127
127
  interface PickerFieldUIContextProviderProps {
128
128
  children: React.ReactNode;
129
129
  inputRef: React.Ref<HTMLInputElement> | undefined;
@@ -64,4 +64,4 @@ export interface PickerPopperProps extends ExportedPickerPopperProps {
64
64
  slots?: PickerPopperSlots;
65
65
  slotProps?: PickerPopperSlotProps;
66
66
  }
67
- export declare function PickerPopper(inProps: PickerPopperProps): React.JSX.Element;
67
+ export declare function PickerPopper(inProps: PickerPopperProps): import("react/jsx-runtime").JSX.Element;
@@ -16,7 +16,7 @@ export declare const PickerPrivateContext: React.Context<PickerPrivateContextVal
16
16
  *
17
17
  * @ignore - do not document.
18
18
  */
19
- export declare function PickerProvider<TValue extends PickerValidValue>(props: PickerProviderProps<TValue>): React.JSX.Element;
19
+ export declare function PickerProvider<TValue extends PickerValidValue>(props: PickerProviderProps<TValue>): import("react/jsx-runtime").JSX.Element;
20
20
  export interface PickerProviderProps<TValue extends PickerValidValue> {
21
21
  contextValue: PickerContextValue<any, any, any>;
22
22
  actionsContextValue: PickerActionsContextValue<any, any, any>;
@@ -232,6 +232,14 @@ export interface SetValueActionOptions<TError = string | null> {
232
232
  * It should not be defined if the change does not come from a shortcut.
233
233
  */
234
234
  shortcut?: PickersShortcutsItemContext;
235
+ /**
236
+ * Source of the change.
237
+ * Simplified to one of the following values:
238
+ * - 'field' (changes coming from the text field)
239
+ * - 'view' (any interaction inside the picker UI: views, toolbar, action bar, shortcuts, etc.)
240
+ * - 'unknown' (unspecified or third-party triggers)
241
+ */
242
+ source?: 'field' | 'view' | 'unknown';
235
243
  /**
236
244
  * Whether the value should call `onChange` and `onAccept` when the value is not controlled and has never been modified.
237
245
  * If `true`, the `onChange` and `onAccept` callback will only be fired if the value has been modified (and is not equal to the last published value).
@@ -45,4 +45,4 @@ export interface PickersModalDialogProps {
45
45
  */
46
46
  slotProps?: PickersModalDialogSlotProps;
47
47
  }
48
- export declare function PickersModalDialog(props: React.PropsWithChildren<PickersModalDialogProps>): React.JSX.Element;
48
+ export declare function PickersModalDialog(props: React.PropsWithChildren<PickersModalDialogProps>): import("react/jsx-runtime").JSX.Element;
@@ -14,7 +14,7 @@ interface DemoItemProps extends Omit<StackProps, 'component'> {
14
14
  * WARNING: This is an internal component used in documentation to achieve a desired layout.
15
15
  * Please do not use it in your application.
16
16
  */
17
- export declare function DemoItem(props: DemoItemProps): React.JSX.Element;
17
+ export declare function DemoItem(props: DemoItemProps): import("react/jsx-runtime").JSX.Element;
18
18
  export declare namespace DemoItem {
19
19
  var displayName: string;
20
20
  }
@@ -22,5 +22,5 @@ export declare namespace DemoItem {
22
22
  * WARNING: This is an internal component used in documentation to achieve a desired layout.
23
23
  * Please do not use it in your application.
24
24
  */
25
- export declare function DemoContainer(props: DemoGridProps): React.JSX.Element;
25
+ export declare function DemoContainer(props: DemoGridProps): import("react/jsx-runtime").JSX.Element;
26
26
  export {};
@@ -1,4 +1,3 @@
1
- import * as React from 'react';
2
1
  import { UseDesktopPickerParams, UseDesktopPickerProps } from "./useDesktopPicker.types.js";
3
2
  import { DateOrTimeViewWithMeridiem } from "../../models/index.js";
4
3
  /**
@@ -12,5 +11,5 @@ export declare const useDesktopPicker: <TView extends DateOrTimeViewWithMeridiem
12
11
  steps,
13
12
  ...pickerParams
14
13
  }: UseDesktopPickerParams<TView, TEnableAccessibleFieldDOMStructure, TExternalProps>) => {
15
- renderPicker: () => React.JSX.Element;
14
+ renderPicker: () => import("react/jsx-runtime").JSX.Element;
16
15
  };
@@ -1,14 +1,12 @@
1
1
  "use strict";
2
2
 
3
3
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
- var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
5
4
  Object.defineProperty(exports, "__esModule", {
6
5
  value: true
7
6
  });
8
7
  exports.useDesktopPicker = void 0;
9
8
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
10
9
  var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
11
- var React = _interopRequireWildcard(require("react"));
12
10
  var _useSlotProps2 = _interopRequireDefault(require("@mui/utils/useSlotProps"));
13
11
  var _PickerPopper = require("../../components/PickerPopper/PickerPopper");
14
12
  var _usePicker = require("../usePicker");
@@ -75,14 +75,6 @@ const useFieldState = parameters => {
75
75
  value,
76
76
  onError: internalPropsWithDefaults.onError
77
77
  });
78
- const error = React.useMemo(() => {
79
- // only override when `error` is undefined.
80
- // in case of multi input fields, the `error` value is provided externally and will always be defined.
81
- if (errorProp !== undefined) {
82
- return errorProp;
83
- }
84
- return hasValidationError;
85
- }, [hasValidationError, errorProp]);
86
78
  const localizedDigits = React.useMemo(() => (0, _useField.getLocalizedDigits)(adapter), [adapter]);
87
79
  const sectionsValueBoundaries = React.useMemo(() => (0, _useField.getSectionsBoundaries)(adapter, localizedDigits, timezone), [adapter, localizedDigits, timezone]);
88
80
  const getSectionsFromValue = React.useCallback(valueToAnalyze => fieldValueManager.getSectionsFromValue(valueToAnalyze, date => (0, _buildSectionsFromFormat.buildSectionsFromFormat)({
@@ -137,6 +129,22 @@ const useFieldState = parameters => {
137
129
  const activeSectionIndex = parsedSelectedSections === 'all' ? 0 : parsedSelectedSections;
138
130
  const sectionOrder = React.useMemo(() => (0, _useField.getSectionOrder)(state.sections, isRtl && !enableAccessibleFieldDOMStructure), [state.sections, isRtl, enableAccessibleFieldDOMStructure]);
139
131
  const areAllSectionsEmpty = React.useMemo(() => state.sections.every(section => section.value === ''), [state.sections]);
132
+
133
+ // When the field loses focus (no active section), consider partially filled sections as invalid.
134
+ // This enforces that the field must be entirely filled or entirely empty on blur.
135
+ const hasPartiallyFilledSectionsOnBlur = React.useMemo(() => {
136
+ if (activeSectionIndex != null) {
137
+ return false;
138
+ }
139
+ const filledSections = state.sections.filter(s => s.value !== '');
140
+ return filledSections.length > 0 && state.sections.length - filledSections.length > 0;
141
+ }, [state.sections, activeSectionIndex]);
142
+ const error = React.useMemo(() => {
143
+ if (errorProp !== undefined) {
144
+ return errorProp;
145
+ }
146
+ return hasValidationError || hasPartiallyFilledSectionsOnBlur;
147
+ }, [hasValidationError, hasPartiallyFilledSectionsOnBlur, errorProp]);
140
148
  const publishValue = newValue => {
141
149
  const context = {
142
150
  validationError: validator({
@@ -285,11 +293,12 @@ const useFieldState = parameters => {
285
293
 
286
294
  /**
287
295
  * If the previous date is not null,
288
- * Then we publish the date as `null`.
296
+ * Then we publish the date as `newActiveDate to prevent error state oscillation`.
297
+ * @link: https://github.com/mui/mui-x/issues/17967
289
298
  */
290
299
  if (activeDate != null) {
291
300
  setSectionUpdateToApplyOnNextInvalidDate(newSectionValue);
292
- return publishValue(fieldValueManager.updateDateInValue(value, section, null));
301
+ publishValue(fieldValueManager.updateDateInValue(value, section, newActiveDate));
293
302
  }
294
303
 
295
304
  /**
@@ -392,6 +392,7 @@ const useFieldV6TextField = parameters => {
392
392
  }));
393
393
  return (0, _extends2.default)({}, forwardedProps, {
394
394
  error,
395
+ 'aria-invalid': error,
395
396
  clearable: Boolean(clearable && !areAllSectionsEmpty && !readOnly && !disabled),
396
397
  onBlur: handleContainerBlur,
397
398
  onClick: handleInputClick,
@@ -1,4 +1,3 @@
1
- import * as React from 'react';
2
1
  import { UseMobilePickerParams, UseMobilePickerProps } from "./useMobilePicker.types.js";
3
2
  import { DateOrTimeViewWithMeridiem } from "../../models/index.js";
4
3
  /**
@@ -12,5 +11,5 @@ export declare const useMobilePicker: <TView extends DateOrTimeViewWithMeridiem,
12
11
  steps,
13
12
  ...pickerParams
14
13
  }: UseMobilePickerParams<TView, TEnableAccessibleFieldDOMStructure, TExternalProps>) => {
15
- renderPicker: () => React.JSX.Element;
14
+ renderPicker: () => import("react/jsx-runtime").JSX.Element;
16
15
  };
@@ -1,14 +1,12 @@
1
1
  "use strict";
2
2
 
3
3
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
- var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
5
4
  Object.defineProperty(exports, "__esModule", {
6
5
  value: true
7
6
  });
8
7
  exports.useMobilePicker = void 0;
9
8
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
10
9
  var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
11
- var React = _interopRequireWildcard(require("react"));
12
10
  var _useSlotProps2 = _interopRequireDefault(require("@mui/utils/useSlotProps"));
13
11
  var _PickersModalDialog = require("../../components/PickersModalDialog");
14
12
  var _usePicker = require("../usePicker");
@@ -112,6 +112,7 @@ function useValueAndOpenStates(parameters) {
112
112
  skipPublicationIfPristine = false,
113
113
  validationError,
114
114
  shortcut,
115
+ source,
115
116
  shouldClose = changeImportance === 'accept'
116
117
  } = options ?? {};
117
118
  let shouldFireOnChange;
@@ -134,8 +135,18 @@ function useValueAndOpenStates(parameters) {
134
135
  let cachedContext = null;
135
136
  const getContext = () => {
136
137
  if (!cachedContext) {
138
+ let inferredSource;
139
+ if (source) {
140
+ inferredSource = source;
141
+ } else if (shortcut) {
142
+ inferredSource = 'view';
143
+ } else {
144
+ // Default to unknown when not explicitly tagged by a picker call site
145
+ inferredSource = 'unknown';
146
+ }
137
147
  cachedContext = {
138
- validationError: validationError == null ? getValidationErrorForNewValue(newValue) : validationError
148
+ validationError: validationError == null ? getValidationErrorForNewValue(newValue) : validationError,
149
+ source: inferredSource
139
150
  };
140
151
  if (shortcut) {
141
152
  cachedContext.shortcut = shortcut;
@@ -172,7 +183,8 @@ function useValueAndOpenStates(parameters) {
172
183
  return;
173
184
  }
174
185
  setValue(newValue, {
175
- changeImportance: selectionState === 'finish' && closeOnSelect ? 'accept' : 'set'
186
+ changeImportance: selectionState === 'finish' && closeOnSelect ? 'accept' : 'set',
187
+ source: 'view'
176
188
  });
177
189
  });
178
190
 
@@ -118,15 +118,23 @@ const usePicker = ({
118
118
  autoFocus: autoFocusView,
119
119
  getStepNavigation
120
120
  });
121
- const clearValue = (0, _useEventCallback.default)(() => setValue(valueManager.emptyValue));
122
- const setValueToToday = (0, _useEventCallback.default)(() => setValue(valueManager.getTodayValue(adapter, timezone, valueType)));
123
- const acceptValueChanges = (0, _useEventCallback.default)(() => setValue(value));
121
+ const clearValue = (0, _useEventCallback.default)(() => setValue(valueManager.emptyValue, {
122
+ source: 'view'
123
+ }));
124
+ const setValueToToday = (0, _useEventCallback.default)(() => setValue(valueManager.getTodayValue(adapter, timezone, valueType), {
125
+ source: 'view'
126
+ }));
127
+ const acceptValueChanges = (0, _useEventCallback.default)(() => setValue(value, {
128
+ source: 'view'
129
+ }));
124
130
  const cancelValueChanges = (0, _useEventCallback.default)(() => setValue(state.lastCommittedValue, {
125
- skipPublicationIfPristine: true
131
+ skipPublicationIfPristine: true,
132
+ source: 'view'
126
133
  }));
127
134
  const dismissViews = (0, _useEventCallback.default)(() => {
128
135
  setValue(value, {
129
- skipPublicationIfPristine: true
136
+ skipPublicationIfPristine: true,
137
+ source: 'view'
130
138
  });
131
139
  });
132
140
  const {