UNPKG

@mui/x-date-pickers

Version:

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

266 lines (257 loc) 10.9 kB
"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.useFieldCharacterEditing = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var React = _interopRequireWildcard(require("react")); var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallback")); var _useUtils = require("../useUtils"); var _useField = require("./useField.utils"); /** * The letter editing and the numeric editing each define a `CharacterEditingApplier`. * This function decides what the new section value should be and if the focus should switch to the next section. * * If it returns `null`, then the section value is not updated and the focus does not move. */ /** * Function called by `applyQuery` which decides: * - what is the new section value ? * - should the query used to get this value be stored for the next key press ? * * If it returns `{ sectionValue: string; shouldGoToNextSection: boolean }`, * Then we store the query and update the section with the new value. * * If it returns `{ saveQuery: true` }, * Then we store the query and don't update the section. * * If it returns `{ saveQuery: false }, * Then we do nothing. */ const QUERY_LIFE_DURATION_MS = 5000; const isQueryResponseWithoutValue = response => response.saveQuery != null; /** * Update the active section value when the user pressed a key that is not a navigation key (arrow key for example). * This hook has two main editing behaviors * * 1. The numeric editing when the user presses a digit * 2. The letter editing when the user presses another key */ const useFieldCharacterEditing = ({ sections, updateSectionValue, sectionsValueBoundaries, localizedDigits, setTempAndroidValueStr, timezone }) => { const utils = (0, _useUtils.useUtils)(); const [query, setQuery] = React.useState(null); const resetQuery = (0, _useEventCallback.default)(() => setQuery(null)); React.useEffect(() => { if (query != null && sections[query.sectionIndex]?.type !== query.sectionType) { resetQuery(); } }, [sections, query, resetQuery]); React.useEffect(() => { if (query != null) { const timeout = setTimeout(() => resetQuery(), QUERY_LIFE_DURATION_MS); return () => { clearTimeout(timeout); }; } return () => {}; }, [query, resetQuery]); const applyQuery = ({ keyPressed, sectionIndex }, getFirstSectionValueMatchingWithQuery, isValidQueryValue) => { const cleanKeyPressed = keyPressed.toLowerCase(); const activeSection = sections[sectionIndex]; // The current query targets the section being editing // We can try to concatenate the value if (query != null && (!isValidQueryValue || isValidQueryValue(query.value)) && query.sectionIndex === sectionIndex) { const concatenatedQueryValue = `${query.value}${cleanKeyPressed}`; const queryResponse = getFirstSectionValueMatchingWithQuery(concatenatedQueryValue, activeSection); if (!isQueryResponseWithoutValue(queryResponse)) { setQuery({ sectionIndex, value: concatenatedQueryValue, sectionType: activeSection.type }); return queryResponse; } } const queryResponse = getFirstSectionValueMatchingWithQuery(cleanKeyPressed, activeSection); if (isQueryResponseWithoutValue(queryResponse) && !queryResponse.saveQuery) { resetQuery(); return null; } setQuery({ sectionIndex, value: cleanKeyPressed, sectionType: activeSection.type }); if (isQueryResponseWithoutValue(queryResponse)) { return null; } return queryResponse; }; const applyLetterEditing = params => { const findMatchingOptions = (format, options, queryValue) => { const matchingValues = options.filter(option => option.toLowerCase().startsWith(queryValue)); if (matchingValues.length === 0) { return { saveQuery: false }; } return { sectionValue: matchingValues[0], shouldGoToNextSection: matchingValues.length === 1 }; }; const testQueryOnFormatAndFallbackFormat = (queryValue, activeSection, fallbackFormat, formatFallbackValue) => { const getOptions = format => (0, _useField.getLetterEditingOptions)(utils, timezone, activeSection.type, format); if (activeSection.contentType === 'letter') { return findMatchingOptions(activeSection.format, getOptions(activeSection.format), queryValue); } // When editing a digit-format month / weekDay and the user presses a letter, // We can support the letter editing by using the letter-format month / weekDay and re-formatting the result. // We just have to make sure that the default month / weekDay format is a letter format, if (fallbackFormat && formatFallbackValue != null && (0, _useField.getDateSectionConfigFromFormatToken)(utils, fallbackFormat).contentType === 'letter') { const fallbackOptions = getOptions(fallbackFormat); const response = findMatchingOptions(fallbackFormat, fallbackOptions, queryValue); if (isQueryResponseWithoutValue(response)) { return { saveQuery: false }; } return (0, _extends2.default)({}, response, { sectionValue: formatFallbackValue(response.sectionValue, fallbackOptions) }); } return { saveQuery: false }; }; const getFirstSectionValueMatchingWithQuery = (queryValue, activeSection) => { switch (activeSection.type) { case 'month': { const formatFallbackValue = fallbackValue => (0, _useField.changeSectionValueFormat)(utils, fallbackValue, utils.formats.month, activeSection.format); return testQueryOnFormatAndFallbackFormat(queryValue, activeSection, utils.formats.month, formatFallbackValue); } case 'weekDay': { const formatFallbackValue = (fallbackValue, fallbackOptions) => fallbackOptions.indexOf(fallbackValue).toString(); return testQueryOnFormatAndFallbackFormat(queryValue, activeSection, utils.formats.weekday, formatFallbackValue); } case 'meridiem': { return testQueryOnFormatAndFallbackFormat(queryValue, activeSection); } default: { return { saveQuery: false }; } } }; return applyQuery(params, getFirstSectionValueMatchingWithQuery); }; const applyNumericEditing = params => { const getNewSectionValue = (queryValue, section) => { const cleanQueryValue = (0, _useField.removeLocalizedDigits)(queryValue, localizedDigits); const queryValueNumber = Number(cleanQueryValue); const sectionBoundaries = sectionsValueBoundaries[section.type]({ currentDate: null, format: section.format, contentType: section.contentType }); if (queryValueNumber > sectionBoundaries.maximum) { return { saveQuery: false }; } // If the user types `0` on a month section, // It is below the minimum, but we want to store the `0` in the query, // So that when he pressed `1`, it will store `01` and move to the next section. if (queryValueNumber < sectionBoundaries.minimum) { return { saveQuery: true }; } const shouldGoToNextSection = queryValueNumber * 10 > sectionBoundaries.maximum || cleanQueryValue.length === sectionBoundaries.maximum.toString().length; const newSectionValue = (0, _useField.cleanDigitSectionValue)(utils, queryValueNumber, sectionBoundaries, localizedDigits, section); return { sectionValue: newSectionValue, shouldGoToNextSection }; }; const getFirstSectionValueMatchingWithQuery = (queryValue, activeSection) => { if (activeSection.contentType === 'digit' || activeSection.contentType === 'digit-with-letter') { return getNewSectionValue(queryValue, activeSection); } // When editing a letter-format month and the user presses a digit, // We can support the numeric editing by using the digit-format month and re-formatting the result. if (activeSection.type === 'month') { const hasLeadingZerosInFormat = (0, _useField.doesSectionFormatHaveLeadingZeros)(utils, 'digit', 'month', 'MM'); const response = getNewSectionValue(queryValue, { type: activeSection.type, format: 'MM', hasLeadingZerosInFormat, hasLeadingZerosInInput: true, contentType: 'digit', maxLength: 2 }); if (isQueryResponseWithoutValue(response)) { return response; } const formattedValue = (0, _useField.changeSectionValueFormat)(utils, response.sectionValue, 'MM', activeSection.format); return (0, _extends2.default)({}, response, { sectionValue: formattedValue }); } // When editing a letter-format weekDay and the user presses a digit, // We can support the numeric editing by returning the nth day in the week day array. if (activeSection.type === 'weekDay') { const response = getNewSectionValue(queryValue, activeSection); if (isQueryResponseWithoutValue(response)) { return response; } const formattedValue = (0, _useField.getDaysInWeekStr)(utils, activeSection.format)[Number(response.sectionValue) - 1]; return (0, _extends2.default)({}, response, { sectionValue: formattedValue }); } return { saveQuery: false }; }; return applyQuery(params, getFirstSectionValueMatchingWithQuery, queryValue => (0, _useField.isStringNumber)(queryValue, localizedDigits)); }; const applyCharacterEditing = (0, _useEventCallback.default)(params => { const activeSection = sections[params.sectionIndex]; const isNumericEditing = (0, _useField.isStringNumber)(params.keyPressed, localizedDigits); const response = isNumericEditing ? applyNumericEditing((0, _extends2.default)({}, params, { keyPressed: (0, _useField.applyLocalizedDigits)(params.keyPressed, localizedDigits) })) : applyLetterEditing(params); if (response == null) { setTempAndroidValueStr(null); return; } updateSectionValue({ activeSection, newSectionValue: response.sectionValue, shouldGoToNextSection: response.shouldGoToNextSection }); }); return { applyCharacterEditing, resetCharacterQuery: resetQuery }; }; exports.useFieldCharacterEditing = useFieldCharacterEditing;