UNPKG

@oruga-ui/oruga-next

Version:

UI components for Vue.js and CSS framework agnostic

163 lines (148 loc) 5.59 kB
import { computed } from "vue"; import { matchWithGroups } from "../datepicker/utils"; import type { DatetimepickerProps } from "./props"; const AM = "AM" as const; const PM = "PM" as const; const HOUR_FORMAT_24 = "24" as const; /** Time Format Feature */ export function useDateimepickerMixins(props: DatetimepickerProps) { const localeOptions = computed( () => new Intl.DateTimeFormat(props.locale, { year: "numeric", month: "numeric", day: "numeric", hour: "numeric", minute: "numeric", second: props.timepicker?.enableSeconds ? "numeric" : undefined, }).resolvedOptions() as Intl.DateTimeFormatOptions, ); const isHourFormat24 = computed( () => (props.timepicker?.hourFormat && props.timepicker.hourFormat === HOUR_FORMAT_24) || (!props.timepicker?.hourFormat && !localeOptions.value.hour12), ); const dtf = computed( () => new Intl.DateTimeFormat(props.locale, { year: localeOptions.value.year || "numeric", month: localeOptions.value.month || "numeric", day: localeOptions.value.day || "numeric", hour: localeOptions.value.hour || "numeric", minute: localeOptions.value.minute || "numeric", second: props.timepicker?.enableSeconds ? localeOptions.value.second || "numeric" : undefined, hourCycle: !isHourFormat24.value ? "h12" : "h23", }), ); const amString = computed(() => { if ( dtf.value.formatToParts && typeof dtf.value.formatToParts === "function" ) { const d = datetimeCreator(); d.setHours(10); const dayPeriod = dtf.value .formatToParts(d) .find((part) => part.type === "dayPeriod"); if (dayPeriod) return dayPeriod.value; } return AM; }); const pmString = computed(() => { if ( dtf.value.formatToParts && typeof dtf.value.formatToParts === "function" ) { const d = datetimeCreator(); d.setHours(20); const dayPeriod = dtf.value .formatToParts(d) .find((part) => part.type === "dayPeriod"); if (dayPeriod) return dayPeriod.value; } return PM; }); function datetimeCreator(): Date { return typeof props.creator === "function" ? props.creator() : new Date(); } function datetimeFormatter(date: Date): string { if (typeof props.formatter === "function") return props.formatter(date); if (!date) return ""; return dtf.value.format(date); } function datetimeParser(date: string): Date | undefined { if (typeof props.parser === "function") return props.parser(date); if (!date) return undefined; if ( dtf.value.formatToParts && typeof dtf.value.formatToParts === "function" ) { const dayPeriods = [ AM, PM, AM.toLowerCase(), PM.toLowerCase(), amString.value, pmString.value, ]; const parts = dtf.value.formatToParts(new Date()); const formatRegex = parts .map((part, idx) => { if (part.type === "literal") { if ( idx + 1 < parts.length && parts[idx + 1].type === "hour" ) { return `[^\\d]+`; } return part.value.replace(/ /g, "\\s?"); } else if (part.type === "dayPeriod") { return `((?!=<${part.type}>)(${dayPeriods.join( "|", )})?)`; } return `((?!=<${part.type}>)\\d+)`; }) .join(""); const datetimeGroups = matchWithGroups(formatRegex, date); // We do a simple validation for the group. // If it is not valid, it will fallback to Date.parse below if ( datetimeGroups.year && datetimeGroups.year.length === 4 && datetimeGroups.month && datetimeGroups.month <= 12 && datetimeGroups.day && datetimeGroups.day <= 31 && datetimeGroups.hour && datetimeGroups.hour >= 0 && datetimeGroups.hour < 24 && datetimeGroups.minute && datetimeGroups.minute >= 0 && datetimeGroups.minute <= 59 ) { return new Date( datetimeGroups.year, datetimeGroups.month - 1, datetimeGroups.day, datetimeGroups.hour, datetimeGroups.minute, datetimeGroups.second || 0, ); } } // Fallback if formatToParts is not supported or if we were not able to parse a valid date return new Date(Date.parse(date)); } return { dtf, datetimeCreator, datetimeFormatter, datetimeParser, }; }