{"version":3,"file":"dateFunctions.mjs","names":[],"sources":["../../../../package/common/datePicker/dateFunctions.ts"],"sourcesContent":["import { dateToDay, daysInMonth, formatDay, parseDay, type DayParts } from '../utils/day';\nimport type { Weekday } from '../utils/weekStart';\n\n// Labels are formatted from a UTC date in UTC, so no time zone can move them onto another day.\n// `setUTCFullYear` rather than `Date.UTC`, which reads the years 0 to 99 as 1900 to 1999.\nfunction utcDate(year: number, month: number, day: number): Date {\n  const date = new Date(0);\n  date.setUTCFullYear(year, month - 1, day);\n  return date;\n}\n\nfunction getMonthName(locale: string | undefined, month: number): string {\n  return utcDate(2023, month, 1).toLocaleDateString(locale, { month: 'long', timeZone: 'UTC' });\n}\n\n// Cached: DatePicker renders on every hover and keystroke, and each name costs a formatter.\nconst monthNames = new Map<string, string[]>();\nconst weekDayNames = new Map<string, string[]>();\n\nexport function getMonthNames(locale: string | undefined): string[] {\n  const key = locale ?? '';\n  let names = monthNames.get(key);\n  if (!names) {\n    names = Array.from(Array(12).keys()).map((index) => getMonthName(locale, index + 1));\n    monthNames.set(key, names);\n  }\n  return names;\n}\n\n/** The seven short weekday names, from `weekStart` on. */\nexport function getWeekDays(locale: string | undefined, weekStart: Weekday): string[] {\n  const key = `${locale ?? ''}|${weekStart}`;\n  let names = weekDayNames.get(key);\n  if (!names) {\n    // 9 April 2023 was a Sunday.\n    names = Array.from(Array(7).keys()).map((index) =>\n      utcDate(2023, 4, 9 + weekStart + index).toLocaleDateString(locale, { weekday: 'short', timeZone: 'UTC' }),\n    );\n    weekDayNames.set(key, names);\n  }\n  return names;\n}\n\n/** The weekday of the 1st, as `Date#getDay()` counts: 0 is Sunday. */\nexport function getStartWeekDayOfMonth(month: number, year: number): Weekday {\n  return utcDate(year, month, 1).getUTCDay() as Weekday;\n}\n\n/** `delta` days from a day, rolling over into the months and years around it. */\nexport function addDays(day: number, month: number, year: number, delta: number): DayParts {\n  let d = day + delta;\n  let m = month;\n  let y = year;\n  while (d < 1) {\n    m -= 1;\n    if (m < 1) {\n      m = 12;\n      y -= 1;\n    }\n    d += daysInMonth({ year: y, month: m });\n  }\n  while (d > daysInMonth({ year: y, month: m })) {\n    d -= daysInMonth({ year: y, month: m });\n    m += 1;\n    if (m > 12) {\n      m = 1;\n      y += 1;\n    }\n  }\n  return { day: d, month: m, year: y };\n}\n\n/** Today in the user's time zone. */\nexport function getToday(): DayParts {\n  return parseDay(dateToDay(new Date()))!;\n}\n\n/** A `'YYYY-MM-DD'` day as the field shows it, `dd.mm.yyyy`, or `''` for anything else. */\nexport function getDateString(value: string | null | undefined): string {\n  const parts = parseDay(value);\n  if (!parts) return '';\n  return `${String(parts.day).padStart(2, '0')}.${String(parts.month).padStart(2, '0')}.${String(parts.year).padStart(4, '0')}`;\n}\n\n/** What the field holds, `dd.mm.yyyy`, as `'YYYY-MM-DD'`; `null` while incomplete, or for a day that does not exist. */\nexport function parseDateString(text: string): string | null {\n  const match = /^(\\d{2})\\.(\\d{2})\\.(\\d{4})$/.exec(text);\n  if (!match) return null;\n  const value = formatDay({ day: Number(match[1]), month: Number(match[2]), year: Number(match[3]) });\n  return parseDay(value) ? value : null;\n}\n\nexport interface DateMaskSelection {\n  start: number;\n  end: number;\n}\n\nexport interface DateMaskState {\n  value: string;\n  selection: DateMaskSelection | null;\n}\n\n/**\n * Auto-corrects a partially typed `dd.mm.yyyy` mask value so a single out-of-range\n * digit doesn't force the user to backtrack:\n * - a day \"tens\" digit > 3 (e.g. typing `4`) becomes `04` and the caret jumps to the month\n * - a day of `3x` where x > 1 (e.g. `35`) becomes `0x`\n * - a month \"tens\" digit > 1 (e.g. `2`) becomes `02` and the caret jumps to the year\n * - a month `1x` where x > 2 (e.g. `13`) is clamped to `12`\n *\n * `previousValue` supplies the digits to retain for the part of the field that isn't\n * being rewritten. The returned `selection` is the adjusted caret position, or the\n * passed-in `selection` when no correction applies.\n */\nexport function correctDateMaskValue(\n  nextValue: string,\n  previousValue: string,\n  selection: DateMaskSelection | null,\n): DateMaskState {\n  let value = nextValue;\n  let nextSelection = selection;\n\n  if (value[0] !== '_') {\n    if (value[0] > '3') {\n      value = `0${value[0]}${previousValue.substring(2)}`;\n      nextSelection = { start: 3, end: 3 };\n    } else if (value[0] === '3') {\n      if (value[1] !== '_' && value[1] > '1') {\n        value = `0${value[1]}${previousValue.substring(2)}`;\n        nextSelection = { start: 3, end: 3 };\n      }\n    }\n  }\n  if (value[3] !== '_' && value[3] > '1') {\n    value = `${value.substring(0, 3)}0${value[3]}${previousValue.substring(5)}`;\n    nextSelection = { start: 6, end: 6 };\n  }\n  if (value[3] === '1' && value[4] !== '_' && value[4] > '2') {\n    value = `${value.substring(0, 3)}${value[3]}2${previousValue.substring(5)}`;\n  }\n\n  return { value, selection: nextSelection };\n}\n"],"mappings":"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"}