@12-apps/ui 6.10.0 → 6.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/form/DateRangePicker/DateRangePicker.tsx","../../src/components/form/DateRangePicker/DateRangePicker.dates.ts","../../src/components/form/DateRangePicker/DateRangePicker.hooks.ts","../../src/components/form/DateRangePicker/DateRangePicker.range.ts","../../src/components/form/DateRangePicker/DateRangePicker.quick.ts","../../src/components/form/DateRangePicker/DateRangePickerFields.tsx","../../src/components/form/DateRangePicker/DateRangePickerQuickList.tsx"],"sourcesContent":["'use client';\n\n/**\n * Three views of ONE range: a calendar, a quick-pick column, and two typed\n * dates. Change any and the other two follow.\n *\n * WHY IT EXISTS: a range calendar alone makes \"this quarter\" cost two clicks,\n * a month of paging, and a mental note of which day a quarter starts on; a list\n * of presets alone cannot express \"the 3rd to the 19th\"; and typed fields alone\n * make you spell out a window you can see. Each of the three is the fastest\n * route to a different range, so the control offers all three over one value\n * rather than picking a favourite.\n *\n * WHAT IT DOES NOT KNOW: anything about the data behind the range. No preset\n * list of a product's own, no ceiling of its own, no notion of whose clock\n * \"today\" runs on — `quickRanges`, `maxRangeDays` and `timeZone` are props, and\n * a consumer that needs its own periods passes them rather than teaching this\n * file about its domain. The calendar is `Calendar` in `selectionMode=\"range\"`,\n * not a second implementation of one.\n *\n * The value is a DRAFT (`{ from, to }`, either end possibly null) rather than a\n * finished window, so a half-picked or impossible range has somewhere to live\n * while it is being fixed. Every `onChange` carries the verdict with it.\n */\nimport { Box, Paper, useMediaQuery } from '@mui/material';\nimport type { SxProps, Theme } from '@mui/material';\nimport React from 'react';\n\nimport { Calendar } from '../Calendar';\n\nimport { toLocalDay } from './DateRangePicker.dates';\nimport { useDateRangePicker } from './DateRangePicker.hooks';\nimport { DEFAULT_QUICK_RANGES } from './DateRangePicker.quick';\nimport type { DateRangeDraft, DateRangePickerProps, WeekStart } from './DateRangePicker.types';\nimport { DateRangeFields } from './DateRangePickerFields';\nimport { DateRangeQuickList } from './DateRangePickerQuickList';\n\nconst CALENDAR_CLASS = 'date-range-picker__calendar';\n\n/** Below this the picker is a phone layout. MUI's own `md`, written out. */\nconst NARROW_QUERY = '(max-width:899.95px)';\n\nconst ROOT_SX: SxProps<Theme> = {\n display: 'inline-flex',\n flexDirection: 'column',\n gap: 2,\n p: 2,\n maxWidth: '100%',\n // `Calendar` renders its own `Paper` with 24px of padding. Nested in this one\n // that reads as a box inside a box, so the inner frame is flattened here\n // through the className hook the component exposes for exactly this.\n [`& .${CALENDAR_CLASS}`]: {\n p: 0,\n boxShadow: 'none',\n backgroundColor: 'transparent',\n backgroundImage: 'none',\n },\n};\n\nconst BODY_SX: SxProps<Theme> = {\n display: 'flex',\n // The quick column sits BESIDE the calendar on a wide screen. Narrow, it\n // moves ABOVE it — `column-reverse`, so the DOM order stays calendar-then-\n // list (the calendar is the primary control and should be reached first by a\n // screen reader and by Tab) while the eye meets the quick ranges first, which\n // is the order the phone mock asks for and the order a thumb wants: nine\n // one-tap answers before a grid of thirty.\n //\n // A side column at 390px would squeeze the day grid to roughly half its width\n // and make the numbers unreadable. Checked at 390px.\n flexDirection: { xs: 'column-reverse', md: 'row' },\n alignItems: { xs: 'stretch', md: 'flex-start' },\n gap: 2,\n maxWidth: '100%',\n};\n\n/**\n * The rule between the calendar and the quick ranges.\n *\n * Two lists of dates side by side with only whitespace between them read as one\n * ragged thing; the rule says which numbers belong to which control. It turns\n * with the layout — a vertical rule when the list is a column beside the\n * calendar, a horizontal one when it has moved above it — because a divider\n * that keeps its axis while the flex direction flips ends up separating nothing.\n */\nconst QUICK_DIVIDER_SX: SxProps<Theme> = {\n borderColor: 'divider',\n borderStyle: 'solid',\n borderWidth: 0,\n borderLeftWidth: { xs: 0, md: '1px' },\n borderBottomWidth: { xs: '1px', md: 0 },\n pl: { xs: 0, md: 2 },\n pb: { xs: 2, md: 0 },\n alignSelf: 'stretch',\n};\n\n/** And the rule above the typed pair, which is a third way in, not a caption. */\nconst FIELDS_DIVIDER_SX: SxProps<Theme> = {\n borderTop: '1px solid',\n borderColor: 'divider',\n pt: 2,\n};\n\ntype Picker = ReturnType<typeof useDateRangePicker>;\n\n/**\n * How many months to draw.\n *\n * A month grid has a floor: seven columns that must stay legible, which is\n * about 280px. Two of them need 580, so on a phone the consumer's\n * `numberOfMonths` is not a preference that can be honoured — it is a request\n * for a layout that does not fit. Capped here rather than left to the consumer,\n * because the consumer chooses for its own reason (the reports dialog wants two\n * because a period often crosses a month boundary) and has no way to know the\n * picker is currently 390px wide.\n *\n * A media query rather than an `sx` breakpoint: this decides what to RENDER,\n * and CSS cannot un-render a second month.\n *\n * The query is a LITERAL, not `theme.breakpoints.down('md')`. The callback form\n * reads the theme from context and throws on a null one, so a consumer that\n * mounts this outside a `ThemeProvider` would crash — which the unit tests here\n * do, and which is a fair thing for a consumer to do.\n */\nfunction useMonthCount(requested: number | undefined): number | undefined {\n const narrow = useMediaQuery(NARROW_QUERY);\n return narrow ? 1 : requested;\n}\n\n/** The grid, in range mode — `Calendar`, never a second implementation of one. */\nfunction RangeCalendar({\n calendarLabel,\n picker,\n value,\n locale,\n weekStartsOn,\n months,\n maxRangeDays,\n}: {\n picker: Picker;\n value: DateRangeDraft;\n locale: string;\n weekStartsOn: WeekStart;\n months: number | undefined;\n maxRangeDays: number | undefined;\n calendarLabel: string;\n}): React.JSX.Element {\n return (\n <Calendar\n key={picker.viewNonce}\n ariaLabel={calendarLabel}\n className={CALENDAR_CLASS}\n selectionMode=\"range\"\n locale={locale}\n // One prop drives the grid's first column AND the day \"this week\" starts\n // on, so a highlighted week can never begin mid-row.\n firstDayOfWeek={weekStartsOn}\n numberOfMonths={months}\n range={{ start: toLocalDay(value.from), end: toLocalDay(value.to) }}\n // BOTH callbacks, and the intermediate one does the work: the other fires\n // only on the click that CLOSES a range, so a picker wired to it alone\n // would not repaint after the first click.\n onIntermediateRangeChange={picker.pickOnCalendar}\n onRangeChange={picker.pickOnCalendar}\n // The same ceiling the quick list is judged against, so the calendar\n // cannot hand back a window the control has just called too long.\n maxRangeLength={maxRangeDays}\n />\n );\n}\n\n/** The quick ranges, inside the rule that separates them from the grid. */\nfunction QuickColumn({\n picker,\n maxRangeDays,\n dataTestId,\n}: {\n picker: Picker;\n maxRangeDays: number | undefined;\n dataTestId: string;\n}): React.JSX.Element | null {\n if (picker.options.length === 0) return null;\n return (\n <Box sx={QUICK_DIVIDER_SX}>\n <DateRangeQuickList\n options={picker.options}\n activeId={picker.activeId}\n onPick={picker.pickQuick}\n reasonFor={(option) =>\n picker.copy.overMax({ maxRangeDays: maxRangeDays ?? option.days, days: option.days })\n }\n label={picker.copy.quickRanges}\n dataTestId={dataTestId}\n />\n </Box>\n );\n}\n\nexport function DateRangePicker({\n value,\n onChange,\n timeZone,\n now,\n maxRangeDays,\n weekStartsOn = 0,\n quickRanges = DEFAULT_QUICK_RANGES,\n locale = 'en-US',\n numberOfMonths,\n messages,\n dataTestId = 'date-range-picker',\n className,\n}: DateRangePickerProps): React.JSX.Element {\n const picker = useDateRangePicker({\n value,\n onChange,\n timeZone,\n now,\n maxRangeDays,\n weekStartsOn,\n quickRanges,\n messages,\n });\n const months = useMonthCount(numberOfMonths);\n\n return (\n <Paper className={className} data-testid={dataTestId} sx={ROOT_SX}>\n <Box sx={BODY_SX}>\n <RangeCalendar\n calendarLabel={picker.copy.calendarLabel}\n picker={picker}\n value={value}\n locale={locale}\n weekStartsOn={weekStartsOn}\n months={months}\n maxRangeDays={maxRangeDays}\n />\n <QuickColumn picker={picker} maxRangeDays={maxRangeDays} dataTestId={dataTestId} />\n </Box>\n <Box sx={FIELDS_DIVIDER_SX}>\n <DateRangeFields\n value={value}\n status={picker.status}\n messages={picker.copy}\n maxRangeDays={maxRangeDays}\n onEdit={picker.editBound}\n statusId={picker.statusId}\n dataTestId={dataTestId}\n />\n </Box>\n </Paper>\n );\n}\n\nexport default DateRangePicker;\n","/**\n * Civil-day arithmetic for the range picker.\n *\n * Two representations meet here and the boundary between them is the whole\n * point of the file:\n *\n * - `AAAA-MM-DD` — what the picker's value, the quick ranges and any caller\n * speak. A day with no instant attached, so it cannot drift.\n * - a LOCAL `Date` at NOON — what `Calendar` deals in. Noon (not midnight) is\n * `Calendar.dates.normalizeDate`'s own rule: a daylight-saving jump at\n * midnight can move a date across a day boundary, and midday never can.\n *\n * The arithmetic itself is `Calendar.dates`' — `addDays` and `startOfWeek` are\n * imported rather than re-written, so a week here starts on the same day the\n * grid draws it.\n *\n * ONE thing needs a time zone: which day is today. Everything after that is\n * calendar arithmetic that has no clock in it.\n */\nimport { addDays, startOfWeek } from '../Calendar/Calendar.dates';\n\nimport type { DayString, WeekStart } from './DateRangePicker.types';\n\nconst NOON = 12;\nconst MS_PER_DAY = 86_400_000;\nconst MONTHS_PER_QUARTER = 3;\nconst DAY_PATTERN = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\n/** `[year, month 1-12, day]`, or null when the text is not a day at all. */\nfunction dayParts(day: DayString): [number, number, number] | null {\n const parts = DAY_PATTERN.exec(day);\n if (!parts) return null;\n return [Number(parts[1]), Number(parts[2]), Number(parts[3])];\n}\n\nconst pad = (value: number): string => String(value).padStart(2, '0');\n\n/** `AAAA-MM-DD` from calendar parts. Month is 1-12. */\nfunction formatDay(year: number, month: number, day: number): DayString {\n return `${String(year).padStart(4, '0')}-${pad(month)}-${pad(day)}`;\n}\n\n/** A LOCAL `Date` → the day it falls on, read off the same local getters. */\nexport function toDayString(date: Date): DayString {\n return formatDay(date.getFullYear(), date.getMonth() + 1, date.getDate());\n}\n\n/**\n * `AAAA-MM-DD` → a LOCAL `Date` at noon, or null when the text is not a real\n * day.\n *\n * Deliberately not `new Date(day)`: the spec reads a bare `AAAA-MM-DD` as UTC\n * midnight, so west of Greenwich it lands on the day BEFORE and every date in\n * the picker is off by one. The round-trip check is what rejects `2026-02-31`,\n * which `Date` would otherwise roll silently into March.\n */\nexport function toLocalDay(day: DayString | null | undefined): Date | null {\n if (!day) return null;\n const parts = dayParts(day);\n if (!parts) return null;\n const date = new Date(parts[0], parts[1] - 1, parts[2], NOON);\n return toDayString(date) === day ? date : null;\n}\n\nconst civilFormatters = new Map<string, Intl.DateTimeFormat>();\n\nfunction civilFormatter(timeZone: string): Intl.DateTimeFormat {\n const cached = civilFormatters.get(timeZone);\n if (cached) return cached;\n const created = new Intl.DateTimeFormat('en-US', {\n timeZone,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n });\n civilFormatters.set(timeZone, created);\n return created;\n}\n\n/**\n * The civil day `now` falls on, on `timeZone`'s clock (the host's when absent).\n *\n * Read through `formatToParts` rather than by adding an offset to an epoch: the\n * zone database already knows about every transition, and reconstructing one by\n * hand is how a picker ends up a day out for exactly one week of the year.\n */\nexport function todayIn(timeZone: string | undefined, now: Date): DayString {\n if (!timeZone) return toDayString(now);\n const parts = civilFormatter(timeZone).formatToParts(now);\n const read = (type: Intl.DateTimeFormatPartTypes): string =>\n parts.find((part) => part.type === type)?.value ?? '';\n return `${read('year')}-${read('month')}-${read('day')}`;\n}\n\n/** The same day `days` later (or earlier). */\nexport function shiftDay(day: DayString, days: number): DayString {\n const date = toLocalDay(day);\n return date ? toDayString(addDays(date, days)) : day;\n}\n\n/** The 1st of `day`'s month. */\nexport function startOfMonthDay(day: DayString): DayString {\n const parts = dayParts(day);\n return parts ? formatDay(parts[0], parts[1], 1) : day;\n}\n\n/**\n * The 1st of `day`'s CALENDAR quarter — Jan/Apr/Jul/Oct. Fiscal quarters are a\n * different thing and belong in a caller's own quick range, not in a default.\n */\nexport function startOfQuarterDay(day: DayString): DayString {\n const parts = dayParts(day);\n if (!parts) return day;\n const month = parts[1] - ((parts[1] - 1) % MONTHS_PER_QUARTER);\n return formatDay(parts[0], month, 1);\n}\n\n/** The 1st of January of `day`'s year. */\nexport function startOfYearDay(day: DayString): DayString {\n const parts = dayParts(day);\n return parts ? formatDay(parts[0], 1, 1) : day;\n}\n\n/** The first day of `day`'s week, on the same week start the grid uses. */\nexport function startOfWeekDay(day: DayString, weekStartsOn: WeekStart): DayString {\n const date = toLocalDay(day);\n return date ? toDayString(startOfWeek(date, weekStartsOn)) : day;\n}\n\n/**\n * How many days a window covers, both ends INCLUDED — so a single day is 1.\n *\n * Measured on UTC epochs rather than on the local dates: the difference between\n * two local noons can be 23 or 25 hours across a transition, and dividing that\n * by a fixed day length is how a 30-day window starts reporting 29.96.\n */\nexport function dayCount(from: DayString, to: DayString): number {\n const start = dayParts(from);\n const end = dayParts(to);\n if (!start || !end) return 0;\n const startMs = Date.UTC(start[0], start[1] - 1, start[2]);\n const endMs = Date.UTC(end[0], end[1] - 1, end[2]);\n return Math.round((endMs - startMs) / MS_PER_DAY) + 1;\n}\n\n/** `AAAA-MM-DD` sorts lexicographically, so this needs no parsing at all. */\nexport function isAfterDay(a: DayString, b: DayString): boolean {\n return a > b;\n}\n","/**\n * Everything the picker derives and every way its range can move, kept out of\n * the component so that file is a layout and this one is the behaviour — the\n * same split `Calendar.hooks.ts` uses next door.\n */\nimport { useId, useMemo, useState } from 'react';\n\nimport { toDayString, todayIn } from './DateRangePicker.dates';\nimport {\n activeQuickRangeId,\n defaultMessages,\n resolveDayRange,\n resolveQuickRanges,\n} from './DateRangePicker.range';\nimport type {\n DateRangeChangeMeta,\n DateRangeDraft,\n DateRangePickerState,\n UseDateRangePickerArgs,\n} from './DateRangePicker.types';\n\nexport function useDateRangePicker({\n value,\n onChange,\n timeZone,\n now,\n maxRangeDays,\n weekStartsOn,\n quickRanges,\n messages,\n}: UseDateRangePickerArgs): DateRangePickerState {\n const statusId = useId();\n // `Calendar` reads which month to open on from the range it is handed, and\n // only when it MOUNTS. Bumping this key remounts it, which is how the other\n // two views move it. It changes for a quick pick and for a typed date and\n // NEVER for a click inside the grid — a calendar that jumped under the\n // pointer picking in it would be unusable.\n const [viewNonce, setViewNonce] = useState(0);\n\n const copy = useMemo(() => ({ ...defaultMessages(), ...messages }), [messages]);\n const today = useMemo(() => todayIn(timeZone, now ?? new Date()), [timeZone, now]);\n const options = useMemo(\n () => resolveQuickRanges(quickRanges, { today, weekStartsOn }, maxRangeDays),\n [quickRanges, today, weekStartsOn, maxRangeDays],\n );\n const status = useMemo(() => resolveDayRange(value, maxRangeDays), [value, maxRangeDays]);\n\n const emit = (\n next: DateRangeDraft,\n source: DateRangeChangeMeta['source'],\n quickRangeId?: string,\n ): void => {\n onChange(next, {\n source,\n ...(quickRangeId ? { quickRangeId } : {}),\n // Judged here, once. A caller left to re-derive \"is this usable\" is a\n // second opinion able to disagree with the message on screen.\n status: resolveDayRange(next, maxRangeDays),\n });\n };\n\n return {\n copy,\n options,\n activeId: activeQuickRangeId(options, value),\n status,\n statusId,\n viewNonce,\n pickQuick: (option) => {\n setViewNonce((nonce) => nonce + 1);\n emit({ from: option.window.from, to: option.window.to }, 'quick', option.id);\n },\n editBound: (which, bound) => {\n setViewNonce((nonce) => nonce + 1);\n emit({ ...value, [which]: bound }, which);\n },\n pickOnCalendar: (range) => {\n emit(\n {\n from: range.start ? toDayString(range.start) : null,\n to: range.end ? toDayString(range.end) : null,\n },\n 'calendar',\n );\n },\n };\n}\n","/**\n * Judging a draft, and saying so in words.\n *\n * The picker never repairs what it is given. A reversed pair is not silently\n * swapped and an over-long one is not clipped to the cap: both are reported,\n * because a control that returns a different range from the one on screen is\n * indistinguishable from one that ignored you. The caller reads\n * {@link DateRangeStatus} and keeps its own confirm button shut.\n */\nimport { isoToBr } from '../../data-display/DataViews/data-views-day-input';\n\nimport { dayCount, isAfterDay } from './DateRangePicker.dates';\nimport type {\n DateRangePickerMessages,\n DateRangeDraft,\n DateRangeStatus,\n QuickRange,\n QuickRangeContext,\n ResolvedQuickRange,\n} from './DateRangePicker.types';\n\n/**\n * Whether a draft is a window this picker will hand over.\n *\n * Exported because the caller needs the same verdict the picker shows: a dialog\n * disabling its \"Apply\" button must not re-derive \"is this legal\" from the two\n * strings, or the two answers drift and the button ends up enabled over a\n * message saying the range is impossible.\n */\nexport function resolveDayRange(\n draft: DateRangeDraft,\n maxRangeDays?: number,\n): DateRangeStatus {\n const { from, to } = draft;\n if (!from || !to) return { ok: false, problem: 'incomplete', days: 0 };\n if (isAfterDay(from, to)) return { ok: false, problem: 'reversed', days: 0 };\n\n const days = dayCount(from, to);\n if (maxRangeDays !== undefined && days > maxRangeDays) {\n return { ok: false, problem: 'over-max', days };\n }\n return { ok: true, window: { from, to }, days };\n}\n\n/**\n * The English defaults.\n *\n * The summary prints the days in the SAME `dd/mm/aaaa` the two fields are\n * masked to, rather than in the host locale's order. One control cannot show\n * the same date two ways: an `en-US` host formatting the summary as `08/05`\n * over a field reading `05/08` leaves the reader to work out which of the two\n * is lying. A host that wants its own order replaces `messages.summary`, which\n * moves both halves of the decision to the same place.\n */\nexport function defaultMessages(): DateRangePickerMessages {\n return {\n from: 'Start date',\n to: 'End date',\n quickRanges: 'Quick ranges',\n incomplete: 'Choose both dates.',\n reversed: 'The end date must be on or after the start date.',\n overMax: ({ maxRangeDays }) => `Choose a range of at most ${maxRangeDays} days.`,\n summary: ({ from, to }) => `${isoToBr(from)} – ${isoToBr(to)}`,\n calendarLabel: 'Calendar',\n dayMask: 'dd/mm/yyyy',\n };\n}\n\n/** The line under the fields: the chosen window, or why there isn't one. */\nexport function statusMessage(\n status: DateRangeStatus,\n messages: DateRangePickerMessages,\n maxRangeDays: number | undefined,\n): string {\n if (status.ok) return messages.summary(status.window);\n if (status.problem === 'incomplete') return messages.incomplete;\n if (status.problem === 'reversed') return messages.reversed;\n return messages.overMax({ maxRangeDays: maxRangeDays ?? status.days, days: status.days });\n}\n\n/** Every quick range with its window, its length, and whether it is over cap. */\nexport function resolveQuickRanges(\n quickRanges: QuickRange[],\n context: QuickRangeContext,\n maxRangeDays: number | undefined,\n): ResolvedQuickRange[] {\n return quickRanges.map((quickRange) => {\n const window = quickRange.resolve(context);\n const days = dayCount(window.from, window.to);\n return {\n ...quickRange,\n window,\n days,\n overMax: maxRangeDays !== undefined && days > maxRangeDays,\n };\n });\n}\n\n/** The quick range the draft currently IS, if it is exactly one of them. */\nexport function activeQuickRangeId(\n options: ResolvedQuickRange[],\n draft: DateRangeDraft,\n): string | undefined {\n return options.find(\n (option) => option.window.from === draft.from && option.window.to === draft.to,\n )?.id;\n}\n","/**\n * The quick-pick column's default list, and how to relabel it.\n *\n * These are DOMAIN-FREE on purpose: every one of them is derivable from \"today\"\n * and the calendar, so the design system can ship them without knowing what the\n * range is for. A product's own periods (a fiscal quarter, \"since the store\n * opened\", the last closed month) are a `quickRanges` array the caller passes —\n * the prop exists so that list never has to be smuggled in here.\n *\n * \"Last N days\" INCLUDES today, which is the reading every dashboard in the\n * wild uses: on the 10th, \"last 7 days\" is the 4th through the 10th, not the\n * 3rd through the 9th.\n */\nimport {\n shiftDay,\n startOfMonthDay,\n startOfQuarterDay,\n startOfWeekDay,\n startOfYearDay,\n} from './DateRangePicker.dates';\nimport type { QuickRange, QuickRangeContext } from './DateRangePicker.types';\n\n/**\n * The ids the built-in list uses. Stable API: a caller keys off these to map a\n * quick pick onto something of its own (a stored preset, an event name), and\n * renaming one is a breaking change in a way that renaming a label is not.\n */\nexport const QUICK_RANGE_IDS = [\n 'today',\n 'yesterday',\n 'this-week',\n 'last-7-days',\n 'this-month',\n 'last-30-days',\n 'this-quarter',\n 'this-year',\n 'last-365-days',\n] as const;\n\nexport type QuickRangeId = (typeof QUICK_RANGE_IDS)[number];\n\n/** English defaults. Every one is replaceable through {@link createQuickRanges}. */\nexport const DEFAULT_QUICK_RANGE_LABELS: Record<QuickRangeId, string> = {\n today: 'Today',\n yesterday: 'Yesterday',\n 'this-week': 'This week',\n 'last-7-days': 'Last 7 days',\n 'this-month': 'This month',\n 'last-30-days': 'Last 30 days',\n 'this-quarter': 'This quarter',\n 'this-year': 'This year',\n 'last-365-days': 'Last 365 days',\n};\n\n/** A window that ends today and reaches back `days` days, today included. */\nconst trailing =\n (days: number) =>\n ({ today }: QuickRangeContext) => ({ from: shiftDay(today, 1 - days), to: today });\n\n/** A window from the start of some period through today. */\nconst sinceStartOf =\n (start: (context: QuickRangeContext) => string) => (context: QuickRangeContext) => ({\n from: start(context),\n to: context.today,\n });\n\nconst RESOLVERS: Record<QuickRangeId, QuickRange['resolve']> = {\n today: trailing(1),\n yesterday: ({ today }) => ({ from: shiftDay(today, -1), to: shiftDay(today, -1) }),\n 'this-week': sinceStartOf(({ today, weekStartsOn }) => startOfWeekDay(today, weekStartsOn)),\n 'last-7-days': trailing(7),\n 'this-month': sinceStartOf(({ today }) => startOfMonthDay(today)),\n 'last-30-days': trailing(30),\n 'this-quarter': sinceStartOf(({ today }) => startOfQuarterDay(today)),\n 'this-year': sinceStartOf(({ today }) => startOfYearDay(today)),\n 'last-365-days': trailing(365),\n};\n\n/**\n * The built-in quick ranges, optionally relabelled.\n *\n * Relabelling rather than rebuilding is the point: a Portuguese host wants\n * \"Este mês\" over the same month-to-date arithmetic, and re-deriving the dates\n * to get the word is how two lists that claim the same thing start disagreeing.\n */\nexport function createQuickRanges(\n labels: Partial<Record<QuickRangeId, string>> = {},\n): QuickRange[] {\n return QUICK_RANGE_IDS.map((id) => ({\n id,\n label: labels[id] ?? DEFAULT_QUICK_RANGE_LABELS[id],\n resolve: RESOLVERS[id],\n }));\n}\n\n/** The list a picker uses when the caller says nothing. */\nexport const DEFAULT_QUICK_RANGES: QuickRange[] = createQuickRanges();\n","/**\n * The two typed ends, and the one line that says what the picker currently has.\n *\n * WHEN A TYPED DATE COMMITS: the moment it is a WHOLE, REAL day — eight digits\n * that name a date that exists. Not on every keystroke (`2026` passes through\n * `0002`, `0020` and `0202`, each a legal year, and committing those makes the\n * calendar jump to the year 20 while you are still typing) and not only on blur\n * (a reader who types a date and looks at the calendar to check it would see\n * the old month until they clicked somewhere else). Half-typed text stays in\n * the field and changes nothing; leaving the field discards it and shows what\n * the range actually is. Enter needs no special case — by the time it can be\n * pressed the date has already committed.\n *\n * The field itself is `DayBoundInput`, the masked `dd/mm/aaaa` control the data\n * views already use. Same package, imported rather than re-implemented: a\n * second masked date field is a second set of rules for what backspace does.\n */\nimport { Box, Typography } from '@mui/material';\nimport React from 'react';\n\nimport { DayBoundInput } from '../../data-display/DataViews/data-views-day-input';\n\nimport { statusMessage } from './DateRangePicker.range';\nimport type {\n DateRangePickerMessages,\n DateRangeDraft,\n DateRangeStatus,\n DayString,\n} from './DateRangePicker.types';\n\nexport interface DateRangeFieldsProps {\n value: DateRangeDraft;\n status: DateRangeStatus;\n messages: DateRangePickerMessages;\n maxRangeDays: number | undefined;\n onEdit: (which: 'from' | 'to', bound: DayString | null) => void;\n /** Id of the status line, so both fields can point at it. */\n statusId: string;\n dataTestId: string;\n}\n\nexport function DateRangeFields({\n value,\n status,\n messages,\n maxRangeDays,\n onEdit,\n statusId,\n dataTestId,\n}: DateRangeFieldsProps): React.JSX.Element {\n // \"Incomplete\" is not an error — it is a range that is not finished yet, and\n // painting it red would make the first click on a two-click control look like\n // a mistake. The pair being impossible is what gets marked.\n const rejected = !status.ok && status.problem !== 'incomplete';\n\n return (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>\n <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 2 }}>\n <DayBoundInput\n mask={messages.dayMask}\n label={messages.from}\n value={value.from ?? undefined}\n onChange={(bound) => onEdit('from', bound ?? null)}\n testId={`${dataTestId}-from`}\n error={rejected}\n describedBy={statusId}\n />\n <DayBoundInput\n mask={messages.dayMask}\n label={messages.to}\n value={value.to ?? undefined}\n onChange={(bound) => onEdit('to', bound ?? null)}\n testId={`${dataTestId}-to`}\n error={rejected}\n describedBy={statusId}\n />\n </Box>\n <Typography\n id={statusId}\n // A live region, so the reason a range was refused is spoken when it\n // appears rather than only being found by someone who goes looking.\n role=\"status\"\n aria-live=\"polite\"\n variant=\"body2\"\n color={rejected ? 'error.main' : 'text.secondary'}\n data-testid={`${dataTestId}-status`}\n >\n {statusMessage(status, messages, maxRangeDays)}\n </Typography>\n </Box>\n );\n}\n","/**\n * The quick-pick column beside the calendar.\n *\n * These are BUTTONS, not links or list rows: each one sets the range and the\n * pressed one stays visibly pressed, which is what `aria-pressed` says out\n * loud. (A listbox with `aria-selected` would model it too — the rule is to\n * pick one and use it for every entry, so a reader's screen reader describes\n * the whole column the same way.)\n *\n * An over-cap entry is `aria-disabled` and keeps its place in the tab order,\n * with the reason rendered under the label. Removing it, or quietly shortening\n * the window it hands back, both answer \"why can't I have this year?\" with\n * silence.\n */\nimport { Box } from '@mui/material';\nimport type { SxProps, Theme } from '@mui/material';\nimport React, { useId } from 'react';\n\nimport type { ResolvedQuickRange } from './DateRangePicker.types';\n\nconst optionSx = (active: boolean, overMax: boolean): SxProps<Theme> => ({\n display: 'block',\n // Full-width rows in the side column; pills in the narrow row. A fixed full\n // width in both would make the narrow layout nine stacked lines.\n width: { xs: 'auto', md: '100%' },\n // A pill must not be squeezed by its neighbours — the row SCROLLS rather\n // than compressing \"Este trimestre\" into two characters and an ellipsis.\n flex: { xs: '0 0 auto', md: '0 1 auto' },\n textAlign: 'left',\n font: 'inherit',\n fontSize: '0.875rem',\n fontWeight: active ? 600 : 400,\n lineHeight: 1.4,\n px: 1.5,\n py: 0.75,\n whiteSpace: { xs: 'nowrap', md: 'normal' },\n border: '1px solid',\n // Narrow, an entry has to look tappable on its own, with no column and no\n // rule to group it — so the pill carries a visible edge. Beside the calendar\n // the group already reads as a list and a border on every row would be nine\n // boxes where the selected one should be the only marked thing.\n borderColor: active ? 'primary.main' : { xs: 'divider', md: 'transparent' },\n borderRadius: { xs: 999, md: 1 },\n cursor: overMax ? 'not-allowed' : 'pointer',\n color: overMax ? 'text.disabled' : active ? 'primary.main' : 'text.primary',\n backgroundColor: active ? 'action.selected' : 'transparent',\n '&:hover': { backgroundColor: overMax ? 'transparent' : 'action.hover' },\n '&:focus-visible': { outline: '2px solid', outlineColor: 'primary.main', outlineOffset: 1 },\n});\n\nconst REASON_SX: SxProps<Theme> = {\n display: 'block',\n fontSize: '0.6875rem',\n lineHeight: 1.3,\n mt: 0.25,\n color: 'text.disabled',\n};\n\nexport interface DateRangeQuickListProps {\n options: ResolvedQuickRange[];\n /** The entry the current draft equals, if any. */\n activeId: string | undefined;\n onPick: (option: ResolvedQuickRange) => void;\n /** Why an entry is refused, rendered under it. */\n reasonFor: (option: ResolvedQuickRange) => string;\n /** Accessible name of the group. */\n label: string;\n dataTestId: string;\n}\n\nexport function DateRangeQuickList({\n options,\n activeId,\n onPick,\n reasonFor,\n label,\n dataTestId,\n}: DateRangeQuickListProps): React.JSX.Element {\n const reasonPrefix = useId();\n\n return (\n <Box\n role=\"group\"\n aria-label={label}\n data-testid={`${dataTestId}-quick-list`}\n sx={{\n display: 'flex',\n // A column beside the calendar; ONE scrolling row of pills above it\n // once there is no width for both.\n //\n // Scrolling rather than wrapping: nine wrapped pills take three or four\n // lines at 390px, which pushes the calendar most of a screen down and\n // makes the quick ranges — the fastest way to answer — the thing you\n // have to scroll past. One line keeps the calendar in view and costs a\n // horizontal swipe, which is the gesture a chip row already invites.\n flexDirection: { xs: 'row', md: 'column' },\n flexWrap: { xs: 'nowrap', md: 'wrap' },\n overflowX: { xs: 'auto', md: 'visible' },\n // Room for the focus ring, which an `overflow` container would clip.\n px: { xs: 0.25, md: 0 },\n py: { xs: 0.25, md: 0 },\n // The scrollbar is chrome on a phone and noise on a trackpad; the pills\n // themselves are the affordance, and the last one sits half-cut at the\n // edge to say the row continues.\n scrollbarWidth: 'none',\n '&::-webkit-scrollbar': { display: 'none' },\n alignContent: 'flex-start',\n gap: 0.5,\n minWidth: { md: 168 },\n maxWidth: { md: 200 },\n }}\n >\n {options.map((option) => {\n const active = option.id === activeId;\n const reasonId = `${reasonPrefix}-${option.id}`;\n return (\n <Box\n component=\"button\"\n type=\"button\"\n key={option.id}\n aria-pressed={active}\n // `aria-disabled`, never the `disabled` attribute: a disabled button\n // is skipped by the tab order, so the reason under it is unreachable\n // by exactly the reader most likely to need it.\n aria-disabled={option.overMax || undefined}\n aria-describedby={option.overMax ? reasonId : undefined}\n data-testid={`${dataTestId}-quick-${option.id}`}\n onClick={() => {\n if (!option.overMax) onPick(option);\n }}\n sx={optionSx(active, option.overMax)}\n >\n {option.label}\n {option.overMax && (\n <Box component=\"span\" id={reasonId} sx={REASON_SX}>\n {reasonFor(option)}\n </Box>\n )}\n </Box>\n );\n })}\n </Box>\n );\n}\n"],"mappings":"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","names":["Box","Box","useId","jsx","jsxs","jsx","jsxs","Box"]}
1
+ {"version":3,"sources":["../../src/components/form/DateRangePicker/DateRangePicker.tsx","../../src/components/form/DateRangePicker/DateRangePicker.dates.ts","../../src/components/form/DateRangePicker/DateRangePicker.hooks.ts","../../src/components/form/DateRangePicker/DateRangePicker.range.ts","../../src/components/form/DateRangePicker/DateRangePicker.quick.ts","../../src/components/form/DateRangePicker/DateRangePickerFields.tsx","../../src/components/form/DateRangePicker/DateRangePickerQuickList.tsx"],"sourcesContent":["'use client';\n\n/**\n * Three views of ONE range: a calendar, a quick-pick column, and two typed\n * dates. Change any and the other two follow.\n *\n * WHY IT EXISTS: a range calendar alone makes \"this quarter\" cost two clicks,\n * a month of paging, and a mental note of which day a quarter starts on; a list\n * of presets alone cannot express \"the 3rd to the 19th\"; and typed fields alone\n * make you spell out a window you can see. Each of the three is the fastest\n * route to a different range, so the control offers all three over one value\n * rather than picking a favourite.\n *\n * WHAT IT DOES NOT KNOW: anything about the data behind the range. No preset\n * list of a product's own, no ceiling of its own, no notion of whose clock\n * \"today\" runs on — `quickRanges`, `maxRangeDays` and `timeZone` are props, and\n * a consumer that needs its own periods passes them rather than teaching this\n * file about its domain. The calendar is `Calendar` in `selectionMode=\"range\"`,\n * not a second implementation of one.\n *\n * The value is a DRAFT (`{ from, to }`, either end possibly null) rather than a\n * finished window, so a half-picked or impossible range has somewhere to live\n * while it is being fixed. Every `onChange` carries the verdict with it.\n */\nimport { Box, Paper, useMediaQuery } from '@mui/material';\nimport type { SxProps, Theme } from '@mui/material';\nimport React from 'react';\n\nimport { Calendar } from '../Calendar';\n\nimport { toLocalDay } from './DateRangePicker.dates';\nimport { useDateRangePicker } from './DateRangePicker.hooks';\nimport { DEFAULT_QUICK_RANGES } from './DateRangePicker.quick';\nimport type { DateRangeDraft, DateRangePickerProps, WeekStart } from './DateRangePicker.types';\nimport { DateRangeFields } from './DateRangePickerFields';\nimport { DateRangeQuickList } from './DateRangePickerQuickList';\n\nconst CALENDAR_CLASS = 'date-range-picker__calendar';\n\n/** Below this the picker is a phone layout. MUI's own `md`, written out. */\nconst NARROW_QUERY = '(max-width:899.95px)';\n\nconst ROOT_SX: SxProps<Theme> = {\n display: 'inline-flex',\n flexDirection: 'column',\n gap: 2,\n p: 2,\n maxWidth: '100%',\n // `Calendar` renders its own `Paper` with 24px of padding. Nested in this one\n // that reads as a box inside a box, so the inner frame is flattened here\n // through the className hook the component exposes for exactly this.\n [`& .${CALENDAR_CLASS}`]: {\n p: 0,\n boxShadow: 'none',\n backgroundColor: 'transparent',\n backgroundImage: 'none',\n },\n};\n\nconst BODY_SX: SxProps<Theme> = {\n display: 'flex',\n // The quick column sits BESIDE the calendar on a wide screen. Narrow, it\n // moves ABOVE it — `column-reverse`, so the DOM order stays calendar-then-\n // list (the calendar is the primary control and should be reached first by a\n // screen reader and by Tab) while the eye meets the quick ranges first, which\n // is the order the phone mock asks for and the order a thumb wants: nine\n // one-tap answers before a grid of thirty.\n //\n // A side column at 390px would squeeze the day grid to roughly half its width\n // and make the numbers unreadable. Checked at 390px.\n flexDirection: { xs: 'column-reverse', md: 'row' },\n alignItems: { xs: 'stretch', md: 'flex-start' },\n gap: 2,\n maxWidth: '100%',\n};\n\n/**\n * The rule between the calendar and the quick ranges.\n *\n * Two lists of dates side by side with only whitespace between them read as one\n * ragged thing; the rule says which numbers belong to which control. It turns\n * with the layout — a vertical rule when the list is a column beside the\n * calendar, a horizontal one when it has moved above it — because a divider\n * that keeps its axis while the flex direction flips ends up separating nothing.\n */\nconst QUICK_DIVIDER_SX: SxProps<Theme> = {\n borderColor: 'divider',\n borderStyle: 'solid',\n borderWidth: 0,\n borderLeftWidth: { xs: 0, md: '1px' },\n borderBottomWidth: { xs: '1px', md: 0 },\n pl: { xs: 0, md: 2 },\n pb: { xs: 2, md: 0 },\n alignSelf: 'stretch',\n};\n\n/** And the rule above the typed pair, which is a third way in, not a caption. */\nconst FIELDS_DIVIDER_SX: SxProps<Theme> = {\n borderTop: '1px solid',\n borderColor: 'divider',\n pt: 2,\n};\n\ntype Picker = ReturnType<typeof useDateRangePicker>;\n\n/**\n * How many months to draw.\n *\n * A month grid has a floor: seven columns that must stay legible, which is\n * about 280px. Two of them need 580, so on a phone the consumer's\n * `numberOfMonths` is not a preference that can be honoured — it is a request\n * for a layout that does not fit. Capped here rather than left to the consumer,\n * because the consumer chooses for its own reason (the reports dialog wants two\n * because a period often crosses a month boundary) and has no way to know the\n * picker is currently 390px wide.\n *\n * A media query rather than an `sx` breakpoint: this decides what to RENDER,\n * and CSS cannot un-render a second month.\n *\n * The query is a LITERAL, not `theme.breakpoints.down('md')`. The callback form\n * reads the theme from context and throws on a null one, so a consumer that\n * mounts this outside a `ThemeProvider` would crash — which the unit tests here\n * do, and which is a fair thing for a consumer to do.\n */\nfunction useMonthCount(requested: number | undefined): number | undefined {\n const narrow = useMediaQuery(NARROW_QUERY);\n return narrow ? 1 : requested;\n}\n\n/** The grid, in range mode — `Calendar`, never a second implementation of one. */\nfunction RangeCalendar({\n calendarLabel,\n picker,\n value,\n locale,\n weekStartsOn,\n months,\n maxRangeDays,\n}: {\n picker: Picker;\n value: DateRangeDraft;\n locale: string;\n weekStartsOn: WeekStart;\n months: number | undefined;\n maxRangeDays: number | undefined;\n calendarLabel: string;\n}): React.JSX.Element {\n return (\n <Calendar\n key={picker.viewNonce}\n ariaLabel={calendarLabel}\n className={CALENDAR_CLASS}\n selectionMode=\"range\"\n locale={locale}\n // One prop drives the grid's first column AND the day \"this week\" starts\n // on, so a highlighted week can never begin mid-row.\n firstDayOfWeek={weekStartsOn}\n numberOfMonths={months}\n range={{ start: toLocalDay(value.from), end: toLocalDay(value.to) }}\n // BOTH callbacks, and the intermediate one does the work: the other fires\n // only on the click that CLOSES a range, so a picker wired to it alone\n // would not repaint after the first click.\n onIntermediateRangeChange={picker.pickOnCalendar}\n onRangeChange={picker.pickOnCalendar}\n // The same ceiling the quick list is judged against, so the calendar\n // cannot hand back a window the control has just called too long.\n maxRangeLength={maxRangeDays}\n />\n );\n}\n\n/** The quick ranges, inside the rule that separates them from the grid. */\nfunction QuickColumn({\n picker,\n maxRangeDays,\n dataTestId,\n}: {\n picker: Picker;\n maxRangeDays: number | undefined;\n dataTestId: string;\n}): React.JSX.Element | null {\n if (picker.options.length === 0) return null;\n return (\n <Box sx={QUICK_DIVIDER_SX}>\n <DateRangeQuickList\n options={picker.options}\n activeId={picker.activeId}\n onPick={picker.pickQuick}\n reasonFor={(option) =>\n picker.copy.overMax({ maxRangeDays: maxRangeDays ?? option.days, days: option.days })\n }\n label={picker.copy.quickRanges}\n dataTestId={dataTestId}\n />\n </Box>\n );\n}\n\nexport function DateRangePicker({\n value,\n onChange,\n timeZone,\n now,\n maxRangeDays,\n weekStartsOn = 0,\n quickRanges = DEFAULT_QUICK_RANGES,\n locale = 'en-US',\n numberOfMonths,\n messages,\n dataTestId = 'date-range-picker',\n className,\n}: DateRangePickerProps): React.JSX.Element {\n const picker = useDateRangePicker({\n value,\n onChange,\n timeZone,\n now,\n maxRangeDays,\n weekStartsOn,\n quickRanges,\n messages,\n });\n const months = useMonthCount(numberOfMonths);\n\n return (\n <Paper className={className} data-testid={dataTestId} sx={ROOT_SX}>\n <Box sx={BODY_SX}>\n <RangeCalendar\n calendarLabel={picker.copy.calendarLabel}\n picker={picker}\n value={value}\n locale={locale}\n weekStartsOn={weekStartsOn}\n months={months}\n maxRangeDays={maxRangeDays}\n />\n <QuickColumn picker={picker} maxRangeDays={maxRangeDays} dataTestId={dataTestId} />\n </Box>\n <Box sx={FIELDS_DIVIDER_SX}>\n <DateRangeFields\n value={value}\n status={picker.status}\n messages={picker.copy}\n maxRangeDays={maxRangeDays}\n onEdit={picker.editBound}\n statusId={picker.statusId}\n dataTestId={dataTestId}\n />\n </Box>\n </Paper>\n );\n}\n\nexport default DateRangePicker;\n","/**\n * Civil-day arithmetic for the range picker.\n *\n * Two representations meet here and the boundary between them is the whole\n * point of the file:\n *\n * - `AAAA-MM-DD` — what the picker's value, the quick ranges and any caller\n * speak. A day with no instant attached, so it cannot drift.\n * - a LOCAL `Date` at NOON — what `Calendar` deals in. Noon (not midnight) is\n * `Calendar.dates.normalizeDate`'s own rule: a daylight-saving jump at\n * midnight can move a date across a day boundary, and midday never can.\n *\n * The arithmetic itself is `Calendar.dates`' — `addDays` and `startOfWeek` are\n * imported rather than re-written, so a week here starts on the same day the\n * grid draws it.\n *\n * ONE thing needs a time zone: which day is today. Everything after that is\n * calendar arithmetic that has no clock in it.\n */\nimport { addDays, startOfWeek } from '../Calendar/Calendar.dates';\n\nimport type { DayString, WeekStart } from './DateRangePicker.types';\n\nconst NOON = 12;\nconst MS_PER_DAY = 86_400_000;\nconst MONTHS_PER_QUARTER = 3;\nconst DAY_PATTERN = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n\n/** `[year, month 1-12, day]`, or null when the text is not a day at all. */\nfunction dayParts(day: DayString): [number, number, number] | null {\n const parts = DAY_PATTERN.exec(day);\n if (!parts) return null;\n return [Number(parts[1]), Number(parts[2]), Number(parts[3])];\n}\n\nconst pad = (value: number): string => String(value).padStart(2, '0');\n\n/** `AAAA-MM-DD` from calendar parts. Month is 1-12. */\nfunction formatDay(year: number, month: number, day: number): DayString {\n return `${String(year).padStart(4, '0')}-${pad(month)}-${pad(day)}`;\n}\n\n/** A LOCAL `Date` → the day it falls on, read off the same local getters. */\nexport function toDayString(date: Date): DayString {\n return formatDay(date.getFullYear(), date.getMonth() + 1, date.getDate());\n}\n\n/**\n * `AAAA-MM-DD` → a LOCAL `Date` at noon, or null when the text is not a real\n * day.\n *\n * Deliberately not `new Date(day)`: the spec reads a bare `AAAA-MM-DD` as UTC\n * midnight, so west of Greenwich it lands on the day BEFORE and every date in\n * the picker is off by one. The round-trip check is what rejects `2026-02-31`,\n * which `Date` would otherwise roll silently into March.\n */\nexport function toLocalDay(day: DayString | null | undefined): Date | null {\n if (!day) return null;\n const parts = dayParts(day);\n if (!parts) return null;\n const date = new Date(parts[0], parts[1] - 1, parts[2], NOON);\n return toDayString(date) === day ? date : null;\n}\n\nconst civilFormatters = new Map<string, Intl.DateTimeFormat>();\n\nfunction civilFormatter(timeZone: string): Intl.DateTimeFormat {\n const cached = civilFormatters.get(timeZone);\n if (cached) return cached;\n const created = new Intl.DateTimeFormat('en-US', {\n timeZone,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n });\n civilFormatters.set(timeZone, created);\n return created;\n}\n\n/**\n * The civil day `now` falls on, on `timeZone`'s clock (the host's when absent).\n *\n * Read through `formatToParts` rather than by adding an offset to an epoch: the\n * zone database already knows about every transition, and reconstructing one by\n * hand is how a picker ends up a day out for exactly one week of the year.\n */\nexport function todayIn(timeZone: string | undefined, now: Date): DayString {\n if (!timeZone) return toDayString(now);\n const parts = civilFormatter(timeZone).formatToParts(now);\n const read = (type: Intl.DateTimeFormatPartTypes): string =>\n parts.find((part) => part.type === type)?.value ?? '';\n return `${read('year')}-${read('month')}-${read('day')}`;\n}\n\n/** The same day `days` later (or earlier). */\nexport function shiftDay(day: DayString, days: number): DayString {\n const date = toLocalDay(day);\n return date ? toDayString(addDays(date, days)) : day;\n}\n\n/** The 1st of `day`'s month. */\nexport function startOfMonthDay(day: DayString): DayString {\n const parts = dayParts(day);\n return parts ? formatDay(parts[0], parts[1], 1) : day;\n}\n\n/**\n * The 1st of `day`'s CALENDAR quarter — Jan/Apr/Jul/Oct. Fiscal quarters are a\n * different thing and belong in a caller's own quick range, not in a default.\n */\nexport function startOfQuarterDay(day: DayString): DayString {\n const parts = dayParts(day);\n if (!parts) return day;\n const month = parts[1] - ((parts[1] - 1) % MONTHS_PER_QUARTER);\n return formatDay(parts[0], month, 1);\n}\n\n/** The 1st of January of `day`'s year. */\nexport function startOfYearDay(day: DayString): DayString {\n const parts = dayParts(day);\n return parts ? formatDay(parts[0], 1, 1) : day;\n}\n\n/** The first day of `day`'s week, on the same week start the grid uses. */\nexport function startOfWeekDay(day: DayString, weekStartsOn: WeekStart): DayString {\n const date = toLocalDay(day);\n return date ? toDayString(startOfWeek(date, weekStartsOn)) : day;\n}\n\n/**\n * How many days a window covers, both ends INCLUDED — so a single day is 1.\n *\n * Measured on UTC epochs rather than on the local dates: the difference between\n * two local noons can be 23 or 25 hours across a transition, and dividing that\n * by a fixed day length is how a 30-day window starts reporting 29.96.\n */\nexport function dayCount(from: DayString, to: DayString): number {\n const start = dayParts(from);\n const end = dayParts(to);\n if (!start || !end) return 0;\n const startMs = Date.UTC(start[0], start[1] - 1, start[2]);\n const endMs = Date.UTC(end[0], end[1] - 1, end[2]);\n return Math.round((endMs - startMs) / MS_PER_DAY) + 1;\n}\n\n/** `AAAA-MM-DD` sorts lexicographically, so this needs no parsing at all. */\nexport function isAfterDay(a: DayString, b: DayString): boolean {\n return a > b;\n}\n","/**\n * Everything the picker derives and every way its range can move, kept out of\n * the component so that file is a layout and this one is the behaviour — the\n * same split `Calendar.hooks.ts` uses next door.\n */\nimport { useId, useMemo, useState } from 'react';\n\nimport { toDayString, todayIn } from './DateRangePicker.dates';\nimport {\n activeQuickRangeId,\n defaultMessages,\n resolveDayRange,\n resolveQuickRanges,\n} from './DateRangePicker.range';\nimport type {\n DateRangeChangeMeta,\n DateRangeDraft,\n DateRangePickerState,\n UseDateRangePickerArgs,\n} from './DateRangePicker.types';\n\nexport function useDateRangePicker({\n value,\n onChange,\n timeZone,\n now,\n maxRangeDays,\n weekStartsOn,\n quickRanges,\n messages,\n}: UseDateRangePickerArgs): DateRangePickerState {\n const statusId = useId();\n // `Calendar` reads which month to open on from the range it is handed, and\n // only when it MOUNTS. Bumping this key remounts it, which is how the other\n // two views move it. It changes for a quick pick and for a typed date and\n // NEVER for a click inside the grid — a calendar that jumped under the\n // pointer picking in it would be unusable.\n const [viewNonce, setViewNonce] = useState(0);\n\n const copy = useMemo(() => ({ ...defaultMessages(), ...messages }), [messages]);\n const today = useMemo(() => todayIn(timeZone, now ?? new Date()), [timeZone, now]);\n const options = useMemo(\n () => resolveQuickRanges(quickRanges, { today, weekStartsOn }, maxRangeDays),\n [quickRanges, today, weekStartsOn, maxRangeDays],\n );\n const status = useMemo(() => resolveDayRange(value, maxRangeDays), [value, maxRangeDays]);\n\n const emit = (\n next: DateRangeDraft,\n source: DateRangeChangeMeta['source'],\n quickRangeId?: string,\n ): void => {\n onChange(next, {\n source,\n ...(quickRangeId ? { quickRangeId } : {}),\n // Judged here, once. A caller left to re-derive \"is this usable\" is a\n // second opinion able to disagree with the message on screen.\n status: resolveDayRange(next, maxRangeDays),\n });\n };\n\n return {\n copy,\n options,\n activeId: activeQuickRangeId(options, value),\n status,\n statusId,\n viewNonce,\n pickQuick: (option) => {\n setViewNonce((nonce) => nonce + 1);\n emit({ from: option.window.from, to: option.window.to }, 'quick', option.id);\n },\n editBound: (which, bound) => {\n setViewNonce((nonce) => nonce + 1);\n emit({ ...value, [which]: bound }, which);\n },\n pickOnCalendar: (range) => {\n emit(\n {\n from: range.start ? toDayString(range.start) : null,\n to: range.end ? toDayString(range.end) : null,\n },\n 'calendar',\n );\n },\n };\n}\n","/**\n * Judging a draft, and saying so in words.\n *\n * The picker never repairs what it is given. A reversed pair is not silently\n * swapped and an over-long one is not clipped to the cap: both are reported,\n * because a control that returns a different range from the one on screen is\n * indistinguishable from one that ignored you. The caller reads\n * {@link DateRangeStatus} and keeps its own confirm button shut.\n */\nimport { isoToMasked } from '../../data-display/DataViews/data-views-day-input';\n\nimport { dayCount, isAfterDay } from './DateRangePicker.dates';\nimport type {\n DateRangePickerMessages,\n DateRangeDraft,\n DateRangeStatus,\n QuickRange,\n QuickRangeContext,\n ResolvedQuickRange,\n} from './DateRangePicker.types';\n\n/**\n * Whether a draft is a window this picker will hand over.\n *\n * Exported because the caller needs the same verdict the picker shows: a dialog\n * disabling its \"Apply\" button must not re-derive \"is this legal\" from the two\n * strings, or the two answers drift and the button ends up enabled over a\n * message saying the range is impossible.\n */\nexport function resolveDayRange(\n draft: DateRangeDraft,\n maxRangeDays?: number,\n): DateRangeStatus {\n const { from, to } = draft;\n if (!from || !to) return { ok: false, problem: 'incomplete', days: 0 };\n if (isAfterDay(from, to)) return { ok: false, problem: 'reversed', days: 0 };\n\n const days = dayCount(from, to);\n if (maxRangeDays !== undefined && days > maxRangeDays) {\n return { ok: false, problem: 'over-max', days };\n }\n return { ok: true, window: { from, to }, days };\n}\n\n/**\n * The English defaults.\n *\n * The summary prints the days in the SAME `dd/mm/aaaa` the two fields are\n * masked to, rather than in the host locale's order. One control cannot show\n * the same date two ways: an `en-US` host formatting the summary as `08/05`\n * over a field reading `05/08` leaves the reader to work out which of the two\n * is lying. A host that wants its own order replaces `messages.summary`, which\n * moves both halves of the decision to the same place.\n */\nexport function defaultMessages(): DateRangePickerMessages {\n // ONE mask, read by both the fields and the summary below. They are the same\n // date in the same control, so a summary formatted in a different order from\n // the boxes it summarises is a control arguing with itself — which is what\n // two independent literals eventually become.\n const dayMask = 'dd/mm/yyyy';\n return {\n from: 'Start date',\n to: 'End date',\n quickRanges: 'Quick ranges',\n incomplete: 'Choose both dates.',\n reversed: 'The end date must be on or after the start date.',\n overMax: ({ maxRangeDays }) => `Choose a range of at most ${maxRangeDays} days.`,\n summary: ({ from, to }) => `${isoToMasked(from, dayMask)} – ${isoToMasked(to, dayMask)}`,\n calendarLabel: 'Calendar',\n dayMask,\n };\n}\n\n/** The line under the fields: the chosen window, or why there isn't one. */\nexport function statusMessage(\n status: DateRangeStatus,\n messages: DateRangePickerMessages,\n maxRangeDays: number | undefined,\n): string {\n if (status.ok) return messages.summary(status.window);\n if (status.problem === 'incomplete') return messages.incomplete;\n if (status.problem === 'reversed') return messages.reversed;\n return messages.overMax({ maxRangeDays: maxRangeDays ?? status.days, days: status.days });\n}\n\n/** Every quick range with its window, its length, and whether it is over cap. */\nexport function resolveQuickRanges(\n quickRanges: QuickRange[],\n context: QuickRangeContext,\n maxRangeDays: number | undefined,\n): ResolvedQuickRange[] {\n return quickRanges.map((quickRange) => {\n const window = quickRange.resolve(context);\n const days = dayCount(window.from, window.to);\n return {\n ...quickRange,\n window,\n days,\n overMax: maxRangeDays !== undefined && days > maxRangeDays,\n };\n });\n}\n\n/** The quick range the draft currently IS, if it is exactly one of them. */\nexport function activeQuickRangeId(\n options: ResolvedQuickRange[],\n draft: DateRangeDraft,\n): string | undefined {\n return options.find(\n (option) => option.window.from === draft.from && option.window.to === draft.to,\n )?.id;\n}\n","/**\n * The quick-pick column's default list, and how to relabel it.\n *\n * These are DOMAIN-FREE on purpose: every one of them is derivable from \"today\"\n * and the calendar, so the design system can ship them without knowing what the\n * range is for. A product's own periods (a fiscal quarter, \"since the store\n * opened\", the last closed month) are a `quickRanges` array the caller passes —\n * the prop exists so that list never has to be smuggled in here.\n *\n * \"Last N days\" INCLUDES today, which is the reading every dashboard in the\n * wild uses: on the 10th, \"last 7 days\" is the 4th through the 10th, not the\n * 3rd through the 9th.\n */\nimport {\n shiftDay,\n startOfMonthDay,\n startOfQuarterDay,\n startOfWeekDay,\n startOfYearDay,\n} from './DateRangePicker.dates';\nimport type { QuickRange, QuickRangeContext } from './DateRangePicker.types';\n\n/**\n * The ids the built-in list uses. Stable API: a caller keys off these to map a\n * quick pick onto something of its own (a stored preset, an event name), and\n * renaming one is a breaking change in a way that renaming a label is not.\n */\nexport const QUICK_RANGE_IDS = [\n 'today',\n 'yesterday',\n 'this-week',\n 'last-7-days',\n 'this-month',\n 'last-30-days',\n 'this-quarter',\n 'this-year',\n 'last-365-days',\n] as const;\n\nexport type QuickRangeId = (typeof QUICK_RANGE_IDS)[number];\n\n/** English defaults. Every one is replaceable through {@link createQuickRanges}. */\nexport const DEFAULT_QUICK_RANGE_LABELS: Record<QuickRangeId, string> = {\n today: 'Today',\n yesterday: 'Yesterday',\n 'this-week': 'This week',\n 'last-7-days': 'Last 7 days',\n 'this-month': 'This month',\n 'last-30-days': 'Last 30 days',\n 'this-quarter': 'This quarter',\n 'this-year': 'This year',\n 'last-365-days': 'Last 365 days',\n};\n\n/** A window that ends today and reaches back `days` days, today included. */\nconst trailing =\n (days: number) =>\n ({ today }: QuickRangeContext) => ({ from: shiftDay(today, 1 - days), to: today });\n\n/** A window from the start of some period through today. */\nconst sinceStartOf =\n (start: (context: QuickRangeContext) => string) => (context: QuickRangeContext) => ({\n from: start(context),\n to: context.today,\n });\n\nconst RESOLVERS: Record<QuickRangeId, QuickRange['resolve']> = {\n today: trailing(1),\n yesterday: ({ today }) => ({ from: shiftDay(today, -1), to: shiftDay(today, -1) }),\n 'this-week': sinceStartOf(({ today, weekStartsOn }) => startOfWeekDay(today, weekStartsOn)),\n 'last-7-days': trailing(7),\n 'this-month': sinceStartOf(({ today }) => startOfMonthDay(today)),\n 'last-30-days': trailing(30),\n 'this-quarter': sinceStartOf(({ today }) => startOfQuarterDay(today)),\n 'this-year': sinceStartOf(({ today }) => startOfYearDay(today)),\n 'last-365-days': trailing(365),\n};\n\n/**\n * The built-in quick ranges, optionally relabelled.\n *\n * Relabelling rather than rebuilding is the point: a Portuguese host wants\n * \"Este mês\" over the same month-to-date arithmetic, and re-deriving the dates\n * to get the word is how two lists that claim the same thing start disagreeing.\n */\nexport function createQuickRanges(\n labels: Partial<Record<QuickRangeId, string>> = {},\n): QuickRange[] {\n return QUICK_RANGE_IDS.map((id) => ({\n id,\n label: labels[id] ?? DEFAULT_QUICK_RANGE_LABELS[id],\n resolve: RESOLVERS[id],\n }));\n}\n\n/** The list a picker uses when the caller says nothing. */\nexport const DEFAULT_QUICK_RANGES: QuickRange[] = createQuickRanges();\n","/**\n * The two typed ends, and the one line that says what the picker currently has.\n *\n * WHEN A TYPED DATE COMMITS: the moment it is a WHOLE, REAL day — eight digits\n * that name a date that exists. Not on every keystroke (`2026` passes through\n * `0002`, `0020` and `0202`, each a legal year, and committing those makes the\n * calendar jump to the year 20 while you are still typing) and not only on blur\n * (a reader who types a date and looks at the calendar to check it would see\n * the old month until they clicked somewhere else). Half-typed text stays in\n * the field and changes nothing; leaving the field discards it and shows what\n * the range actually is. Enter needs no special case — by the time it can be\n * pressed the date has already committed.\n *\n * The field itself is `DayBoundInput`, the masked `dd/mm/aaaa` control the data\n * views already use. Same package, imported rather than re-implemented: a\n * second masked date field is a second set of rules for what backspace does.\n */\nimport { Box, Typography } from '@mui/material';\nimport React from 'react';\n\nimport { DayBoundInput } from '../../data-display/DataViews/data-views-day-input';\n\nimport { statusMessage } from './DateRangePicker.range';\nimport type {\n DateRangePickerMessages,\n DateRangeDraft,\n DateRangeStatus,\n DayString,\n} from './DateRangePicker.types';\n\nexport interface DateRangeFieldsProps {\n value: DateRangeDraft;\n status: DateRangeStatus;\n messages: DateRangePickerMessages;\n maxRangeDays: number | undefined;\n onEdit: (which: 'from' | 'to', bound: DayString | null) => void;\n /** Id of the status line, so both fields can point at it. */\n statusId: string;\n dataTestId: string;\n}\n\nexport function DateRangeFields({\n value,\n status,\n messages,\n maxRangeDays,\n onEdit,\n statusId,\n dataTestId,\n}: DateRangeFieldsProps): React.JSX.Element {\n // \"Incomplete\" is not an error — it is a range that is not finished yet, and\n // painting it red would make the first click on a two-click control look like\n // a mistake. The pair being impossible is what gets marked.\n const rejected = !status.ok && status.problem !== 'incomplete';\n\n return (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>\n <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 2 }}>\n <DayBoundInput\n mask={messages.dayMask}\n label={messages.from}\n value={value.from ?? undefined}\n onChange={(bound) => onEdit('from', bound ?? null)}\n testId={`${dataTestId}-from`}\n error={rejected}\n describedBy={statusId}\n />\n <DayBoundInput\n mask={messages.dayMask}\n label={messages.to}\n value={value.to ?? undefined}\n onChange={(bound) => onEdit('to', bound ?? null)}\n testId={`${dataTestId}-to`}\n error={rejected}\n describedBy={statusId}\n />\n </Box>\n <Typography\n id={statusId}\n // A live region, so the reason a range was refused is spoken when it\n // appears rather than only being found by someone who goes looking.\n role=\"status\"\n aria-live=\"polite\"\n variant=\"body2\"\n color={rejected ? 'error.main' : 'text.secondary'}\n data-testid={`${dataTestId}-status`}\n >\n {statusMessage(status, messages, maxRangeDays)}\n </Typography>\n </Box>\n );\n}\n","/**\n * The quick-pick column beside the calendar.\n *\n * These are BUTTONS, not links or list rows: each one sets the range and the\n * pressed one stays visibly pressed, which is what `aria-pressed` says out\n * loud. (A listbox with `aria-selected` would model it too — the rule is to\n * pick one and use it for every entry, so a reader's screen reader describes\n * the whole column the same way.)\n *\n * An over-cap entry is `aria-disabled` and keeps its place in the tab order,\n * with the reason rendered under the label. Removing it, or quietly shortening\n * the window it hands back, both answer \"why can't I have this year?\" with\n * silence.\n */\nimport { Box } from '@mui/material';\nimport type { SxProps, Theme } from '@mui/material';\nimport React, { useId } from 'react';\n\nimport type { ResolvedQuickRange } from './DateRangePicker.types';\n\nconst optionSx = (active: boolean, overMax: boolean): SxProps<Theme> => ({\n display: 'block',\n // Full-width rows in the side column; pills in the narrow row. A fixed full\n // width in both would make the narrow layout nine stacked lines.\n width: { xs: 'auto', md: '100%' },\n // A pill must not be squeezed by its neighbours — the row SCROLLS rather\n // than compressing \"Este trimestre\" into two characters and an ellipsis.\n flex: { xs: '0 0 auto', md: '0 1 auto' },\n textAlign: 'left',\n font: 'inherit',\n fontSize: '0.875rem',\n fontWeight: active ? 600 : 400,\n lineHeight: 1.4,\n px: 1.5,\n py: 0.75,\n whiteSpace: { xs: 'nowrap', md: 'normal' },\n border: '1px solid',\n // Narrow, an entry has to look tappable on its own, with no column and no\n // rule to group it — so the pill carries a visible edge. Beside the calendar\n // the group already reads as a list and a border on every row would be nine\n // boxes where the selected one should be the only marked thing.\n borderColor: active ? 'primary.main' : { xs: 'divider', md: 'transparent' },\n borderRadius: { xs: 999, md: 1 },\n cursor: overMax ? 'not-allowed' : 'pointer',\n color: overMax ? 'text.disabled' : active ? 'primary.main' : 'text.primary',\n backgroundColor: active ? 'action.selected' : 'transparent',\n '&:hover': { backgroundColor: overMax ? 'transparent' : 'action.hover' },\n '&:focus-visible': { outline: '2px solid', outlineColor: 'primary.main', outlineOffset: 1 },\n});\n\nconst REASON_SX: SxProps<Theme> = {\n display: 'block',\n fontSize: '0.6875rem',\n lineHeight: 1.3,\n mt: 0.25,\n color: 'text.disabled',\n};\n\nexport interface DateRangeQuickListProps {\n options: ResolvedQuickRange[];\n /** The entry the current draft equals, if any. */\n activeId: string | undefined;\n onPick: (option: ResolvedQuickRange) => void;\n /** Why an entry is refused, rendered under it. */\n reasonFor: (option: ResolvedQuickRange) => string;\n /** Accessible name of the group. */\n label: string;\n dataTestId: string;\n}\n\nexport function DateRangeQuickList({\n options,\n activeId,\n onPick,\n reasonFor,\n label,\n dataTestId,\n}: DateRangeQuickListProps): React.JSX.Element {\n const reasonPrefix = useId();\n\n return (\n <Box\n role=\"group\"\n aria-label={label}\n data-testid={`${dataTestId}-quick-list`}\n sx={{\n display: 'flex',\n // A column beside the calendar; ONE scrolling row of pills above it\n // once there is no width for both.\n //\n // Scrolling rather than wrapping: nine wrapped pills take three or four\n // lines at 390px, which pushes the calendar most of a screen down and\n // makes the quick ranges — the fastest way to answer — the thing you\n // have to scroll past. One line keeps the calendar in view and costs a\n // horizontal swipe, which is the gesture a chip row already invites.\n flexDirection: { xs: 'row', md: 'column' },\n flexWrap: { xs: 'nowrap', md: 'wrap' },\n overflowX: { xs: 'auto', md: 'visible' },\n // Room for the focus ring, which an `overflow` container would clip.\n px: { xs: 0.25, md: 0 },\n py: { xs: 0.25, md: 0 },\n // The scrollbar is chrome on a phone and noise on a trackpad; the pills\n // themselves are the affordance, and the last one sits half-cut at the\n // edge to say the row continues.\n scrollbarWidth: 'none',\n '&::-webkit-scrollbar': { display: 'none' },\n alignContent: 'flex-start',\n gap: 0.5,\n minWidth: { md: 168 },\n maxWidth: { md: 200 },\n }}\n >\n {options.map((option) => {\n const active = option.id === activeId;\n const reasonId = `${reasonPrefix}-${option.id}`;\n return (\n <Box\n component=\"button\"\n type=\"button\"\n key={option.id}\n aria-pressed={active}\n // `aria-disabled`, never the `disabled` attribute: a disabled button\n // is skipped by the tab order, so the reason under it is unreachable\n // by exactly the reader most likely to need it.\n aria-disabled={option.overMax || undefined}\n aria-describedby={option.overMax ? reasonId : undefined}\n data-testid={`${dataTestId}-quick-${option.id}`}\n onClick={() => {\n if (!option.overMax) onPick(option);\n }}\n sx={optionSx(active, option.overMax)}\n >\n {option.label}\n {option.overMax && (\n <Box component=\"span\" id={reasonId} sx={REASON_SX}>\n {reasonFor(option)}\n </Box>\n )}\n </Box>\n );\n })}\n </Box>\n );\n}\n"],"mappings":"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","names":["Box","Box","useId","jsx","jsxs","jsx","jsxs","Box"]}