Files
ETB/ETB-FrontEnd/node_modules/@mui/x-date-pickers/internals/hooks/useField/useField.js
Iliyan Angelov 306b20e24a Frontend start
2025-09-14 00:54:48 +03:00

315 lines
12 KiB
JavaScript

import _extends from "@babel/runtime/helpers/esm/extends";
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
const _excluded = ["onClick", "onKeyDown", "onFocus", "onBlur"];
import * as React from 'react';
import useEnhancedEffect from '@mui/utils/useEnhancedEffect';
import useEventCallback from '@mui/utils/useEventCallback';
import { useValidation } from '../validation/useValidation';
import { useUtils } from '../useUtils';
import { cleanTrailingZeroInNumericSectionValue, getMonthsMatchingQuery, getSectionValueNumericBoundaries, getSectionVisibleValue, adjustDateSectionValue, adjustInvalidDateSectionValue, setSectionValue } from './useField.utils';
export const useField = params => {
const utils = useUtils();
if (!utils.formatTokenMap) {
throw new Error('This adapter is not compatible with the field components');
}
const inputRef = React.useRef(null);
const {
internalProps: {
value: valueProp,
defaultValue,
onChange,
format = utils.formats.keyboardDate,
readOnly = false
},
forwardedProps: {
onClick,
onKeyDown,
onFocus,
onBlur
},
valueManager,
fieldValueManager,
validator
} = params,
otherForwardedProps = _objectWithoutPropertiesLoose(params.forwardedProps, _excluded);
const firstDefaultValue = React.useRef(defaultValue);
const focusTimeoutRef = React.useRef(undefined);
const valueParsed = React.useMemo(() => {
var _ref, _firstDefaultValue$cu;
// TODO: Avoid this type casting, the emptyValues are both valid TDate and TInputDate
const value = (_ref = (_firstDefaultValue$cu = firstDefaultValue.current) != null ? _firstDefaultValue$cu : valueProp) != null ? _ref : valueManager.emptyValue;
return valueManager.parseInput(utils, value);
}, [valueProp, valueManager, utils]);
const [state, setState] = React.useState(() => {
const sections = fieldValueManager.getSectionsFromValue(utils, null, valueParsed, format);
return {
sections,
valueParsed,
valueStr: fieldValueManager.getValueStrFromSections(sections),
selectedSectionIndexes: null
};
});
const updateSections = sections => {
const {
value: newValueParsed,
shouldPublish
} = fieldValueManager.getValueFromSections(utils, state.sections, sections, format);
setState(prevState => _extends({}, prevState, {
sections,
valueStr: fieldValueManager.getValueStrFromSections(sections),
valueParsed: newValueParsed
}));
if (onChange && shouldPublish) {
onChange(newValueParsed);
}
};
const updateSelectedSections = (start, end) => {
setState(prevState => _extends({}, prevState, {
selectedSectionIndexes: start == null ? null : {
start,
end: end != null ? end : start
},
selectedSectionQuery: null
}));
};
const handleInputClick = useEventCallback((...args) => {
onClick == null ? void 0 : onClick(...args);
if (state.sections.length === 0) {
return;
}
const nextSectionIndex = state.sections.findIndex(section => {
var _inputRef$current$sel, _inputRef$current;
return section.start > ((_inputRef$current$sel = (_inputRef$current = inputRef.current) == null ? void 0 : _inputRef$current.selectionStart) != null ? _inputRef$current$sel : 0);
});
const sectionIndex = nextSectionIndex === -1 ? state.sections.length - 1 : nextSectionIndex - 1;
updateSelectedSections(sectionIndex);
});
const handleInputFocus = useEventCallback((...args) => {
onFocus == null ? void 0 : onFocus(...args);
focusTimeoutRef.current = setTimeout(() => {
var _inputRef$current$sel2, _inputRef$current2, _inputRef$current$sel3, _inputRef$current3;
if (((_inputRef$current$sel2 = (_inputRef$current2 = inputRef.current) == null ? void 0 : _inputRef$current2.selectionEnd) != null ? _inputRef$current$sel2 : 0) - ((_inputRef$current$sel3 = (_inputRef$current3 = inputRef.current) == null ? void 0 : _inputRef$current3.selectionStart) != null ? _inputRef$current$sel3 : 0) === 0) {
handleInputClick();
} else {
updateSelectedSections(0, state.sections.length - 1);
}
});
});
const handleInputBlur = useEventCallback((...args) => {
onBlur == null ? void 0 : onBlur(...args);
updateSelectedSections();
});
const handleInputKeyDown = useEventCallback(event => {
onKeyDown == null ? void 0 : onKeyDown(event);
if (!inputRef.current || state.sections.length === 0) {
return;
} // eslint-disable-next-line default-case
switch (true) {
// Select all
case event.key === 'a' && (event.ctrlKey || event.metaKey):
{
event.preventDefault();
updateSelectedSections(0, state.sections.length - 1);
return;
}
// Move selection to next section
case event.key === 'ArrowRight':
{
event.preventDefault();
if (state.selectedSectionIndexes == null) {
updateSelectedSections(0);
} else if (state.selectedSectionIndexes.start < state.sections.length - 1) {
updateSelectedSections(state.selectedSectionIndexes.start + 1);
} else if (state.selectedSectionIndexes.start !== state.selectedSectionIndexes.end) {
updateSelectedSections(state.selectedSectionIndexes.end);
}
return;
}
// Move selection to previous section
case event.key === 'ArrowLeft':
{
event.preventDefault();
if (state.selectedSectionIndexes == null) {
updateSelectedSections(state.sections.length - 1);
} else if (state.selectedSectionIndexes.start !== state.selectedSectionIndexes.end) {
updateSelectedSections(state.selectedSectionIndexes.start);
} else if (state.selectedSectionIndexes.start > 0) {
updateSelectedSections(state.selectedSectionIndexes.start - 1);
}
return;
}
// Reset the value of the selected section
case ['Backspace', 'Delete'].includes(event.key):
{
event.preventDefault();
if (readOnly) {
return;
}
const resetSections = (startIndex, endIndex) => {
let sections = state.sections;
for (let i = startIndex; i <= endIndex; i += 1) {
sections = setSectionValue(sections, i, '');
}
return sections;
};
if (state.selectedSectionIndexes == null) {
updateSections(resetSections(0, state.sections.length));
} else {
updateSections(resetSections(state.selectedSectionIndexes.start, state.selectedSectionIndexes.end));
}
break;
}
// Increment / decrement the selected section value
case ['ArrowUp', 'ArrowDown', 'Home', 'End', 'PageUp', 'PageDown'].includes(event.key):
{
event.preventDefault();
if (readOnly || state.selectedSectionIndexes == null) {
return;
}
const activeSection = state.sections[state.selectedSectionIndexes.start];
const activeDate = fieldValueManager.getActiveDateFromActiveSection(state.valueParsed, activeSection); // The date is not valid, we have to increment the section value rather than the date
if (!utils.isValid(activeDate.value)) {
const newSectionValue = adjustInvalidDateSectionValue(utils, activeSection, event.key);
updateSections(setSectionValue(state.sections, state.selectedSectionIndexes.start, newSectionValue));
} else {
const newDate = adjustDateSectionValue(utils, activeDate.value, activeSection.dateSectionName, event.key);
const newValue = activeDate.update(newDate);
const sections = fieldValueManager.getSectionsFromValue(utils, state.sections, newValue, format);
updateSections(sections);
}
return;
}
// Apply numeric editing on the selected section value
case !Number.isNaN(Number(event.key)):
{
var _activeDate$value;
event.preventDefault();
if (readOnly || state.selectedSectionIndexes == null) {
return;
}
const activeSection = state.sections[state.selectedSectionIndexes.start];
const activeDate = fieldValueManager.getActiveDateFromActiveSection(state.valueParsed, activeSection);
const boundaries = getSectionValueNumericBoundaries(utils, (_activeDate$value = activeDate.value) != null ? _activeDate$value : utils.date(), activeSection.dateSectionName);
const concatenatedSectionValue = `${activeSection.value}${event.key}`;
const newSectionValue = Number(concatenatedSectionValue) > boundaries.maximum ? event.key : concatenatedSectionValue;
updateSections(setSectionValue(state.sections, state.selectedSectionIndexes.start, cleanTrailingZeroInNumericSectionValue(newSectionValue, boundaries.maximum)));
return;
}
// Apply full letter editing on the selected section value
case event.key.length === 1:
{
var _activeSection$query;
event.preventDefault();
if (readOnly || state.selectedSectionIndexes == null) {
return;
}
const activeSection = state.sections[state.selectedSectionIndexes.start]; // TODO: Do not hardcode the compatible formatValue
if (activeSection.formatValue !== 'MMMM') {
return;
}
const newQuery = event.key.toLowerCase();
const concatenatedQuery = `${(_activeSection$query = activeSection.query) != null ? _activeSection$query : ''}${newQuery}`;
const matchingMonthsWithConcatenatedQuery = getMonthsMatchingQuery(utils, activeSection.formatValue, concatenatedQuery);
if (matchingMonthsWithConcatenatedQuery.length > 0) {
updateSections(setSectionValue(state.sections, state.selectedSectionIndexes.start, matchingMonthsWithConcatenatedQuery[0], concatenatedQuery));
} else {
const matchingMonthsWithNewQuery = getMonthsMatchingQuery(utils, activeSection.formatValue, newQuery);
if (matchingMonthsWithNewQuery.length > 0) {
updateSections(setSectionValue(state.sections, state.selectedSectionIndexes.start, matchingMonthsWithNewQuery[0], newQuery));
}
}
}
}
});
useEnhancedEffect(() => {
if (!inputRef.current || state.selectedSectionIndexes == null) {
return;
}
const updateSelectionRangeIfChanged = (selectionStart, selectionEnd) => {
if (selectionStart !== inputRef.current.selectionStart || selectionEnd !== inputRef.current.selectionEnd) {
inputRef.current.setSelectionRange(selectionStart, selectionEnd);
}
};
const firstSelectedSection = state.sections[state.selectedSectionIndexes.start];
const lastSelectedSection = state.sections[state.selectedSectionIndexes.end];
updateSelectionRangeIfChanged(firstSelectedSection.start, lastSelectedSection.start + getSectionVisibleValue(lastSelectedSection).length);
});
React.useEffect(() => {
if (!valueManager.areValuesEqual(utils, state.valueParsed, valueParsed)) {
const sections = fieldValueManager.getSectionsFromValue(utils, state.sections, valueParsed, format);
setState(prevState => _extends({}, prevState, {
valueParsed,
valueStr: fieldValueManager.getValueStrFromSections(sections),
sections
}));
}
}, [valueParsed]); // eslint-disable-line react-hooks/exhaustive-deps
// TODO: Make validation work with TDate instead of TInputDate
const validationError = useValidation(_extends({}, params.internalProps, {
value: state.valueParsed
}), validator, fieldValueManager.isSameError);
const inputError = React.useMemo(() => fieldValueManager.hasError(validationError), [fieldValueManager, validationError]);
React.useEffect(() => {
return () => window.clearTimeout(focusTimeoutRef.current);
}, []);
return {
inputProps: _extends({}, otherForwardedProps, {
value: state.valueStr,
onClick: handleInputClick,
onFocus: handleInputFocus,
onBlur: handleInputBlur,
onKeyDown: handleInputKeyDown,
error: inputError
}),
inputRef
};
};