@mui/x-date-pickers
Version:
The community edition of the Date and Time Picker components (MUI X).
237 lines (234 loc) • 9.16 kB
JavaScript
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useFieldSectionContentProps = useFieldSectionContentProps;
var React = _interopRequireWildcard(require("react"));
var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallback"));
var _useId = _interopRequireDefault(require("@mui/utils/useId"));
var _useUtils = require("../useUtils");
var _hooks = require("../../../hooks");
var _syncSelectionToDOM = require("./syncSelectionToDOM");
/**
* Generate the props to pass to the content element of each section of the field.
* It is not used by the non-accessible DOM structure (with an <input /> element for editing).
* It should be used in the MUI accessible DOM structure and the Base UI implementation.
* @param {UseFieldRootPropsParameters} parameters The parameters of the hook.
* @returns {UseFieldRootPropsReturnValue} The props to forward to the content element of each section of the field.
*/
function useFieldSectionContentProps(parameters) {
const utils = (0, _useUtils.useUtils)();
const translations = (0, _hooks.usePickerTranslations)();
const id = (0, _useId.default)();
const {
focused,
domGetters,
stateResponse,
applyCharacterEditing,
manager: {
internal_fieldValueManager: fieldValueManager
},
stateResponse: {
// States and derived states
parsedSelectedSections,
sectionsValueBoundaries,
state,
value,
// Methods to update the states
clearActiveSection,
setCharacterQuery,
setSelectedSections,
updateSectionValue,
updateValueFromValueStr
},
internalPropsWithDefaults: {
disabled = false,
readOnly = false
}
} = parameters;
const isContainerEditable = parsedSelectedSections === 'all';
const isEditable = !isContainerEditable && !disabled && !readOnly;
/**
* If a section content has been updated with a value we don't want to keep,
* Then we need to imperatively revert it (we can't let React do it because the value did not change in his internal representation).
*/
const revertDOMSectionChange = (0, _useEventCallback.default)(sectionIndex => {
if (!domGetters.isReady()) {
return;
}
const section = state.sections[sectionIndex];
domGetters.getSectionContent(sectionIndex).innerHTML = section.value || section.placeholder;
(0, _syncSelectionToDOM.syncSelectionToDOM)({
focused,
domGetters,
stateResponse
});
});
const handleInput = (0, _useEventCallback.default)(event => {
if (!domGetters.isReady()) {
return;
}
const target = event.target;
const keyPressed = target.textContent ?? '';
const sectionIndex = domGetters.getSectionIndexFromDOMElement(target);
const section = state.sections[sectionIndex];
if (readOnly) {
revertDOMSectionChange(sectionIndex);
return;
}
if (keyPressed.length === 0) {
if (section.value === '') {
revertDOMSectionChange(sectionIndex);
return;
}
const inputType = event.nativeEvent.inputType;
if (inputType === 'insertParagraph' || inputType === 'insertLineBreak') {
revertDOMSectionChange(sectionIndex);
return;
}
revertDOMSectionChange(sectionIndex);
clearActiveSection();
return;
}
applyCharacterEditing({
keyPressed,
sectionIndex
});
// The DOM value needs to remain the one React is expecting.
revertDOMSectionChange(sectionIndex);
});
const handleMouseUp = (0, _useEventCallback.default)(event => {
// Without this, the browser will remove the selected when clicking inside an already-selected section.
event.preventDefault();
});
const handlePaste = (0, _useEventCallback.default)(event => {
// prevent default to avoid the input `onInput` handler being called
event.preventDefault();
if (readOnly || disabled || typeof parsedSelectedSections !== 'number') {
return;
}
const activeSection = state.sections[parsedSelectedSections];
const pastedValue = event.clipboardData.getData('text');
const lettersOnly = /^[a-zA-Z]+$/.test(pastedValue);
const digitsOnly = /^[0-9]+$/.test(pastedValue);
const digitsAndLetterOnly = /^(([a-zA-Z]+)|)([0-9]+)(([a-zA-Z]+)|)$/.test(pastedValue);
const isValidPastedValue = activeSection.contentType === 'letter' && lettersOnly || activeSection.contentType === 'digit' && digitsOnly || activeSection.contentType === 'digit-with-letter' && digitsAndLetterOnly;
if (isValidPastedValue) {
setCharacterQuery(null);
updateSectionValue({
section: activeSection,
newSectionValue: pastedValue,
shouldGoToNextSection: true
});
}
// If the pasted value corresponds to a single section, but not the expected type, we skip the modification
else if (!lettersOnly && !digitsOnly) {
setCharacterQuery(null);
updateValueFromValueStr(pastedValue);
}
});
const handleDragOver = (0, _useEventCallback.default)(event => {
event.preventDefault();
event.dataTransfer.dropEffect = 'none';
});
const createFocusHandler = (0, _useEventCallback.default)(sectionIndex => () => {
if (disabled) {
return;
}
setSelectedSections(sectionIndex);
});
return React.useCallback((section, sectionIndex) => {
const sectionBoundaries = sectionsValueBoundaries[section.type]({
currentDate: fieldValueManager.getDateFromSection(value, section),
contentType: section.contentType,
format: section.format
});
return {
// Event handlers
onInput: handleInput,
onPaste: handlePaste,
onMouseUp: handleMouseUp,
onDragOver: handleDragOver,
onFocus: createFocusHandler(sectionIndex),
// Aria attributes
'aria-labelledby': `${id}-${section.type}`,
'aria-readonly': readOnly,
'aria-valuenow': getSectionValueNow(section, utils),
'aria-valuemin': sectionBoundaries.minimum,
'aria-valuemax': sectionBoundaries.maximum,
'aria-valuetext': section.value ? getSectionValueText(section, utils) : translations.empty,
'aria-label': translations[section.type],
'aria-disabled': disabled,
// Other
tabIndex: isContainerEditable || sectionIndex > 0 ? -1 : 0,
contentEditable: !isContainerEditable && !disabled && !readOnly,
role: 'spinbutton',
id: `${id}-${section.type}`,
'data-range-position': section.dateName || undefined,
spellCheck: isEditable ? false : undefined,
autoCapitalize: isEditable ? 'off' : undefined,
autoCorrect: isEditable ? 'off' : undefined,
children: section.value || section.placeholder,
inputMode: section.contentType === 'letter' ? 'text' : 'numeric'
};
}, [sectionsValueBoundaries, id, isContainerEditable, disabled, readOnly, isEditable, translations, utils, handleInput, handlePaste, handleMouseUp, handleDragOver, createFocusHandler, fieldValueManager, value]);
}
function getSectionValueText(section, utils) {
if (!section.value) {
return undefined;
}
switch (section.type) {
case 'month':
{
if (section.contentType === 'digit') {
return utils.format(utils.setMonth(utils.date(), Number(section.value) - 1), 'month');
}
const parsedDate = utils.parse(section.value, section.format);
return parsedDate ? utils.format(parsedDate, 'month') : undefined;
}
case 'day':
return section.contentType === 'digit' ? utils.format(utils.setDate(utils.startOfYear(utils.date()), Number(section.value)), 'dayOfMonthFull') : section.value;
case 'weekDay':
// TODO: improve by providing the label of the week day
return undefined;
default:
return undefined;
}
}
function getSectionValueNow(section, utils) {
if (!section.value) {
return undefined;
}
switch (section.type) {
case 'weekDay':
{
if (section.contentType === 'letter') {
// TODO: improve by resolving the week day number from a letter week day
return undefined;
}
return Number(section.value);
}
case 'meridiem':
{
const parsedDate = utils.parse(`01:00 ${section.value}`, `${utils.formats.hours12h}:${utils.formats.minutes} ${section.format}`);
if (parsedDate) {
return utils.getHours(parsedDate) >= 12 ? 1 : 0;
}
return undefined;
}
case 'day':
return section.contentType === 'digit-with-letter' ? parseInt(section.value, 10) : Number(section.value);
case 'month':
{
if (section.contentType === 'digit') {
return Number(section.value);
}
const parsedDate = utils.parse(section.value, section.format);
return parsedDate ? utils.getMonth(parsedDate) + 1 : undefined;
}
default:
return section.contentType !== 'letter' ? Number(section.value) : undefined;
}
}
;