@esri/calcite-components
Version:
Web Components for Esri's Calcite Design System.
443 lines (442 loc) • 14.9 kB
JavaScript
/*! All material copyright ESRI, All Rights Reserved, unless otherwise specified.
See https://github.com/Esri/calcite-design-system/blob/dev/LICENSE.md for details.
v3.2.1 */
import { i as isValidNumber, n as numberStringFormatter, g as getDateTimeFormat, l as localizedTwentyFourHourMeridiems, a as getSupportedNumberingSystem } from "./locale.js";
import { d as decimalPlaces } from "./math.js";
const maxTenthForMinuteAndSecond = 5;
function createLocaleDateTimeFormatter({
locale,
numberingSystem,
includeSeconds = true,
fractionalSecondDigits,
hour12
}) {
const options = {
hour: "2-digit",
minute: "2-digit",
timeZone: "UTC",
numberingSystem: getSupportedNumberingSystem(numberingSystem)
};
if (typeof hour12 === "boolean") {
options.hour12 = hour12;
}
if (includeSeconds) {
options.second = "2-digit";
if (fractionalSecondDigits) {
options.fractionalSecondDigits = fractionalSecondDigits;
}
}
return getDateTimeFormat(locale, options);
}
function formatFractionalSecond(fractionalSecondAsIntegerString, step) {
return parseFloat(`0.${fractionalSecondAsIntegerString}`).toFixed(decimalPlaces(step)).replace("0.", "");
}
function formatTimePart(number, minLength) {
if (number === null || number === void 0) {
return;
}
const numberAsString = number.toString();
const numberDecimalPlaces = decimalPlaces(number);
if (number < 1 && numberDecimalPlaces > 0 && numberDecimalPlaces < 4) {
const fractionalDigits = numberAsString.replace("0.", "");
if (!minLength || fractionalDigits.length === minLength) {
return fractionalDigits;
}
if (fractionalDigits.length < minLength) {
return fractionalDigits.padEnd(minLength, "0");
}
return fractionalDigits;
}
if (number >= 0 && number < 10) {
return numberAsString.padStart(2, "0");
}
if (number >= 10) {
return numberAsString;
}
}
function fractionalSecondPartToMilliseconds(fractionalSecondPart) {
return parseInt((parseFloat(`0.${fractionalSecondPart}`) / 1e-3).toFixed(3));
}
function getLocaleHourFormat(locale) {
const options = { locale };
if (locale === "mk") {
options.hour12 = false;
} else if (locale.toLowerCase() === "es-mx") {
options.hour12 = true;
}
const formatter = createLocaleDateTimeFormatter(options);
const parts = formatter.formatToParts(new Date(Date.UTC(0, 0, 0, 0, 0, 0)));
return parts.find(({ type }) => type === "dayPeriod")?.value ? "12" : "24";
}
function getLocalizedMeridiem({
locale,
meridiem,
parts: fromParts
}) {
const localesWithBrowserBugs = ["he", "bs", "mk"];
let localizedMeridiem;
if (fromParts) {
localizedMeridiem = fromParts.find(({ type }) => type === "dayPeriod")?.value || null;
if (locale && localesWithBrowserBugs.includes(locale)) {
const localeData = localizedTwentyFourHourMeridiems.get(locale);
if (localizedMeridiem === "PM") {
localizedMeridiem = localeData.pm;
}
if (localizedMeridiem === "AM") {
localizedMeridiem = localeData.am;
}
}
} else if (meridiem) {
if (localesWithBrowserBugs.includes(locale)) {
const localeData = localizedTwentyFourHourMeridiems.get(locale);
localizedMeridiem = meridiem === "PM" ? localeData.pm : localeData.am;
} else {
const formatter = createLocaleDateTimeFormatter({ locale, hour12: true });
const arbitraryAMHour = 6;
const arbitraryPMHour = 18;
const dateWithHourBasedOnMeridiem = new Date(
Date.UTC(0, 0, 0, meridiem === "AM" ? arbitraryAMHour : arbitraryPMHour, 0)
);
const parts = formatter.formatToParts(dateWithHourBasedOnMeridiem);
localizedMeridiem = parts.find(({ type }) => type === "dayPeriod")?.value || null;
}
}
return localizedMeridiem;
}
function getLocalizedDecimalSeparator(locale, numberingSystem) {
numberStringFormatter.numberFormatOptions = {
locale,
numberingSystem
};
return numberStringFormatter.localize("1.1").split("")[1];
}
function getLocalizedTimePartSuffix(part, locale, numberingSystem = "latn") {
const formatter = createLocaleDateTimeFormatter({ locale, numberingSystem });
const parts = formatter.formatToParts(new Date(Date.UTC(0, 0, 0, 0, 0, 0)));
return getLocalizedTimePart(`${part}Suffix`, parts);
}
function getLocalizedTimePart(part, parts, locale = "en") {
if (!part || !parts) {
return null;
}
if (part === "hourSuffix") {
const hourIndex = parts.indexOf(parts.find(({ type }) => type === "hour"));
const minuteIndex = parts.indexOf(parts.find(({ type }) => type === "minute"));
const hourSuffix = parts[hourIndex + 1];
return hourSuffix && hourSuffix.type === "literal" && minuteIndex - hourIndex === 2 ? hourSuffix.value?.trim() || null : null;
}
if (part === "minuteSuffix") {
const minuteIndex = parts.indexOf(parts.find(({ type }) => type === "minute"));
const secondIndex = parts.indexOf(parts.find(({ type }) => type === "second"));
const minuteSuffix = parts[minuteIndex + 1];
return minuteSuffix && minuteSuffix.type === "literal" && secondIndex - minuteIndex === 2 ? minuteSuffix.value?.trim() || null : null;
}
if (part === "secondSuffix") {
let secondSuffixPart;
const fractionalSecondIndex = parts.indexOf(parts.find(({ type }) => type === "fractionalSecond"));
if (fractionalSecondIndex) {
secondSuffixPart = parts[fractionalSecondIndex + 1];
} else {
const secondIndex = parts.indexOf(parts.find(({ type }) => type === "second"));
secondSuffixPart = parts[secondIndex + 1];
}
return secondSuffixPart?.type === "literal" && secondSuffixPart.value?.trim() || null;
}
if (part === "meridiem") {
const meridiemFromBrowser = parts.find(({ type }) => type === "dayPeriod")?.value || null;
if (meridiemFromBrowser) {
return getLocalizedMeridiem({ locale, parts });
}
}
return parts.find(({ type }) => type === part)?.value || null;
}
function getMeridiem(hour) {
if (!isValidNumber(hour)) {
return null;
}
const hourAsNumber = parseInt(hour);
return hourAsNumber >= 0 && hourAsNumber <= 11 ? "AM" : "PM";
}
function getMeridiemOrder(locale) {
const formatter = new Intl.DateTimeFormat(locale, {
hour: "2-digit",
hour12: true,
minute: "2-digit",
timeZone: "UTC"
});
const timeParts = formatter.formatToParts(new Date(Date.UTC(0, 0, 0, 0, 0)));
return timeParts.findIndex((value) => value.type === "dayPeriod");
}
function isValidTime(value) {
const isString = typeof value === "string";
if (!value || isString && (value.startsWith(":") || value.endsWith(":")) || !isString && (!value.hour || !value.minute)) {
return false;
}
let hour;
let minute;
let second;
if (isString) {
[hour, minute, second] = value.split(":");
} else {
({ hour, minute, second } = value);
}
if (!hour || !minute) {
return false;
}
const hourAsNumber = parseInt(hour);
const minuteAsNumber = parseInt(minute);
const secondAsNumber = parseInt(second);
const hourValid = isValidNumber(hour) && hourAsNumber >= 0 && hourAsNumber < 24;
const minuteValid = isValidNumber(minute) && minuteAsNumber >= 0 && minuteAsNumber < 60;
const secondValid = isValidNumber(second) && secondAsNumber >= 0 && secondAsNumber < 60;
if (hourValid && minuteValid && !second || hourValid && minuteValid && secondValid) {
return true;
}
return false;
}
function isValidTimePart(value, part) {
if (part === "meridiem") {
return value === "AM" || value === "PM";
}
if (!isValidNumber(value)) {
return false;
}
const valueAsNumber = Number(value);
const isZeroOrGreater = valueAsNumber >= 0;
const isLessThanMaxHour = valueAsNumber < 24;
const isLessThanMaxSecond = valueAsNumber < 60;
const isLessThanMaxFractionalSecond = valueAsNumber <= 999;
if (part === "hour") {
return isZeroOrGreater && isLessThanMaxHour;
}
if (part === "fractionalSecond") {
return isZeroOrGreater && isLessThanMaxFractionalSecond;
}
return isZeroOrGreater && isLessThanMaxSecond;
}
function localizeTimePart({
value,
part,
locale,
numberingSystem = "latn",
hour12
}) {
if (!isValidTimePart(value, part)) {
return;
}
if (part === "fractionalSecond") {
const localizedDecimalSeparator = getLocalizedDecimalSeparator(locale, numberingSystem);
let localizedFractionalSecond = null;
if (value) {
numberStringFormatter.numberFormatOptions = {
locale,
numberingSystem
};
const localizedZero = numberStringFormatter.localize("0");
if (parseInt(value) === 0) {
localizedFractionalSecond = "".padStart(value.length, localizedZero);
} else {
localizedFractionalSecond = numberStringFormatter.localize(`0.${value}`).replace(`${localizedZero}${localizedDecimalSeparator}`, "");
if (localizedFractionalSecond.length < value.length) {
localizedFractionalSecond = localizedFractionalSecond.padEnd(value.length, localizedZero);
}
}
}
return localizedFractionalSecond;
}
const valueAsNumber = parseInt(value);
const date = new Date(
Date.UTC(
0,
0,
0,
part === "hour" ? valueAsNumber : part === "meridiem" ? value === "AM" ? 0 : 12 : 0,
part === "minute" ? valueAsNumber : 0,
part === "second" ? valueAsNumber : 0
)
);
if (!date) {
return;
}
const formatter = createLocaleDateTimeFormatter({ hour12, locale, numberingSystem });
const parts = formatter.formatToParts(date);
return getLocalizedTimePart(part, parts, locale);
}
function localizeTimeString({
hour12,
includeSeconds = true,
locale,
numberingSystem = "latn",
parts: toParts = false,
step,
value
}) {
if (!isValidTime(value)) {
return null;
}
const { hour, minute, second = "0", fractionalSecond } = parseTimeString(value, step);
const dateFromTimeString = new Date(
Date.UTC(
0,
0,
0,
parseInt(hour),
parseInt(minute),
parseInt(second),
fractionalSecond && fractionalSecondPartToMilliseconds(fractionalSecond)
)
);
const formatter = createLocaleDateTimeFormatter({
fractionalSecondDigits: decimalPlaces(step),
hour12,
includeSeconds,
locale,
numberingSystem
});
if (toParts) {
const parts = formatter.formatToParts(dateFromTimeString);
return {
hour: getLocalizedTimePart("hour", parts),
hourSuffix: getLocalizedTimePart("hourSuffix", parts),
minute: getLocalizedTimePart("minute", parts),
minuteSuffix: getLocalizedTimePart("minuteSuffix", parts),
second: getLocalizedTimePart("second", parts),
decimalSeparator: getLocalizedDecimalSeparator(locale, numberingSystem),
fractionalSecond: getLocalizedTimePart("fractionalSecond", parts),
secondSuffix: locale !== "bg" && getLocalizedTimePart("secondSuffix", parts),
meridiem: getLocalizedTimePart("meridiem", parts, locale)
};
} else {
let result = formatter.format(dateFromTimeString) || null;
if (!toParts && typeof result === "string" && locale === "bg" && result && result.includes(" ч.")) {
result = result.replaceAll(" ч.", "");
}
if (["he", "bs", "mk"].includes(locale)) {
const localeData = localizedTwentyFourHourMeridiems.get(locale);
if (result.includes("AM")) {
result = result.replaceAll("AM", localeData.am);
} else if (result.includes("PM")) {
result = result.replaceAll("PM", localeData.pm);
}
if (locale !== "he" && result.indexOf(".") !== result.length - 1) {
result = result.replace(".", ",");
}
}
return result;
}
}
function localizeTimeStringToParts({
hour12,
locale,
numberingSystem = "latn",
step = 60,
value
}) {
if (!isValidTime(value)) {
return null;
}
const { hour, minute, second = "0", fractionalSecond } = parseTimeString(value, step);
const dateFromTimeString = new Date(
Date.UTC(
0,
0,
0,
parseInt(hour),
parseInt(minute),
parseInt(second),
fractionalSecond && fractionalSecondPartToMilliseconds(fractionalSecond)
)
);
if (dateFromTimeString) {
const formatter = createLocaleDateTimeFormatter({
fractionalSecondDigits: decimalPlaces(step),
hour12,
locale,
numberingSystem
});
const parts = formatter.formatToParts(dateFromTimeString);
return {
hour: getLocalizedTimePart("hour", parts),
hourSuffix: getLocalizedTimePart("hourSuffix", parts),
minute: getLocalizedTimePart("minute", parts),
minuteSuffix: getLocalizedTimePart("minuteSuffix", parts),
second: getLocalizedTimePart("second", parts),
decimalSeparator: getLocalizedDecimalSeparator(locale, numberingSystem),
fractionalSecond: getLocalizedTimePart("fractionalSecond", parts),
secondSuffix: locale !== "bg" && getLocalizedTimePart("secondSuffix", parts),
meridiem: getLocalizedTimePart("meridiem", parts, locale)
};
}
return null;
}
function parseTimeString(value, step) {
if (isValidTime(value)) {
const [hour, minute, secondDecimal] = value.split(":");
let second = secondDecimal;
let fractionalSecond = null;
if (secondDecimal?.includes(".")) {
[second, fractionalSecond] = secondDecimal.split(".");
}
if (step) {
fractionalSecond = formatFractionalSecond(fractionalSecond, step);
}
return {
fractionalSecond,
hour,
minute,
second
};
}
return {
fractionalSecond: null,
hour: null,
minute: null,
second: null
};
}
function toISOTimeString(value, step = 60) {
if (!isValidTime(value)) {
return null;
}
let hour;
let minute;
let second;
let secondDecimal;
let fractionalSecond;
let isoTimeString = null;
if (typeof value === "string") {
[hour, minute, secondDecimal] = value.split(":");
[second, fractionalSecond] = secondDecimal?.split(".") || ["0"];
} else {
hour = value.hour;
minute = value.minute;
second = value.second;
fractionalSecond = value.fractionalSecond;
}
if (hour && minute) {
isoTimeString = `${formatTimePart(parseInt(hour))}:${formatTimePart(parseInt(minute))}`;
if (step < 60) {
isoTimeString += `:${formatTimePart(parseInt(second || "0"))}`;
if (step < 1) {
isoTimeString += `.${formatFractionalSecond(fractionalSecond || "0", step)}`;
}
}
}
return isoTimeString;
}
export {
getLocalizedTimePartSuffix as a,
getLocalizedDecimalSeparator as b,
localizeTimePart as c,
getLocaleHourFormat as d,
getMeridiemOrder as e,
formatTimePart as f,
getMeridiem as g,
localizeTimeString as h,
isValidTime as i,
getLocalizedMeridiem as j,
localizeTimeStringToParts as l,
maxTenthForMinuteAndSecond as m,
parseTimeString as p,
toISOTimeString as t
};