UNPKG

@mui/x-date-pickers

Version:

The community edition of the MUI X Date and Time Picker components.

363 lines (358 loc) 17.3 kB
"use strict"; 'use client'; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.PickerFieldUI = PickerFieldUI; exports.PickerFieldUIContext = void 0; exports.PickerFieldUIContextProvider = PickerFieldUIContextProvider; exports.cleanFieldResponse = void 0; exports.mergeSlotProps = mergeSlotProps; exports.useFieldTextFieldProps = useFieldTextFieldProps; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose")); var React = _interopRequireWildcard(require("react")); var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallback")); var _useForkRef = _interopRequireDefault(require("@mui/utils/useForkRef")); var _resolveComponentProps = _interopRequireDefault(require("@mui/utils/resolveComponentProps")); var _IconButton = _interopRequireDefault(require("@mui/material/IconButton")); var _InputAdornment = _interopRequireDefault(require("@mui/material/InputAdornment")); var _useSlotProps5 = _interopRequireDefault(require("@mui/utils/useSlotProps")); var _warning = require("@mui/x-internals/warning"); var _useFieldOwnerState = require("../hooks/useFieldOwnerState"); var _hooks = require("../../hooks"); var _icons = require("../../icons"); var _useNullablePickerContext = require("../hooks/useNullablePickerContext"); var _PickersTextField = require("../../PickersTextField"); var _jsxRuntime = require("react/jsx-runtime"); const _excluded = ["readOnly", "onClear", "clearable", "clearButtonPosition", "openPickerButtonPosition", "openPickerAriaLabel", "InputProps", "inputProps", "InputLabelProps", "FormHelperTextProps"], _excluded2 = ["ownerState"], _excluded3 = ["ownerState"], _excluded4 = ["ownerState"], _excluded5 = ["ownerState"], _excluded6 = ["InputProps", "inputProps", "InputLabelProps", "FormHelperTextProps"]; const cleanFieldResponse = fieldResponse => { const _ref = fieldResponse, { readOnly, onClear, clearable, clearButtonPosition, openPickerButtonPosition, openPickerAriaLabel, // TODO v10: remove // Explicitly discard legacy props that are no longer supported on `PickersTextField`. // Without this, any leftover values would silently leak into `...other` and end up spread // as unknown attributes on the underlying form control. InputProps: legacyInputProps, inputProps: legacyHtmlInputProps, InputLabelProps: legacyInputLabelProps, FormHelperTextProps: legacyFormHelperTextProps } = _ref, other = (0, _objectWithoutPropertiesLoose2.default)(_ref, _excluded); if (process.env.NODE_ENV !== 'production') { if (legacyInputProps || legacyHtmlInputProps || legacyInputLabelProps || legacyFormHelperTextProps) { (0, _warning.warnOnce)(['MUI X: The `InputProps`, `inputProps`, `InputLabelProps` and `FormHelperTextProps` props are no longer supported on Picker / Field components.', 'They have been silently dropped because they would otherwise be forwarded as unknown attributes on the underlying form control.', 'Use the `slotProps` shape instead (`slotProps.input`, `slotProps.htmlInput`, `slotProps.inputLabel`, `slotProps.formHelperText`).', 'See https://mui.com/x/migration/migration-pickers-v8/#textfield-props for migration details.']); } } return { clearable, onClear, clearButtonPosition, openPickerButtonPosition, openPickerAriaLabel, textFieldProps: (0, _extends2.default)({}, other, { slotProps: (0, _extends2.default)({}, other?.slotProps, { input: (0, _extends2.default)({}, other?.slotProps?.input, { readOnly }) }) }) }; }; exports.cleanFieldResponse = cleanFieldResponse; const PickerFieldUIContext = exports.PickerFieldUIContext = /*#__PURE__*/React.createContext({ slots: {}, slotProps: {}, inputRef: undefined }); /** * Adds the button to open the Picker and the button to clear the value of the field. * @ignore - internal component. */ if (process.env.NODE_ENV !== "production") PickerFieldUIContext.displayName = "PickerFieldUIContext"; function PickerFieldUI(props) { const { fieldResponse, defaultOpenPickerIcon } = props; const translations = (0, _hooks.usePickerTranslations)(); const pickerContext = (0, _useNullablePickerContext.useNullablePickerContext)(); const pickerFieldUIContext = React.useContext(PickerFieldUIContext); const { textFieldProps, onClear, clearable, openPickerAriaLabel, clearButtonPosition: clearButtonPositionProp = 'end', openPickerButtonPosition: openPickerButtonPositionProp = 'end' } = cleanFieldResponse(fieldResponse); const ownerState = (0, _useFieldOwnerState.useFieldOwnerState)(textFieldProps); const handleClickOpeningButton = (0, _useEventCallback.default)(event => { event.preventDefault(); // Force open instead of toggling to avoid conflicts with field-level open-on-focus logic pickerContext?.setOpen(true); }); const triggerStatus = pickerContext ? pickerContext.triggerStatus : 'hidden'; const clearButtonPosition = clearable ? clearButtonPositionProp : null; const openPickerButtonPosition = triggerStatus !== 'hidden' ? openPickerButtonPositionProp : null; const TextField = pickerFieldUIContext.slots.textField ?? _PickersTextField.PickersTextField; const InputAdornment = pickerFieldUIContext.slots.inputAdornment ?? _InputAdornment.default; const _useSlotProps = (0, _useSlotProps5.default)({ elementType: InputAdornment, externalSlotProps: pickerFieldUIContext.slotProps.inputAdornment, additionalProps: { position: 'start' }, ownerState: (0, _extends2.default)({}, ownerState, { position: 'start' }) }), startInputAdornmentProps = (0, _objectWithoutPropertiesLoose2.default)(_useSlotProps, _excluded2); const _useSlotProps2 = (0, _useSlotProps5.default)({ elementType: InputAdornment, externalSlotProps: pickerFieldUIContext.slotProps.inputAdornment, additionalProps: { position: 'end' }, ownerState: (0, _extends2.default)({}, ownerState, { position: 'end' }) }), endInputAdornmentProps = (0, _objectWithoutPropertiesLoose2.default)(_useSlotProps2, _excluded3); const OpenPickerButton = pickerFieldUIContext.slots.openPickerButton ?? _IconButton.default; // We don't want to forward the `ownerState` to the `<IconButton />` component, see mui/material-ui#34056 const _useSlotProps3 = (0, _useSlotProps5.default)({ elementType: OpenPickerButton, externalSlotProps: pickerFieldUIContext.slotProps.openPickerButton, additionalProps: { disabled: triggerStatus === 'disabled', onClick: handleClickOpeningButton, 'aria-label': openPickerAriaLabel, // Mark this element so field handlers can ignore its events 'data-mui-picker-open-button': 'true', edge: // open button is always rendered at the edge textFieldProps.variant !== 'standard' ? openPickerButtonPosition : false }, ownerState }), openPickerButtonProps = (0, _objectWithoutPropertiesLoose2.default)(_useSlotProps3, _excluded4); const OpenPickerIcon = pickerFieldUIContext.slots.openPickerIcon ?? defaultOpenPickerIcon; const openPickerIconProps = (0, _useSlotProps5.default)({ elementType: OpenPickerIcon, externalSlotProps: pickerFieldUIContext.slotProps.openPickerIcon, ownerState }); const ClearButton = pickerFieldUIContext.slots.clearButton ?? _IconButton.default; // We don't want to forward the `ownerState` to the `<IconButton />` component, see mui/material-ui#34056 const _useSlotProps4 = (0, _useSlotProps5.default)({ elementType: ClearButton, externalSlotProps: pickerFieldUIContext.slotProps.clearButton, className: 'clearButton', additionalProps: { title: translations.fieldClearLabel, tabIndex: -1, onClick: onClear, disabled: fieldResponse.disabled || fieldResponse.readOnly, edge: // clear button can only be at the edge if it's position differs from the open button textFieldProps.variant !== 'standard' && clearButtonPosition !== openPickerButtonPosition ? clearButtonPosition : false }, ownerState }), clearButtonProps = (0, _objectWithoutPropertiesLoose2.default)(_useSlotProps4, _excluded5); const ClearIcon = pickerFieldUIContext.slots.clearIcon ?? _icons.ClearIcon; const clearIconProps = (0, _useSlotProps5.default)({ elementType: ClearIcon, externalSlotProps: pickerFieldUIContext.slotProps.clearIcon, additionalProps: { fontSize: 'small' }, ownerState }); textFieldProps.ref = (0, _useForkRef.default)(textFieldProps.ref, pickerContext?.rootRef); const externalInputSlotProps = textFieldProps.slotProps?.input; const additionalInputSlotProps = {}; const forkedInputRef = (0, _useForkRef.default)(externalInputSlotProps?.ref, pickerContext?.triggerRef); if (pickerContext) { additionalInputSlotProps.ref = forkedInputRef; } if (!externalInputSlotProps?.startAdornment && (clearButtonPosition === 'start' || openPickerButtonPosition === 'start')) { additionalInputSlotProps.startAdornment = /*#__PURE__*/(0, _jsxRuntime.jsxs)(InputAdornment, (0, _extends2.default)({}, startInputAdornmentProps, { children: [openPickerButtonPosition === 'start' && /*#__PURE__*/(0, _jsxRuntime.jsx)(OpenPickerButton, (0, _extends2.default)({}, openPickerButtonProps, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(OpenPickerIcon, (0, _extends2.default)({}, openPickerIconProps)) })), clearButtonPosition === 'start' && /*#__PURE__*/(0, _jsxRuntime.jsx)(ClearButton, (0, _extends2.default)({}, clearButtonProps, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(ClearIcon, (0, _extends2.default)({}, clearIconProps)) }))] })); } if (!externalInputSlotProps?.endAdornment && (clearButtonPosition === 'end' || openPickerButtonPosition === 'end')) { additionalInputSlotProps.endAdornment = /*#__PURE__*/(0, _jsxRuntime.jsxs)(InputAdornment, (0, _extends2.default)({}, endInputAdornmentProps, { children: [clearButtonPosition === 'end' && /*#__PURE__*/(0, _jsxRuntime.jsx)(ClearButton, (0, _extends2.default)({}, clearButtonProps, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(ClearIcon, (0, _extends2.default)({}, clearIconProps)) })), openPickerButtonPosition === 'end' && /*#__PURE__*/(0, _jsxRuntime.jsx)(OpenPickerButton, (0, _extends2.default)({}, openPickerButtonProps, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(OpenPickerIcon, (0, _extends2.default)({}, openPickerIconProps)) }))] })); } // handle the case of showing custom `inputAdornment` for Field components if (!additionalInputSlotProps.endAdornment && !additionalInputSlotProps.startAdornment && pickerFieldUIContext.slots.inputAdornment) { additionalInputSlotProps.endAdornment = /*#__PURE__*/(0, _jsxRuntime.jsx)(InputAdornment, (0, _extends2.default)({}, endInputAdornmentProps)); } if (clearButtonPosition != null) { textFieldProps.sx = [{ '& .clearButton': { opacity: 1 }, '@media (pointer: fine)': { '& .clearButton': { opacity: 0 }, '&:hover, &:focus-within': { '.clearButton': { opacity: 1 } } } }, ...(Array.isArray(textFieldProps.sx) ? textFieldProps.sx : [textFieldProps.sx])]; } textFieldProps.slotProps = (0, _extends2.default)({}, textFieldProps.slotProps, { input: (0, _extends2.default)({}, externalInputSlotProps, additionalInputSlotProps) }); return /*#__PURE__*/(0, _jsxRuntime.jsx)(TextField, (0, _extends2.default)({}, textFieldProps)); } function mergeSlotProps(slotPropsA, slotPropsB) { if (!slotPropsA) { return slotPropsB; } if (!slotPropsB) { return slotPropsA; } return ownerState => { return (0, _extends2.default)({}, (0, _resolveComponentProps.default)(slotPropsB, ownerState), (0, _resolveComponentProps.default)(slotPropsA, ownerState)); }; } /** * The `textField` slot props cannot be handled inside `PickerFieldUI` because it would be a breaking change to not pass the enriched props to `useField`. * TODO v10: Remove the `textField` slot and clean this logic up. */ function useFieldTextFieldProps(parameters) { const { ref, externalForwardedProps, slotProps } = parameters; const pickerFieldUIContext = React.useContext(PickerFieldUIContext); const pickerContext = (0, _useNullablePickerContext.useNullablePickerContext)(); const ownerState = (0, _useFieldOwnerState.useFieldOwnerState)(externalForwardedProps); // TODO v10: remove // Strip the legacy `InputProps` / `inputProps` / `InputLabelProps` / `FormHelperTextProps` // before they reach `PickersTextField`, which would silently ignore them. JS users without // TypeScript checks would otherwise see their configuration vanish. const _ref2 = externalForwardedProps ?? {}, { InputProps: legacyInputProps, inputProps: legacyHtmlInputProps, InputLabelProps: legacyInputLabelProps, FormHelperTextProps: legacyFormHelperTextProps } = _ref2, sanitizedExternalForwardedProps = (0, _objectWithoutPropertiesLoose2.default)(_ref2, _excluded6); if (process.env.NODE_ENV !== 'production') { if (legacyInputProps || legacyHtmlInputProps || legacyInputLabelProps || legacyFormHelperTextProps) { (0, _warning.warnOnce)(['MUI X: Field components no longer accept the `InputProps`, `inputProps`, `InputLabelProps` and `FormHelperTextProps` props.', 'They have been dropped to avoid leaking unknown attributes onto the underlying form control.', 'Use the nested `slotProps.textField.slotProps.{input,htmlInput,inputLabel,formHelperText}` shape instead.']); } } const textFieldProps = (0, _useSlotProps5.default)({ elementType: _PickersTextField.PickersTextField, externalSlotProps: mergeSlotProps(pickerFieldUIContext.slotProps.textField, slotProps?.textField), externalForwardedProps: sanitizedExternalForwardedProps, additionalProps: { ref, sx: pickerContext?.rootSx, label: pickerContext?.label, name: pickerContext?.name, className: pickerContext?.rootClassName, inputRef: pickerFieldUIContext.inputRef }, ownerState }); // When requested, open the picker when the user focuses/clicks the field to edit if (pickerContext && pickerContext.keepOpenDuringFieldFocus && pickerContext.triggerStatus === 'enabled' && !pickerContext.open && !pickerContext.readOnly && !pickerContext.disabled) { const prevOnFocus = textFieldProps.onFocus; const prevOnMouseDown = textFieldProps.onMouseDown; const isFromOpenButton = event => { const nativeEvent = event.nativeEvent ?? event; const path = nativeEvent?.composedPath?.(); if (Array.isArray(path)) { for (const el of path) { if (el && el.getAttribute && el.getAttribute('data-mui-picker-open-button') === 'true') { return true; } } } const target = event.target; if (target && target.closest) { return Boolean(target.closest('[data-mui-picker-open-button="true"]')); } return false; }; textFieldProps.onFocus = event => { prevOnFocus?.(event); // Avoid opening if event was prevented by user code if (!event.isDefaultPrevented() && !isFromOpenButton(event)) { pickerContext.setOpen(true); } }; textFieldProps.onMouseDown = event => { prevOnMouseDown?.(event); if (!event.isDefaultPrevented() && !isFromOpenButton(event)) { pickerContext.setOpen(true); } }; } return textFieldProps; } function PickerFieldUIContextProvider(props) { const { slots = {}, slotProps = {}, inputRef, children } = props; const contextValue = React.useMemo(() => ({ inputRef, slots: { openPickerButton: slots.openPickerButton, openPickerIcon: slots.openPickerIcon, textField: slots.textField, inputAdornment: slots.inputAdornment, clearIcon: slots.clearIcon, clearButton: slots.clearButton }, slotProps: { openPickerButton: slotProps.openPickerButton, openPickerIcon: slotProps.openPickerIcon, textField: slotProps.textField, inputAdornment: slotProps.inputAdornment, clearIcon: slotProps.clearIcon, clearButton: slotProps.clearButton } }), [inputRef, slots.openPickerButton, slots.openPickerIcon, slots.textField, slots.inputAdornment, slots.clearIcon, slots.clearButton, slotProps.openPickerButton, slotProps.openPickerIcon, slotProps.textField, slotProps.inputAdornment, slotProps.clearIcon, slotProps.clearButton]); return /*#__PURE__*/(0, _jsxRuntime.jsx)(PickerFieldUIContext.Provider, { value: contextValue, children: children }); }