UNPKG

@mui/x-date-pickers-pro

Version:

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

248 lines (245 loc) 8.47 kB
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose"; import _extends from "@babel/runtime/helpers/esm/extends"; const _excluded = ["clearable", "onClear"]; import * as React from 'react'; import { resolveComponentProps } from '@mui/base/utils'; import useEventCallback from '@mui/utils/useEventCallback'; import useForkRef from '@mui/utils/useForkRef'; import { usePickersTranslations } from '@mui/x-date-pickers/hooks'; import { onSpaceOrEnter } from '@mui/x-date-pickers/internals'; const useMultiInputFieldSlotProps = ({ wrapperVariant, open, actions, readOnly, labelId, disableOpenPicker, onBlur, rangePosition, onRangePositionChange, localeText: inLocaleText, pickerSlotProps, pickerSlots, fieldProps, anchorRef, currentView, initialView, onViewChange, startFieldRef, endFieldRef }) => { const translations = usePickersTranslations(); const handleStartFieldRef = useForkRef(fieldProps.unstableStartFieldRef, startFieldRef); const handleEndFieldRef = useForkRef(fieldProps.unstableEndFieldRef, endFieldRef); const previousRangePosition = React.useRef(rangePosition); React.useEffect(() => { if (!open) { return; } const currentFieldRef = rangePosition === 'start' ? startFieldRef : endFieldRef; currentFieldRef.current?.focusField(); if (!currentFieldRef.current || !currentView) { // could happen when the user is switching between the inputs previousRangePosition.current = rangePosition; return; } // bring back focus to the field currentFieldRef.current.setSelectedSections( // use the current view or `0` when the range position has just been swapped previousRangePosition.current === rangePosition ? currentView : 0); previousRangePosition.current = rangePosition; }, [rangePosition, open, currentView, startFieldRef, endFieldRef]); const openRangeStartSelection = event => { event.stopPropagation(); onRangePositionChange('start'); if (!readOnly && !disableOpenPicker) { actions.onOpen(event); } }; const openRangeEndSelection = event => { event.stopPropagation(); onRangePositionChange('end'); if (!readOnly && !disableOpenPicker) { actions.onOpen(event); } }; const handleFocusStart = () => { if (open) { onRangePositionChange('start'); if (previousRangePosition.current !== 'start' && initialView) { onViewChange?.(initialView); } } }; const handleFocusEnd = () => { if (open) { onRangePositionChange('end'); if (previousRangePosition.current !== 'end' && initialView) { onViewChange?.(initialView); } } }; const slots = _extends({ textField: pickerSlots?.textField, root: pickerSlots?.fieldRoot, separator: pickerSlots?.fieldSeparator }, fieldProps.slots); const slotProps = _extends({}, fieldProps.slotProps, { textField: ownerState => { const resolvedComponentProps = resolveComponentProps(pickerSlotProps?.textField, ownerState); let textFieldProps; let InputProps; if (ownerState.position === 'start') { textFieldProps = _extends({ label: inLocaleText?.start ?? translations.start, onKeyDown: onSpaceOrEnter(openRangeStartSelection), onFocus: handleFocusStart, focused: open ? rangePosition === 'start' : undefined }, !readOnly && !fieldProps.disabled && { onClick: openRangeStartSelection }, wrapperVariant === 'mobile' && { readOnly: true }); if (anchorRef) { InputProps = _extends({}, resolvedComponentProps?.InputProps, { ref: anchorRef }); } } else { textFieldProps = _extends({ label: inLocaleText?.end ?? translations.end, onKeyDown: onSpaceOrEnter(openRangeEndSelection), onFocus: handleFocusEnd, focused: open ? rangePosition === 'end' : undefined }, !readOnly && !fieldProps.disabled && { onClick: openRangeEndSelection }, wrapperVariant === 'mobile' && { readOnly: true }); InputProps = resolvedComponentProps?.InputProps; } return _extends({}, labelId != null && { id: `${labelId}-${ownerState.position}` }, textFieldProps, resolveComponentProps(pickerSlotProps?.textField, ownerState), { InputProps }); }, root: ownerState => { const rootProps = { onBlur }; return _extends({}, rootProps, resolveComponentProps(pickerSlotProps?.fieldRoot, ownerState)); }, separator: pickerSlotProps?.fieldSeparator }); /* TODO: remove this when a clearable behavior for multiple input range fields is implemented */ const _ref = fieldProps, restFieldProps = _objectWithoutPropertiesLoose(_ref, _excluded); const enrichedFieldProps = _extends({}, restFieldProps, { unstableStartFieldRef: handleStartFieldRef, unstableEndFieldRef: handleEndFieldRef, slots, slotProps }); return enrichedFieldProps; }; const useSingleInputFieldSlotProps = ({ wrapperVariant, open, actions, readOnly, labelId, disableOpenPicker, label, onBlur, rangePosition, onRangePositionChange, startFieldRef, endFieldRef, pickerSlots, pickerSlotProps, fieldProps, anchorRef, currentView }) => { const handleFieldRef = useForkRef(fieldProps.unstableFieldRef, startFieldRef, endFieldRef); React.useEffect(() => { if (!open || !startFieldRef.current) { return; } if (startFieldRef.current.isFieldFocused()) { return; } // bring back focus to the field with the current view section selected if (currentView) { const sections = startFieldRef.current.getSections().map(section => section.type); const newSelectedSection = rangePosition === 'start' ? sections.indexOf(currentView) : sections.lastIndexOf(currentView); startFieldRef.current?.focusField(newSelectedSection); } }, [rangePosition, open, currentView, startFieldRef]); const updateRangePosition = () => { if (!startFieldRef.current?.isFieldFocused()) { return; } const sections = startFieldRef.current.getSections(); const activeSectionIndex = startFieldRef.current?.getActiveSectionIndex(); const domRangePosition = activeSectionIndex == null || activeSectionIndex < sections.length / 2 ? 'start' : 'end'; if (domRangePosition != null && domRangePosition !== rangePosition) { onRangePositionChange(domRangePosition); } }; const handleSelectedSectionsChange = useEventCallback(selectedSection => { setTimeout(updateRangePosition); fieldProps.onSelectedSectionsChange?.(selectedSection); }); const openPicker = event => { event.stopPropagation(); if (!readOnly && !disableOpenPicker) { actions.onOpen(event); } }; const slots = _extends({}, fieldProps.slots, { textField: pickerSlots?.textField, clearButton: pickerSlots?.clearButton, clearIcon: pickerSlots?.clearIcon }); const slotProps = _extends({}, fieldProps.slotProps, { textField: pickerSlotProps?.textField, clearButton: pickerSlots?.clearButton, clearIcon: pickerSlots?.clearIcon }); const enrichedFieldProps = _extends({}, fieldProps, { slots, slotProps, label, unstableFieldRef: handleFieldRef, onKeyDown: onSpaceOrEnter(openPicker, fieldProps.onKeyDown), onSelectedSectionsChange: handleSelectedSectionsChange, onBlur, InputProps: _extends({ ref: anchorRef }, fieldProps?.InputProps), focused: open ? true : undefined }, labelId != null && { id: labelId }, wrapperVariant === 'mobile' && { readOnly: true }, !readOnly && !fieldProps.disabled && { onClick: openPicker }); return enrichedFieldProps; }; export const useEnrichedRangePickerFieldProps = params => { /* eslint-disable react-hooks/rules-of-hooks */ if (process.env.NODE_ENV !== 'production') { const fieldTypeRef = React.useRef(params.fieldType); if (params.fieldType !== fieldTypeRef.current) { console.error('Should not switch between a multi input field and a single input field on a range picker.'); } } if (params.fieldType === 'multi-input') { return useMultiInputFieldSlotProps(params); } return useSingleInputFieldSlotProps(params); /* eslint-enable react-hooks/rules-of-hooks */ };