UNPKG

@mui/x-date-pickers

Version:

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

475 lines (473 loc) 17.3 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.PickersInputBaseSectionsContainer = exports.PickersInputBaseRoot = exports.PickersInputBase = void 0; var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose")); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var React = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _FormControl = require("@mui/material/FormControl"); var _styles = require("@mui/material/styles"); var _useForkRef = _interopRequireDefault(require("@mui/utils/useForkRef")); var _utils = require("@mui/utils"); var _composeClasses = _interopRequireDefault(require("@mui/utils/composeClasses")); var _capitalize = _interopRequireDefault(require("@mui/utils/capitalize")); var _useSlotProps = _interopRequireDefault(require("@mui/utils/useSlotProps")); var _visuallyHidden = _interopRequireDefault(require("@mui/utils/visuallyHidden")); var _pickersInputBaseClasses = require("./pickersInputBaseClasses"); var _PickersSectionList = require("../../PickersSectionList"); var _usePickerTextFieldOwnerState = require("../usePickerTextFieldOwnerState"); var _jsxRuntime = require("react/jsx-runtime"); const _excluded = ["elements", "areAllSectionsEmpty", "defaultValue", "label", "value", "onChange", "id", "autoFocus", "endAdornment", "startAdornment", "renderSuffix", "slots", "slotProps", "contentEditable", "tabIndex", "onInput", "onPaste", "onKeyDown", "fullWidth", "name", "readOnly", "inputProps", "inputRef", "sectionListRef", "onFocus", "onBlur", "classes", "ownerState"]; const round = value => Math.round(value * 1e5) / 1e5; const PickersInputBaseRoot = exports.PickersInputBaseRoot = (0, _styles.styled)('div', { name: 'MuiPickersInputBase', slot: 'Root' })(({ theme }) => (0, _extends2.default)({}, theme.typography.body1, { color: (theme.vars || theme).palette.text.primary, cursor: 'text', padding: 0, display: 'flex', justifyContent: 'flex-start', alignItems: 'center', position: 'relative', boxSizing: 'border-box', // Prevent padding issue with fullWidth. letterSpacing: `${round(0.15 / 16)}em`, variants: [{ props: { isInputInFullWidth: true }, style: { width: '100%' } }] })); const PickersInputBaseSectionsContainer = exports.PickersInputBaseSectionsContainer = (0, _styles.styled)(_PickersSectionList.Unstable_PickersSectionListRoot, { name: 'MuiPickersInputBase', slot: 'SectionsContainer' })(({ theme }) => ({ padding: '4px 0 5px', fontFamily: theme.typography.fontFamily, fontSize: 'inherit', lineHeight: '1.4375em', // 23px flexGrow: 1, outline: 'none', display: 'flex', flexWrap: 'nowrap', overflow: 'hidden', letterSpacing: 'inherit', // Baseline behavior width: '182px', variants: [{ props: { fieldDirection: 'rtl' }, style: { textAlign: 'right /*! @noflip */' } }, { props: { inputSize: 'small' }, style: { paddingTop: 1 } }, { props: { hasStartAdornment: false, isFieldFocused: false, isFieldValueEmpty: true }, style: { color: 'currentColor', opacity: 0 } }, { props: { hasStartAdornment: false, isFieldFocused: false, isFieldValueEmpty: true, inputHasLabel: false }, style: theme.vars ? { opacity: theme.vars.opacity.inputPlaceholder } : { opacity: theme.palette.mode === 'light' ? 0.42 : 0.5 } }] })); const PickersInputBaseSection = (0, _styles.styled)(_PickersSectionList.Unstable_PickersSectionListSection, { name: 'MuiPickersInputBase', slot: 'Section' })(({ theme }) => ({ fontFamily: theme.typography.fontFamily, fontSize: 'inherit', letterSpacing: 'inherit', lineHeight: '1.4375em', // 23px display: 'inline-block', whiteSpace: 'nowrap' })); const PickersInputBaseSectionContent = (0, _styles.styled)(_PickersSectionList.Unstable_PickersSectionListSectionContent, { name: 'MuiPickersInputBase', slot: 'SectionContent', overridesResolver: (props, styles) => styles.content // FIXME: Inconsistent naming with slot })(({ theme }) => ({ fontFamily: theme.typography.fontFamily, lineHeight: '1.4375em', // 23px letterSpacing: 'inherit', width: 'fit-content', outline: 'none' })); const PickersInputBaseSectionSeparator = (0, _styles.styled)(_PickersSectionList.Unstable_PickersSectionListSectionSeparator, { name: 'MuiPickersInputBase', slot: 'Separator' })(() => ({ whiteSpace: 'pre', letterSpacing: 'inherit' })); const PickersInputBaseInput = (0, _styles.styled)('input', { name: 'MuiPickersInputBase', slot: 'Input', overridesResolver: (props, styles) => styles.hiddenInput // FIXME: Inconsistent naming with slot })((0, _extends2.default)({}, _visuallyHidden.default)); const PickersInputBaseActiveBar = (0, _styles.styled)('div', { name: 'MuiPickersInputBase', slot: 'ActiveBar' })(({ theme, ownerState }) => ({ display: 'none', position: 'absolute', height: 2, bottom: 2, borderTopLeftRadius: 2, borderTopRightRadius: 2, transition: theme.transitions.create(['width', 'left'], { duration: theme.transitions.duration.shortest }), backgroundColor: (theme.vars || theme).palette.primary.main, '[data-active-range-position="start"] &, [data-active-range-position="end"] &': { display: 'block' }, '[data-active-range-position="start"] &': { left: ownerState.sectionOffsets[0] }, '[data-active-range-position="end"] &': { left: ownerState.sectionOffsets[1] } })); const useUtilityClasses = (classes, ownerState) => { const { isFieldFocused, isFieldDisabled, isFieldReadOnly, hasFieldError, inputSize, isInputInFullWidth, inputColor, hasStartAdornment, hasEndAdornment } = ownerState; const slots = { root: ['root', isFieldFocused && !isFieldDisabled && 'focused', isFieldDisabled && 'disabled', isFieldReadOnly && 'readOnly', hasFieldError && 'error', isInputInFullWidth && 'fullWidth', `color${(0, _capitalize.default)(inputColor)}`, inputSize === 'small' && 'inputSizeSmall', hasStartAdornment && 'adornedStart', hasEndAdornment && 'adornedEnd'], notchedOutline: ['notchedOutline'], input: ['input'], sectionsContainer: ['sectionsContainer'], sectionContent: ['sectionContent'], sectionBefore: ['sectionBefore'], sectionAfter: ['sectionAfter'], activeBar: ['activeBar'] }; return (0, _composeClasses.default)(slots, _pickersInputBaseClasses.getPickersInputBaseUtilityClass, classes); }; function resolveSectionElementWidth(sectionElement, rootRef, index, dateRangePosition) { if (sectionElement.content.id) { const activeSectionElements = rootRef.current?.querySelectorAll(`[data-sectionindex="${index}"] [data-range-position="${dateRangePosition}"]`); if (activeSectionElements) { return Array.from(activeSectionElements).reduce((currentActiveBarWidth, element) => { return currentActiveBarWidth + element.offsetWidth; }, 0); } } return 0; } function resolveSectionWidthAndOffsets(elements, rootRef) { let activeBarWidth = 0; const activeRangePosition = rootRef.current?.getAttribute('data-active-range-position'); if (activeRangePosition === 'end') { for (let i = elements.length - 1; i >= elements.length / 2; i -= 1) { activeBarWidth += resolveSectionElementWidth(elements[i], rootRef, i, 'end'); } } else { for (let i = 0; i < elements.length / 2; i += 1) { activeBarWidth += resolveSectionElementWidth(elements[i], rootRef, i, 'start'); } } return { activeBarWidth, sectionOffsets: [rootRef.current?.querySelector(`[data-sectionindex="0"]`)?.offsetLeft || 0, rootRef.current?.querySelector(`[data-sectionindex="${elements.length / 2}"]`)?.offsetLeft || 0] }; } /** * @ignore - internal component. */ const PickersInputBase = exports.PickersInputBase = /*#__PURE__*/React.forwardRef(function PickersInputBase(inProps, ref) { const props = (0, _styles.useThemeProps)({ props: inProps, name: 'MuiPickersInputBase' }); const { elements, areAllSectionsEmpty, value, onChange, id, endAdornment, startAdornment, renderSuffix, slots, slotProps, contentEditable, tabIndex, onInput, onPaste, onKeyDown, name, readOnly, inputProps, inputRef, sectionListRef, onFocus, onBlur, classes: classesProp, ownerState: ownerStateProp } = props, other = (0, _objectWithoutPropertiesLoose2.default)(props, _excluded); const ownerStateContext = (0, _usePickerTextFieldOwnerState.usePickerTextFieldOwnerState)(); const rootRef = React.useRef(null); const activeBarRef = React.useRef(null); const sectionOffsetsRef = React.useRef([]); const handleRootRef = (0, _useForkRef.default)(ref, rootRef); const handleInputRef = (0, _useForkRef.default)(inputProps?.ref, inputRef); const muiFormControl = (0, _FormControl.useFormControl)(); if (!muiFormControl) { throw new Error('MUI X: PickersInputBase should always be used inside a PickersTextField component'); } const ownerState = ownerStateProp ?? ownerStateContext; const handleInputFocus = event => { muiFormControl.onFocus?.(event); onFocus?.(event); }; const handleHiddenInputFocus = event => { handleInputFocus(event); }; const handleKeyDown = event => { onKeyDown?.(event); if (event.key === 'Enter' && !event.defaultMuiPrevented) { // Do nothing if it's a multi input field if (rootRef.current?.dataset.multiInput) { return; } const closestForm = rootRef.current?.closest('form'); const submitTrigger = closestForm?.querySelector('[type="submit"]'); if (!closestForm || !submitTrigger) { // do nothing if there is no form or no submit button (trigger) return; } event.preventDefault(); // native input trigger submit with the `submitter` field set closestForm.requestSubmit(submitTrigger); } }; const handleInputBlur = event => { muiFormControl.onBlur?.(event); onBlur?.(event); }; React.useEffect(() => { if (muiFormControl) { muiFormControl.setAdornedStart(Boolean(startAdornment)); } }, [muiFormControl, startAdornment]); React.useEffect(() => { if (!muiFormControl) { return; } if (areAllSectionsEmpty) { muiFormControl.onEmpty(); } else { muiFormControl.onFilled(); } }, [muiFormControl, areAllSectionsEmpty]); const classes = useUtilityClasses(classesProp, ownerState); const InputRoot = slots?.root || PickersInputBaseRoot; const inputRootProps = (0, _useSlotProps.default)({ elementType: InputRoot, externalSlotProps: slotProps?.root, externalForwardedProps: other, additionalProps: { 'aria-invalid': muiFormControl.error, ref: handleRootRef }, className: classes.root, ownerState }); const InputSectionsContainer = slots?.input || PickersInputBaseSectionsContainer; const isSingleInputRange = elements.some(element => element.content['data-range-position'] !== undefined); React.useEffect(() => { if (!isSingleInputRange || !ownerState.isPickerOpen) { return; } const { activeBarWidth, sectionOffsets } = resolveSectionWidthAndOffsets(elements, rootRef); sectionOffsetsRef.current = [sectionOffsets[0], sectionOffsets[1]]; if (activeBarRef.current) { activeBarRef.current.style.width = `${activeBarWidth}px`; } }, [elements, isSingleInputRange, ownerState.isPickerOpen]); return /*#__PURE__*/(0, _jsxRuntime.jsxs)(InputRoot, (0, _extends2.default)({}, inputRootProps, { children: [startAdornment, /*#__PURE__*/(0, _jsxRuntime.jsx)(_PickersSectionList.Unstable_PickersSectionList, { sectionListRef: sectionListRef, elements: elements, contentEditable: contentEditable, tabIndex: tabIndex, className: classes.sectionsContainer, onFocus: handleInputFocus, onBlur: handleInputBlur, onInput: onInput, onPaste: onPaste, onKeyDown: handleKeyDown, slots: { root: InputSectionsContainer, section: PickersInputBaseSection, sectionContent: PickersInputBaseSectionContent, sectionSeparator: PickersInputBaseSectionSeparator }, slotProps: { root: (0, _extends2.default)({}, slotProps?.input, { ownerState }), sectionContent: { className: _pickersInputBaseClasses.pickersInputBaseClasses.sectionContent }, sectionSeparator: ({ separatorPosition }) => ({ className: separatorPosition === 'before' ? _pickersInputBaseClasses.pickersInputBaseClasses.sectionBefore : _pickersInputBaseClasses.pickersInputBaseClasses.sectionAfter }) } }), endAdornment, renderSuffix ? renderSuffix((0, _extends2.default)({}, muiFormControl)) : null, /*#__PURE__*/(0, _jsxRuntime.jsx)(PickersInputBaseInput, (0, _extends2.default)({ name: name, className: classes.input, value: value, onChange: onChange, id: id, "aria-hidden": "true", tabIndex: -1, readOnly: readOnly, required: muiFormControl.required, disabled: muiFormControl.disabled // Hidden input element cannot be focused, trigger the root focus instead // This allows to maintain the ability to do `inputRef.current.focus()` to focus the field , onFocus: handleHiddenInputFocus }, inputProps, { ref: handleInputRef })), isSingleInputRange && /*#__PURE__*/(0, _jsxRuntime.jsx)(PickersInputBaseActiveBar, { className: classes.activeBar, ref: activeBarRef, ownerState: { sectionOffsets: sectionOffsetsRef.current } })] })); }); process.env.NODE_ENV !== "production" ? PickersInputBase.propTypes = { // ----------------------------- Warning -------------------------------- // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "pnpm proptypes" | // ---------------------------------------------------------------------- /** * Is `true` if the current values equals the empty value. * For a single item value, it means that `value === null` * For a range value, it means that `value === [null, null]` */ areAllSectionsEmpty: _propTypes.default.bool.isRequired, className: _propTypes.default.string, component: _propTypes.default.elementType, /** * If true, the whole element is editable. * Useful when all the sections are selected. */ contentEditable: _propTypes.default.bool.isRequired, 'data-multi-input': _propTypes.default.string, /** * The elements to render. * Each element contains the prop to edit a section of the value. */ elements: _propTypes.default.arrayOf(_propTypes.default.shape({ after: _propTypes.default.object.isRequired, before: _propTypes.default.object.isRequired, container: _propTypes.default.object.isRequired, content: _propTypes.default.object.isRequired })).isRequired, endAdornment: _propTypes.default.node, fullWidth: _propTypes.default.bool, id: _propTypes.default.string, inputProps: _propTypes.default.object, inputRef: _utils.refType, label: _propTypes.default.node, margin: _propTypes.default.oneOf(['dense', 'none', 'normal']), name: _propTypes.default.string, onChange: _propTypes.default.func.isRequired, onClick: _propTypes.default.func.isRequired, onInput: _propTypes.default.func.isRequired, onKeyDown: _propTypes.default.func.isRequired, onPaste: _propTypes.default.func.isRequired, ownerState: _propTypes.default /* @typescript-to-proptypes-ignore */.any, readOnly: _propTypes.default.bool, renderSuffix: _propTypes.default.func, sectionListRef: _propTypes.default.oneOfType([_propTypes.default.func, _propTypes.default.shape({ current: _propTypes.default.shape({ getRoot: _propTypes.default.func.isRequired, getSectionContainer: _propTypes.default.func.isRequired, getSectionContent: _propTypes.default.func.isRequired, getSectionIndexFromDOMElement: _propTypes.default.func.isRequired }) })]), /** * The props used for each component slot. * @default {} */ slotProps: _propTypes.default.object, /** * The components used for each slot inside. * * @default {} */ slots: _propTypes.default.object, startAdornment: _propTypes.default.node, style: _propTypes.default.object, /** * The system prop that allows defining system overrides as well as additional CSS styles. */ 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]), value: _propTypes.default.string.isRequired } : void 0;