stimeo-ui 0.9.0 → 0.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.
- package/CHANGELOG.md +149 -0
- package/dist/cable/index.d.ts +79 -14
- package/dist/cable/index.js +226 -43
- package/dist/cable/index.js.map +1 -1
- package/dist/controllers/accordion_controller.js.map +1 -1
- package/dist/controllers/alert_dialog_controller.js +17 -7
- package/dist/controllers/alert_dialog_controller.js.map +1 -1
- package/dist/controllers/announcer_controller.js +1 -1
- package/dist/controllers/announcer_controller.js.map +1 -1
- package/dist/controllers/auto_submit_controller.js.map +1 -1
- package/dist/controllers/avatar_controller.js.map +1 -1
- package/dist/controllers/breadcrumb_controller.js.map +1 -1
- package/dist/controllers/bulk_select_controller.js +2 -2
- package/dist/controllers/bulk_select_controller.js.map +1 -1
- package/dist/controllers/calendar_controller.js.map +1 -1
- package/dist/controllers/carousel_controller.js.map +1 -1
- package/dist/controllers/character_counter_controller.js.map +1 -1
- package/dist/controllers/clipboard_controller.js.map +1 -1
- package/dist/controllers/collapsible_controller.d.ts +1 -1
- package/dist/controllers/collapsible_controller.js +1 -1
- package/dist/controllers/collapsible_controller.js.map +1 -1
- package/dist/controllers/color_picker_controller.d.ts +1 -1
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/combobox_controller.js.map +1 -1
- package/dist/controllers/command_palette_controller.js +15 -5
- package/dist/controllers/command_palette_controller.js.map +1 -1
- package/dist/controllers/conditional_fields_controller.js.map +1 -1
- package/dist/controllers/confirm_controller.js +15 -5
- package/dist/controllers/confirm_controller.js.map +1 -1
- package/dist/controllers/context_menu_controller.d.ts +5 -4
- package/dist/controllers/context_menu_controller.js.map +1 -1
- package/dist/controllers/count_up_controller.js.map +1 -1
- package/dist/controllers/countdown_controller.js +1 -1
- package/dist/controllers/countdown_controller.js.map +1 -1
- package/dist/controllers/data_grid_controller.js +1 -1
- package/dist/controllers/data_grid_controller.js.map +1 -1
- package/dist/controllers/date_range_picker_controller.js.map +1 -1
- package/dist/controllers/dialog_controller.js +15 -5
- package/dist/controllers/dialog_controller.js.map +1 -1
- package/dist/controllers/direct_upload_controller.d.ts +2 -2
- package/dist/controllers/direct_upload_controller.js +1 -5
- package/dist/controllers/direct_upload_controller.js.map +1 -1
- package/dist/controllers/dismissible_controller.js.map +1 -1
- package/dist/controllers/drawer_controller.d.ts +2 -2
- package/dist/controllers/drawer_controller.js +17 -7
- package/dist/controllers/drawer_controller.js.map +1 -1
- package/dist/controllers/file_dropzone_controller.js.map +1 -1
- package/dist/controllers/flash_controller.js.map +1 -1
- package/dist/controllers/focus_controller.d.ts +5 -0
- package/dist/controllers/focus_controller.js +45 -7
- package/dist/controllers/focus_controller.js.map +1 -1
- package/dist/controllers/form_field_controller.js +1 -1
- package/dist/controllers/form_field_controller.js.map +1 -1
- package/dist/controllers/form_validation_controller.js.map +1 -1
- package/dist/controllers/frame_loading_controller.js.map +1 -1
- package/dist/controllers/highlight_controller.js.map +1 -1
- package/dist/controllers/input_mask_controller.js.map +1 -1
- package/dist/controllers/intersection_controller.d.ts +4 -3
- package/dist/controllers/intersection_controller.js.map +1 -1
- package/dist/controllers/lazy_frame_controller.d.ts +2 -2
- package/dist/controllers/lazy_frame_controller.js.map +1 -1
- package/dist/controllers/listbox_controller.js.map +1 -1
- package/dist/controllers/masonry_controller.d.ts +3 -1
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/menu_controller.d.ts +1 -1
- package/dist/controllers/menu_controller.js.map +1 -1
- package/dist/controllers/menubar_controller.js +2 -2
- package/dist/controllers/menubar_controller.js.map +1 -1
- package/dist/controllers/meter_controller.d.ts +1 -1
- package/dist/controllers/meter_controller.js.map +1 -1
- package/dist/controllers/multi_select_controller.js +1 -1
- package/dist/controllers/multi_select_controller.js.map +1 -1
- package/dist/controllers/navigation_menu_controller.js.map +1 -1
- package/dist/controllers/nested_form_controller.js.map +1 -1
- package/dist/controllers/number_input_controller.js.map +1 -1
- package/dist/controllers/otp_controller.js.map +1 -1
- package/dist/controllers/overflow_indicator_controller.js.map +1 -1
- package/dist/controllers/overflow_menu_controller.js +2 -2
- package/dist/controllers/overflow_menu_controller.js.map +1 -1
- package/dist/controllers/pagination_controller.d.ts +1 -1
- package/dist/controllers/pagination_controller.js.map +1 -1
- package/dist/controllers/password_reveal_controller.d.ts +27 -2
- package/dist/controllers/password_reveal_controller.js +102 -3
- package/dist/controllers/password_reveal_controller.js.map +1 -1
- package/dist/controllers/password_strength_controller.d.ts +71 -17
- package/dist/controllers/password_strength_controller.js +287 -42
- package/dist/controllers/password_strength_controller.js.map +1 -1
- package/dist/controllers/pointer_drag_controller.d.ts +23 -5
- package/dist/controllers/pointer_drag_controller.js +64 -18
- package/dist/controllers/pointer_drag_controller.js.map +1 -1
- package/dist/controllers/popover_controller.js.map +1 -1
- package/dist/controllers/portal_controller.d.ts +17 -4
- package/dist/controllers/portal_controller.js +32 -11
- package/dist/controllers/portal_controller.js.map +1 -1
- package/dist/controllers/preview_guard_controller.d.ts +22 -14
- package/dist/controllers/preview_guard_controller.js +180 -20
- package/dist/controllers/preview_guard_controller.js.map +1 -1
- package/dist/controllers/progress_controller.js.map +1 -1
- package/dist/controllers/radio_group_controller.js.map +1 -1
- package/dist/controllers/range_slider_controller.js.map +1 -1
- package/dist/controllers/rating_controller.js.map +1 -1
- package/dist/controllers/read_more_controller.js.map +1 -1
- package/dist/controllers/relative_time_controller.js.map +1 -1
- package/dist/controllers/reset_before_cache_controller.d.ts +1 -2
- package/dist/controllers/reset_before_cache_controller.js.map +1 -1
- package/dist/controllers/resizable_controller.d.ts +1 -1
- package/dist/controllers/resizable_controller.js +1 -1
- package/dist/controllers/resizable_controller.js.map +1 -1
- package/dist/controllers/roving_controller.d.ts +17 -4
- package/dist/controllers/roving_controller.js +127 -14
- package/dist/controllers/roving_controller.js.map +1 -1
- package/dist/controllers/scroll_area_controller.js.map +1 -1
- package/dist/controllers/scroll_restore_controller.d.ts +33 -11
- package/dist/controllers/scroll_restore_controller.js +127 -27
- package/dist/controllers/scroll_restore_controller.js.map +1 -1
- package/dist/controllers/scroll_visibility_controller.d.ts +42 -10
- package/dist/controllers/scroll_visibility_controller.js +167 -14
- package/dist/controllers/scroll_visibility_controller.js.map +1 -1
- package/dist/controllers/scrollspy_controller.js.map +1 -1
- package/dist/controllers/separator_controller.js.map +1 -1
- package/dist/controllers/sidebar_controller.js +15 -5
- package/dist/controllers/sidebar_controller.js.map +1 -1
- package/dist/controllers/skeleton_controller.js.map +1 -1
- package/dist/controllers/slider_controller.js.map +1 -1
- package/dist/controllers/spinner_controller.js.map +1 -1
- package/dist/controllers/step_indicator_controller.js +0 -5
- package/dist/controllers/step_indicator_controller.js.map +1 -1
- package/dist/controllers/stick_to_bottom_controller.d.ts +26 -9
- package/dist/controllers/stick_to_bottom_controller.js +149 -28
- package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
- package/dist/controllers/submit_once_controller.js.map +1 -1
- package/dist/controllers/switch_controller.js.map +1 -1
- package/dist/controllers/tabs_controller.js.map +1 -1
- package/dist/controllers/tags_input_controller.js.map +1 -1
- package/dist/controllers/textarea_autosize_controller.js.map +1 -1
- package/dist/controllers/theme_controller.d.ts +32 -6
- package/dist/controllers/theme_controller.js +151 -40
- package/dist/controllers/theme_controller.js.map +1 -1
- package/dist/controllers/time_picker_controller.js.map +1 -1
- package/dist/controllers/toast_controller.d.ts +2 -2
- package/dist/controllers/toast_controller.js +2 -2
- package/dist/controllers/toast_controller.js.map +1 -1
- package/dist/controllers/toggle_group_controller.js.map +1 -1
- package/dist/controllers/toolbar_controller.js.map +1 -1
- package/dist/controllers/transition_controller.d.ts +11 -7
- package/dist/controllers/transition_controller.js +79 -15
- package/dist/controllers/transition_controller.js.map +1 -1
- package/dist/controllers/tree_view_controller.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.js +1188 -318
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.d.ts +3 -4
- package/dist/inspector/cli.js +1 -0
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +6 -5
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +6 -6
- package/dist/inspector/manifest.json +15 -32
- package/dist/positioning/index.d.ts +18 -4
- package/dist/positioning/index.js +84 -25
- package/dist/positioning/index.js.map +1 -1
- package/package.json +6 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/logical_scroll.ts","../../src/utils/arrow_step.ts","../../src/utils/interactive_host.ts","../../src/utils/microtask_coalescer.ts","../../src/controllers/data_grid_controller.ts"],"names":[],"mappings":"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","file":"data_grid_controller.js","sourcesContent":["/** Normalized scroll position and maximum distance on one logical axis. */\nexport interface LogicalScrollMetrics {\n position: number;\n max: number;\n}\n\n/**\n * Whether horizontal scrolling on `element` follows right-to-left inline flow.\n *\n * Resolved from the **computed** `direction`, so the authoring contract is the\n * usual `dir=\"rtl\"` (or a stylesheet) on the element or any ancestor.\n *\n * Scope: horizontal writing modes. A vertical writing mode (`writing-mode:\n * vertical-rl`) also inverts the horizontal axis, which this check does not\n * model — vertical writing modes are out of scope for the scroll utilities\n * (their consumers describe axes as horizontal/vertical, not inline/block).\n */\nexport function isRtl(element: Element): boolean {\n return window.getComputedStyle(element).direction === \"rtl\";\n}\n\n/**\n * Returns scroll distance from the logical start edge.\n *\n * CSSOM View exposes standards-mode RTL horizontal offsets as `0` at the inline\n * start (right) and increasingly negative values toward the inline end (left).\n * The normalized position is always clamped to `[0, max]`, which also absorbs\n * Safari's elastic overscroll values.\n */\nexport function logicalScrollMetrics(\n element: HTMLElement,\n horizontal: boolean,\n): LogicalScrollMetrics {\n const max = Math.max(\n 0,\n horizontal\n ? element.scrollWidth - element.clientWidth\n : element.scrollHeight - element.clientHeight,\n );\n const raw = horizontal ? element.scrollLeft : element.scrollTop;\n const position = horizontal && isRtl(element) ? -raw : raw;\n return { position: Math.min(max, Math.max(0, position)), max };\n}\n\n/**\n * Converts a logical start/end delta to the physical value accepted by\n * `Element.scrollBy`.\n */\nexport function physicalScrollDelta(\n element: HTMLElement,\n horizontal: boolean,\n logicalDelta: number,\n): number {\n return horizontal && isRtl(element) ? -logicalDelta : logicalDelta;\n}\n","import { isRtl } from \"./logical_scroll\";\n\n/**\n * Turns an arrow key into a **logical** step: `+1` for \"next\", `-1` for\n * \"previous\", `0` when the key names neither.\n *\n * APG defines the horizontal pair as *next / previous* and says a vertical\n * arrangement swaps in Down/Up for the same meaning — so the pair is one axis's\n * spelling of an order, and the order reverses with the writing direction. Only\n * the horizontal pair reverses. Down/Up name an axis the writing direction does\n * not mirror, and returning them unchanged is the point: many controllers fold\n * both pairs into one branch, where swapping the branches under RTL would flip\n * the vertical axis too — a bug that reads as \"the arrows work\" until someone\n * presses Down.\n *\n * **Direction is read from the element the caller passes, which should be the\n * container that lays the items out** — not the focused child. A child may carry\n * its own `dir` (an LTR input inside an RTL form is ordinary authoring), and\n * probing per handler makes two handlers disagree at the boundary between them.\n *\n * This decides direction only. Whether the axis is even active (an\n * `orientation=\"horizontal\"` widget ignoring Down/Up), how far the step lands,\n * and what wrapping does all stay with the caller.\n *\n * **It encodes the list-order convention: `ArrowDown` is *next*.** Widgets that\n * pair the arrows by *value* instead — `ArrowUp` meaning \"more\", as a rating or a\n * slider does — must not use this, or their vertical axis inverts. Reverse the\n * horizontal pair on its own there.\n *\n * @example\n * ```ts\n * const step = logicalArrowStep(event.key, this.element);\n * if (step === 0) return;\n * this.#roving.setActive(rovingMove(current, length, step, \"wrap\"), { focus: true });\n * ```\n */\nexport function logicalArrowStep(key: string, element: Element): 1 | -1 | 0 {\n if (key === \"ArrowDown\") return 1;\n if (key === \"ArrowUp\") return -1;\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return 0;\n const forward = isRtl(element) ? \"ArrowLeft\" : \"ArrowRight\";\n return key === forward ? 1 : -1;\n}\n\n/**\n * Rewrites `key` so an existing LTR-shaped branch keeps working under RTL:\n * `ArrowRight` and `ArrowLeft` trade places, everything else passes through.\n *\n * The alternative — negating a delta — silently breaks handlers whose two\n * horizontal branches are **not mirror images**. A grid that clamps one edge but\n * not the other, or a segmented field guarding `index > 0` on one side and\n * `index < length - 1` on the other, ends up applying the wrong guard to the\n * wrong direction. Swapping the key leaves each branch, guards and all, exactly\n * where its author put it.\n *\n * Same rule as {@link logicalArrowStep} about which element to read: pass the\n * container that lays the items out, not the focused child.\n *\n * @example\n * ```ts\n * switch (logicalArrowKey(event.key, this.element)) {\n * case \"ArrowLeft\": // \"previous\" — whatever direction that is on screen\n * ```\n */\nexport function logicalArrowKey(key: string, element: Element): string {\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return key;\n if (!isRtl(element)) return key;\n return key === \"ArrowRight\" ? \"ArrowLeft\" : \"ArrowRight\";\n}\n\n/** Modifiers a widget may claim on an arrow key, named for the `allow` list. */\nexport type ArrowModifier = \"alt\" | \"ctrl\" | \"meta\" | \"shift\";\n\n/**\n * True when an arrow key arrived carrying a modifier the widget must leave to\n * the browser: return without calling `preventDefault()` and without moving any\n * state.\n *\n * A bare arrow belongs to the widget; a chorded one usually does not.\n * `Alt`/`Meta` plus a horizontal arrow is history back/forward on every desktop\n * browser, and a widget that swallows it makes the shortcut work or not\n * depending on where focus happens to sit — a coin-flip the user cannot see.\n *\n * `allow` is for the combinations APG assigns to a pattern **and the widget\n * actually implements** — today only Combobox's optional `Alt+Down`/`Alt+Up`.\n * Listing one the widget does not implement defeats the point: the chord then\n * runs the plain-arrow branch, which is exactly what this guard exists to stop.\n * Non-arrow keys return `false`, so chorded letters and\n * `Control+Home`/`Control+End` are untouched.\n *\n * @example\n * ```ts\n * if (isReservedArrowChord(event)) return;\n * ```\n */\nexport function isReservedArrowChord(\n event: KeyboardEvent,\n allow: readonly ArrowModifier[] = [],\n): boolean {\n if (!event.key.startsWith(\"Arrow\")) return false;\n return (\n (event.altKey && !allow.includes(\"alt\")) ||\n (event.ctrlKey && !allow.includes(\"ctrl\")) ||\n (event.metaKey && !allow.includes(\"meta\")) ||\n (event.shiftKey && !allow.includes(\"shift\"))\n );\n}\n","/**\n * Native interactive elements whose built-in activation must not be replaced\n * wholesale by a controller. Deliberately excludes `[tabindex]`: a generic\n * element made focusable is the supported host for several headless patterns.\n * Contenteditable is handled by {@link isInteractiveHost} because its state is\n * inherited and its keywords are ASCII-case-insensitive.\n */\nexport const INTERACTIVE_HOST_SELECTOR =\n \"button, input, select, textarea, label, a[href], area[href], summary, details, audio[controls], video[controls], iframe, object, embed\";\n\n/**\n * Whether an element owns native activation or an inherited editing surface.\n *\n * The `contenteditable` missing and invalid states inherit. Walking explicitly\n * also keeps `contenteditable=\"false\"` as a real boundary inside an editable\n * ancestor instead of treating any ancestor attribute as decisive.\n */\nexport function isInteractiveHost(element: HTMLElement): boolean {\n if (element.matches(INTERACTIVE_HOST_SELECTOR)) return true;\n\n let current: HTMLElement | null = element;\n while (current) {\n const raw = current.getAttribute(\"contenteditable\");\n if (raw !== null) {\n const value = raw.trim().toLowerCase();\n if (value === \"false\") return false;\n if (value === \"\" || value === \"true\" || value === \"plaintext-only\") return true;\n }\n current = current.parentElement;\n }\n return false;\n}\n","/**\n * Collapses many Stimulus lifecycle callbacks from one DOM mutation into a\n * single pass.\n *\n * Stimulus fires `<name>TargetConnected` / `Disconnected` once per element and\n * `<name>ValueChanged` once per changed attribute. Replacing a list of N options\n * or morphing several render Values therefore delivers N callbacks — but the\n * useful unit of work is \"reconcile against the resulting declarative input\",\n * once, after the batch has settled. Every controller with reconcilable targets\n * or render Values needs the same shape: a `queued` flag plus `queueMicrotask`.\n *\n * **A microtask is the right horizon, and the reason is specific.** Stimulus\n * drives these callbacks from a `MutationObserver`, whose own callback already\n * runs as a microtask with the whole batch in hand; scheduling one more lands\n * after the last sibling callback of that batch and still before paint or any\n * event handler. A timer would be later than it needs to be, and reconciling\n * synchronously would run once per element against a half-applied DOM.\n *\n * **The two guards are not the same guard.** Scheduling is refused before the\n * controller connects, and running is refused after it disconnects:\n *\n * - **Before `connect()`** — Stimulus delivers initial target and Value callbacks\n * ahead of `connect()`. Reconciling there would compute output against a\n * controller whose own state has not been initialised, and `connect()` is\n * about to do a full pass anyway.\n * - **After `disconnect()`** — Stimulus fires a callback for **every** target\n * during teardown, and a microtask queued just before it would otherwise run\n * against a detached tree. {@link MicrotaskCoalescer.cancel} exists for the\n * teardown path to drop the pending pass outright.\n *\n * Both guards are part of one contract here rather than something each consumer\n * has to remember separately.\n *\n * Scope is the scheduling only. *What* to reconcile — keep the surviving active\n * option, fall back to the next / previous / first visible one, rebuild derived\n * chips or hidden fields — stays in the controller, because no two consumers\n * answer it the same way.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileOptions());\n *\n * connect() { this.#reconcile.activate(); }\n * disconnect() { this.#reconcile.cancel(); }\n *\n * optionTargetConnected() { this.#reconcile.schedule(); }\n * optionTargetDisconnected() { this.#reconcile.schedule(); }\n * ```\n */\nexport class MicrotaskCoalescer {\n readonly #run: () => void;\n #queued = false;\n #active = false;\n #generation = 0;\n\n /** @param run - the single reconciliation pass, invoked at most once per batch. */\n constructor(run: () => void) {\n this.#run = run;\n }\n\n /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */\n activate(): void {\n this.#active = true;\n }\n\n /** Closes the window and drops any pending pass; call from `disconnect()`. */\n cancel(): void {\n this.#active = false;\n this.#queued = false;\n this.#generation += 1;\n }\n\n /** Requests one pass after the batch settles. Idempotent; inert outside the window. */\n schedule(): void {\n if (!this.#active || this.#queued) return;\n this.#queued = true;\n const generation = this.#generation;\n queueMicrotask(() => {\n // A cancelled callback must not consume a pass queued after reconnect.\n if (generation !== this.#generation || !this.#queued || !this.#active) return;\n this.#queued = false;\n this.#run();\n });\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { isReservedArrowChord, logicalArrowKey } from \"../utils/arrow_step\";\nimport { INTERACTIVE_HOST_SELECTOR, isInteractiveHost } from \"../utils/interactive_host\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\n\n/** Cycle order for a sortable column header's `aria-sort`. */\nconst SORT_CYCLE = [\"none\", \"ascending\", \"descending\"] as const;\ntype SortDirection = (typeof SORT_CYCLE)[number];\n\n/**\n * Returns the next `aria-sort` direction in the cycle after `current`. Unknown or\n * ARIA-only values (e.g. `\"other\"`, or an empty/missing attribute) are treated as\n * `\"none\"`, so the first activation always advances to `\"ascending\"` instead of\n * stalling.\n */\nfunction nextSortDirection(current: string): SortDirection {\n const index = SORT_CYCLE.indexOf(current as SortDirection);\n const from = index < 0 ? 0 : index;\n return SORT_CYCLE[(from + 1) % SORT_CYCLE.length] ?? \"ascending\";\n}\n\n/**\n * Headless, accessible **Data Grid** behavior: column sorting, row selection, and\n * roving keyboard navigation over an interactive table.\n *\n * Markup contract (identifier: `stimeo--data-grid`):\n * <table data-controller=\"stimeo--data-grid\" role=\"grid\" aria-label=\"Users\"\n * data-stimeo--data-grid-selection-value=\"single\">\n * <thead><tr role=\"row\">\n * <th role=\"columnheader\" aria-sort=\"none\" tabindex=\"-1\"\n * data-stimeo--data-grid-target=\"columnHeader\"\n * data-action=\"click->stimeo--data-grid#sort\n * keydown->stimeo--data-grid#onKeydown\">Name</th>\n * </tr></thead>\n * <tbody><tr role=\"row\" aria-selected=\"false\"\n * data-stimeo--data-grid-target=\"row\">\n * <td role=\"gridcell\" tabindex=\"0\" data-stimeo--data-grid-target=\"cell\"\n * data-action=\"keydown->stimeo--data-grid#onKeydown\">Jane</td>\n * </tr></tbody>\n * </table>\n *\n * Implements the WAI-ARIA APG **Grid** pattern plus `aria-sort`. The whole grid is\n * a single Tab stop (roving `tabindex`: exactly one cell/header is `0`, the rest\n * `-1`); arrow keys move both DOM focus and that tabbable position. Sort state is\n * exposed via `aria-sort` on headers, selection via `aria-selected` on rows.\n *\n * `selectionchange` dispatches `{ rows: HTMLElement[] }`; `sort` dispatches\n * `{ column: HTMLElement, direction: \"ascending\" | \"descending\" | \"none\" }`.\n *\n * @remarks\n * Behavior only — the consumer performs the actual data sort/render in response to\n * the `sort` event and owns all styling. No timers or observers are held, so there\n * is nothing to leak across Turbo navigations; `connect()` rebuilds the single tab\n * stop idempotently from the DOM, and the target callbacks rebuild it again after\n * rows or cells are added or removed at runtime.\n *\n * Behavior provided:\n * - `Arrow*` move between cells (clamped at edges); `Home`/`End` to the row's\n * first/last cell; `Ctrl+Home`/`Ctrl+End` to the grid's first/last cell.\n * - `Enter`/`Space` cycles a header's sort (`none→ascending→descending`) or toggles\n * the focused row's selection when selection is enabled.\n *\n * Consumer contract — controls nested inside a cell or header:\n * - APG's grid hosts working controls in its cells, so a keystroke or click that\n * reached one — {@link INTERACTIVE_HOST_SELECTOR}, an editable host, or any\n * widget that already called `preventDefault()` — is left to it entirely: no\n * move, no sort, no selection. The one control that hands the event on is a\n * sortable header's own `<button>`, whose activation is what the click carries.\n * - A control keeps its own Tab behavior, so give it `tabindex=\"-1\"` to preserve\n * the grid's single Tab stop. A sortable `columnheader` hosting a `<button>` is\n * the common case: the roving position stays on the header, and the button's\n * own activation reaches `sort` through the click that bubbles to it.\n * - Host `role=\"gridcell\"` / `role=\"columnheader\"` on a non-interactive element\n * (`td`, `th`); an interactive host makes the grid stand down on that cell.\n */\nexport class DataGridController extends Controller<HTMLElement> {\n static override targets = [\"columnHeader\", \"row\", \"cell\"];\n static override values = {\n selection: { type: String, default: \"none\" },\n };\n static actions = [\"onKeydown\", \"sort\", \"toggleSelect\"] as const;\n static events = [\"selectionchange\", \"sort\"] as const;\n\n declare readonly columnHeaderTargets: HTMLElement[];\n declare readonly rowTargets: HTMLElement[];\n declare readonly cellTargets: HTMLElement[];\n declare selectionValue: string;\n\n /**\n * Collapses the per-element target callbacks of one DOM mutation into a single\n * baseline pass, and refuses to run before `connect()` or after `disconnect()`.\n *\n * Stimulus reports every target one at a time, so an ungated pass would re-walk\n * the whole grid once per authored cell on mount and once per streamed cell\n * afterwards — quadratic in the cell count both times.\n */\n readonly #reconcile = new MicrotaskCoalescer(() => this.#restoreBaseline());\n\n /**\n * Establishes a single tab stop across all navigable cells/headers and brings\n * the rows to their baseline.\n *\n * Normalizing here rather than leaving it to {@link selectionValueChanged}\n * guarantees exactly one pass per mount: a re-attached element reuses its\n * cached Stimulus context, whose value observer already knows the `selection`\n * attribute, so the Value callback does not fire a second time.\n */\n override connect(): void {\n this.#restoreBaseline();\n this.#reconcile.activate();\n }\n\n /** Closes the reconcile window so a queued pass cannot run against a detached tree. */\n override disconnect(): void {\n this.#reconcile.cancel();\n }\n\n /**\n * Rebuilds both DOM-owned baselines from the live grid: exactly one navigable\n * cell is in the Tab sequence, and every selectable row carries an explicit\n * `aria-selected`.\n *\n * The tab stop keeps whichever cell already holds it, so a rebuild triggered by\n * an unrelated row arriving does not throw the user's position away; only when\n * no cell holds it — the grid is fresh, or the holder was removed — does the\n * first navigable cell take over. Without that fallback a grid whose active row\n * is removed keeps every cell at `-1` and drops out of the Tab sequence\n * entirely.\n */\n #restoreBaseline(): void {\n const cells = this.#navigableCells();\n const active = cells.find((cell) => cell.tabIndex === 0) ?? cells[0];\n if (active) this.#setActiveCell(active, { focus: false }, cells);\n this.#normalizeSelection();\n }\n\n /**\n * Keeps `aria-multiselectable` in step with the `selection` Value. Fires on connect\n * (so it self-heals after a Turbo morph) and on any runtime change, so the ARIA\n * never drifts from the selection logic, which reads `selectionValue` live.\n */\n selectionValueChanged(): void {\n this.#syncSelectable();\n this.#normalizeSelection();\n }\n\n /** Re-establishes the baselines for a row added after connect. */\n rowTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Re-establishes the tab stop when a cell joins the grid after connect. */\n cellTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Re-establishes the tab stop when a cell leaves the grid. */\n cellTargetDisconnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Re-establishes the tab stop when a header joins the grid after connect. */\n columnHeaderTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Re-establishes the tab stop when a header leaves the grid. */\n columnHeaderTargetDisconnected(): void {\n this.#reconcile.schedule();\n }\n\n /**\n * Brings the authored rows to the shape the APG requires, without changing\n * which rows the author chose.\n *\n * Every selectable row gets an explicit value — an absent `aria-selected` means\n * \"not selectable\" in ARIA, so a forgotten attribute hides a selectable row —\n * and a single-select grid keeps at most one `true`, first in DOM order.\n * A grid that declares `selection=\"none\"` has no selectable rows, so the\n * attribute is removed rather than written: in ARIA its absence is what \"not\n * selectable\" looks like.\n */\n #normalizeSelection(): void {\n const rows = this.rowTargets;\n if (this.selectionValue === \"none\") {\n // Reclaim, do not merely skip: a grid that *became* unselectable would\n // otherwise keep announcing rows as selected while the logic refuses to\n // change them. In ARIA the absence of the attribute is what \"not\n // selectable\" looks like, so the rows have to lose it outright.\n for (const row of rows) row.removeAttribute(\"aria-selected\");\n return;\n }\n const single = this.selectionValue === \"single\";\n const first = rows.find((row) => row.getAttribute(\"aria-selected\") === \"true\");\n for (const row of rows) {\n if (single) {\n row.setAttribute(\"aria-selected\", row === first ? \"true\" : \"false\");\n } else if (row.getAttribute(\"aria-selected\") !== \"true\") {\n row.setAttribute(\"aria-selected\", \"false\");\n }\n }\n }\n\n /**\n * Mirrors `selection=\"multiple\"` onto `aria-multiselectable` (APG Grid) so SRs\n * announce that more than one row can be selected; cleared for single/none so a\n * grid never carries a misleading attribute.\n */\n #syncSelectable(): void {\n if (this.selectionValue === \"multiple\") {\n this.element.setAttribute(\"aria-multiselectable\", \"true\");\n } else {\n this.element.removeAttribute(\"aria-multiselectable\");\n }\n }\n\n /** Cycles the activated column header's sort and emits `sort`. */\n sort(event: Event): void {\n const header = event.currentTarget as HTMLElement;\n if (!this.columnHeaderTargets.includes(header)) return;\n if (event.defaultPrevented) return;\n // A sortable header hosts a `<button>`, and that button's activation is\n // exactly what this click carries, so it is the one control that does not\n // take the event away. A link or a field inside the header is its own\n // destination, and sorting on its click would act in parallel.\n const control = this.#claimingControl(event, header);\n if (control && !(control instanceof HTMLButtonElement)) return;\n\n const direction = nextSortDirection(header.getAttribute(\"aria-sort\") ?? \"none\");\n\n // Only one column is sorted at a time: reset the others to `none`.\n for (const other of this.columnHeaderTargets) {\n other.setAttribute(\"aria-sort\", other === header ? direction : \"none\");\n }\n\n this.#setActiveCell(header, { focus: false });\n this.dispatch(\"sort\", { detail: { column: header, direction } });\n }\n\n /** Toggles selection of the row owning the event target. Bound optionally. */\n toggleSelect(event: Event): void {\n // The pointer path guards on `selection=\"none\"` exactly as the keyboard path\n // does, so a grid that declares itself unselectable never grows selected rows.\n if (this.selectionValue === \"none\") return;\n // A widget that handled the click owns it, exactly as the keyboard path\n // stands down on a keystroke a descendant consumed.\n if (event.defaultPrevented) return;\n const host = event.currentTarget as HTMLElement;\n if (this.#claimedByDescendant(event, host)) return;\n const row = host.closest<HTMLElement>(\"[role='row']\");\n if (row && this.rowTargets.includes(row)) this.#toggleRow(row);\n }\n\n /** Grid navigation + sort/select activation. Bound to cells and headers. */\n onKeydown(event: KeyboardEvent): void {\n // A descendant widget that already claimed the key (a grabbed drag handle, a\n // nested menu) must not ALSO act on it — composition depends on this yield.\n if (event.defaultPrevented) return;\n if (isReservedArrowChord(event)) return;\n if (event.isComposing) return;\n const cell = event.currentTarget as HTMLElement;\n // A native control inside the cell never calls `preventDefault()` — its\n // activation IS the default action — so the yield above cannot see it. This\n // recognises those by element shape instead.\n if (this.#claimedByDescendant(event, cell)) return;\n const matrix = this.#matrix();\n const position = this.#locate(matrix, cell);\n if (!position) return;\n const [row, col] = position;\n const rowCells = matrix[row] ?? [];\n\n let target: HTMLElement | undefined;\n // Logical, not physical. The key is normalised rather than the\n // delta negated: these two branches are not mirror images — their guards\n // differ — so swapping the key keeps each guard with its own direction.\n switch (logicalArrowKey(event.key, this.element)) {\n case \"ArrowRight\":\n target = this.#cellInRow(matrix, row, col + 1);\n break;\n case \"ArrowLeft\":\n target = this.#cellInRow(matrix, row, Math.max(col - 1, 0));\n break;\n case \"ArrowDown\":\n target = this.#cellInRow(matrix, Math.min(row + 1, matrix.length - 1), col);\n break;\n case \"ArrowUp\":\n target = this.#cellInRow(matrix, Math.max(row - 1, 0), col);\n break;\n case \"Home\":\n target = event.ctrlKey ? this.#cellInRow(matrix, 0, 0) : rowCells[0];\n break;\n case \"End\":\n target = event.ctrlKey\n ? this.#cellInRow(matrix, matrix.length - 1, Number.POSITIVE_INFINITY)\n : rowCells[rowCells.length - 1];\n break;\n case \"Enter\":\n case \" \":\n this.#activate(cell);\n event.preventDefault();\n return;\n default:\n return;\n }\n\n if (target) {\n event.preventDefault();\n this.#setActiveCell(target, { focus: true }, matrix.flat());\n }\n }\n\n /**\n * Whether the event was addressed to a control inside `host` rather than to the\n * grid.\n *\n * Cells and headers hold consumer markup, and APG's grid pattern expects that\n * markup to include working controls — a row action button, an inline editor.\n * Those own their own keystrokes and clicks, so the grid stands down entirely\n * rather than acting in parallel. An editable host (its `contenteditable` state\n * is inherited, so the walk is explicit) counts the same way.\n */\n #claimedByDescendant(event: Event, host: HTMLElement): boolean {\n return this.#claimingControl(event, host) !== null;\n }\n\n /**\n * The nested control this event belongs to, or `null` when the host owns it.\n *\n * Naming the control, rather than answering yes or no, is what lets the click\n * path treat a sortable header's `<button>` as the activation it is while every\n * other control still takes the event away.\n */\n #claimingControl(event: Event, host: HTMLElement): HTMLElement | null {\n const source = event.target as HTMLElement;\n const control = source.closest<HTMLElement>(INTERACTIVE_HOST_SELECTOR);\n if (control && host.contains(control)) return control;\n return isInteractiveHost(source) ? source : null;\n }\n\n /** Performs a header's sort or a cell row's selection toggle on activation. */\n #activate(cell: HTMLElement): void {\n if (this.columnHeaderTargets.includes(cell)) {\n this.#cycleSort(cell);\n return;\n }\n if (this.selectionValue === \"none\") return;\n const row = cell.closest<HTMLElement>(\"[role='row']\");\n if (row && this.rowTargets.includes(row)) this.#toggleRow(row);\n }\n\n /** Shared sort logic for both click and keyboard activation. */\n #cycleSort(header: HTMLElement): void {\n const direction = nextSortDirection(header.getAttribute(\"aria-sort\") ?? \"none\");\n for (const other of this.columnHeaderTargets) {\n other.setAttribute(\"aria-sort\", other === header ? direction : \"none\");\n }\n this.dispatch(\"sort\", { detail: { column: header, direction } });\n }\n\n /** Toggles a row's `aria-selected`, honoring single vs. multiple selection. */\n #toggleRow(row: HTMLElement): void {\n const selected = row.getAttribute(\"aria-selected\") === \"true\";\n // Enforce single-ness on every toggle, not only when turning a row on:\n // switching one *off* would otherwise leave a second `true` behind, and\n // nothing else clears it for the rest of the session.\n if (this.selectionValue === \"single\") {\n for (const other of this.rowTargets) {\n if (other !== row) other.setAttribute(\"aria-selected\", \"false\");\n }\n }\n row.setAttribute(\"aria-selected\", selected ? \"false\" : \"true\");\n\n const rows = this.rowTargets.filter((r) => r.getAttribute(\"aria-selected\") === \"true\");\n this.dispatch(\"selectionchange\", { detail: { rows } });\n }\n\n /**\n * Makes `cell` the single tabbable cell (roving) and optionally focuses it.\n *\n * `cells` lets a caller that already walked the grid hand its collection over,\n * so one keystroke rebuilds the matrix once instead of twice. The write is\n * skipped where the attribute already holds the wanted value — comparing the\n * attribute rather than the IDL property, because a cell with no `tabindex` at\n * all reports `-1` and would then never receive the attribute it needs to be\n * focusable.\n */\n #setActiveCell(\n cell: HTMLElement,\n { focus }: { focus: boolean },\n cells?: readonly HTMLElement[],\n ): void {\n for (const candidate of cells ?? this.#navigableCells()) {\n const wanted = candidate === cell ? \"0\" : \"-1\";\n if (candidate.getAttribute(\"tabindex\") !== wanted) {\n candidate.setAttribute(\"tabindex\", wanted);\n }\n }\n if (focus) cell.focus();\n }\n\n /** All navigable elements (headers + cells) in DOM order. */\n #navigableCells(): HTMLElement[] {\n return this.#matrix().flat();\n }\n\n /** The grid as rows of navigable cells, derived from each `role=\"row\"`. */\n #matrix(): HTMLElement[][] {\n const navigable = new Set<HTMLElement>([...this.columnHeaderTargets, ...this.cellTargets]);\n const rows = Array.from(this.element.querySelectorAll<HTMLElement>(\"[role='row']\"));\n return rows\n .map((row) =>\n Array.from(row.children).filter((child): child is HTMLElement =>\n navigable.has(child as HTMLElement),\n ),\n )\n .filter((cells) => cells.length > 0);\n }\n\n /** Finds `[rowIndex, colIndex]` of `cell` within `matrix`, or null. */\n #locate(matrix: HTMLElement[][], cell: HTMLElement): [number, number] | null {\n for (let row = 0; row < matrix.length; row++) {\n const col = (matrix[row] ?? []).indexOf(cell);\n if (col !== -1) return [row, col];\n }\n return null;\n }\n\n /** The cell at `[row, col]`, clamping `col` to that row's last cell. */\n #cellInRow(matrix: HTMLElement[][], row: number, col: number): HTMLElement | undefined {\n const cells = matrix[row];\n if (!cells || cells.length === 0) return undefined;\n return cells[Math.min(col, cells.length - 1)];\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/logical_scroll.ts","../../src/utils/arrow_step.ts","../../src/utils/interactive_host.ts","../../src/utils/microtask_coalescer.ts","../../src/controllers/data_grid_controller.ts"],"names":[],"mappings":"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","file":"data_grid_controller.js","sourcesContent":["/** Normalized scroll position and maximum distance on one logical axis. */\nexport interface LogicalScrollMetrics {\n position: number;\n max: number;\n}\n\n/**\n * Whether horizontal scrolling on `element` follows right-to-left inline flow.\n *\n * Resolved from the **computed** `direction`, so the authoring contract is the\n * usual `dir=\"rtl\"` (or a stylesheet) on the element or any ancestor.\n *\n * Scope: horizontal writing modes. A vertical writing mode (`writing-mode:\n * vertical-rl`) also inverts the horizontal axis, which this check does not\n * model — vertical writing modes are out of scope for the scroll utilities\n * (their consumers describe axes as horizontal/vertical, not inline/block).\n */\nexport function isRtl(element: Element): boolean {\n return window.getComputedStyle(element).direction === \"rtl\";\n}\n\n/**\n * Returns scroll distance from the logical start edge.\n *\n * CSSOM View exposes standards-mode RTL horizontal offsets as `0` at the inline\n * start (right) and increasingly negative values toward the inline end (left).\n * The normalized position is always clamped to `[0, max]`, which also absorbs\n * Safari's elastic overscroll values.\n */\nexport function logicalScrollMetrics(\n element: HTMLElement,\n horizontal: boolean,\n): LogicalScrollMetrics {\n const max = Math.max(\n 0,\n horizontal\n ? element.scrollWidth - element.clientWidth\n : element.scrollHeight - element.clientHeight,\n );\n const raw = horizontal ? element.scrollLeft : element.scrollTop;\n const position = horizontal && isRtl(element) ? -raw : raw;\n return { position: Math.min(max, Math.max(0, position)), max };\n}\n\n/**\n * Converts a logical start/end delta to the physical value accepted by\n * `Element.scrollBy`.\n */\nexport function physicalScrollDelta(\n element: HTMLElement,\n horizontal: boolean,\n logicalDelta: number,\n): number {\n return horizontal && isRtl(element) ? -logicalDelta : logicalDelta;\n}\n","import { isRtl } from \"./logical_scroll\";\n\n/**\n * Turns an arrow key into a **logical** step: `+1` for \"next\", `-1` for\n * \"previous\", `0` when the key names neither.\n *\n * APG defines the horizontal pair as *next / previous* and says a vertical\n * arrangement swaps in Down/Up for the same meaning — so the pair is one axis's\n * spelling of an order, and the order reverses with the writing direction. Only\n * the horizontal pair reverses. Down/Up name an axis the writing direction does\n * not mirror, and returning them unchanged is the point: many controllers fold\n * both pairs into one branch, where swapping the branches under RTL would flip\n * the vertical axis too — a bug that reads as \"the arrows work\" until someone\n * presses Down.\n *\n * **Direction is read from the element the caller passes, which should be the\n * container that lays the items out** — not the focused child. A child may carry\n * its own `dir` (an LTR input inside an RTL form is ordinary authoring), and\n * probing per handler makes two handlers disagree at the boundary between them.\n *\n * This decides direction only. Whether the axis is even active (an\n * `orientation=\"horizontal\"` widget ignoring Down/Up), how far the step lands,\n * and what wrapping does all stay with the caller.\n *\n * **It encodes the list-order convention: `ArrowDown` is *next*.** Widgets that\n * pair the arrows by *value* instead — `ArrowUp` meaning \"more\", as a rating or a\n * slider does — must not use this, or their vertical axis inverts. Reverse the\n * horizontal pair on its own there.\n *\n * @example\n * ```ts\n * const step = logicalArrowStep(event.key, this.element);\n * if (step === 0) return;\n * this.#roving.setActive(rovingMove(current, length, step, \"wrap\"), { focus: true });\n * ```\n */\nexport function logicalArrowStep(key: string, element: Element): 1 | -1 | 0 {\n if (key === \"ArrowDown\") return 1;\n if (key === \"ArrowUp\") return -1;\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return 0;\n const forward = isRtl(element) ? \"ArrowLeft\" : \"ArrowRight\";\n return key === forward ? 1 : -1;\n}\n\n/**\n * Rewrites `key` so an existing LTR-shaped branch keeps working under RTL:\n * `ArrowRight` and `ArrowLeft` trade places, everything else passes through.\n *\n * The alternative — negating a delta — silently breaks handlers whose two\n * horizontal branches are **not mirror images**. A grid that clamps one edge but\n * not the other, or a segmented field guarding `index > 0` on one side and\n * `index < length - 1` on the other, ends up applying the wrong guard to the\n * wrong direction. Swapping the key leaves each branch, guards and all, exactly\n * where its author put it.\n *\n * Same rule as {@link logicalArrowStep} about which element to read: pass the\n * container that lays the items out, not the focused child.\n *\n * @example\n * ```ts\n * switch (logicalArrowKey(event.key, this.element)) {\n * case \"ArrowLeft\": // \"previous\" — whatever direction that is on screen\n * ```\n */\nexport function logicalArrowKey(key: string, element: Element): string {\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return key;\n if (!isRtl(element)) return key;\n return key === \"ArrowRight\" ? \"ArrowLeft\" : \"ArrowRight\";\n}\n\n/** Modifiers a widget may claim on an arrow key, named for the `allow` list. */\nexport type ArrowModifier = \"alt\" | \"ctrl\" | \"meta\" | \"shift\";\n\n/**\n * True when an arrow key arrived carrying a modifier the widget must leave to\n * the browser: return without calling `preventDefault()` and without moving any\n * state.\n *\n * A bare arrow belongs to the widget; a chorded one usually does not.\n * `Alt`/`Meta` plus a horizontal arrow is history back/forward on every desktop\n * browser, and a widget that swallows it makes the shortcut work or not\n * depending on where focus happens to sit — a coin-flip the user cannot see.\n *\n * `allow` is for the combinations APG assigns to a pattern **and the widget\n * actually implements** — today only Combobox's optional `Alt+Down`/`Alt+Up`.\n * Listing one the widget does not implement defeats the point: the chord then\n * runs the plain-arrow branch, which is exactly what this guard exists to stop.\n * Non-arrow keys return `false`, so chorded letters and\n * `Control+Home`/`Control+End` are untouched.\n *\n * @example\n * ```ts\n * if (isReservedArrowChord(event)) return;\n * ```\n */\nexport function isReservedArrowChord(\n event: KeyboardEvent,\n allow: readonly ArrowModifier[] = [],\n): boolean {\n if (!event.key.startsWith(\"Arrow\")) return false;\n return (\n (event.altKey && !allow.includes(\"alt\")) ||\n (event.ctrlKey && !allow.includes(\"ctrl\")) ||\n (event.metaKey && !allow.includes(\"meta\")) ||\n (event.shiftKey && !allow.includes(\"shift\"))\n );\n}\n\n/**\n * True when a press arrived carrying any modifier, for the keys the browser and\n * the OS own outright: return without calling `preventDefault()` and without\n * moving any state.\n *\n * `Control+Home` and `Control+End` jump the document to its ends, and a widget\n * that swallows them makes the shortcut work or not depending on where focus\n * happens to sit. {@link isReservedArrowChord} answers the same question for the\n * arrows, but returns `false` for every other key so that this one can decide.\n *\n * There is no `allow` list here on purpose. APG assigns no modifier chord to\n * `Home`/`End`, so a widget that wanted one would be claiming a combination the\n * pattern never gave it.\n *\n * @example\n * ```ts\n * case \"Home\":\n * case \"End\":\n * if (hasModifierChord(event)) return;\n * ```\n */\nexport function hasModifierChord(event: KeyboardEvent): boolean {\n return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;\n}\n","/**\n * Native interactive elements whose built-in activation must not be replaced\n * wholesale by a controller. Deliberately excludes `[tabindex]`: a generic\n * element made focusable is the supported host for several headless patterns.\n * Contenteditable is handled by {@link isInteractiveHost} because its state is\n * inherited and its keywords are ASCII-case-insensitive.\n */\nexport const INTERACTIVE_HOST_SELECTOR =\n \"button, input, select, textarea, label, a[href], area[href], summary, details, audio[controls], video[controls], iframe, object, embed\";\n\n/**\n * Whether an element owns native activation or an inherited editing surface.\n *\n * The `contenteditable` missing and invalid states inherit. Walking explicitly\n * also keeps `contenteditable=\"false\"` as a real boundary inside an editable\n * ancestor instead of treating any ancestor attribute as decisive.\n */\nexport function isInteractiveHost(element: HTMLElement): boolean {\n if (element.matches(INTERACTIVE_HOST_SELECTOR)) return true;\n\n let current: HTMLElement | null = element;\n while (current) {\n const raw = current.getAttribute(\"contenteditable\");\n if (raw !== null) {\n const value = raw.trim().toLowerCase();\n if (value === \"false\") return false;\n if (value === \"\" || value === \"true\" || value === \"plaintext-only\") return true;\n }\n current = current.parentElement;\n }\n return false;\n}\n","/**\n * Collapses many Stimulus lifecycle callbacks from one DOM mutation into a\n * single pass.\n *\n * Stimulus fires `<name>TargetConnected` / `Disconnected` once per element and\n * `<name>ValueChanged` once per changed attribute. Replacing a list of N options\n * or morphing several render Values therefore delivers N callbacks — but the\n * useful unit of work is \"reconcile against the resulting declarative input\",\n * once, after the batch has settled. Every controller with reconcilable targets\n * or render Values needs the same shape: a `queued` flag plus `queueMicrotask`.\n *\n * **A microtask is the right horizon, and the reason is specific.** Stimulus\n * drives these callbacks from a `MutationObserver`, whose own callback already\n * runs as a microtask with the whole batch in hand; scheduling one more lands\n * after the last sibling callback of that batch and still before paint or any\n * event handler. A timer would be later than it needs to be, and reconciling\n * synchronously would run once per element against a half-applied DOM.\n *\n * **The two guards are not the same guard.** Scheduling is refused before the\n * controller connects, and running is refused after it disconnects:\n *\n * - **Before `connect()`** — Stimulus delivers initial target and Value callbacks\n * ahead of `connect()`. Reconciling there would compute output against a\n * controller whose own state has not been initialised, and `connect()` is\n * about to do a full pass anyway.\n * - **After `disconnect()`** — Stimulus fires a callback for **every** target\n * during teardown, and a microtask queued just before it would otherwise run\n * against a detached tree. {@link MicrotaskCoalescer.cancel} exists for the\n * teardown path to drop the pending pass outright.\n *\n * Both guards are part of one contract here rather than something each consumer\n * has to remember separately.\n *\n * Scope is the scheduling only. *What* to reconcile — keep the surviving active\n * option, fall back to the next / previous / first visible one, rebuild derived\n * chips or hidden fields — stays in the controller, because no two consumers\n * answer it the same way.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileOptions());\n *\n * connect() { this.#reconcile.activate(); }\n * disconnect() { this.#reconcile.cancel(); }\n *\n * optionTargetConnected() { this.#reconcile.schedule(); }\n * optionTargetDisconnected() { this.#reconcile.schedule(); }\n * ```\n */\nexport class MicrotaskCoalescer {\n readonly #run: () => void;\n #queued = false;\n #active = false;\n #generation = 0;\n\n /** @param run - the single reconciliation pass, invoked at most once per batch. */\n constructor(run: () => void) {\n this.#run = run;\n }\n\n /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */\n activate(): void {\n this.#active = true;\n }\n\n /** Closes the window and drops any pending pass; call from `disconnect()`. */\n cancel(): void {\n this.#active = false;\n this.#queued = false;\n this.#generation += 1;\n }\n\n /** Requests one pass after the batch settles. Idempotent; inert outside the window. */\n schedule(): void {\n if (!this.#active || this.#queued) return;\n this.#queued = true;\n const generation = this.#generation;\n queueMicrotask(() => {\n // A cancelled callback must not consume a pass queued after reconnect.\n if (generation !== this.#generation || !this.#queued || !this.#active) return;\n this.#queued = false;\n this.#run();\n });\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { isReservedArrowChord, logicalArrowKey } from \"../utils/arrow_step\";\nimport { INTERACTIVE_HOST_SELECTOR, isInteractiveHost } from \"../utils/interactive_host\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\n\n/** Cycle order for a sortable column header's `aria-sort`. */\nconst SORT_CYCLE = [\"none\", \"ascending\", \"descending\"] as const;\ntype SortDirection = (typeof SORT_CYCLE)[number];\n\n/**\n * Returns the next `aria-sort` direction in the cycle after `current`. Unknown or\n * ARIA-only values (e.g. `\"other\"`, or an empty/missing attribute) are treated as\n * `\"none\"`, so the first activation always advances to `\"ascending\"` instead of\n * stalling.\n */\nfunction nextSortDirection(current: string): SortDirection {\n const index = SORT_CYCLE.indexOf(current as SortDirection);\n const from = index < 0 ? 0 : index;\n return SORT_CYCLE[(from + 1) % SORT_CYCLE.length] ?? \"ascending\";\n}\n\n/**\n * Headless, accessible **Data Grid** behavior: column sorting, row selection, and\n * roving keyboard navigation over an interactive table.\n *\n * Markup contract (identifier: `stimeo--data-grid`):\n * <table data-controller=\"stimeo--data-grid\" role=\"grid\" aria-label=\"Users\"\n * data-stimeo--data-grid-selection-value=\"single\">\n * <thead><tr role=\"row\">\n * <th role=\"columnheader\" aria-sort=\"none\" tabindex=\"-1\"\n * data-stimeo--data-grid-target=\"columnHeader\"\n * data-action=\"click->stimeo--data-grid#sort\n * keydown->stimeo--data-grid#onKeydown\">Name</th>\n * </tr></thead>\n * <tbody><tr role=\"row\" aria-selected=\"false\"\n * data-stimeo--data-grid-target=\"row\">\n * <td role=\"gridcell\" tabindex=\"0\" data-stimeo--data-grid-target=\"cell\"\n * data-action=\"keydown->stimeo--data-grid#onKeydown\">Jane</td>\n * </tr></tbody>\n * </table>\n *\n * Implements the WAI-ARIA APG **Grid** pattern plus `aria-sort`. The whole grid is\n * a single Tab stop (roving `tabindex`: exactly one cell/header is `0`, the rest\n * `-1`); arrow keys move both DOM focus and that tabbable position. Sort state is\n * exposed via `aria-sort` on headers, selection via `aria-selected` on rows.\n *\n * `selectionchange` dispatches `{ rows: HTMLElement[] }`; `sort` dispatches\n * `{ column: HTMLElement, direction: \"ascending\" | \"descending\" | \"none\" }`.\n *\n * @remarks\n * Behavior only — the consumer performs the actual data sort/render in response to\n * the `sort` event and owns all styling. No timers or observers are held, so there\n * is nothing to leak across Turbo navigations; `connect()` rebuilds the single tab\n * stop idempotently from the DOM, and the target callbacks rebuild it again after\n * rows or cells are added or removed at runtime.\n *\n * Behavior provided:\n * - `Arrow*` move between cells (clamped at edges); `Home`/`End` to the row's\n * first/last cell; `Ctrl+Home`/`Ctrl+End` to the grid's first/last cell.\n * - `Enter`/`Space` cycles a header's sort (`none→ascending→descending`) or toggles\n * the focused row's selection when selection is enabled.\n *\n * Consumer contract — controls nested inside a cell or header:\n * - APG's grid hosts working controls in its cells, so a keystroke or click that\n * reached one — {@link INTERACTIVE_HOST_SELECTOR}, an editable host, or any\n * widget that already called `preventDefault()` — is left to it entirely: no\n * move, no sort, no selection. The one control that hands the event on is a\n * sortable header's own `<button>`, whose activation is what the click carries.\n * - A control keeps its own Tab behavior, so give it `tabindex=\"-1\"` to preserve\n * the grid's single Tab stop. A sortable `columnheader` hosting a `<button>` is\n * the common case: the roving position stays on the header, and the button's\n * own activation reaches `sort` through the click that bubbles to it.\n * - Host `role=\"gridcell\"` / `role=\"columnheader\"` on a non-interactive element\n * (`td`, `th`); an interactive host makes the grid stand down on that cell.\n */\nexport class DataGridController extends Controller<HTMLElement> {\n static override targets = [\"columnHeader\", \"row\", \"cell\"];\n static override values = {\n selection: { type: String, default: \"none\" },\n };\n static actions = [\"onKeydown\", \"sort\", \"toggleSelect\"] as const;\n static events = [\"selectionchange\", \"sort\"] as const;\n\n declare readonly columnHeaderTargets: HTMLElement[];\n declare readonly rowTargets: HTMLElement[];\n declare readonly cellTargets: HTMLElement[];\n declare selectionValue: string;\n\n /**\n * Collapses the per-element target callbacks of one DOM mutation into a single\n * baseline pass, and refuses to run before `connect()` or after `disconnect()`.\n *\n * Stimulus reports every target one at a time, so an ungated pass would re-walk\n * the whole grid once per authored cell on mount and once per streamed cell\n * afterwards — quadratic in the cell count both times.\n */\n readonly #reconcile = new MicrotaskCoalescer(() => this.#restoreBaseline());\n\n /**\n * Establishes a single tab stop across all navigable cells/headers and brings\n * the rows to their baseline.\n *\n * Normalizing here rather than leaving it to {@link selectionValueChanged}\n * guarantees exactly one pass per mount: a re-attached element reuses its\n * cached Stimulus context, whose value observer already knows the `selection`\n * attribute, so the Value callback does not fire a second time.\n */\n override connect(): void {\n this.#restoreBaseline();\n this.#reconcile.activate();\n }\n\n /** Closes the reconcile window so a queued pass cannot run against a detached tree. */\n override disconnect(): void {\n this.#reconcile.cancel();\n }\n\n /**\n * Rebuilds both DOM-owned baselines from the live grid: exactly one navigable\n * cell is in the Tab sequence, and every selectable row carries an explicit\n * `aria-selected`.\n *\n * The tab stop keeps whichever cell already holds it, so a rebuild triggered by\n * an unrelated row arriving does not throw the user's position away; only when\n * no cell holds it — the grid is fresh, or the holder was removed — does the\n * first navigable cell take over. Without that fallback a grid whose active row\n * is removed keeps every cell at `-1` and drops out of the Tab sequence\n * entirely.\n */\n #restoreBaseline(): void {\n const cells = this.#navigableCells();\n const active = cells.find((cell) => cell.tabIndex === 0) ?? cells[0];\n if (active) this.#setActiveCell(active, { focus: false }, cells);\n this.#normalizeSelection();\n }\n\n /**\n * Keeps `aria-multiselectable` in step with the `selection` Value. Fires on connect\n * (so it self-heals after a Turbo morph) and on any runtime change, so the ARIA\n * never drifts from the selection logic, which reads `selectionValue` live.\n */\n selectionValueChanged(): void {\n this.#syncSelectable();\n this.#normalizeSelection();\n }\n\n /** Re-establishes the baselines for a row added after connect. */\n rowTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Re-establishes the tab stop when a cell joins the grid after connect. */\n cellTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Re-establishes the tab stop when a cell leaves the grid. */\n cellTargetDisconnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Re-establishes the tab stop when a header joins the grid after connect. */\n columnHeaderTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Re-establishes the tab stop when a header leaves the grid. */\n columnHeaderTargetDisconnected(): void {\n this.#reconcile.schedule();\n }\n\n /**\n * Brings the authored rows to the shape the APG requires, without changing\n * which rows the author chose.\n *\n * Every selectable row gets an explicit value — an absent `aria-selected` means\n * \"not selectable\" in ARIA, so a forgotten attribute hides a selectable row —\n * and a single-select grid keeps at most one `true`, first in DOM order.\n * A grid that declares `selection=\"none\"` has no selectable rows, so the\n * attribute is removed rather than written: in ARIA its absence is what \"not\n * selectable\" looks like.\n */\n #normalizeSelection(): void {\n const rows = this.rowTargets;\n if (this.selectionValue === \"none\") {\n // Reclaim, do not merely skip: a grid that *became* unselectable would\n // otherwise keep announcing rows as selected while the logic refuses to\n // change them. In ARIA the absence of the attribute is what \"not\n // selectable\" looks like, so the rows have to lose it outright.\n for (const row of rows) row.removeAttribute(\"aria-selected\");\n return;\n }\n const single = this.selectionValue === \"single\";\n const first = rows.find((row) => row.getAttribute(\"aria-selected\") === \"true\");\n for (const row of rows) {\n if (single) {\n row.setAttribute(\"aria-selected\", row === first ? \"true\" : \"false\");\n } else if (row.getAttribute(\"aria-selected\") !== \"true\") {\n row.setAttribute(\"aria-selected\", \"false\");\n }\n }\n }\n\n /**\n * Mirrors `selection=\"multiple\"` onto `aria-multiselectable` (APG Grid) so SRs\n * announce that more than one row can be selected; cleared for single/none so a\n * grid never carries a misleading attribute.\n */\n #syncSelectable(): void {\n if (this.selectionValue === \"multiple\") {\n this.element.setAttribute(\"aria-multiselectable\", \"true\");\n } else {\n this.element.removeAttribute(\"aria-multiselectable\");\n }\n }\n\n /** Cycles the activated column header's sort and emits `sort`. */\n sort(event: Event): void {\n const header = event.currentTarget as HTMLElement;\n if (!this.columnHeaderTargets.includes(header)) return;\n if (event.defaultPrevented) return;\n // A sortable header hosts a `<button>`, and that button's activation is\n // exactly what this click carries, so it is the one control that does not\n // take the event away. A link or a field inside the header is its own\n // destination, and sorting on its click would act in parallel.\n const control = this.#claimingControl(event, header);\n if (control && !(control instanceof HTMLButtonElement)) return;\n\n const direction = nextSortDirection(header.getAttribute(\"aria-sort\") ?? \"none\");\n\n // Only one column is sorted at a time: reset the others to `none`.\n for (const other of this.columnHeaderTargets) {\n other.setAttribute(\"aria-sort\", other === header ? direction : \"none\");\n }\n\n this.#setActiveCell(header, { focus: false });\n this.dispatch(\"sort\", { detail: { column: header, direction } });\n }\n\n /** Toggles selection of the row owning the event target. Bound optionally. */\n toggleSelect(event: Event): void {\n // The pointer path guards on `selection=\"none\"` exactly as the keyboard path\n // does, so a grid that declares itself unselectable never grows selected rows.\n if (this.selectionValue === \"none\") return;\n // A widget that handled the click owns it, exactly as the keyboard path\n // stands down on a keystroke a descendant consumed.\n if (event.defaultPrevented) return;\n const host = event.currentTarget as HTMLElement;\n if (this.#claimedByDescendant(event, host)) return;\n const row = host.closest<HTMLElement>(\"[role='row']\");\n if (row && this.rowTargets.includes(row)) this.#toggleRow(row);\n }\n\n /** Grid navigation + sort/select activation. Bound to cells and headers. */\n onKeydown(event: KeyboardEvent): void {\n // A descendant widget that already claimed the key (a grabbed drag handle, a\n // nested menu) must not ALSO act on it — composition depends on this yield.\n if (event.defaultPrevented) return;\n if (isReservedArrowChord(event)) return;\n if (event.isComposing) return;\n const cell = event.currentTarget as HTMLElement;\n // A native control inside the cell never calls `preventDefault()` — its\n // activation IS the default action — so the yield above cannot see it. This\n // recognises those by element shape instead.\n if (this.#claimedByDescendant(event, cell)) return;\n const matrix = this.#matrix();\n const position = this.#locate(matrix, cell);\n if (!position) return;\n const [row, col] = position;\n const rowCells = matrix[row] ?? [];\n\n let target: HTMLElement | undefined;\n // Logical, not physical. The key is normalised rather than the\n // delta negated: these two branches are not mirror images — their guards\n // differ — so swapping the key keeps each guard with its own direction.\n switch (logicalArrowKey(event.key, this.element)) {\n case \"ArrowRight\":\n target = this.#cellInRow(matrix, row, col + 1);\n break;\n case \"ArrowLeft\":\n target = this.#cellInRow(matrix, row, Math.max(col - 1, 0));\n break;\n case \"ArrowDown\":\n target = this.#cellInRow(matrix, Math.min(row + 1, matrix.length - 1), col);\n break;\n case \"ArrowUp\":\n target = this.#cellInRow(matrix, Math.max(row - 1, 0), col);\n break;\n case \"Home\":\n target = event.ctrlKey ? this.#cellInRow(matrix, 0, 0) : rowCells[0];\n break;\n case \"End\":\n target = event.ctrlKey\n ? this.#cellInRow(matrix, matrix.length - 1, Number.POSITIVE_INFINITY)\n : rowCells[rowCells.length - 1];\n break;\n case \"Enter\":\n case \" \":\n this.#activate(cell);\n event.preventDefault();\n return;\n default:\n return;\n }\n\n if (target) {\n event.preventDefault();\n this.#setActiveCell(target, { focus: true }, matrix.flat());\n }\n }\n\n /**\n * Whether the event was addressed to a control inside `host` rather than to the\n * grid.\n *\n * Cells and headers hold consumer markup, and APG's grid pattern expects that\n * markup to include working controls — a row action button, an inline editor.\n * Those own their own keystrokes and clicks, so the grid stands down entirely\n * rather than acting in parallel. An editable host (its `contenteditable` state\n * is inherited, so the walk is explicit) counts the same way.\n */\n #claimedByDescendant(event: Event, host: HTMLElement): boolean {\n return this.#claimingControl(event, host) !== null;\n }\n\n /**\n * The nested control this event belongs to, or `null` when the host owns it.\n *\n * Naming the control, rather than answering yes or no, is what lets the click\n * path treat a sortable header's `<button>` as the activation it is while every\n * other control still takes the event away.\n */\n #claimingControl(event: Event, host: HTMLElement): HTMLElement | null {\n const source = event.target as HTMLElement;\n const control = source.closest<HTMLElement>(INTERACTIVE_HOST_SELECTOR);\n if (control && host.contains(control)) return control;\n return isInteractiveHost(source) ? source : null;\n }\n\n /** Performs a header's sort or a cell row's selection toggle on activation. */\n #activate(cell: HTMLElement): void {\n if (this.columnHeaderTargets.includes(cell)) {\n this.#cycleSort(cell);\n return;\n }\n if (this.selectionValue === \"none\") return;\n const row = cell.closest<HTMLElement>(\"[role='row']\");\n if (row && this.rowTargets.includes(row)) this.#toggleRow(row);\n }\n\n /** Cycles a header's sort on keyboard activation and emits `sort`. */\n #cycleSort(header: HTMLElement): void {\n const direction = nextSortDirection(header.getAttribute(\"aria-sort\") ?? \"none\");\n for (const other of this.columnHeaderTargets) {\n other.setAttribute(\"aria-sort\", other === header ? direction : \"none\");\n }\n this.dispatch(\"sort\", { detail: { column: header, direction } });\n }\n\n /** Toggles a row's `aria-selected`, honoring single vs. multiple selection. */\n #toggleRow(row: HTMLElement): void {\n const selected = row.getAttribute(\"aria-selected\") === \"true\";\n // Enforce single-ness on every toggle, not only when turning a row on:\n // switching one *off* would otherwise leave a second `true` behind until\n // the next baseline pass.\n if (this.selectionValue === \"single\") {\n for (const other of this.rowTargets) {\n if (other !== row) other.setAttribute(\"aria-selected\", \"false\");\n }\n }\n row.setAttribute(\"aria-selected\", selected ? \"false\" : \"true\");\n\n const rows = this.rowTargets.filter((r) => r.getAttribute(\"aria-selected\") === \"true\");\n this.dispatch(\"selectionchange\", { detail: { rows } });\n }\n\n /**\n * Makes `cell` the single tabbable cell (roving) and optionally focuses it.\n *\n * `cells` lets a caller that already walked the grid hand its collection over,\n * so one keystroke rebuilds the matrix once instead of twice. The write is\n * skipped where the attribute already holds the wanted value — comparing the\n * attribute rather than the IDL property, because a cell with no `tabindex` at\n * all reports `-1` and would then never receive the attribute it needs to be\n * focusable.\n */\n #setActiveCell(\n cell: HTMLElement,\n { focus }: { focus: boolean },\n cells?: readonly HTMLElement[],\n ): void {\n for (const candidate of cells ?? this.#navigableCells()) {\n const wanted = candidate === cell ? \"0\" : \"-1\";\n if (candidate.getAttribute(\"tabindex\") !== wanted) {\n candidate.setAttribute(\"tabindex\", wanted);\n }\n }\n if (focus) cell.focus();\n }\n\n /** All navigable elements (headers + cells) in DOM order. */\n #navigableCells(): HTMLElement[] {\n return this.#matrix().flat();\n }\n\n /** The grid as rows of navigable cells, derived from each `role=\"row\"`. */\n #matrix(): HTMLElement[][] {\n const navigable = new Set<HTMLElement>([...this.columnHeaderTargets, ...this.cellTargets]);\n const rows = Array.from(this.element.querySelectorAll<HTMLElement>(\"[role='row']\"));\n return rows\n .map((row) =>\n Array.from(row.children).filter((child): child is HTMLElement =>\n navigable.has(child as HTMLElement),\n ),\n )\n .filter((cells) => cells.length > 0);\n }\n\n /** Finds `[rowIndex, colIndex]` of `cell` within `matrix`, or null. */\n #locate(matrix: HTMLElement[][], cell: HTMLElement): [number, number] | null {\n for (let row = 0; row < matrix.length; row++) {\n const col = (matrix[row] ?? []).indexOf(cell);\n if (col !== -1) return [row, col];\n }\n return null;\n }\n\n /** The cell at `[row, col]`, clamping `col` to that row's last cell. */\n #cellInRow(matrix: HTMLElement[][], row: number, col: number): HTMLElement | undefined {\n const cells = matrix[row];\n if (!cells || cells.length === 0) return undefined;\n return cells[Math.min(col, cells.length - 1)];\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/logical_scroll.ts","../../src/utils/arrow_step.ts","../../src/utils/before_cache_reset.ts","../../src/utils/dates.ts","../../src/utils/microtask_coalescer.ts","../../src/utils/safe_timeout.ts","../../src/utils/string_list.ts","../../src/controllers/date_range_picker_controller.ts"],"names":[],"mappings":"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","file":"date_range_picker_controller.js","sourcesContent":["/** Normalized scroll position and maximum distance on one logical axis. */\nexport interface LogicalScrollMetrics {\n position: number;\n max: number;\n}\n\n/**\n * Whether horizontal scrolling on `element` follows right-to-left inline flow.\n *\n * Resolved from the **computed** `direction`, so the authoring contract is the\n * usual `dir=\"rtl\"` (or a stylesheet) on the element or any ancestor.\n *\n * Scope: horizontal writing modes. A vertical writing mode (`writing-mode:\n * vertical-rl`) also inverts the horizontal axis, which this check does not\n * model — vertical writing modes are out of scope for the scroll utilities\n * (their consumers describe axes as horizontal/vertical, not inline/block).\n */\nexport function isRtl(element: Element): boolean {\n return window.getComputedStyle(element).direction === \"rtl\";\n}\n\n/**\n * Returns scroll distance from the logical start edge.\n *\n * CSSOM View exposes standards-mode RTL horizontal offsets as `0` at the inline\n * start (right) and increasingly negative values toward the inline end (left).\n * The normalized position is always clamped to `[0, max]`, which also absorbs\n * Safari's elastic overscroll values.\n */\nexport function logicalScrollMetrics(\n element: HTMLElement,\n horizontal: boolean,\n): LogicalScrollMetrics {\n const max = Math.max(\n 0,\n horizontal\n ? element.scrollWidth - element.clientWidth\n : element.scrollHeight - element.clientHeight,\n );\n const raw = horizontal ? element.scrollLeft : element.scrollTop;\n const position = horizontal && isRtl(element) ? -raw : raw;\n return { position: Math.min(max, Math.max(0, position)), max };\n}\n\n/**\n * Converts a logical start/end delta to the physical value accepted by\n * `Element.scrollBy`.\n */\nexport function physicalScrollDelta(\n element: HTMLElement,\n horizontal: boolean,\n logicalDelta: number,\n): number {\n return horizontal && isRtl(element) ? -logicalDelta : logicalDelta;\n}\n","import { isRtl } from \"./logical_scroll\";\n\n/**\n * Turns an arrow key into a **logical** step: `+1` for \"next\", `-1` for\n * \"previous\", `0` when the key names neither.\n *\n * APG defines the horizontal pair as *next / previous* and says a vertical\n * arrangement swaps in Down/Up for the same meaning — so the pair is one axis's\n * spelling of an order, and the order reverses with the writing direction. Only\n * the horizontal pair reverses. Down/Up name an axis the writing direction does\n * not mirror, and returning them unchanged is the point: many controllers fold\n * both pairs into one branch, where swapping the branches under RTL would flip\n * the vertical axis too — a bug that reads as \"the arrows work\" until someone\n * presses Down.\n *\n * **Direction is read from the element the caller passes, which should be the\n * container that lays the items out** — not the focused child. A child may carry\n * its own `dir` (an LTR input inside an RTL form is ordinary authoring), and\n * probing per handler makes two handlers disagree at the boundary between them.\n *\n * This decides direction only. Whether the axis is even active (an\n * `orientation=\"horizontal\"` widget ignoring Down/Up), how far the step lands,\n * and what wrapping does all stay with the caller.\n *\n * **It encodes the list-order convention: `ArrowDown` is *next*.** Widgets that\n * pair the arrows by *value* instead — `ArrowUp` meaning \"more\", as a rating or a\n * slider does — must not use this, or their vertical axis inverts. Reverse the\n * horizontal pair on its own there.\n *\n * @example\n * ```ts\n * const step = logicalArrowStep(event.key, this.element);\n * if (step === 0) return;\n * this.#roving.setActive(rovingMove(current, length, step, \"wrap\"), { focus: true });\n * ```\n */\nexport function logicalArrowStep(key: string, element: Element): 1 | -1 | 0 {\n if (key === \"ArrowDown\") return 1;\n if (key === \"ArrowUp\") return -1;\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return 0;\n const forward = isRtl(element) ? \"ArrowLeft\" : \"ArrowRight\";\n return key === forward ? 1 : -1;\n}\n\n/**\n * Rewrites `key` so an existing LTR-shaped branch keeps working under RTL:\n * `ArrowRight` and `ArrowLeft` trade places, everything else passes through.\n *\n * The alternative — negating a delta — silently breaks handlers whose two\n * horizontal branches are **not mirror images**. A grid that clamps one edge but\n * not the other, or a segmented field guarding `index > 0` on one side and\n * `index < length - 1` on the other, ends up applying the wrong guard to the\n * wrong direction. Swapping the key leaves each branch, guards and all, exactly\n * where its author put it.\n *\n * Same rule as {@link logicalArrowStep} about which element to read: pass the\n * container that lays the items out, not the focused child.\n *\n * @example\n * ```ts\n * switch (logicalArrowKey(event.key, this.element)) {\n * case \"ArrowLeft\": // \"previous\" — whatever direction that is on screen\n * ```\n */\nexport function logicalArrowKey(key: string, element: Element): string {\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return key;\n if (!isRtl(element)) return key;\n return key === \"ArrowRight\" ? \"ArrowLeft\" : \"ArrowRight\";\n}\n\n/** Modifiers a widget may claim on an arrow key, named for the `allow` list. */\nexport type ArrowModifier = \"alt\" | \"ctrl\" | \"meta\" | \"shift\";\n\n/**\n * True when an arrow key arrived carrying a modifier the widget must leave to\n * the browser: return without calling `preventDefault()` and without moving any\n * state.\n *\n * A bare arrow belongs to the widget; a chorded one usually does not.\n * `Alt`/`Meta` plus a horizontal arrow is history back/forward on every desktop\n * browser, and a widget that swallows it makes the shortcut work or not\n * depending on where focus happens to sit — a coin-flip the user cannot see.\n *\n * `allow` is for the combinations APG assigns to a pattern **and the widget\n * actually implements** — today only Combobox's optional `Alt+Down`/`Alt+Up`.\n * Listing one the widget does not implement defeats the point: the chord then\n * runs the plain-arrow branch, which is exactly what this guard exists to stop.\n * Non-arrow keys return `false`, so chorded letters and\n * `Control+Home`/`Control+End` are untouched.\n *\n * @example\n * ```ts\n * if (isReservedArrowChord(event)) return;\n * ```\n */\nexport function isReservedArrowChord(\n event: KeyboardEvent,\n allow: readonly ArrowModifier[] = [],\n): boolean {\n if (!event.key.startsWith(\"Arrow\")) return false;\n return (\n (event.altKey && !allow.includes(\"alt\")) ||\n (event.ctrlKey && !allow.includes(\"ctrl\")) ||\n (event.metaKey && !allow.includes(\"meta\")) ||\n (event.shiftKey && !allow.includes(\"shift\"))\n );\n}\n","/**\n * Runs a controller's \"return to the initial state\" pass just before Turbo\n * caches the page.\n *\n * **`disconnect()` cannot do this job, for two independent reasons.** Turbo\n * queues the clone from this event rather than taking it here, and the body swap\n * that runs the controller's `disconnect()` is queued separately — so which of\n * the two lands first is not something a controller can rely on, and a rewind\n * written in `disconnect()` may reach only the DOM being thrown away. In the\n * other direction, `disconnect()` also fires on an in-page move (Stimulus tears\n * down and reconnects the same element), where rewinding would wipe a\n * legitimately in-progress interaction — a spinner mid-load would vanish. One\n * timing is unreliable, the other is too eager; `turbo:before-cache` is the only\n * point that is exactly \"the page is about to be frozen\".\n *\n * Scope is the subscription only: registering on `activate()`, unregistering on\n * `deactivate()`, and one shared document listener no matter how many instances\n * are live. *What* to return to its initial state — which `data-state`, which\n * `hidden`, which `aria-busy` — stays in the controller, because no two\n * consumers answer it the same way (the `MicrotaskCoalescer` split).\n *\n * **Rewind state, not appearance.** The pass writes attributes the controller\n * itself owns; the visual result of those attributes is the consumer's CSS, and\n * a library that reached for style or class names would be guessing at markup\n * it does not own.\n *\n * Both entry points are idempotent, so the lifecycle hooks can call them\n * unconditionally: a second `activate()` does not double-subscribe and does not\n * make the callback run twice, and `deactivate()` on an instance that never\n * subscribed is a no-op.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #beforeCache = new BeforeCacheReset(() => this.#rewind());\n *\n * connect() { this.#beforeCache.activate(); }\n * disconnect() { this.#beforeCache.deactivate(); }\n * ```\n */\nexport class BeforeCacheReset {\n /** Every subscribed instance, iterated by the one shared document listener. */\n static readonly #subscribers = new Set<BeforeCacheReset>();\n\n /** The shared listener; installed while at least one instance is subscribed. */\n static readonly #onBeforeCache = (): void => {\n for (const subscriber of BeforeCacheReset.#subscribers) subscriber.#rewind();\n };\n\n readonly #rewind: () => void;\n\n /** @param rewind - the pass that returns this controller's state to its initial form. */\n constructor(rewind: () => void) {\n this.#rewind = rewind;\n }\n\n /** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */\n activate(): void {\n const first = BeforeCacheReset.#subscribers.size === 0;\n BeforeCacheReset.#subscribers.add(this);\n if (first) {\n document.addEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n }\n\n /** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */\n deactivate(): void {\n BeforeCacheReset.#subscribers.delete(this);\n if (BeforeCacheReset.#subscribers.size > 0) return;\n document.removeEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n}\n","/**\n * Local-time date helpers shared by the calendar-family controllers\n * (`calendar`, `date-range-picker`).\n *\n * All conversions are intentionally **local time** (not UTC): the grid a user\n * sees is built from `Date` components in their own timezone, so round-tripping\n * through ISO strings must use the same frame to avoid off-by-one-day drift near\n * midnight. Strings are bare `YYYY-MM-DD` / `YYYY-MM` with no time or zone.\n */\n\n/** Formats a {@link Date} as a local-time `YYYY-MM-DD` string. */\nexport function toISODateString(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n}\n\n/**\n * Parses a `YYYY-MM-DD` string into a local-time {@link Date}, or `null`.\n *\n * Rejects calendar-invalid dates (e.g. `2026-02-31`): the constructed `Date`\n * would silently roll over to another day, so the parsed components are checked\n * back against it and a mismatch returns `null`.\n */\nexport function parseISODateString(dateStr: string): Date | null {\n if (!dateStr) return null;\n const match = dateStr.match(/^(\\d{4})-(\\d{2})-(\\d{2})$/);\n if (!match) return null;\n const [, y, m, d] = match;\n const year = Number(y);\n const month = Number(m);\n const day = Number(d);\n const date = new Date(year, month - 1, day);\n if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {\n return null;\n }\n return date;\n}\n\n/**\n * Parses a `YYYY-MM` string into its year/month (1-based) parts, or `null`.\n * Rejects months outside `1..12`.\n */\nexport function parseISOMonthString(monthStr: string): { year: number; month: number } | null {\n if (!monthStr) return null;\n const match = monthStr.match(/^(\\d{4})-(\\d{2})$/);\n if (!match) return null;\n const [, y, m] = match;\n const month = Number(m);\n if (month < 1 || month > 12) return null;\n return { year: Number(y), month };\n}\n\n/** Formats a {@link Date} as the local-time `YYYY-MM` string of its month. */\nexport function toISOMonthString(date: Date): string {\n return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, \"0\")}`;\n}\n","/**\n * Collapses many Stimulus lifecycle callbacks from one DOM mutation into a\n * single pass.\n *\n * Stimulus fires `<name>TargetConnected` / `Disconnected` once per element and\n * `<name>ValueChanged` once per changed attribute. Replacing a list of N options\n * or morphing several render Values therefore delivers N callbacks — but the\n * useful unit of work is \"reconcile against the resulting declarative input\",\n * once, after the batch has settled. Every controller with reconcilable targets\n * or render Values needs the same shape: a `queued` flag plus `queueMicrotask`.\n *\n * **A microtask is the right horizon, and the reason is specific.** Stimulus\n * drives these callbacks from a `MutationObserver`, whose own callback already\n * runs as a microtask with the whole batch in hand; scheduling one more lands\n * after the last sibling callback of that batch and still before paint or any\n * event handler. A timer would be later than it needs to be, and reconciling\n * synchronously would run once per element against a half-applied DOM.\n *\n * **The two guards are not the same guard.** Scheduling is refused before the\n * controller connects, and running is refused after it disconnects:\n *\n * - **Before `connect()`** — Stimulus delivers initial target and Value callbacks\n * ahead of `connect()`. Reconciling there would compute output against a\n * controller whose own state has not been initialised, and `connect()` is\n * about to do a full pass anyway.\n * - **After `disconnect()`** — Stimulus fires a callback for **every** target\n * during teardown, and a microtask queued just before it would otherwise run\n * against a detached tree. {@link MicrotaskCoalescer.cancel} exists for the\n * teardown path to drop the pending pass outright.\n *\n * Both guards are part of one contract here rather than something each consumer\n * has to remember separately.\n *\n * Scope is the scheduling only. *What* to reconcile — keep the surviving active\n * option, fall back to the next / previous / first visible one, rebuild derived\n * chips or hidden fields — stays in the controller, because no two consumers\n * answer it the same way.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileOptions());\n *\n * connect() { this.#reconcile.activate(); }\n * disconnect() { this.#reconcile.cancel(); }\n *\n * optionTargetConnected() { this.#reconcile.schedule(); }\n * optionTargetDisconnected() { this.#reconcile.schedule(); }\n * ```\n */\nexport class MicrotaskCoalescer {\n readonly #run: () => void;\n #queued = false;\n #active = false;\n #generation = 0;\n\n /** @param run - the single reconciliation pass, invoked at most once per batch. */\n constructor(run: () => void) {\n this.#run = run;\n }\n\n /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */\n activate(): void {\n this.#active = true;\n }\n\n /** Closes the window and drops any pending pass; call from `disconnect()`. */\n cancel(): void {\n this.#active = false;\n this.#queued = false;\n this.#generation += 1;\n }\n\n /** Requests one pass after the batch settles. Idempotent; inert outside the window. */\n schedule(): void {\n if (!this.#active || this.#queued) return;\n this.#queued = true;\n const generation = this.#generation;\n queueMicrotask(() => {\n // A cancelled callback must not consume a pass queued after reconnect.\n if (generation !== this.#generation || !this.#queued || !this.#active) return;\n this.#queued = false;\n this.#run();\n });\n }\n}\n","/**\n * Self-cleaning timer registries shared by Stimeo controllers.\n *\n * Stimulus controllers frequently schedule `setTimeout` / `setInterval` work\n * (auto-dismiss, debouncing, polling). When the element leaves the DOM — a\n * Turbo Drive navigation, a Turbo Stream replacement, or any `disconnect()` —\n * orphaned timers keep firing against a detached controller, leaking memory and\n * mutating stale state. {@link SafeTimeout} and {@link SafeInterval} track every\n * timer they create so a single {@link TimerRegistry.clearAll | clearAll()} call\n * in `disconnect()` tears them all down.\n *\n * These are intentionally low-level primitives: they own *registration and\n * cleanup only*. Higher-level policy (pause/resume, remaining-time accounting)\n * stays in the individual controllers so per-widget semantics are not flattened\n * into a lowest-common-denominator helper.\n */\n\n/**\n * Shared registry bookkeeping for the timeout/interval variants.\n *\n * Subclasses provide the scheduling primitive ({@link schedule}) and its matching\n * canceller ({@link cancel}); this base owns the set of live ids plus the\n * per-id and bulk teardown shared by both.\n */\nabstract class TimerRegistry {\n /** Live timer ids that have not yet been cleared (or, for timeouts, fired). */\n protected readonly ids = new Set<number>();\n\n /** Schedules the underlying platform timer and returns its id. */\n protected abstract schedule(callback: () => void, delay: number): number;\n\n /** Cancels the underlying platform timer for `id`. */\n protected abstract cancel(id: number): void;\n\n /**\n * Cancels a single tracked timer.\n *\n * No-ops if the id is unknown (already cleared, fired, or never owned by this\n * registry), so callers can clear defensively without guarding.\n */\n clear(id: number): void {\n if (this.ids.delete(id)) {\n this.cancel(id);\n }\n }\n\n /**\n * Cancels every tracked timer. Call this from a controller's `disconnect()`\n * to guarantee no timer outlives the element.\n */\n clearAll(): void {\n for (const id of this.ids) {\n this.cancel(id);\n }\n this.ids.clear();\n }\n\n /** Number of timers currently tracked (pending). */\n get size(): number {\n return this.ids.size;\n }\n}\n\n/**\n * `setTimeout` wrapper that auto-forgets each timer once it fires and supports\n * bulk teardown on disconnect.\n *\n * @example\n * ```ts\n * #timers = new SafeTimeout();\n *\n * connect() {\n * this.#timers.set(() => this.dismiss(), 5000);\n * }\n *\n * disconnect() {\n * this.#timers.clearAll();\n * }\n * ```\n */\nexport class SafeTimeout extends TimerRegistry {\n /**\n * Schedules `callback` after `delay` ms and returns the timer id.\n *\n * The id is removed from the registry automatically when the timeout fires,\n * so {@link TimerRegistry.size | size} reflects only still-pending timers.\n */\n set(callback: () => void, delay: number): number {\n const id = this.schedule(() => {\n this.ids.delete(id);\n callback();\n }, delay);\n this.ids.add(id);\n return id;\n }\n\n protected schedule(callback: () => void, delay: number): number {\n return window.setTimeout(callback, delay);\n }\n\n protected cancel(id: number): void {\n window.clearTimeout(id);\n }\n}\n\n/**\n * `setInterval` wrapper that tracks every interval for bulk teardown on\n * disconnect. Unlike {@link SafeTimeout}, intervals are retained until they are\n * explicitly cleared because they fire repeatedly.\n *\n * @example\n * ```ts\n * #intervals = new SafeInterval();\n *\n * connect() {\n * this.#intervals.set(() => this.tick(), 1000);\n * }\n *\n * disconnect() {\n * this.#intervals.clearAll();\n * }\n * ```\n */\nexport class SafeInterval extends TimerRegistry {\n /** Schedules a repeating `callback` every `delay` ms and returns the timer id. */\n set(callback: () => void, delay: number): number {\n const id = this.schedule(callback, delay);\n this.ids.add(id);\n return id;\n }\n\n protected schedule(callback: () => void, delay: number): number {\n return window.setInterval(callback, delay);\n }\n\n protected cancel(id: number): void {\n window.clearInterval(id);\n }\n}\n","/**\n * JSON string-list parsing for the controllers that take a list as a Value.\n *\n * Stimulus offers an `Array` Value type, but its reader runs `JSON.parse` inside\n * the value observer — **before** the `<name>ValueChanged` callback — and\n * rethrows on malformed text. The throw propagates out of the observer that runs\n * during connection, so a single unparseable attribute stops the controller from\n * connecting at all: no lifecycle callback runs and the element is left inert\n * rather than degraded. A consumer cannot guard against it either, because the\n * callback that would hold the `try` never runs.\n *\n * Declaring the attribute as a `String` Value and parsing it here keeps a\n * malformed declaration local to the value it declares. The attribute text is\n * identical either way (`'[\"a\", \"b\"]'`), so markup does not change with the\n * declaration.\n */\n\n/**\n * Parses `raw` as a JSON array of strings.\n *\n * Returns `fallback` when the text is absent, unparseable, or not an array, so a\n * malformed declaration behaves like an omitted one. A parsed array keeps only\n * its string entries: every caller indexes or compares strings, and a stray\n * number would otherwise sit in the list without ever matching.\n *\n * An explicit `\"[]\"` is honoured as an empty list rather than falling back — it\n * is the only way to declare \"none\" against a non-empty default.\n *\n * @param raw - the attribute text, e.g. `'[\"password\"]'`.\n * @param fallback - the list to use when `raw` declares nothing usable.\n */\nexport function parseStringList(raw: string, fallback: readonly string[] = []): string[] {\n // The common case is an undeclared attribute, and `JSON.parse(\"\")` answers it\n // by throwing. Reaching the same fallback without building an exception keeps\n // the callers that ask per element off that path.\n const text = raw.trim();\n if (text.length === 0) return [...fallback];\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return [...fallback];\n }\n\n if (!Array.isArray(parsed)) return [...fallback];\n return parsed.filter((entry): entry is string => typeof entry === \"string\");\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { isReservedArrowChord, logicalArrowKey } from \"../utils/arrow_step\";\nimport { BeforeCacheReset } from \"../utils/before_cache_reset\";\nimport {\n parseISODateString,\n parseISOMonthString,\n toISODateString,\n toISOMonthString,\n} from \"../utils/dates\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\nimport { SafeTimeout } from \"../utils/safe_timeout\";\nimport { parseStringList } from \"../utils/string_list\";\n\n/** Number of cells in a six-week month grid (7 × 6). */\nconst GRID_SIZE = 42;\n\n/**\n * Headless, accessible **date range picker** behavior. A derivative of\n * {@link CalendarController}: it reuses the month-grid navigation model and adds\n * two-point range selection, in-progress range preview, and presets.\n *\n * Markup contract (identifier: `stimeo--date-range-picker`):\n * <div data-controller=\"stimeo--date-range-picker\"\n * data-stimeo--date-range-picker-min-value=\"2026-01-01\"\n * data-stimeo--date-range-picker-max-value=\"2026-12-31\"\n * data-stimeo--date-range-picker-disabled-dates-value='[\"2026-06-15\"]'>\n * <button data-action=\"stimeo--date-range-picker#prev\">Prev</button>\n * <span data-stimeo--date-range-picker-target=\"monthLabel\" aria-live=\"polite\"></span>\n * <button data-action=\"stimeo--date-range-picker#next\">Next</button>\n * <div role=\"grid\" data-stimeo--date-range-picker-target=\"grid\">\n * <!-- exactly 42 cell targets (7 days × 6 rows) -->\n * <button role=\"gridcell\" tabindex=\"-1\"\n * data-stimeo--date-range-picker-target=\"cell\"\n * data-action=\"click->stimeo--date-range-picker#selectDate\n * mouseenter->stimeo--date-range-picker#previewTo\n * focus->stimeo--date-range-picker#previewTo\n * keydown->stimeo--date-range-picker#onKeydown\"></button>\n * </div>\n * <button data-range=\"last7\" data-action=\"stimeo--date-range-picker#applyPreset\">…</button>\n * <span role=\"status\" aria-live=\"polite\" data-stimeo--date-range-picker-target=\"status\"></span>\n * <input type=\"hidden\" data-stimeo--date-range-picker-target=\"startField\" />\n * <input type=\"hidden\" data-stimeo--date-range-picker-target=\"endField\" />\n * </div>\n *\n * @remarks\n * Behavior only — the consumer styles the grid and renders the range using the\n * `data-range-start` / `data-in-range` / `data-range-end` hooks. Assistive tech\n * is told the two confirmed endpoints via `aria-selected`; inner cells use\n * `data-in-range` (visual only) so the announcement stays to the two ends. The\n * confirmed range is also mirrored to the live `status` region.\n *\n * Selection model: the first click/Enter sets a *pending* start and enters\n * \"selecting\" mode (preview follows the pointer/focus); the second confirms the\n * end (auto-swapped if earlier than the start) and dispatches `change` with\n * `{ start, end }` ISO dates. Escape abandons an in-progress selection,\n * restoring the last confirmed range.\n *\n * Availability is declarative on both axes: `min` / `max` bound the selectable\n * interval and `disabledDates` excludes individual dates inside it. Both are\n * render inputs, so a cell's `aria-disabled` is derived during the paint that\n * needs it rather than written back afterwards — selection, preview, and the\n * grid paint all read one predicate and cannot disagree. A painted-month\n * navigation dispatches `monthchange` with `{ month }` as a notification (for\n * fetching a month's availability, say); the fetched result comes back in\n * through `disabledDates`, which repaints on its own.\n */\nexport class DateRangePickerController extends Controller<HTMLElement> {\n static override targets = [\"grid\", \"monthLabel\", \"cell\", \"status\", \"startField\", \"endField\"];\n static override values = {\n min: { type: String, default: \"\" },\n max: { type: String, default: \"\" },\n // A JSON list read through `parseStringList` rather than Stimulus's `Array`\n // type: that reader throws out of the value observer before any callback\n // runs, so one malformed attribute would stop the picker from connecting.\n disabledDates: { type: String, default: \"\" },\n };\n static actions = [\"applyPreset\", \"next\", \"onKeydown\", \"prev\", \"previewTo\", \"selectDate\"] as const;\n static events = [\"change\", \"monthchange\"] as const;\n\n declare readonly gridTarget: HTMLElement;\n declare readonly hasGridTarget: boolean;\n declare readonly monthLabelTarget: HTMLElement;\n declare readonly cellTargets: HTMLElement[];\n declare readonly statusTarget: HTMLElement;\n declare readonly startFieldTarget: HTMLInputElement;\n declare readonly endFieldTarget: HTMLInputElement;\n declare readonly hasMonthLabelTarget: boolean;\n declare readonly hasStatusTarget: boolean;\n declare readonly hasStartFieldTarget: boolean;\n declare readonly hasEndFieldTarget: boolean;\n declare minValue: string;\n declare maxValue: string;\n declare disabledDatesValue: string;\n\n /** The month currently rendered, as `YYYY-MM`. */\n #viewMonth = \"\";\n /** The confirmed range endpoints (ISO), or \"\" when unset. */\n #startDate = \"\";\n #endDate = \"\";\n /** The first endpoint of an in-progress selection (ISO), or \"\" when idle. */\n #pendingStart = \"\";\n /** The hovered/focused date previewed while selecting (ISO), or \"\". */\n #previewDate = \"\";\n /** The roving-focus date in the grid (local time). */\n #focusedDate = new Date();\n\n /** Deferred focus after an async month transition (cancelled on teardown). */\n readonly #focusTimer = new SafeTimeout();\n\n /** The declared unavailable dates, indexed for the per-cell paint lookup. */\n #disabledDates = new Set<string>();\n\n /** Rewinds an unfinished selection before Turbo snapshots the page. */\n readonly #beforeCache = new BeforeCacheReset(() => this.#rewindForCache());\n\n /** Last painted month, or `null` until the initial paint has settled. */\n #announcedMonth: string | null = null;\n\n /**\n * Collapses a morph that swaps render inputs into one repaint, and refuses the\n * pass Stimulus delivers before `connect()`.\n */\n readonly #repaint = new MicrotaskCoalescer(() => {\n this.#render();\n });\n\n /** Seeds and normalizes the range from optional hidden fields, then paints the grid. */\n override connect(): void {\n this.#repaint.activate();\n this.#beforeCache.activate();\n const authoredStart = this.hasStartFieldTarget ? normalizeISO(this.startFieldTarget.value) : \"\";\n const authoredEnd = this.hasEndFieldTarget ? normalizeISO(this.endFieldTarget.value) : \"\";\n [this.#startDate, this.#endDate] = orderRange(authoredStart, authoredEnd);\n this.#pendingStart = \"\";\n this.#previewDate = \"\";\n this.#announcedMonth = null;\n this.#commitFields();\n\n const anchor =\n parseISODateString(this.#startDate) ?? this.#clampToBounds(new Date()) ?? new Date();\n this.#focusedDate = anchor;\n this.#viewMonth = toISOMonthString(anchor);\n // Two cells carry `aria-selected=\"true\"` whenever a range is confirmed, so the\n // grid has to say that more than one is selectable — otherwise a single-select\n // grid is claiming two selections.\n if (this.hasGridTarget) this.gridTarget.setAttribute(\"aria-multiselectable\", \"true\");\n this.#render();\n }\n\n /** Cancels any pending deferred focus so it never fires on a detached element. */\n override disconnect(): void {\n this.#repaint.cancel();\n this.#beforeCache.deactivate();\n this.#focusTimer.clearAll();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `min` at runtime. */\n minValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `max` at runtime. */\n maxValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Re-indexes the unavailable dates and repaints when the declared set changes. */\n disabledDatesValueChanged(): void {\n this.#disabledDates = new Set(parseStringList(this.disabledDatesValue));\n this.#repaint.schedule();\n }\n\n /** Navigates to the previous month. */\n prev(event?: Event): void {\n event?.preventDefault();\n this.#shiftMonth(-1);\n }\n\n /** Navigates to the next month. */\n next(event?: Event): void {\n event?.preventDefault();\n this.#shiftMonth(1);\n }\n\n /** Confirms a range endpoint from a clicked cell. */\n selectDate(event: Event): void {\n const cell = this.#cellFrom(event.target);\n if (!cell) return;\n const date = cell.getAttribute(\"data-date\");\n if (!date || !this.#isSelectable(date)) return;\n this.#choose(date);\n }\n\n /** Previews the range up to a hovered/focused cell while selecting. */\n previewTo(event: Event): void {\n const cell = this.#cellFrom(event.target);\n if (!cell) return;\n const date = cell.getAttribute(\"data-date\");\n if (!date) return;\n let shouldRender = false;\n // Focus moves the roving tabindex; hover does not.\n if (event.type.startsWith(\"focus\")) {\n const parsed = parseISODateString(date);\n if (parsed) this.#focusedDate = parsed;\n shouldRender = cell.getAttribute(\"tabindex\") !== \"0\";\n }\n // An unavailable day can hold focus (APG keeps disabled cells reachable) but\n // never becomes the previewed endpoint, so the preview stays where it was.\n if (this.#pendingStart && this.#isSelectable(date) && this.#previewDate !== date) {\n this.#previewDate = date;\n shouldRender = true;\n }\n if (shouldRender) this.#render();\n }\n\n /** Applies a named preset (`today` / `last7` / `last30` / `thisMonth`). */\n applyPreset(event: Event): void {\n const button = (event.target as HTMLElement | null)?.closest(\"[data-range]\");\n const range = computePreset(button?.getAttribute(\"data-range\") ?? \"\");\n if (!range) return;\n\n const intersection = this.#intersectRange(range);\n if (!intersection) return;\n const { start, end } = intersection;\n // A preset is the consumer's own button, but what it produces is still a\n // range, and an unavailable day cannot be one of its endpoints — the same\n // rule a click or Enter obeys. Refusing keeps one answer per date instead of\n // one per entry point, and stops a cell from being the confirmed edge while\n // still painted `aria-disabled=\"true\"`.\n if (!this.#isSelectable(start) || !this.#isSelectable(end)) return;\n\n this.#startDate = start;\n this.#endDate = end;\n this.#pendingStart = \"\";\n this.#previewDate = \"\";\n const endDate = parseISODateString(end);\n if (endDate) this.#focusedDate = endDate;\n this.#commitFields();\n this.#transitionTo(toISOMonthString(parseISODateString(end) ?? new Date()), end);\n this.#announce();\n this.dispatch(\"change\", { detail: { start, end } });\n }\n\n /** Grid keyboard navigation, selection (Enter/Space), and Escape-to-cancel. */\n onKeydown(event: KeyboardEvent): void {\n // A descendant widget that already claimed the key must not ALSO move the\n // grid focus or choose a date — composition depends on this yield.\n if (event.defaultPrevented) return;\n if (isReservedArrowChord(event)) return;\n const cell = this.#cellFrom(event.target);\n if (!cell) return;\n const dateStr = cell.getAttribute(\"data-date\") ?? \"\";\n const date = parseISODateString(dateStr);\n if (!date) return;\n\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n if (this.#isSelectable(dateStr)) this.#choose(dateStr);\n return;\n }\n if (event.key === \"Escape\") {\n // A press an inner handler already owned is yielded at the top of this\n // handler. What is checked here is the IME half: a press during a\n // composition steers the conversion, not the range.\n if (this.#pendingStart && !event.isComposing) {\n event.preventDefault();\n this.#pendingStart = \"\";\n this.#previewDate = \"\";\n this.#render();\n }\n return;\n }\n\n let next: Date | null = null;\n // Logical, not physical. The key is normalised rather than the\n // delta negated: these two branches are not mirror images — their guards\n // differ — so swapping the key keeps each guard with its own direction.\n switch (logicalArrowKey(event.key, this.element)) {\n case \"ArrowLeft\":\n next = addDays(date, -1);\n break;\n case \"ArrowRight\":\n next = addDays(date, 1);\n break;\n case \"ArrowUp\":\n next = addDays(date, -7);\n break;\n case \"ArrowDown\":\n next = addDays(date, 7);\n break;\n case \"Home\":\n next = addDays(date, -date.getDay());\n break;\n case \"End\":\n next = addDays(date, 6 - date.getDay());\n break;\n case \"PageUp\":\n next = event.shiftKey ? shiftYearClamped(date, -1) : shiftMonthClamped(date, -1);\n break;\n case \"PageDown\":\n next = event.shiftKey ? shiftYearClamped(date, 1) : shiftMonthClamped(date, 1);\n break;\n default:\n return;\n }\n event.preventDefault();\n this.#moveFocusTo(next);\n }\n\n /** Records a chosen date as either the pending start or the confirmed end. */\n #choose(date: string): void {\n if (!this.#pendingStart) {\n this.#pendingStart = date;\n this.#previewDate = date;\n const parsed = parseISODateString(date);\n if (parsed) this.#focusedDate = parsed;\n this.#render();\n return;\n }\n // Second click confirms; order the two so start ≤ end.\n const [start, end] =\n date < this.#pendingStart ? [date, this.#pendingStart] : [this.#pendingStart, date];\n this.#startDate = start;\n this.#endDate = end;\n this.#pendingStart = \"\";\n this.#previewDate = \"\";\n this.#commitFields();\n this.#render();\n this.#announce();\n this.dispatch(\"change\", { detail: { start, end } });\n }\n\n /** Moves roving focus to `date`, transitioning the month when needed. */\n #moveFocusTo(date: Date): void {\n this.#focusedDate = date;\n const iso = toISODateString(date);\n // Availability is known from the Values, not from the cells, so a target in\n // a month that has not been painted yet resolves in this same pass.\n if (this.#pendingStart && this.#isSelectable(iso)) this.#previewDate = iso;\n this.#transitionTo(toISOMonthString(date), iso);\n }\n\n /** Renders `month`, then focuses the cell for `dateStr` (deferred if async). */\n #transitionTo(month: string, dateStr: string): void {\n const isTransition = month !== this.#viewMonth;\n this.#focusTimer.clearAll();\n this.#viewMonth = month;\n this.#render();\n const focusCell = (): void => {\n this.cellTargets.find((c) => c.getAttribute(\"data-date\") === dateStr)?.focus();\n };\n if (isTransition) {\n // Let the synchronous render settle before focusing the freshly bound cell.\n this.#focusTimer.set(focusCell, 0);\n } else {\n focusCell();\n }\n }\n\n /** Shifts the displayed month by `delta`, keeping focus within it. */\n #shiftMonth(delta: number): void {\n const info = parseISOMonthString(this.#viewMonth);\n if (!info) return;\n const target = new Date(info.year, info.month - 1 + delta, 1);\n this.#viewMonth = toISOMonthString(target);\n // Keep the same day-of-month where possible, clamped to the new month.\n const lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();\n target.setDate(Math.min(this.#focusedDate.getDate(), lastDay));\n this.#focusedDate = target;\n this.#render();\n }\n\n /**\n * Builds the six-week grid and binds range/roving/disabled state per cell.\n *\n * @stimeoRenderRoot\n */\n #render(): void {\n const info = parseISOMonthString(this.#viewMonth);\n if (!info) return;\n const { year, month } = info;\n\n // Tightening `min` / `max` / `disabledDates` mid-selection can strand the\n // preview on a day that is no longer choosable; drop it back to the pending\n // start rather than advertising a range the user cannot confirm.\n if (this.#previewDate && !this.#isSelectable(this.#previewDate)) this.#previewDate = \"\";\n\n if (this.hasMonthLabelTarget) {\n const lang = document.documentElement.lang || \"en\";\n const formatter = monthFormatter(lang);\n this.monthLabelTarget.textContent = formatter.format(new Date(year, month - 1, 1));\n }\n\n const [rangeStart, rangeEnd] = this.#visualRange();\n const days = gridDays(year, month);\n const focusedStr = toISODateString(this.#focusedDate);\n const todayStr = toISODateString(new Date());\n\n const cells = this.cellTargets;\n for (let i = 0; i < GRID_SIZE; i++) {\n const el = cells[i];\n const date = days[i];\n if (!el || !date) continue;\n const iso = toISODateString(date);\n\n el.setAttribute(\"data-date\", iso);\n el.textContent = String(date.getDate());\n el.setAttribute(\"data-outside\", String(date.getMonth() !== month - 1));\n el.setAttribute(\"data-today\", String(iso === todayStr));\n el.setAttribute(\"tabindex\", iso === focusedStr ? \"0\" : \"-1\");\n\n if (this.#isSelectable(iso)) el.removeAttribute(\"aria-disabled\");\n else el.setAttribute(\"aria-disabled\", \"true\");\n\n const isStart = !!rangeStart && iso === rangeStart;\n const isEnd = !!rangeEnd && iso === rangeEnd && rangeEnd !== rangeStart;\n const inside = !!rangeStart && !!rangeEnd && iso > rangeStart && iso < rangeEnd;\n el.toggleAttribute(\"data-range-start\", isStart);\n el.toggleAttribute(\"data-range-end\", isEnd);\n el.toggleAttribute(\"data-in-range\", inside);\n // Selection is what the user committed, never what the pointer is hovering:\n // `aria-selected` marks the two confirmed endpoints only. The preview lives\n // in the `data-*` trio above, which styling reads and AT does not.\n el.setAttribute(\n \"aria-selected\",\n String(\n (!!this.#startDate && iso === this.#startDate) ||\n (!!this.#endDate && iso === this.#endDate),\n ),\n );\n }\n\n // Every declared cell is part of the roving composite, even when authored\n // beyond the documented 42-cell grid. Extras must never become a second stop.\n for (const extra of cells.slice(GRID_SIZE)) extra.setAttribute(\"tabindex\", \"-1\");\n\n // Malformed short markup still gets a usable entry point. Prefer a date in\n // the displayed month so arrow navigation begins from the visible context.\n if (!cells.some((cell) => cell.getAttribute(\"tabindex\") === \"0\")) {\n const fallback =\n cells.find((cell) => cell.getAttribute(\"data-outside\") === \"false\") ?? cells[0];\n fallback?.setAttribute(\"tabindex\", \"0\");\n }\n\n // A month event belongs to the completed paint so a listener that reads the\n // grid sees the new dates. It reports the paint; it is not a hook the paint\n // waits on, so nothing here depends on what a listener does with it.\n const previous = this.#announcedMonth;\n this.#announcedMonth = this.#viewMonth;\n if (previous !== null && previous !== this.#viewMonth) {\n this.dispatch(\"monthchange\", { detail: { month: this.#viewMonth } });\n }\n }\n\n /** The ordered [start, end] pair to paint: the preview while selecting, else confirmed. */\n #visualRange(): [string, string] {\n if (this.#pendingStart) {\n const other = this.#previewDate || this.#pendingStart;\n return this.#pendingStart <= other\n ? [this.#pendingStart, other]\n : [other, this.#pendingStart];\n }\n return [this.#startDate, this.#endDate];\n }\n\n /** Writes the confirmed range to the hidden fields. */\n #commitFields(): void {\n if (this.hasStartFieldTarget) this.startFieldTarget.value = this.#startDate;\n if (this.hasEndFieldTarget) this.endFieldTarget.value = this.#endDate;\n }\n\n /** Announces the confirmed range in the live status region. */\n #announce(): void {\n if (this.hasStatusTarget && this.#startDate && this.#endDate) {\n this.statusTarget.textContent = `${this.#startDate} – ${this.#endDate}`;\n }\n }\n\n /**\n * True when `iso` may be chosen as a range endpoint.\n *\n * The single availability question in the controller: the grid paint, the\n * preview, and both commit paths ask it, so a cell's `aria-disabled` and what\n * a click on that cell does are the same decision rather than two that have to\n * be kept in step.\n */\n #isSelectable(iso: string): boolean {\n return !this.#outOfBounds(iso) && !this.#disabledDates.has(iso);\n }\n\n /** True when `iso` falls outside the `[min, max]` bounds. */\n #outOfBounds(iso: string): boolean {\n if (this.minValue && iso < this.minValue) return true;\n if (this.maxValue && iso > this.maxValue) return true;\n return false;\n }\n\n /** Clamps a generated ISO date string into `[min, max]`. */\n #clampISO(iso: string): string {\n if (this.minValue && iso < this.minValue) return this.minValue;\n if (this.maxValue && iso > this.maxValue) return this.maxValue;\n return iso;\n }\n\n /** Clamps a Date into `[min, max]`, returning null only when unparseable. */\n #clampToBounds(date: Date): Date | null {\n const clamped = this.#clampISO(toISODateString(date));\n return parseISODateString(clamped);\n }\n\n /**\n * Intersects a preset with `[min, max]`, rejecting a disjoint interval.\n *\n * Only the bounds narrow a preset here: `disabledDates` excludes single days,\n * not sub-intervals, so it cannot shrink one to a still-contiguous range. A\n * day it excludes is still refused as an endpoint — the caller checks that —\n * but a preset that merely spans one keeps its span.\n */\n #intersectRange(range: { start: string; end: string }): { start: string; end: string } | null {\n const start = this.minValue && range.start < this.minValue ? this.minValue : range.start;\n const end = this.maxValue && range.end > this.maxValue ? this.maxValue : range.end;\n return start <= end ? { start, end } : null;\n }\n\n /** Removes provisional range state before Turbo freezes a cached snapshot. */\n #rewindForCache(): void {\n this.#focusTimer.clearAll();\n if (!this.#pendingStart && !this.#previewDate) return;\n this.#pendingStart = \"\";\n this.#previewDate = \"\";\n this.#render();\n }\n\n /** Resolves the cell element from an event target, or null. */\n #cellFrom(target: EventTarget | null): HTMLElement | null {\n return (\n (target as HTMLElement | null)?.closest<HTMLElement>(\n \"[data-stimeo--date-range-picker-target='cell']\",\n ) ?? null\n );\n }\n}\n\n/** Returns a new Date `n` days from `date`. */\nfunction addDays(date: Date, n: number): Date {\n const next = new Date(date);\n next.setDate(next.getDate() + n);\n return next;\n}\n\n/** Shifts `date` by `delta` months, clamping the day to the target month length. */\nfunction shiftMonthClamped(date: Date, delta: number): Date {\n const target = new Date(date.getFullYear(), date.getMonth() + delta, 1);\n const lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();\n target.setDate(Math.min(date.getDate(), lastDay));\n return target;\n}\n\n/** Shifts `date` by `delta` years, clamping leap days to the target month. */\nfunction shiftYearClamped(date: Date, delta: number): Date {\n const target = new Date(date.getFullYear() + delta, date.getMonth(), 1);\n const lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();\n target.setDate(Math.min(date.getDate(), lastDay));\n return target;\n}\n\n/** Builds the 42 local-time dates of a Sunday-started six-week grid for a month. */\nfunction gridDays(year: number, month: number): Date[] {\n const first = new Date(year, month - 1, 1);\n const start = new Date(first);\n start.setDate(first.getDate() - first.getDay());\n const days: Date[] = [];\n const current = new Date(start);\n for (let i = 0; i < GRID_SIZE; i++) {\n days.push(new Date(current));\n current.setDate(current.getDate() + 1);\n }\n return days;\n}\n\n/** Validates and re-serializes an ISO date string, returning \"\" when invalid. */\nfunction normalizeISO(value: string): string {\n const date = parseISODateString(value.trim());\n return date ? toISODateString(date) : \"\";\n}\n\n/** Orders a complete range while preserving either valid lone endpoint. */\nfunction orderRange(start: string, end: string): [string, string] {\n return start && end && end < start ? [end, start] : [start, end];\n}\n\n/** Creates the month formatter, falling back when the document locale is malformed. */\nfunction monthFormatter(locale: string): Intl.DateTimeFormat {\n const options: Intl.DateTimeFormatOptions = { month: \"long\", year: \"numeric\" };\n try {\n return new Intl.DateTimeFormat(locale, options);\n } catch (error) {\n if (!(error instanceof RangeError)) throw error;\n return new Intl.DateTimeFormat(\"en\", options);\n }\n}\n\n/** Computes a preset range relative to today, or null for an unknown name. */\nfunction computePreset(name: string): { start: string; end: string } | null {\n const today = new Date();\n const todayStr = toISODateString(today);\n switch (name) {\n case \"today\":\n return { start: todayStr, end: todayStr };\n case \"last7\":\n return { start: toISODateString(addDays(today, -6)), end: todayStr };\n case \"last30\":\n return { start: toISODateString(addDays(today, -29)), end: todayStr };\n case \"thisMonth\": {\n const start = new Date(today.getFullYear(), today.getMonth(), 1);\n const end = new Date(today.getFullYear(), today.getMonth() + 1, 0);\n return { start: toISODateString(start), end: toISODateString(end) };\n }\n default:\n return null;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/logical_scroll.ts","../../src/utils/arrow_step.ts","../../src/utils/before_cache_reset.ts","../../src/utils/dates.ts","../../src/utils/microtask_coalescer.ts","../../src/utils/safe_timeout.ts","../../src/utils/string_list.ts","../../src/controllers/date_range_picker_controller.ts"],"names":[],"mappings":"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","file":"date_range_picker_controller.js","sourcesContent":["/** Normalized scroll position and maximum distance on one logical axis. */\nexport interface LogicalScrollMetrics {\n position: number;\n max: number;\n}\n\n/**\n * Whether horizontal scrolling on `element` follows right-to-left inline flow.\n *\n * Resolved from the **computed** `direction`, so the authoring contract is the\n * usual `dir=\"rtl\"` (or a stylesheet) on the element or any ancestor.\n *\n * Scope: horizontal writing modes. A vertical writing mode (`writing-mode:\n * vertical-rl`) also inverts the horizontal axis, which this check does not\n * model — vertical writing modes are out of scope for the scroll utilities\n * (their consumers describe axes as horizontal/vertical, not inline/block).\n */\nexport function isRtl(element: Element): boolean {\n return window.getComputedStyle(element).direction === \"rtl\";\n}\n\n/**\n * Returns scroll distance from the logical start edge.\n *\n * CSSOM View exposes standards-mode RTL horizontal offsets as `0` at the inline\n * start (right) and increasingly negative values toward the inline end (left).\n * The normalized position is always clamped to `[0, max]`, which also absorbs\n * Safari's elastic overscroll values.\n */\nexport function logicalScrollMetrics(\n element: HTMLElement,\n horizontal: boolean,\n): LogicalScrollMetrics {\n const max = Math.max(\n 0,\n horizontal\n ? element.scrollWidth - element.clientWidth\n : element.scrollHeight - element.clientHeight,\n );\n const raw = horizontal ? element.scrollLeft : element.scrollTop;\n const position = horizontal && isRtl(element) ? -raw : raw;\n return { position: Math.min(max, Math.max(0, position)), max };\n}\n\n/**\n * Converts a logical start/end delta to the physical value accepted by\n * `Element.scrollBy`.\n */\nexport function physicalScrollDelta(\n element: HTMLElement,\n horizontal: boolean,\n logicalDelta: number,\n): number {\n return horizontal && isRtl(element) ? -logicalDelta : logicalDelta;\n}\n","import { isRtl } from \"./logical_scroll\";\n\n/**\n * Turns an arrow key into a **logical** step: `+1` for \"next\", `-1` for\n * \"previous\", `0` when the key names neither.\n *\n * APG defines the horizontal pair as *next / previous* and says a vertical\n * arrangement swaps in Down/Up for the same meaning — so the pair is one axis's\n * spelling of an order, and the order reverses with the writing direction. Only\n * the horizontal pair reverses. Down/Up name an axis the writing direction does\n * not mirror, and returning them unchanged is the point: many controllers fold\n * both pairs into one branch, where swapping the branches under RTL would flip\n * the vertical axis too — a bug that reads as \"the arrows work\" until someone\n * presses Down.\n *\n * **Direction is read from the element the caller passes, which should be the\n * container that lays the items out** — not the focused child. A child may carry\n * its own `dir` (an LTR input inside an RTL form is ordinary authoring), and\n * probing per handler makes two handlers disagree at the boundary between them.\n *\n * This decides direction only. Whether the axis is even active (an\n * `orientation=\"horizontal\"` widget ignoring Down/Up), how far the step lands,\n * and what wrapping does all stay with the caller.\n *\n * **It encodes the list-order convention: `ArrowDown` is *next*.** Widgets that\n * pair the arrows by *value* instead — `ArrowUp` meaning \"more\", as a rating or a\n * slider does — must not use this, or their vertical axis inverts. Reverse the\n * horizontal pair on its own there.\n *\n * @example\n * ```ts\n * const step = logicalArrowStep(event.key, this.element);\n * if (step === 0) return;\n * this.#roving.setActive(rovingMove(current, length, step, \"wrap\"), { focus: true });\n * ```\n */\nexport function logicalArrowStep(key: string, element: Element): 1 | -1 | 0 {\n if (key === \"ArrowDown\") return 1;\n if (key === \"ArrowUp\") return -1;\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return 0;\n const forward = isRtl(element) ? \"ArrowLeft\" : \"ArrowRight\";\n return key === forward ? 1 : -1;\n}\n\n/**\n * Rewrites `key` so an existing LTR-shaped branch keeps working under RTL:\n * `ArrowRight` and `ArrowLeft` trade places, everything else passes through.\n *\n * The alternative — negating a delta — silently breaks handlers whose two\n * horizontal branches are **not mirror images**. A grid that clamps one edge but\n * not the other, or a segmented field guarding `index > 0` on one side and\n * `index < length - 1` on the other, ends up applying the wrong guard to the\n * wrong direction. Swapping the key leaves each branch, guards and all, exactly\n * where its author put it.\n *\n * Same rule as {@link logicalArrowStep} about which element to read: pass the\n * container that lays the items out, not the focused child.\n *\n * @example\n * ```ts\n * switch (logicalArrowKey(event.key, this.element)) {\n * case \"ArrowLeft\": // \"previous\" — whatever direction that is on screen\n * ```\n */\nexport function logicalArrowKey(key: string, element: Element): string {\n if (key !== \"ArrowRight\" && key !== \"ArrowLeft\") return key;\n if (!isRtl(element)) return key;\n return key === \"ArrowRight\" ? \"ArrowLeft\" : \"ArrowRight\";\n}\n\n/** Modifiers a widget may claim on an arrow key, named for the `allow` list. */\nexport type ArrowModifier = \"alt\" | \"ctrl\" | \"meta\" | \"shift\";\n\n/**\n * True when an arrow key arrived carrying a modifier the widget must leave to\n * the browser: return without calling `preventDefault()` and without moving any\n * state.\n *\n * A bare arrow belongs to the widget; a chorded one usually does not.\n * `Alt`/`Meta` plus a horizontal arrow is history back/forward on every desktop\n * browser, and a widget that swallows it makes the shortcut work or not\n * depending on where focus happens to sit — a coin-flip the user cannot see.\n *\n * `allow` is for the combinations APG assigns to a pattern **and the widget\n * actually implements** — today only Combobox's optional `Alt+Down`/`Alt+Up`.\n * Listing one the widget does not implement defeats the point: the chord then\n * runs the plain-arrow branch, which is exactly what this guard exists to stop.\n * Non-arrow keys return `false`, so chorded letters and\n * `Control+Home`/`Control+End` are untouched.\n *\n * @example\n * ```ts\n * if (isReservedArrowChord(event)) return;\n * ```\n */\nexport function isReservedArrowChord(\n event: KeyboardEvent,\n allow: readonly ArrowModifier[] = [],\n): boolean {\n if (!event.key.startsWith(\"Arrow\")) return false;\n return (\n (event.altKey && !allow.includes(\"alt\")) ||\n (event.ctrlKey && !allow.includes(\"ctrl\")) ||\n (event.metaKey && !allow.includes(\"meta\")) ||\n (event.shiftKey && !allow.includes(\"shift\"))\n );\n}\n\n/**\n * True when a press arrived carrying any modifier, for the keys the browser and\n * the OS own outright: return without calling `preventDefault()` and without\n * moving any state.\n *\n * `Control+Home` and `Control+End` jump the document to its ends, and a widget\n * that swallows them makes the shortcut work or not depending on where focus\n * happens to sit. {@link isReservedArrowChord} answers the same question for the\n * arrows, but returns `false` for every other key so that this one can decide.\n *\n * There is no `allow` list here on purpose. APG assigns no modifier chord to\n * `Home`/`End`, so a widget that wanted one would be claiming a combination the\n * pattern never gave it.\n *\n * @example\n * ```ts\n * case \"Home\":\n * case \"End\":\n * if (hasModifierChord(event)) return;\n * ```\n */\nexport function hasModifierChord(event: KeyboardEvent): boolean {\n return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;\n}\n","/**\n * Runs a controller's \"return to the initial state\" pass just before Turbo\n * caches the page.\n *\n * **`disconnect()` cannot do this job, for two independent reasons.** Turbo\n * queues the clone from this event rather than taking it here, and the body swap\n * that runs the controller's `disconnect()` is queued separately — so which of\n * the two lands first is not something a controller can rely on, and a rewind\n * written in `disconnect()` may reach only the DOM being thrown away. In the\n * other direction, `disconnect()` also fires on an in-page move (Stimulus tears\n * down and reconnects the same element), where rewinding would wipe a\n * legitimately in-progress interaction — a spinner mid-load would vanish. One\n * timing is unreliable, the other is too eager; `turbo:before-cache` is the only\n * point that is exactly \"the page is about to be frozen\".\n *\n * Scope is the subscription only: registering on `activate()`, unregistering on\n * `deactivate()`, and one shared document listener no matter how many instances\n * are live. *What* to return to its initial state — which `data-state`, which\n * `hidden`, which `aria-busy` — stays in the controller, because no two\n * consumers answer it the same way.\n *\n * **Rewind state, not appearance.** The pass writes attributes the controller\n * itself owns; the visual result of those attributes is the consumer's CSS, and\n * a library that reached for style or class names would be guessing at markup\n * it does not own.\n *\n * Both entry points are idempotent, so the lifecycle hooks can call them\n * unconditionally: a second `activate()` does not double-subscribe and does not\n * make the callback run twice, and `deactivate()` on an instance that never\n * subscribed is a no-op.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #beforeCache = new BeforeCacheReset(() => this.#rewind());\n *\n * connect() { this.#beforeCache.activate(); }\n * disconnect() { this.#beforeCache.deactivate(); }\n * ```\n */\nexport class BeforeCacheReset {\n /** Every subscribed instance, iterated by the one shared document listener. */\n static readonly #subscribers = new Set<BeforeCacheReset>();\n\n /** The shared listener; installed while at least one instance is subscribed. */\n static readonly #onBeforeCache = (): void => {\n for (const subscriber of BeforeCacheReset.#subscribers) subscriber.#rewind();\n };\n\n readonly #rewind: () => void;\n\n /** @param rewind - the pass that returns this controller's state to its initial form. */\n constructor(rewind: () => void) {\n this.#rewind = rewind;\n }\n\n /** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */\n activate(): void {\n const first = BeforeCacheReset.#subscribers.size === 0;\n BeforeCacheReset.#subscribers.add(this);\n if (first) {\n document.addEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n }\n\n /** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */\n deactivate(): void {\n BeforeCacheReset.#subscribers.delete(this);\n if (BeforeCacheReset.#subscribers.size > 0) return;\n document.removeEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n}\n","/**\n * Local-time date helpers shared by the calendar-family controllers\n * (`calendar`, `date-range-picker`).\n *\n * All conversions are intentionally **local time** (not UTC): the grid a user\n * sees is built from `Date` components in their own timezone, so round-tripping\n * through ISO strings must use the same frame to avoid off-by-one-day drift near\n * midnight. Strings are bare `YYYY-MM-DD` / `YYYY-MM` with no time or zone.\n */\n\n/** Formats a {@link Date} as a local-time `YYYY-MM-DD` string. */\nexport function toISODateString(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n}\n\n/**\n * Parses a `YYYY-MM-DD` string into a local-time {@link Date}, or `null`.\n *\n * Rejects calendar-invalid dates (e.g. `2026-02-31`): the constructed `Date`\n * would silently roll over to another day, so the parsed components are checked\n * back against it and a mismatch returns `null`.\n */\nexport function parseISODateString(dateStr: string): Date | null {\n if (!dateStr) return null;\n const match = dateStr.match(/^(\\d{4})-(\\d{2})-(\\d{2})$/);\n if (!match) return null;\n const [, y, m, d] = match;\n const year = Number(y);\n const month = Number(m);\n const day = Number(d);\n const date = new Date(year, month - 1, day);\n if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) {\n return null;\n }\n return date;\n}\n\n/**\n * Parses a `YYYY-MM` string into its year/month (1-based) parts, or `null`.\n * Rejects months outside `1..12`.\n */\nexport function parseISOMonthString(monthStr: string): { year: number; month: number } | null {\n if (!monthStr) return null;\n const match = monthStr.match(/^(\\d{4})-(\\d{2})$/);\n if (!match) return null;\n const [, y, m] = match;\n const month = Number(m);\n if (month < 1 || month > 12) return null;\n return { year: Number(y), month };\n}\n\n/** Formats a {@link Date} as the local-time `YYYY-MM` string of its month. */\nexport function toISOMonthString(date: Date): string {\n return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, \"0\")}`;\n}\n","/**\n * Collapses many Stimulus lifecycle callbacks from one DOM mutation into a\n * single pass.\n *\n * Stimulus fires `<name>TargetConnected` / `Disconnected` once per element and\n * `<name>ValueChanged` once per changed attribute. Replacing a list of N options\n * or morphing several render Values therefore delivers N callbacks — but the\n * useful unit of work is \"reconcile against the resulting declarative input\",\n * once, after the batch has settled. Every controller with reconcilable targets\n * or render Values needs the same shape: a `queued` flag plus `queueMicrotask`.\n *\n * **A microtask is the right horizon, and the reason is specific.** Stimulus\n * drives these callbacks from a `MutationObserver`, whose own callback already\n * runs as a microtask with the whole batch in hand; scheduling one more lands\n * after the last sibling callback of that batch and still before paint or any\n * event handler. A timer would be later than it needs to be, and reconciling\n * synchronously would run once per element against a half-applied DOM.\n *\n * **The two guards are not the same guard.** Scheduling is refused before the\n * controller connects, and running is refused after it disconnects:\n *\n * - **Before `connect()`** — Stimulus delivers initial target and Value callbacks\n * ahead of `connect()`. Reconciling there would compute output against a\n * controller whose own state has not been initialised, and `connect()` is\n * about to do a full pass anyway.\n * - **After `disconnect()`** — Stimulus fires a callback for **every** target\n * during teardown, and a microtask queued just before it would otherwise run\n * against a detached tree. {@link MicrotaskCoalescer.cancel} exists for the\n * teardown path to drop the pending pass outright.\n *\n * Both guards are part of one contract here rather than something each consumer\n * has to remember separately.\n *\n * Scope is the scheduling only. *What* to reconcile — keep the surviving active\n * option, fall back to the next / previous / first visible one, rebuild derived\n * chips or hidden fields — stays in the controller, because no two consumers\n * answer it the same way.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileOptions());\n *\n * connect() { this.#reconcile.activate(); }\n * disconnect() { this.#reconcile.cancel(); }\n *\n * optionTargetConnected() { this.#reconcile.schedule(); }\n * optionTargetDisconnected() { this.#reconcile.schedule(); }\n * ```\n */\nexport class MicrotaskCoalescer {\n readonly #run: () => void;\n #queued = false;\n #active = false;\n #generation = 0;\n\n /** @param run - the single reconciliation pass, invoked at most once per batch. */\n constructor(run: () => void) {\n this.#run = run;\n }\n\n /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */\n activate(): void {\n this.#active = true;\n }\n\n /** Closes the window and drops any pending pass; call from `disconnect()`. */\n cancel(): void {\n this.#active = false;\n this.#queued = false;\n this.#generation += 1;\n }\n\n /** Requests one pass after the batch settles. Idempotent; inert outside the window. */\n schedule(): void {\n if (!this.#active || this.#queued) return;\n this.#queued = true;\n const generation = this.#generation;\n queueMicrotask(() => {\n // A cancelled callback must not consume a pass queued after reconnect.\n if (generation !== this.#generation || !this.#queued || !this.#active) return;\n this.#queued = false;\n this.#run();\n });\n }\n}\n","/**\n * Self-cleaning timer registries shared by Stimeo controllers.\n *\n * Stimulus controllers frequently schedule `setTimeout` / `setInterval` work\n * (auto-dismiss, debouncing, polling). When the element leaves the DOM — a\n * Turbo Drive navigation, a Turbo Stream replacement, or any `disconnect()` —\n * orphaned timers keep firing against a detached controller, leaking memory and\n * mutating stale state. {@link SafeTimeout} and {@link SafeInterval} track every\n * timer they create so a single {@link TimerRegistry.clearAll | clearAll()} call\n * in `disconnect()` tears them all down.\n *\n * These are intentionally low-level primitives: they own *registration and\n * cleanup only*. Higher-level policy (pause/resume, remaining-time accounting)\n * stays in the individual controllers so per-widget semantics are not flattened\n * into a lowest-common-denominator helper.\n */\n\n/**\n * Shared registry bookkeeping for the timeout/interval variants.\n *\n * Subclasses provide the scheduling primitive ({@link schedule}) and its matching\n * canceller ({@link cancel}); this base owns the set of live ids plus the\n * per-id and bulk teardown shared by both.\n */\nabstract class TimerRegistry {\n /** Live timer ids that have not yet been cleared (or, for timeouts, fired). */\n protected readonly ids = new Set<number>();\n\n /** Schedules the underlying platform timer and returns its id. */\n protected abstract schedule(callback: () => void, delay: number): number;\n\n /** Cancels the underlying platform timer for `id`. */\n protected abstract cancel(id: number): void;\n\n /**\n * Cancels a single tracked timer.\n *\n * No-ops if the id is unknown (already cleared, fired, or never owned by this\n * registry), so callers can clear defensively without guarding.\n */\n clear(id: number): void {\n if (this.ids.delete(id)) {\n this.cancel(id);\n }\n }\n\n /**\n * Cancels every tracked timer. Call this from a controller's `disconnect()`\n * to guarantee no timer outlives the element.\n */\n clearAll(): void {\n for (const id of this.ids) {\n this.cancel(id);\n }\n this.ids.clear();\n }\n\n /** Number of timers currently tracked (pending). */\n get size(): number {\n return this.ids.size;\n }\n}\n\n/**\n * `setTimeout` wrapper that auto-forgets each timer once it fires and supports\n * bulk teardown on disconnect.\n *\n * @example\n * ```ts\n * #timers = new SafeTimeout();\n *\n * connect() {\n * this.#timers.set(() => this.dismiss(), 5000);\n * }\n *\n * disconnect() {\n * this.#timers.clearAll();\n * }\n * ```\n */\nexport class SafeTimeout extends TimerRegistry {\n /**\n * Schedules `callback` after `delay` ms and returns the timer id.\n *\n * The id is removed from the registry automatically when the timeout fires,\n * so {@link TimerRegistry.size | size} reflects only still-pending timers.\n */\n set(callback: () => void, delay: number): number {\n const id = this.schedule(() => {\n this.ids.delete(id);\n callback();\n }, delay);\n this.ids.add(id);\n return id;\n }\n\n protected schedule(callback: () => void, delay: number): number {\n return window.setTimeout(callback, delay);\n }\n\n protected cancel(id: number): void {\n window.clearTimeout(id);\n }\n}\n\n/**\n * `setInterval` wrapper that tracks every interval for bulk teardown on\n * disconnect. Unlike {@link SafeTimeout}, intervals are retained until they are\n * explicitly cleared because they fire repeatedly.\n *\n * @example\n * ```ts\n * #intervals = new SafeInterval();\n *\n * connect() {\n * this.#intervals.set(() => this.tick(), 1000);\n * }\n *\n * disconnect() {\n * this.#intervals.clearAll();\n * }\n * ```\n */\nexport class SafeInterval extends TimerRegistry {\n /** Schedules a repeating `callback` every `delay` ms and returns the timer id. */\n set(callback: () => void, delay: number): number {\n const id = this.schedule(callback, delay);\n this.ids.add(id);\n return id;\n }\n\n protected schedule(callback: () => void, delay: number): number {\n return window.setInterval(callback, delay);\n }\n\n protected cancel(id: number): void {\n window.clearInterval(id);\n }\n}\n","/**\n * JSON string-list parsing for the controllers that take a list as a Value.\n *\n * Stimulus offers an `Array` Value type, but its reader runs `JSON.parse` inside\n * the value observer — **before** the `<name>ValueChanged` callback — and\n * rethrows on malformed text. The throw propagates out of the observer that runs\n * during connection, so a single unparseable attribute stops the controller from\n * connecting at all: no lifecycle callback runs and the element is left inert\n * rather than degraded. A consumer cannot guard against it either, because the\n * callback that would hold the `try` never runs.\n *\n * Declaring the attribute as a `String` Value and parsing it here keeps a\n * malformed declaration local to the value it declares. The attribute text is\n * identical either way (`'[\"a\", \"b\"]'`), so markup does not change with the\n * declaration.\n */\n\n/**\n * Parses `raw` as a JSON array of strings.\n *\n * Returns `fallback` when the text is absent, unparseable, or not an array, so a\n * malformed declaration behaves like an omitted one. A parsed array keeps only\n * its string entries: every caller indexes or compares strings, and a stray\n * number would otherwise sit in the list without ever matching.\n *\n * An explicit `\"[]\"` is honoured as an empty list rather than falling back — it\n * is the only way to declare \"none\" against a non-empty default.\n *\n * @param raw - the attribute text, e.g. `'[\"password\"]'`.\n * @param fallback - the list to use when `raw` declares nothing usable.\n */\nexport function parseStringList(raw: string, fallback: readonly string[] = []): string[] {\n // The common case is an undeclared attribute, and `JSON.parse(\"\")` answers it\n // by throwing. Reaching the same fallback without building an exception keeps\n // the callers that ask per element off that path.\n const text = raw.trim();\n if (text.length === 0) return [...fallback];\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return [...fallback];\n }\n\n if (!Array.isArray(parsed)) return [...fallback];\n return parsed.filter((entry): entry is string => typeof entry === \"string\");\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { isReservedArrowChord, logicalArrowKey } from \"../utils/arrow_step\";\nimport { BeforeCacheReset } from \"../utils/before_cache_reset\";\nimport {\n parseISODateString,\n parseISOMonthString,\n toISODateString,\n toISOMonthString,\n} from \"../utils/dates\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\nimport { SafeTimeout } from \"../utils/safe_timeout\";\nimport { parseStringList } from \"../utils/string_list\";\n\n/** Number of cells in a six-week month grid (7 × 6). */\nconst GRID_SIZE = 42;\n\n/**\n * Headless, accessible **date range picker** behavior. A derivative of\n * {@link CalendarController}: it reuses the month-grid navigation model and adds\n * two-point range selection, in-progress range preview, and presets.\n *\n * Markup contract (identifier: `stimeo--date-range-picker`):\n * <div data-controller=\"stimeo--date-range-picker\"\n * data-stimeo--date-range-picker-min-value=\"2026-01-01\"\n * data-stimeo--date-range-picker-max-value=\"2026-12-31\"\n * data-stimeo--date-range-picker-disabled-dates-value='[\"2026-06-15\"]'>\n * <button data-action=\"stimeo--date-range-picker#prev\">Prev</button>\n * <span data-stimeo--date-range-picker-target=\"monthLabel\" aria-live=\"polite\"></span>\n * <button data-action=\"stimeo--date-range-picker#next\">Next</button>\n * <div role=\"grid\" data-stimeo--date-range-picker-target=\"grid\">\n * <!-- exactly 42 cell targets (7 days × 6 rows) -->\n * <button role=\"gridcell\" tabindex=\"-1\"\n * data-stimeo--date-range-picker-target=\"cell\"\n * data-action=\"click->stimeo--date-range-picker#selectDate\n * mouseenter->stimeo--date-range-picker#previewTo\n * focus->stimeo--date-range-picker#previewTo\n * keydown->stimeo--date-range-picker#onKeydown\"></button>\n * </div>\n * <button data-range=\"last7\" data-action=\"stimeo--date-range-picker#applyPreset\">…</button>\n * <span role=\"status\" aria-live=\"polite\" data-stimeo--date-range-picker-target=\"status\"></span>\n * <input type=\"hidden\" data-stimeo--date-range-picker-target=\"startField\" />\n * <input type=\"hidden\" data-stimeo--date-range-picker-target=\"endField\" />\n * </div>\n *\n * @remarks\n * Behavior only — the consumer styles the grid and renders the range using the\n * `data-range-start` / `data-in-range` / `data-range-end` hooks. Assistive tech\n * is told the two confirmed endpoints via `aria-selected`; inner cells use\n * `data-in-range` (visual only) so the announcement stays to the two ends. The\n * confirmed range is also mirrored to the live `status` region.\n *\n * Selection model: the first click/Enter sets a *pending* start and enters\n * \"selecting\" mode (preview follows the pointer/focus); the second confirms the\n * end (auto-swapped if earlier than the start) and dispatches `change` with\n * `{ start, end }` ISO dates. Escape abandons an in-progress selection,\n * restoring the last confirmed range.\n *\n * Availability is declarative on both axes: `min` / `max` bound the selectable\n * interval and `disabledDates` excludes individual dates inside it. Both are\n * render inputs, so a cell's `aria-disabled` is derived during the paint that\n * needs it rather than written back afterwards — selection, preview, and the\n * grid paint all read one predicate and cannot disagree. A painted-month\n * navigation dispatches `monthchange` with `{ month }` as a notification (for\n * fetching a month's availability, say); the fetched result comes back in\n * through `disabledDates`, which repaints on its own.\n */\nexport class DateRangePickerController extends Controller<HTMLElement> {\n static override targets = [\"grid\", \"monthLabel\", \"cell\", \"status\", \"startField\", \"endField\"];\n static override values = {\n min: { type: String, default: \"\" },\n max: { type: String, default: \"\" },\n // A JSON list read through `parseStringList` rather than Stimulus's `Array`\n // type: that reader throws out of the value observer before any callback\n // runs, so one malformed attribute would stop the picker from connecting.\n disabledDates: { type: String, default: \"\" },\n };\n static actions = [\"applyPreset\", \"next\", \"onKeydown\", \"prev\", \"previewTo\", \"selectDate\"] as const;\n static events = [\"change\", \"monthchange\"] as const;\n\n declare readonly gridTarget: HTMLElement;\n declare readonly hasGridTarget: boolean;\n declare readonly monthLabelTarget: HTMLElement;\n declare readonly cellTargets: HTMLElement[];\n declare readonly statusTarget: HTMLElement;\n declare readonly startFieldTarget: HTMLInputElement;\n declare readonly endFieldTarget: HTMLInputElement;\n declare readonly hasMonthLabelTarget: boolean;\n declare readonly hasStatusTarget: boolean;\n declare readonly hasStartFieldTarget: boolean;\n declare readonly hasEndFieldTarget: boolean;\n declare minValue: string;\n declare maxValue: string;\n declare disabledDatesValue: string;\n\n /** The month currently rendered, as `YYYY-MM`. */\n #viewMonth = \"\";\n /** The confirmed range endpoints (ISO), or \"\" when unset. */\n #startDate = \"\";\n #endDate = \"\";\n /** The first endpoint of an in-progress selection (ISO), or \"\" when idle. */\n #pendingStart = \"\";\n /** The hovered/focused date previewed while selecting (ISO), or \"\". */\n #previewDate = \"\";\n /** The roving-focus date in the grid (local time). */\n #focusedDate = new Date();\n\n /** Deferred focus after an async month transition (cancelled on teardown). */\n readonly #focusTimer = new SafeTimeout();\n\n /** The declared unavailable dates, indexed for the per-cell paint lookup. */\n #disabledDates = new Set<string>();\n\n /** Rewinds an unfinished selection before Turbo snapshots the page. */\n readonly #beforeCache = new BeforeCacheReset(() => this.#rewindForCache());\n\n /** Last painted month, or `null` until the initial paint has settled. */\n #announcedMonth: string | null = null;\n\n /**\n * Collapses a morph that swaps render inputs into one repaint, and refuses the\n * pass Stimulus delivers before `connect()`.\n */\n readonly #repaint = new MicrotaskCoalescer(() => {\n this.#render();\n });\n\n /** Seeds and normalizes the range from optional hidden fields, then paints the grid. */\n override connect(): void {\n this.#repaint.activate();\n this.#beforeCache.activate();\n const authoredStart = this.hasStartFieldTarget ? normalizeISO(this.startFieldTarget.value) : \"\";\n const authoredEnd = this.hasEndFieldTarget ? normalizeISO(this.endFieldTarget.value) : \"\";\n [this.#startDate, this.#endDate] = orderRange(authoredStart, authoredEnd);\n this.#pendingStart = \"\";\n this.#previewDate = \"\";\n this.#announcedMonth = null;\n this.#commitFields();\n\n const anchor =\n parseISODateString(this.#startDate) ?? this.#clampToBounds(new Date()) ?? new Date();\n this.#focusedDate = anchor;\n this.#viewMonth = toISOMonthString(anchor);\n // A confirmed range can carry `aria-selected=\"true\"` on two cells, so the\n // grid has to say that more than one is selectable — otherwise a single-select\n // grid is claiming two selections.\n if (this.hasGridTarget) this.gridTarget.setAttribute(\"aria-multiselectable\", \"true\");\n this.#render();\n }\n\n /** Cancels any pending deferred focus so it never fires on a detached element. */\n override disconnect(): void {\n this.#repaint.cancel();\n this.#beforeCache.deactivate();\n this.#focusTimer.clearAll();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `min` at runtime. */\n minValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Repaints when application code (or a Turbo morph) changes `max` at runtime. */\n maxValueChanged(): void {\n this.#repaint.schedule();\n }\n\n /** Re-indexes the unavailable dates and repaints when the declared set changes. */\n disabledDatesValueChanged(): void {\n this.#disabledDates = new Set(parseStringList(this.disabledDatesValue));\n this.#repaint.schedule();\n }\n\n /** Navigates to the previous month. */\n prev(event?: Event): void {\n event?.preventDefault();\n this.#shiftMonth(-1);\n }\n\n /** Navigates to the next month. */\n next(event?: Event): void {\n event?.preventDefault();\n this.#shiftMonth(1);\n }\n\n /** Confirms a range endpoint from a clicked cell. */\n selectDate(event: Event): void {\n const cell = this.#cellFrom(event.target);\n if (!cell) return;\n const date = cell.getAttribute(\"data-date\");\n if (!date || !this.#isSelectable(date)) return;\n this.#choose(date);\n }\n\n /** Previews the range up to a hovered/focused cell while selecting. */\n previewTo(event: Event): void {\n const cell = this.#cellFrom(event.target);\n if (!cell) return;\n const date = cell.getAttribute(\"data-date\");\n if (!date) return;\n let shouldRender = false;\n // Focus moves the roving tabindex; hover does not.\n if (event.type.startsWith(\"focus\")) {\n const parsed = parseISODateString(date);\n if (parsed) this.#focusedDate = parsed;\n shouldRender = cell.getAttribute(\"tabindex\") !== \"0\";\n }\n // An unavailable day can hold focus (APG keeps disabled cells reachable) but\n // never becomes the previewed endpoint, so the preview stays where it was.\n if (this.#pendingStart && this.#isSelectable(date) && this.#previewDate !== date) {\n this.#previewDate = date;\n shouldRender = true;\n }\n if (shouldRender) this.#render();\n }\n\n /** Applies a named preset (`today` / `last7` / `last30` / `thisMonth`). */\n applyPreset(event: Event): void {\n const button = (event.target as HTMLElement | null)?.closest(\"[data-range]\");\n const range = computePreset(button?.getAttribute(\"data-range\") ?? \"\");\n if (!range) return;\n\n const intersection = this.#intersectRange(range);\n if (!intersection) return;\n const { start, end } = intersection;\n // A preset is the consumer's own button, but what it produces is still a\n // range, and an unavailable day cannot be one of its endpoints — the same\n // rule a click or Enter obeys. Refusing keeps one answer per date instead of\n // one per entry point, and stops a cell from being the confirmed edge while\n // still painted `aria-disabled=\"true\"`.\n if (!this.#isSelectable(start) || !this.#isSelectable(end)) return;\n\n this.#startDate = start;\n this.#endDate = end;\n this.#pendingStart = \"\";\n this.#previewDate = \"\";\n const endDate = parseISODateString(end);\n if (endDate) this.#focusedDate = endDate;\n this.#commitFields();\n this.#transitionTo(toISOMonthString(parseISODateString(end) ?? new Date()), end);\n this.#announce();\n this.dispatch(\"change\", { detail: { start, end } });\n }\n\n /** Grid keyboard navigation, selection (Enter/Space), and Escape-to-cancel. */\n onKeydown(event: KeyboardEvent): void {\n // A descendant widget that already claimed the key must not ALSO move the\n // grid focus or choose a date — composition depends on this yield.\n if (event.defaultPrevented) return;\n if (isReservedArrowChord(event)) return;\n const cell = this.#cellFrom(event.target);\n if (!cell) return;\n const dateStr = cell.getAttribute(\"data-date\") ?? \"\";\n const date = parseISODateString(dateStr);\n if (!date) return;\n\n if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n if (this.#isSelectable(dateStr)) this.#choose(dateStr);\n return;\n }\n if (event.key === \"Escape\") {\n // A press an inner handler already owned is yielded at the top of this\n // handler. What is checked here is the IME half: a press during a\n // composition steers the conversion, not the range.\n if (this.#pendingStart && !event.isComposing) {\n event.preventDefault();\n this.#pendingStart = \"\";\n this.#previewDate = \"\";\n this.#render();\n }\n return;\n }\n\n let next: Date | null = null;\n // Logical, not physical. The key is normalised rather than the\n // delta negated: these two branches are not mirror images — their guards\n // differ — so swapping the key keeps each guard with its own direction.\n switch (logicalArrowKey(event.key, this.element)) {\n case \"ArrowLeft\":\n next = addDays(date, -1);\n break;\n case \"ArrowRight\":\n next = addDays(date, 1);\n break;\n case \"ArrowUp\":\n next = addDays(date, -7);\n break;\n case \"ArrowDown\":\n next = addDays(date, 7);\n break;\n case \"Home\":\n next = addDays(date, -date.getDay());\n break;\n case \"End\":\n next = addDays(date, 6 - date.getDay());\n break;\n case \"PageUp\":\n next = event.shiftKey ? shiftYearClamped(date, -1) : shiftMonthClamped(date, -1);\n break;\n case \"PageDown\":\n next = event.shiftKey ? shiftYearClamped(date, 1) : shiftMonthClamped(date, 1);\n break;\n default:\n return;\n }\n event.preventDefault();\n this.#moveFocusTo(next);\n }\n\n /** Records a chosen date as either the pending start or the confirmed end. */\n #choose(date: string): void {\n if (!this.#pendingStart) {\n this.#pendingStart = date;\n this.#previewDate = date;\n const parsed = parseISODateString(date);\n if (parsed) this.#focusedDate = parsed;\n this.#render();\n return;\n }\n // Second click confirms; order the two so start ≤ end.\n const [start, end] =\n date < this.#pendingStart ? [date, this.#pendingStart] : [this.#pendingStart, date];\n this.#startDate = start;\n this.#endDate = end;\n this.#pendingStart = \"\";\n this.#previewDate = \"\";\n this.#commitFields();\n this.#render();\n this.#announce();\n this.dispatch(\"change\", { detail: { start, end } });\n }\n\n /** Moves roving focus to `date`, transitioning the month when needed. */\n #moveFocusTo(date: Date): void {\n this.#focusedDate = date;\n const iso = toISODateString(date);\n // Availability is known from the Values, not from the cells, so a target in\n // a month that has not been painted yet resolves in this same pass.\n if (this.#pendingStart && this.#isSelectable(iso)) this.#previewDate = iso;\n this.#transitionTo(toISOMonthString(date), iso);\n }\n\n /** Renders `month`, then focuses the cell for `dateStr` (deferred if async). */\n #transitionTo(month: string, dateStr: string): void {\n const isTransition = month !== this.#viewMonth;\n this.#focusTimer.clearAll();\n this.#viewMonth = month;\n this.#render();\n const focusCell = (): void => {\n this.cellTargets.find((c) => c.getAttribute(\"data-date\") === dateStr)?.focus();\n };\n if (isTransition) {\n // Let the synchronous render settle before focusing the freshly bound cell.\n this.#focusTimer.set(focusCell, 0);\n } else {\n focusCell();\n }\n }\n\n /** Shifts the displayed month by `delta`, keeping focus within it. */\n #shiftMonth(delta: number): void {\n const info = parseISOMonthString(this.#viewMonth);\n if (!info) return;\n const target = new Date(info.year, info.month - 1 + delta, 1);\n this.#viewMonth = toISOMonthString(target);\n // Keep the same day-of-month where possible, clamped to the new month.\n const lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();\n target.setDate(Math.min(this.#focusedDate.getDate(), lastDay));\n this.#focusedDate = target;\n this.#render();\n }\n\n /**\n * Builds the six-week grid and binds range/roving/disabled state per cell.\n *\n * @stimeoRenderRoot\n */\n #render(): void {\n const info = parseISOMonthString(this.#viewMonth);\n if (!info) return;\n const { year, month } = info;\n\n // Tightening `min` / `max` / `disabledDates` mid-selection can strand the\n // preview on a day that is no longer choosable; drop it back to the pending\n // start rather than advertising a range the user cannot confirm.\n if (this.#previewDate && !this.#isSelectable(this.#previewDate)) this.#previewDate = \"\";\n\n if (this.hasMonthLabelTarget) {\n const lang = document.documentElement.lang || \"en\";\n const formatter = monthFormatter(lang);\n this.monthLabelTarget.textContent = formatter.format(new Date(year, month - 1, 1));\n }\n\n const [rangeStart, rangeEnd] = this.#visualRange();\n const days = gridDays(year, month);\n const focusedStr = toISODateString(this.#focusedDate);\n const todayStr = toISODateString(new Date());\n\n const cells = this.cellTargets;\n for (let i = 0; i < GRID_SIZE; i++) {\n const el = cells[i];\n const date = days[i];\n if (!el || !date) continue;\n const iso = toISODateString(date);\n\n el.setAttribute(\"data-date\", iso);\n el.textContent = String(date.getDate());\n el.setAttribute(\"data-outside\", String(date.getMonth() !== month - 1));\n el.setAttribute(\"data-today\", String(iso === todayStr));\n el.setAttribute(\"tabindex\", iso === focusedStr ? \"0\" : \"-1\");\n\n if (this.#isSelectable(iso)) el.removeAttribute(\"aria-disabled\");\n else el.setAttribute(\"aria-disabled\", \"true\");\n\n const isStart = !!rangeStart && iso === rangeStart;\n const isEnd = !!rangeEnd && iso === rangeEnd && rangeEnd !== rangeStart;\n const inside = !!rangeStart && !!rangeEnd && iso > rangeStart && iso < rangeEnd;\n el.toggleAttribute(\"data-range-start\", isStart);\n el.toggleAttribute(\"data-range-end\", isEnd);\n el.toggleAttribute(\"data-in-range\", inside);\n // Selection is what the user committed, never what the pointer is hovering:\n // `aria-selected` marks the two confirmed endpoints only. The preview lives\n // in the `data-*` trio above, which styling reads and AT does not.\n el.setAttribute(\n \"aria-selected\",\n String(\n (!!this.#startDate && iso === this.#startDate) ||\n (!!this.#endDate && iso === this.#endDate),\n ),\n );\n }\n\n // Every declared cell is part of the roving composite, even when authored\n // beyond the documented 42-cell grid. Extras must never become a second stop.\n for (const extra of cells.slice(GRID_SIZE)) extra.setAttribute(\"tabindex\", \"-1\");\n\n // Malformed short markup still gets a usable entry point. Prefer a date in\n // the displayed month so arrow navigation begins from the visible context.\n if (!cells.some((cell) => cell.getAttribute(\"tabindex\") === \"0\")) {\n const fallback =\n cells.find((cell) => cell.getAttribute(\"data-outside\") === \"false\") ?? cells[0];\n fallback?.setAttribute(\"tabindex\", \"0\");\n }\n\n // A month event belongs to the completed paint so a listener that reads the\n // grid sees the new dates. It reports the paint; it is not a hook the paint\n // waits on, so nothing here depends on what a listener does with it.\n const previous = this.#announcedMonth;\n this.#announcedMonth = this.#viewMonth;\n if (previous !== null && previous !== this.#viewMonth) {\n this.dispatch(\"monthchange\", { detail: { month: this.#viewMonth } });\n }\n }\n\n /** The ordered [start, end] pair to paint: the preview while selecting, else confirmed. */\n #visualRange(): [string, string] {\n if (this.#pendingStart) {\n const other = this.#previewDate || this.#pendingStart;\n return this.#pendingStart <= other\n ? [this.#pendingStart, other]\n : [other, this.#pendingStart];\n }\n return [this.#startDate, this.#endDate];\n }\n\n /** Writes the confirmed range to the hidden fields. */\n #commitFields(): void {\n if (this.hasStartFieldTarget) this.startFieldTarget.value = this.#startDate;\n if (this.hasEndFieldTarget) this.endFieldTarget.value = this.#endDate;\n }\n\n /** Announces the confirmed range in the live status region. */\n #announce(): void {\n if (this.hasStatusTarget && this.#startDate && this.#endDate) {\n this.statusTarget.textContent = `${this.#startDate} – ${this.#endDate}`;\n }\n }\n\n /**\n * True when `iso` may be chosen as a range endpoint.\n *\n * The single availability question in the controller: the grid paint, the\n * preview, and both commit paths ask it, so a cell's `aria-disabled` and what\n * a click on that cell does are the same decision rather than two that have to\n * be kept in step.\n */\n #isSelectable(iso: string): boolean {\n return !this.#outOfBounds(iso) && !this.#disabledDates.has(iso);\n }\n\n /** True when `iso` falls outside the `[min, max]` bounds. */\n #outOfBounds(iso: string): boolean {\n if (this.minValue && iso < this.minValue) return true;\n if (this.maxValue && iso > this.maxValue) return true;\n return false;\n }\n\n /** Clamps a generated ISO date string into `[min, max]`. */\n #clampISO(iso: string): string {\n if (this.minValue && iso < this.minValue) return this.minValue;\n if (this.maxValue && iso > this.maxValue) return this.maxValue;\n return iso;\n }\n\n /** Clamps a Date into `[min, max]`, returning null only when unparseable. */\n #clampToBounds(date: Date): Date | null {\n const clamped = this.#clampISO(toISODateString(date));\n return parseISODateString(clamped);\n }\n\n /**\n * Intersects a preset with `[min, max]`, rejecting a disjoint interval.\n *\n * Only the bounds narrow a preset here: `disabledDates` excludes single days,\n * not sub-intervals, so it cannot shrink one to a still-contiguous range. A\n * day it excludes is still refused as an endpoint — the caller checks that —\n * but a preset that merely spans one keeps its span.\n */\n #intersectRange(range: { start: string; end: string }): { start: string; end: string } | null {\n const start = this.minValue && range.start < this.minValue ? this.minValue : range.start;\n const end = this.maxValue && range.end > this.maxValue ? this.maxValue : range.end;\n return start <= end ? { start, end } : null;\n }\n\n /** Removes provisional range state before Turbo freezes a cached snapshot. */\n #rewindForCache(): void {\n this.#focusTimer.clearAll();\n if (!this.#pendingStart && !this.#previewDate) return;\n this.#pendingStart = \"\";\n this.#previewDate = \"\";\n this.#render();\n }\n\n /** Resolves the cell element from an event target, or null. */\n #cellFrom(target: EventTarget | null): HTMLElement | null {\n return (\n (target as HTMLElement | null)?.closest<HTMLElement>(\n \"[data-stimeo--date-range-picker-target='cell']\",\n ) ?? null\n );\n }\n}\n\n/** Returns a new Date `n` days from `date`. */\nfunction addDays(date: Date, n: number): Date {\n const next = new Date(date);\n next.setDate(next.getDate() + n);\n return next;\n}\n\n/** Shifts `date` by `delta` months, clamping the day to the target month length. */\nfunction shiftMonthClamped(date: Date, delta: number): Date {\n const target = new Date(date.getFullYear(), date.getMonth() + delta, 1);\n const lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();\n target.setDate(Math.min(date.getDate(), lastDay));\n return target;\n}\n\n/** Shifts `date` by `delta` years, clamping leap days to the target month. */\nfunction shiftYearClamped(date: Date, delta: number): Date {\n const target = new Date(date.getFullYear() + delta, date.getMonth(), 1);\n const lastDay = new Date(target.getFullYear(), target.getMonth() + 1, 0).getDate();\n target.setDate(Math.min(date.getDate(), lastDay));\n return target;\n}\n\n/** Builds the 42 local-time dates of a Sunday-started six-week grid for a month. */\nfunction gridDays(year: number, month: number): Date[] {\n const first = new Date(year, month - 1, 1);\n const start = new Date(first);\n start.setDate(first.getDate() - first.getDay());\n const days: Date[] = [];\n const current = new Date(start);\n for (let i = 0; i < GRID_SIZE; i++) {\n days.push(new Date(current));\n current.setDate(current.getDate() + 1);\n }\n return days;\n}\n\n/** Validates and re-serializes an ISO date string, returning \"\" when invalid. */\nfunction normalizeISO(value: string): string {\n const date = parseISODateString(value.trim());\n return date ? toISODateString(date) : \"\";\n}\n\n/** Orders a complete range while preserving either valid lone endpoint. */\nfunction orderRange(start: string, end: string): [string, string] {\n return start && end && end < start ? [end, start] : [start, end];\n}\n\n/** Creates the month formatter, falling back when the document locale is malformed. */\nfunction monthFormatter(locale: string): Intl.DateTimeFormat {\n const options: Intl.DateTimeFormatOptions = { month: \"long\", year: \"numeric\" };\n try {\n return new Intl.DateTimeFormat(locale, options);\n } catch (error) {\n if (!(error instanceof RangeError)) throw error;\n return new Intl.DateTimeFormat(\"en\", options);\n }\n}\n\n/** Computes a preset range relative to today, or null for an unknown name. */\nfunction computePreset(name: string): { start: string; end: string } | null {\n const today = new Date();\n const todayStr = toISODateString(today);\n switch (name) {\n case \"today\":\n return { start: todayStr, end: todayStr };\n case \"last7\":\n return { start: toISODateString(addDays(today, -6)), end: todayStr };\n case \"last30\":\n return { start: toISODateString(addDays(today, -29)), end: todayStr };\n case \"thisMonth\": {\n const start = new Date(today.getFullYear(), today.getMonth(), 1);\n const end = new Date(today.getFullYear(), today.getMonth() + 1, 0);\n return { start: toISODateString(start), end: toISODateString(end) };\n }\n default:\n return null;\n }\n}\n"]}
|
|
@@ -315,15 +315,25 @@ var FocusTrap = class {
|
|
|
315
315
|
* content cannot be focused or reached by assistive technology, honoring the
|
|
316
316
|
* `aria-modal="true"` contract. An element that was *already* `inert` is left
|
|
317
317
|
* untracked so `#releaseBackground` does not wrongly clear it.
|
|
318
|
+
*
|
|
319
|
+
* The walk climbs from the container to `body` and inerts each ancestor's other
|
|
320
|
+
* children. Scanning only `body`'s children would skip the branch the container
|
|
321
|
+
* sits in — everything beside it inside that branch is background too, and a
|
|
322
|
+
* nested container is the ordinary case.
|
|
318
323
|
*/
|
|
319
324
|
#isolateBackground() {
|
|
320
325
|
const container = this.#getContainer();
|
|
321
326
|
this.#inertedSiblings = [];
|
|
322
|
-
for (
|
|
323
|
-
|
|
324
|
-
if (
|
|
325
|
-
sibling.
|
|
326
|
-
|
|
327
|
+
for (let node = container; node !== document.body; ) {
|
|
328
|
+
const parent = node.parentElement;
|
|
329
|
+
if (!parent) break;
|
|
330
|
+
for (const sibling of Array.from(parent.children)) {
|
|
331
|
+
if (!(sibling instanceof HTMLElement)) continue;
|
|
332
|
+
if (sibling === node || sibling.inert) continue;
|
|
333
|
+
sibling.inert = true;
|
|
334
|
+
this.#inertedSiblings.push(sibling);
|
|
335
|
+
}
|
|
336
|
+
node = parent;
|
|
327
337
|
}
|
|
328
338
|
}
|
|
329
339
|
/** Reverts the `inert` flags applied by `#isolateBackground`. */
|