263 lines
No EOL
8.5 KiB
JavaScript
263 lines
No EOL
8.5 KiB
JavaScript
"use strict";
|
|
|
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.buildSectionsFromFormat = void 0;
|
|
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
var _useField = require("./useField.utils");
|
|
const expandFormat = ({
|
|
adapter,
|
|
format
|
|
}) => {
|
|
// Expand the provided format
|
|
let formatExpansionOverflow = 10;
|
|
let prevFormat = format;
|
|
let nextFormat = adapter.expandFormat(format);
|
|
while (nextFormat !== prevFormat) {
|
|
prevFormat = nextFormat;
|
|
nextFormat = adapter.expandFormat(prevFormat);
|
|
formatExpansionOverflow -= 1;
|
|
if (formatExpansionOverflow < 0) {
|
|
throw new Error('MUI X: The format expansion seems to be in an infinite loop. Please open an issue with the format passed to the component.');
|
|
}
|
|
}
|
|
return nextFormat;
|
|
};
|
|
const getEscapedPartsFromFormat = ({
|
|
adapter,
|
|
expandedFormat
|
|
}) => {
|
|
const escapedParts = [];
|
|
const {
|
|
start: startChar,
|
|
end: endChar
|
|
} = adapter.escapedCharacters;
|
|
const regExp = new RegExp(`(\\${startChar}[^\\${endChar}]*\\${endChar})+`, 'g');
|
|
let match = null;
|
|
// eslint-disable-next-line no-cond-assign
|
|
while (match = regExp.exec(expandedFormat)) {
|
|
escapedParts.push({
|
|
start: match.index,
|
|
end: regExp.lastIndex - 1
|
|
});
|
|
}
|
|
return escapedParts;
|
|
};
|
|
const getSectionPlaceholder = (adapter, localeText, sectionConfig, sectionFormat) => {
|
|
switch (sectionConfig.type) {
|
|
case 'year':
|
|
{
|
|
return localeText.fieldYearPlaceholder({
|
|
digitAmount: adapter.formatByString(adapter.date(undefined, 'default'), sectionFormat).length,
|
|
format: sectionFormat
|
|
});
|
|
}
|
|
case 'month':
|
|
{
|
|
return localeText.fieldMonthPlaceholder({
|
|
contentType: sectionConfig.contentType,
|
|
format: sectionFormat
|
|
});
|
|
}
|
|
case 'day':
|
|
{
|
|
return localeText.fieldDayPlaceholder({
|
|
format: sectionFormat
|
|
});
|
|
}
|
|
case 'weekDay':
|
|
{
|
|
return localeText.fieldWeekDayPlaceholder({
|
|
contentType: sectionConfig.contentType,
|
|
format: sectionFormat
|
|
});
|
|
}
|
|
case 'hours':
|
|
{
|
|
return localeText.fieldHoursPlaceholder({
|
|
format: sectionFormat
|
|
});
|
|
}
|
|
case 'minutes':
|
|
{
|
|
return localeText.fieldMinutesPlaceholder({
|
|
format: sectionFormat
|
|
});
|
|
}
|
|
case 'seconds':
|
|
{
|
|
return localeText.fieldSecondsPlaceholder({
|
|
format: sectionFormat
|
|
});
|
|
}
|
|
case 'meridiem':
|
|
{
|
|
return localeText.fieldMeridiemPlaceholder({
|
|
format: sectionFormat
|
|
});
|
|
}
|
|
default:
|
|
{
|
|
return sectionFormat;
|
|
}
|
|
}
|
|
};
|
|
const createSection = ({
|
|
adapter,
|
|
date,
|
|
shouldRespectLeadingZeros,
|
|
localeText,
|
|
localizedDigits,
|
|
now,
|
|
token,
|
|
startSeparator
|
|
}) => {
|
|
if (token === '') {
|
|
throw new Error('MUI X: Should not call `commitToken` with an empty token');
|
|
}
|
|
const sectionConfig = (0, _useField.getDateSectionConfigFromFormatToken)(adapter, token);
|
|
const hasLeadingZerosInFormat = (0, _useField.doesSectionFormatHaveLeadingZeros)(adapter, sectionConfig.contentType, sectionConfig.type, token);
|
|
const hasLeadingZerosInInput = shouldRespectLeadingZeros ? hasLeadingZerosInFormat : sectionConfig.contentType === 'digit';
|
|
const isValidDate = adapter.isValid(date);
|
|
let sectionValue = isValidDate ? adapter.formatByString(date, token) : '';
|
|
let maxLength = null;
|
|
if (hasLeadingZerosInInput) {
|
|
if (hasLeadingZerosInFormat) {
|
|
maxLength = sectionValue === '' ? adapter.formatByString(now, token).length : sectionValue.length;
|
|
} else {
|
|
if (sectionConfig.maxLength == null) {
|
|
throw new Error(`MUI X: The token ${token} should have a 'maxLength' property on it's adapter`);
|
|
}
|
|
maxLength = sectionConfig.maxLength;
|
|
if (isValidDate) {
|
|
sectionValue = (0, _useField.applyLocalizedDigits)((0, _useField.cleanLeadingZeros)((0, _useField.removeLocalizedDigits)(sectionValue, localizedDigits), maxLength), localizedDigits);
|
|
}
|
|
}
|
|
}
|
|
return (0, _extends2.default)({}, sectionConfig, {
|
|
format: token,
|
|
maxLength,
|
|
value: sectionValue,
|
|
placeholder: getSectionPlaceholder(adapter, localeText, sectionConfig, token),
|
|
hasLeadingZerosInFormat,
|
|
hasLeadingZerosInInput,
|
|
startSeparator,
|
|
endSeparator: '',
|
|
modified: false
|
|
});
|
|
};
|
|
const buildSections = parameters => {
|
|
const {
|
|
adapter,
|
|
expandedFormat,
|
|
escapedParts
|
|
} = parameters;
|
|
const now = adapter.date(undefined);
|
|
const sections = [];
|
|
let startSeparator = '';
|
|
|
|
// This RegExp tests if the beginning of a string corresponds to a supported token
|
|
const validTokens = Object.keys(adapter.formatTokenMap).sort((a, b) => b.length - a.length); // Sort to put longest word first
|
|
|
|
const regExpFirstWordInFormat = /^([a-zA-Z]+)/;
|
|
const regExpWordOnlyComposedOfTokens = new RegExp(`^(${validTokens.join('|')})*$`);
|
|
const regExpFirstTokenInWord = new RegExp(`^(${validTokens.join('|')})`);
|
|
const getEscapedPartOfCurrentChar = i => escapedParts.find(escapeIndex => escapeIndex.start <= i && escapeIndex.end >= i);
|
|
let i = 0;
|
|
while (i < expandedFormat.length) {
|
|
const escapedPartOfCurrentChar = getEscapedPartOfCurrentChar(i);
|
|
const isEscapedChar = escapedPartOfCurrentChar != null;
|
|
const firstWordInFormat = regExpFirstWordInFormat.exec(expandedFormat.slice(i))?.[1];
|
|
|
|
// The first word in the format is only composed of tokens.
|
|
// We extract those tokens to create a new sections.
|
|
if (!isEscapedChar && firstWordInFormat != null && regExpWordOnlyComposedOfTokens.test(firstWordInFormat)) {
|
|
let word = firstWordInFormat;
|
|
while (word.length > 0) {
|
|
const firstWord = regExpFirstTokenInWord.exec(word)[1];
|
|
word = word.slice(firstWord.length);
|
|
sections.push(createSection((0, _extends2.default)({}, parameters, {
|
|
now,
|
|
token: firstWord,
|
|
startSeparator
|
|
})));
|
|
startSeparator = '';
|
|
}
|
|
i += firstWordInFormat.length;
|
|
}
|
|
// The remaining format does not start with a token,
|
|
// We take the first character and add it to the current section's end separator.
|
|
else {
|
|
const char = expandedFormat[i];
|
|
|
|
// If we are on the opening or closing character of an escaped part of the format,
|
|
// Then we ignore this character.
|
|
const isEscapeBoundary = isEscapedChar && escapedPartOfCurrentChar?.start === i || escapedPartOfCurrentChar?.end === i;
|
|
if (!isEscapeBoundary) {
|
|
if (sections.length === 0) {
|
|
startSeparator += char;
|
|
} else {
|
|
sections[sections.length - 1].endSeparator += char;
|
|
sections[sections.length - 1].isEndFormatSeparator = true;
|
|
}
|
|
}
|
|
i += 1;
|
|
}
|
|
}
|
|
if (sections.length === 0 && startSeparator.length > 0) {
|
|
sections.push({
|
|
type: 'empty',
|
|
contentType: 'letter',
|
|
maxLength: null,
|
|
format: '',
|
|
value: '',
|
|
placeholder: '',
|
|
hasLeadingZerosInFormat: false,
|
|
hasLeadingZerosInInput: false,
|
|
startSeparator,
|
|
endSeparator: '',
|
|
modified: false
|
|
});
|
|
}
|
|
return sections;
|
|
};
|
|
const postProcessSections = ({
|
|
isRtl,
|
|
formatDensity,
|
|
sections
|
|
}) => {
|
|
return sections.map(section => {
|
|
const cleanSeparator = separator => {
|
|
let cleanedSeparator = separator;
|
|
if (isRtl && cleanedSeparator !== null && cleanedSeparator.includes(' ')) {
|
|
cleanedSeparator = `\u2069${cleanedSeparator}\u2066`;
|
|
}
|
|
if (formatDensity === 'spacious' && ['/', '.', '-'].includes(cleanedSeparator)) {
|
|
cleanedSeparator = ` ${cleanedSeparator} `;
|
|
}
|
|
return cleanedSeparator;
|
|
};
|
|
section.startSeparator = cleanSeparator(section.startSeparator);
|
|
section.endSeparator = cleanSeparator(section.endSeparator);
|
|
return section;
|
|
});
|
|
};
|
|
const buildSectionsFromFormat = parameters => {
|
|
let expandedFormat = expandFormat(parameters);
|
|
if (parameters.isRtl && parameters.enableAccessibleFieldDOMStructure) {
|
|
expandedFormat = expandedFormat.split(' ').reverse().join(' ');
|
|
}
|
|
const escapedParts = getEscapedPartsFromFormat((0, _extends2.default)({}, parameters, {
|
|
expandedFormat
|
|
}));
|
|
const sections = buildSections((0, _extends2.default)({}, parameters, {
|
|
expandedFormat,
|
|
escapedParts
|
|
}));
|
|
return postProcessSections((0, _extends2.default)({}, parameters, {
|
|
sections
|
|
}));
|
|
};
|
|
exports.buildSectionsFromFormat = buildSectionsFromFormat; |