stimeo-ui 0.6.0 → 0.8.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 +124 -0
- package/dist/controllers/alert_dialog_controller.d.ts +2 -0
- package/dist/controllers/alert_dialog_controller.js +75 -4
- package/dist/controllers/alert_dialog_controller.js.map +1 -1
- package/dist/controllers/auto_submit_controller.d.ts +16 -3
- package/dist/controllers/auto_submit_controller.js +94 -16
- package/dist/controllers/auto_submit_controller.js.map +1 -1
- package/dist/controllers/avatar_controller.js +47 -5
- package/dist/controllers/avatar_controller.js.map +1 -1
- package/dist/controllers/breadcrumb_controller.d.ts +2 -0
- package/dist/controllers/breadcrumb_controller.js.map +1 -1
- package/dist/controllers/bulk_select_controller.d.ts +2 -0
- package/dist/controllers/bulk_select_controller.js.map +1 -1
- package/dist/controllers/calendar_controller.d.ts +2 -0
- package/dist/controllers/calendar_controller.js.map +1 -1
- package/dist/controllers/carousel_controller.d.ts +81 -47
- package/dist/controllers/carousel_controller.js +451 -100
- package/dist/controllers/carousel_controller.js.map +1 -1
- package/dist/controllers/character_counter_controller.d.ts +52 -20
- package/dist/controllers/character_counter_controller.js +338 -63
- package/dist/controllers/character_counter_controller.js.map +1 -1
- package/dist/controllers/checkbox_controller.d.ts +3 -0
- package/dist/controllers/checkbox_controller.js.map +1 -1
- package/dist/controllers/color_picker_controller.d.ts +3 -0
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/combobox_controller.d.ts +2 -0
- package/dist/controllers/combobox_controller.js.map +1 -1
- package/dist/controllers/command_palette_controller.d.ts +2 -0
- package/dist/controllers/command_palette_controller.js +75 -4
- package/dist/controllers/command_palette_controller.js.map +1 -1
- package/dist/controllers/conditional_fields_controller.d.ts +42 -14
- package/dist/controllers/conditional_fields_controller.js +345 -51
- package/dist/controllers/conditional_fields_controller.js.map +1 -1
- package/dist/controllers/confirm_controller.d.ts +2 -0
- package/dist/controllers/confirm_controller.js +75 -4
- package/dist/controllers/confirm_controller.js.map +1 -1
- package/dist/controllers/count_up_controller.d.ts +2 -0
- package/dist/controllers/count_up_controller.js.map +1 -1
- package/dist/controllers/countdown_controller.d.ts +4 -0
- package/dist/controllers/countdown_controller.js.map +1 -1
- package/dist/controllers/currency_input_controller.d.ts +40 -4
- package/dist/controllers/currency_input_controller.js +305 -74
- package/dist/controllers/currency_input_controller.js.map +1 -1
- package/dist/controllers/data_grid_controller.d.ts +3 -0
- package/dist/controllers/data_grid_controller.js.map +1 -1
- package/dist/controllers/dialog_controller.js +75 -4
- package/dist/controllers/dialog_controller.js.map +1 -1
- package/dist/controllers/direct_upload_controller.d.ts +59 -25
- package/dist/controllers/direct_upload_controller.js +212 -46
- package/dist/controllers/direct_upload_controller.js.map +1 -1
- package/dist/controllers/dirty_form_controller.d.ts +14 -6
- package/dist/controllers/dirty_form_controller.js +192 -29
- package/dist/controllers/dirty_form_controller.js.map +1 -1
- package/dist/controllers/dismissible_controller.d.ts +2 -0
- package/dist/controllers/dismissible_controller.js +83 -18
- package/dist/controllers/dismissible_controller.js.map +1 -1
- package/dist/controllers/drawer_controller.js +75 -4
- package/dist/controllers/drawer_controller.js.map +1 -1
- package/dist/controllers/empty_state_controller.d.ts +2 -0
- package/dist/controllers/empty_state_controller.js.map +1 -1
- package/dist/controllers/file_dropzone_controller.d.ts +123 -27
- package/dist/controllers/file_dropzone_controller.js +386 -63
- package/dist/controllers/file_dropzone_controller.js.map +1 -1
- package/dist/controllers/filter_controller.d.ts +2 -0
- package/dist/controllers/filter_controller.js.map +1 -1
- package/dist/controllers/flash_controller.d.ts +7 -1
- package/dist/controllers/flash_controller.js +3 -1
- package/dist/controllers/flash_controller.js.map +1 -1
- package/dist/controllers/focus_controller.d.ts +2 -0
- package/dist/controllers/focus_controller.js +75 -4
- package/dist/controllers/focus_controller.js.map +1 -1
- package/dist/controllers/form_field_controller.d.ts +50 -10
- package/dist/controllers/form_field_controller.js +280 -62
- package/dist/controllers/form_field_controller.js.map +1 -1
- package/dist/controllers/form_validation_controller.d.ts +10 -8
- package/dist/controllers/form_validation_controller.js +208 -83
- package/dist/controllers/form_validation_controller.js.map +1 -1
- package/dist/controllers/frame_loading_controller.d.ts +5 -1
- package/dist/controllers/frame_loading_controller.js +2 -1
- package/dist/controllers/frame_loading_controller.js.map +1 -1
- package/dist/controllers/highlight_controller.d.ts +2 -0
- package/dist/controllers/highlight_controller.js.map +1 -1
- package/dist/controllers/idle_controller.d.ts +2 -0
- package/dist/controllers/idle_controller.js.map +1 -1
- package/dist/controllers/input_mask_controller.d.ts +43 -15
- package/dist/controllers/input_mask_controller.js +251 -76
- package/dist/controllers/input_mask_controller.js.map +1 -1
- package/dist/controllers/lazy_frame_controller.d.ts +2 -0
- package/dist/controllers/lazy_frame_controller.js.map +1 -1
- package/dist/controllers/listbox_controller.d.ts +2 -0
- package/dist/controllers/listbox_controller.js.map +1 -1
- package/dist/controllers/local_time_controller.d.ts +2 -0
- package/dist/controllers/local_time_controller.js.map +1 -1
- package/dist/controllers/masonry_controller.d.ts +2 -0
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/meter_controller.d.ts +2 -0
- package/dist/controllers/meter_controller.js.map +1 -1
- package/dist/controllers/multi_select_controller.d.ts +2 -0
- package/dist/controllers/multi_select_controller.js.map +1 -1
- package/dist/controllers/nested_form_controller.d.ts +52 -13
- package/dist/controllers/nested_form_controller.js +450 -42
- package/dist/controllers/nested_form_controller.js.map +1 -1
- package/dist/controllers/network_status_controller.d.ts +2 -0
- package/dist/controllers/network_status_controller.js.map +1 -1
- package/dist/controllers/number_input_controller.d.ts +2 -0
- package/dist/controllers/number_input_controller.js +47 -5
- package/dist/controllers/number_input_controller.js.map +1 -1
- package/dist/controllers/otp_controller.d.ts +62 -23
- package/dist/controllers/otp_controller.js +472 -114
- package/dist/controllers/otp_controller.js.map +1 -1
- package/dist/controllers/overflow_indicator_controller.d.ts +2 -0
- package/dist/controllers/overflow_indicator_controller.js.map +1 -1
- package/dist/controllers/overflow_menu_controller.d.ts +2 -0
- package/dist/controllers/overflow_menu_controller.js +2 -1
- package/dist/controllers/overflow_menu_controller.js.map +1 -1
- package/dist/controllers/pagination_controller.d.ts +2 -0
- package/dist/controllers/pagination_controller.js +2 -1
- package/dist/controllers/pagination_controller.js.map +1 -1
- package/dist/controllers/password_reveal_controller.d.ts +2 -0
- package/dist/controllers/password_reveal_controller.js.map +1 -1
- package/dist/controllers/password_strength_controller.d.ts +2 -0
- package/dist/controllers/password_strength_controller.js.map +1 -1
- package/dist/controllers/persist_controller.d.ts +30 -16
- package/dist/controllers/persist_controller.js +432 -122
- package/dist/controllers/persist_controller.js.map +1 -1
- package/dist/controllers/pointer_drag_controller.d.ts +3 -0
- package/dist/controllers/pointer_drag_controller.js.map +1 -1
- package/dist/controllers/popover_controller.js +77 -4
- package/dist/controllers/popover_controller.js.map +1 -1
- package/dist/controllers/portal_controller.d.ts +2 -0
- package/dist/controllers/portal_controller.js.map +1 -1
- package/dist/controllers/preview_guard_controller.d.ts +2 -0
- package/dist/controllers/preview_guard_controller.js.map +1 -1
- package/dist/controllers/progress_controller.d.ts +3 -0
- package/dist/controllers/progress_controller.js.map +1 -1
- package/dist/controllers/radio_group_controller.d.ts +3 -0
- package/dist/controllers/radio_group_controller.js.map +1 -1
- package/dist/controllers/rating_controller.d.ts +2 -0
- package/dist/controllers/rating_controller.js +9 -5
- package/dist/controllers/rating_controller.js.map +1 -1
- package/dist/controllers/reading_progress_controller.d.ts +2 -0
- package/dist/controllers/reading_progress_controller.js.map +1 -1
- package/dist/controllers/resizable_controller.d.ts +2 -0
- package/dist/controllers/resizable_controller.js.map +1 -1
- package/dist/controllers/roving_controller.d.ts +2 -0
- package/dist/controllers/roving_controller.js.map +1 -1
- package/dist/controllers/scroll_area_controller.d.ts +23 -15
- package/dist/controllers/scroll_area_controller.js +462 -162
- package/dist/controllers/scroll_area_controller.js.map +1 -1
- package/dist/controllers/scroll_visibility_controller.d.ts +2 -0
- package/dist/controllers/scroll_visibility_controller.js.map +1 -1
- package/dist/controllers/scrollspy_controller.d.ts +2 -0
- package/dist/controllers/scrollspy_controller.js.map +1 -1
- package/dist/controllers/separator_controller.d.ts +54 -11
- package/dist/controllers/separator_controller.js +354 -38
- package/dist/controllers/separator_controller.js.map +1 -1
- package/dist/controllers/sidebar_controller.js +83 -10
- package/dist/controllers/sidebar_controller.js.map +1 -1
- package/dist/controllers/skeleton_controller.d.ts +2 -0
- package/dist/controllers/skeleton_controller.js.map +1 -1
- package/dist/controllers/slider_controller.d.ts +2 -0
- package/dist/controllers/slider_controller.js.map +1 -1
- package/dist/controllers/smart_sticky_header_controller.d.ts +2 -0
- package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
- package/dist/controllers/spinner_controller.d.ts +4 -1
- package/dist/controllers/spinner_controller.js +7 -5
- package/dist/controllers/spinner_controller.js.map +1 -1
- package/dist/controllers/step_indicator_controller.d.ts +2 -0
- package/dist/controllers/step_indicator_controller.js.map +1 -1
- package/dist/controllers/stepper_controller.d.ts +2 -0
- package/dist/controllers/stepper_controller.js.map +1 -1
- package/dist/controllers/stick_to_bottom_controller.d.ts +2 -0
- package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
- package/dist/controllers/sticky_observer_controller.d.ts +2 -0
- package/dist/controllers/sticky_observer_controller.js.map +1 -1
- package/dist/controllers/submit_once_controller.d.ts +98 -39
- package/dist/controllers/submit_once_controller.js +402 -122
- package/dist/controllers/submit_once_controller.js.map +1 -1
- package/dist/controllers/switch_controller.d.ts +2 -0
- package/dist/controllers/switch_controller.js.map +1 -1
- package/dist/controllers/tags_input_controller.d.ts +2 -0
- package/dist/controllers/tags_input_controller.js.map +1 -1
- package/dist/controllers/textarea_autosize_controller.d.ts +31 -9
- package/dist/controllers/textarea_autosize_controller.js +131 -3
- package/dist/controllers/textarea_autosize_controller.js.map +1 -1
- package/dist/controllers/theme_controller.d.ts +2 -0
- package/dist/controllers/theme_controller.js +8 -6
- package/dist/controllers/theme_controller.js.map +1 -1
- package/dist/controllers/time_picker_controller.d.ts +2 -0
- package/dist/controllers/time_picker_controller.js.map +1 -1
- package/dist/controllers/toast_controller.d.ts +4 -0
- package/dist/controllers/toast_controller.js.map +1 -1
- package/dist/controllers/toggle_group_controller.d.ts +2 -0
- 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 +2 -0
- package/dist/controllers/transition_controller.js.map +1 -1
- package/dist/controllers/tree_view_controller.d.ts +2 -0
- package/dist/controllers/tree_view_controller.js +2 -1
- package/dist/controllers/tree_view_controller.js.map +1 -1
- package/dist/index.js +4293 -1447
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.d.ts +115 -4
- package/dist/inspector/cli.js +195 -15
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +257 -47
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +11 -11
- package/dist/inspector/manifest.json +615 -66
- package/dist/positioning/index.d.ts +2 -0
- package/dist/positioning/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/logical_scroll.ts","../../src/utils/arrow_step.ts","../../src/utils/dates.ts","../../src/utils/safe_timeout.ts","../../src/controllers/calendar_controller.ts"],"names":[],"mappings":"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","file":"calendar_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 * 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 * 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","import { Controller } from \"@hotwired/stimulus\";\nimport { isReservedArrowChord, logicalArrowKey } from \"../utils/arrow_step\";\nimport {\n parseISODateString,\n parseISOMonthString,\n toISODateString,\n toISOMonthString,\n} from \"../utils/dates\";\nimport { SafeTimeout } from \"../utils/safe_timeout\";\n\n/**\n * Marks an `aria-disabled` this controller wrote, so a re-paint takes back only\n * its own. A consumer marks holidays and booked days with the same attribute;\n * without the marker a paint would clear their intent.\n *\n * The marker is scoped to the date the cell currently shows, not to the cell: the\n * 42 cells are recycled every month, so a value that outlived its date would\n * disable a different day. A consumer that marks specific dates applies them once\n * for the month the grid opens on, then re-applies after\n * `stimeo--calendar:monthchange`, which reports a move to a different month.\n */\nconst OWNED_DISABLED = \"data-stimeo--calendar-owns-disabled\";\n\n/**\n * Headless, highly accessible calendar grid behavior.\n *\n * Markup contract (identifier: `stimeo--calendar`):\n * <div data-controller=\"stimeo--calendar\"\n * data-stimeo--calendar-month-value=\"2026-05\"\n * data-stimeo--calendar-selected-value=\"2026-05-31\">\n * <button data-action=\"stimeo--calendar#prev\">Previous</button>\n * <span data-stimeo--calendar-target=\"label\">May 2026</span>\n * <button data-action=\"stimeo--calendar#next\">Next</button>\n * <table role=\"grid\">\n * <tbody data-stimeo--calendar-target=\"grid\"\n * data-action=\"keydown->stimeo--calendar#onKeydown\n * click->stimeo--calendar#selectByClick\">\n * <!-- Markup must contain exactly 42 day targets (7 days x 6 rows) -->\n * <tr role=\"row\">\n * <td role=\"gridcell\" data-stimeo--calendar-target=\"day\" tabindex=\"-1\"></td>\n * </tr>\n * </tbody>\n * </table>\n * </div>\n *\n * Implements the WAI-ARIA APG **Date Picker Dialog** grid navigation pattern:\n * - Local-aware month/year labels using native `Intl.DateTimeFormat`.\n * - Roving tabindex focus tracking (exactly one focusable day at any time).\n * - Full grid keyboard controls (arrows, PageUp/Down, Home/End, Shift+PageUp/Down).\n * - Automatic month wrapping and date clamping for missing dates (e.g. leap years, 31st to 30th).\n *\n * @remarks\n * Behavior only. The controller updates classes, attributes (aria-selected, data-outside, etc.),\n * and text contents dynamically on 42 pre-allocated `day` targets.\n */\nexport class CalendarController extends Controller<HTMLElement> {\n static override targets = [\"label\", \"grid\", \"day\"];\n static override values = {\n month: { type: String, default: \"\" },\n selected: { type: String, default: \"\" },\n min: { type: String, default: \"\" },\n max: { type: String, default: \"\" },\n weekStart: { type: Number, default: 0 }, // 0 = Sunday, 1 = Monday, etc.\n };\n static actions = [\"next\", \"onKeydown\", \"prev\", \"selectByClick\"] as const;\n static events = [\"monthchange\", \"select\"] as const;\n\n declare readonly labelTarget: HTMLElement;\n declare readonly gridTarget: HTMLElement;\n declare readonly dayTargets: HTMLElement[];\n declare readonly hasLabelTarget: boolean;\n declare readonly hasGridTarget: boolean;\n\n declare monthValue: string;\n declare selectedValue: string;\n declare minValue: string;\n declare maxValue: string;\n declare weekStartValue: number;\n\n /** The date currently receiving focus in the grid (local time). */\n focusedDate: Date = new Date();\n\n /**\n * Deferred focus moves scheduled after an asynchronous month transition.\n * Tracked so {@link disconnect} can cancel any pending move and a detached\n * controller never steals focus after the element leaves the DOM (Turbo).\n */\n #focusTimer = new SafeTimeout();\n\n /**\n * The painted month the last `monthchange` reported, or `null` before the first\n * paint. Settling on the initial month — whether it comes from the attribute or\n * is derived here — is the grid describing itself, not a navigation, so it must\n * not reach a listener that refetches inventory or pushes history.\n */\n #announcedMonth: string | null = null;\n\n override connect(): void {\n // Initialize monthValue to current month if not provided\n if (!this.monthValue) {\n const today = new Date();\n const monthStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, \"0\")}`;\n this.monthValue = monthStr;\n return;\n }\n\n this.#initializeFocusedDate();\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.#focusTimer.clearAll();\n }\n\n /**\n * Stimulus lifecycle callback triggered automatically when the monthValue changes.\n * Forces a re-render of the date grid and updates labels.\n */\n monthValueChanged(): void {\n if (!this.monthValue) return;\n this.#syncFocusedDateWithMonth();\n this.render();\n }\n\n /**\n * Stimulus lifecycle callback triggered automatically when the selectedValue changes.\n * Re-renders grid cells to update `aria-selected` indicators.\n */\n selectedValueChanged(): void {\n if (this.selectedValue) {\n const selected = parseISODateString(this.selectedValue);\n if (selected) {\n this.focusedDate = selected;\n }\n }\n this.render();\n }\n\n /** Navigates to the previous month. */\n prev(event?: Event): void {\n if (event) event.preventDefault();\n this.#shiftMonth(-1);\n }\n\n /** Navigates to the next month. */\n next(event?: Event): void {\n if (event) event.preventDefault();\n this.#shiftMonth(1);\n }\n\n /** Handles day selection when a gridcell is clicked. */\n selectByClick(event: MouseEvent): void {\n const dayElement = (event.target as HTMLElement | null)?.closest<HTMLElement>(\n \"[data-stimeo--calendar-target='day']\",\n );\n if (!dayElement) return;\n\n this.selectDayElement(dayElement);\n }\n\n /** Handles grid cell keyboard navigation and triggers selection. */\n onKeydown(event: KeyboardEvent): void {\n // A widget that already claimed the key (a nested control, an enclosing\n // composite) must not ALSO move the roving focus or select a day.\n if (event.defaultPrevented) return;\n if (isReservedArrowChord(event)) return;\n const dayElement = (event.target as HTMLElement | null)?.closest<HTMLElement>(\n \"[data-stimeo--calendar-target='day']\",\n );\n if (!dayElement) return;\n\n // A cell the paint never reached carries no `data-date`, and an empty string\n // parses to null — one exit covers both.\n const date = parseISODateString(dayElement.getAttribute(\"data-date\") ?? \"\");\n if (!date) return;\n\n let handled = true;\n let nextDate = new Date(date);\n\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 nextDate.setDate(nextDate.getDate() - 1);\n break;\n case \"ArrowRight\":\n nextDate.setDate(nextDate.getDate() + 1);\n break;\n case \"ArrowUp\":\n nextDate.setDate(nextDate.getDate() - 7);\n break;\n case \"ArrowDown\":\n nextDate.setDate(nextDate.getDate() + 7);\n break;\n case \"PageUp\":\n if (event.shiftKey) {\n nextDate = this.#calculateShiftedYearDate(date, -1);\n } else {\n nextDate = this.#calculateShiftedMonthDate(date, -1);\n }\n break;\n case \"PageDown\":\n if (event.shiftKey) {\n nextDate = this.#calculateShiftedYearDate(date, 1);\n } else {\n nextDate = this.#calculateShiftedMonthDate(date, 1);\n }\n break;\n case \"Home\":\n nextDate = this.#getStartOfWeekDate(date);\n break;\n case \"End\":\n nextDate = this.#getEndOfWeekDate(date);\n break;\n case \"t\":\n case \"T\": {\n // A single printable key must not be claimed out of a modifier chord:\n // Ctrl/Cmd/Alt+T belongs to the browser, not to the grid.\n if (event.ctrlKey || event.metaKey || event.altKey) {\n handled = false;\n break;\n }\n const now = new Date();\n nextDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n break;\n }\n case \"Enter\":\n case \" \":\n event.preventDefault();\n this.selectDayElement(dayElement);\n return;\n default:\n handled = false;\n break;\n }\n\n if (handled) {\n event.preventDefault();\n this.#focusAndNavigateToDate(nextDate);\n }\n }\n\n /**\n * First day of the month the grid paints: the `month` Value when it parses,\n * otherwise the focused date's month.\n *\n * A malformed `month` falls back instead of stopping the paint: every cell\n * keeps its `aria-selected` and the grid keeps its tab stop, so a Value typo\n * still leaves the grid reachable by Tab and the author can see what they\n * typed. Every consumer of \"which month is on screen\" reads it from here, so\n * the paint and the `monthchange` report cannot name different months.\n */\n #paintedMonthStart(): Date {\n const monthInfo = parseISOMonthString(this.monthValue);\n return monthInfo\n ? new Date(monthInfo.year, monthInfo.month - 1, 1)\n : new Date(this.focusedDate.getFullYear(), this.focusedDate.getMonth(), 1);\n }\n\n /**\n * Renders the grid days and updates the month/year label, then reports the\n * painted month once it differs from the one already announced.\n *\n * The report belongs to the paint, not to the `month` Value: the Value is only\n * one of the things that decide the month on screen. While a malformed `month`\n * falls back, changing `selected` and selecting a neighbouring month's cell\n * move the painted month too, and both repaint from here. Reading the report\n * off the paint keeps the event naming the month the grid shows, in the\n * `YYYY-MM` the detail contract promises, whichever route repainted.\n */\n render(): void {\n const monthStart = this.#paintedMonthStart();\n const year = monthStart.getFullYear();\n const month = monthStart.getMonth() + 1;\n\n // Update label with localized month/year\n if (this.hasLabelTarget) {\n const lang = document.documentElement.lang || \"en\";\n const formatter = new Intl.DateTimeFormat(lang, { month: \"long\", year: \"numeric\" });\n this.labelTarget.textContent = formatter.format(monthStart);\n }\n\n const days = this.#calculateGridDays(year, month);\n const dayElements = this.dayTargets;\n\n // Driven by the dates, so every iteration has one. A short `day` target set\n // is the consumer's markup contradicting the documented 42 cells: paint the\n // ones that exist rather than dropping the grid out of the tab order.\n for (const [index, date] of days.entries()) {\n const el = dayElements[index];\n if (!el) continue;\n\n const dateStr = toISODateString(date);\n // The 42 cells are recycled across months, so an `aria-disabled` the\n // consumer wrote describes the date the cell showed before this paint.\n // Carrying it over would silently disable an unrelated day, so a date change\n // resets the attribute to whatever this render decides below.\n if (el.getAttribute(\"data-date\") !== dateStr) {\n el.removeAttribute(\"aria-disabled\");\n el.removeAttribute(OWNED_DISABLED);\n }\n el.setAttribute(\"data-date\", dateStr);\n el.textContent = String(date.getDate());\n\n // outside current month\n const isOutside = date.getFullYear() !== year || date.getMonth() !== month - 1;\n el.setAttribute(\"data-outside\", String(isOutside));\n\n // today\n const todayStr = toISODateString(new Date());\n el.setAttribute(\"data-today\", String(dateStr === todayStr));\n\n // selection state\n const isSelected = dateStr === this.selectedValue;\n el.setAttribute(\"aria-selected\", String(isSelected));\n\n // roving tabindex\n const isFocused = toISODateString(this.focusedDate) === dateStr;\n el.setAttribute(\"tabindex\", isFocused ? \"0\" : \"-1\");\n\n // min/max limits. Only the value this controller wrote comes back off: a\n // consumer marks holidays and booked days with the same attribute, and\n // clearing it on every paint would silently throw their intent away.\n const isDisabled = this.#isDateOutOfBounds(dateStr);\n if (isDisabled) {\n if (!el.hasAttribute(\"aria-disabled\")) el.setAttribute(OWNED_DISABLED, \"\");\n el.setAttribute(\"aria-disabled\", \"true\");\n } else if (el.hasAttribute(OWNED_DISABLED)) {\n el.removeAttribute(\"aria-disabled\");\n el.removeAttribute(OWNED_DISABLED);\n }\n }\n\n // Roving contract: exactly one focusable cell, always. `focusedDate` can sit\n // outside the rendered range — `selected` names a day in another month, and\n // nothing forces the two Values to agree — in which case no cell matched\n // above and the grid would be unreachable by Tab. Fall back to the first day\n // of the shown month so there is always a way in; arrow navigation reads the\n // date off the focused cell, so it continues from wherever the tab stop is.\n if (!dayElements.some((el) => el.getAttribute(\"tabindex\") === \"0\")) {\n const fallback =\n dayElements.find((el) => el.getAttribute(\"data-outside\") === \"false\") ?? dayElements[0];\n fallback?.setAttribute(\"tabindex\", \"0\");\n }\n\n // Post-paint, so a listener that re-marks holidays and booked days sees the\n // cells of the month it is being told about.\n const painted = toISOMonthString(monthStart);\n const previous = this.#announcedMonth;\n this.#announcedMonth = painted;\n if (previous !== null && previous !== painted) {\n this.dispatch(\"monthchange\", { detail: { month: painted } });\n }\n }\n\n selectDayElement(dayElement: HTMLElement): void {\n if (dayElement.getAttribute(\"aria-disabled\") === \"true\") return;\n\n const dateStr = dayElement.getAttribute(\"data-date\");\n if (!dateStr) return;\n\n this.selectedValue = dateStr;\n // Reflect the selection synchronously (move roving focus to the selected day and\n // repaint aria-selected) instead of waiting on the async value observer, so a\n // click or Enter updates the grid in the same tick — consistent with how the\n // navigation handler re-renders directly. `selectedValueChanged` covers\n // external (consumer-driven) value changes.\n const selected = parseISODateString(dateStr);\n if (selected) this.focusedDate = selected;\n this.render();\n this.dispatch(\"select\", { detail: { date: dateStr } });\n }\n\n #focusAndNavigateToDate(date: Date): void {\n this.focusedDate = date;\n const targetMonthStr = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, \"0\")}`;\n const isMonthTransition = targetMonthStr !== this.monthValue;\n\n if (isMonthTransition) {\n // Automatic month transition: assigning monthValue triggers\n // `monthValueChanged`, which re-renders the grid and keeps the already-set\n // focusedDate (it sits in the target month, so `#syncFocusedDateWithMonth`\n // is a no-op). Do NOT render synchronously here too — that double-renders;\n // focus is deferred below until after that async re-render lands.\n this.monthValue = targetMonthStr;\n } else {\n this.render();\n }\n\n const focusTarget = () => {\n const dateStr = toISODateString(date);\n const targetEl = this.dayTargets.find((el) => el.getAttribute(\"data-date\") === dateStr);\n targetEl?.focus();\n };\n\n if (isMonthTransition) {\n // Defer focus until Stimulus async lifecycle (monthValueChanged) has fully resolved\n this.#focusTimer.set(focusTarget, 0);\n } else {\n focusTarget();\n }\n }\n\n #isDateOutOfBounds(dateStr: string): boolean {\n if (this.minValue && dateStr < this.minValue) return true;\n if (this.maxValue && dateStr > this.maxValue) return true;\n return false;\n }\n\n #shiftMonth(delta: number): void {\n const monthInfo = parseISOMonthString(this.monthValue);\n if (!monthInfo) return;\n\n const nextMonthDate = new Date(monthInfo.year, monthInfo.month - 1 + delta, 1);\n this.monthValue = `${nextMonthDate.getFullYear()}-${String(nextMonthDate.getMonth() + 1).padStart(2, \"0\")}`;\n }\n\n #calculateShiftedMonthDate(baseDate: Date, delta: number): Date {\n const targetDate = new Date(baseDate.getFullYear(), baseDate.getMonth() + delta, 1);\n const lastDayInTarget = new Date(\n targetDate.getFullYear(),\n targetDate.getMonth() + 1,\n 0,\n ).getDate();\n const clampedDay = Math.min(baseDate.getDate(), lastDayInTarget);\n targetDate.setDate(clampedDay);\n return targetDate;\n }\n\n #calculateShiftedYearDate(baseDate: Date, delta: number): Date {\n const targetDate = new Date(baseDate.getFullYear() + delta, baseDate.getMonth(), 1);\n const lastDayInTarget = new Date(\n targetDate.getFullYear(),\n targetDate.getMonth() + 1,\n 0,\n ).getDate();\n const clampedDay = Math.min(baseDate.getDate(), lastDayInTarget);\n targetDate.setDate(clampedDay);\n return targetDate;\n }\n\n #getStartOfWeekDate(date: Date): Date {\n const currentDay = date.getDay();\n const shift = (currentDay - this.weekStartValue + 7) % 7;\n const target = new Date(date);\n target.setDate(date.getDate() - shift);\n return target;\n }\n\n #getEndOfWeekDate(date: Date): Date {\n const start = this.#getStartOfWeekDate(date);\n const target = new Date(start);\n target.setDate(start.getDate() + 6);\n return target;\n }\n\n #initializeFocusedDate(): void {\n if (this.selectedValue) {\n const selected = parseISODateString(this.selectedValue);\n if (selected) {\n this.focusedDate = selected;\n return;\n }\n }\n\n const monthInfo = parseISOMonthString(this.monthValue);\n if (monthInfo) {\n const today = new Date();\n if (today.getFullYear() === monthInfo.year && today.getMonth() === monthInfo.month - 1) {\n this.focusedDate = today;\n } else {\n this.focusedDate = new Date(monthInfo.year, monthInfo.month - 1, 1);\n }\n }\n }\n\n #syncFocusedDateWithMonth(): void {\n const monthInfo = parseISOMonthString(this.monthValue);\n if (!monthInfo) return;\n\n // Only align if focusedDate is outside current monthValue\n if (\n this.focusedDate.getFullYear() !== monthInfo.year ||\n this.focusedDate.getMonth() !== monthInfo.month - 1\n ) {\n const today = new Date();\n if (today.getFullYear() === monthInfo.year && today.getMonth() === monthInfo.month - 1) {\n this.focusedDate = today;\n } else {\n // Keep same day if possible, otherwise clamp to end of target month\n const targetDate = new Date(monthInfo.year, monthInfo.month - 1, 1);\n const lastDayInTarget = new Date(monthInfo.year, monthInfo.month, 0).getDate();\n const clampedDay = Math.min(this.focusedDate.getDate(), lastDayInTarget);\n targetDate.setDate(clampedDay);\n this.focusedDate = targetDate;\n }\n }\n }\n\n #calculateGridDays(year: number, month: number): Date[] {\n const firstDay = new Date(year, month - 1, 1);\n const dayOfWeek = firstDay.getDay();\n\n // calculate offset days based on weekStartValue\n const offset = (dayOfWeek - this.weekStartValue + 7) % 7;\n\n const days: Date[] = [];\n const current = new Date(firstDay);\n current.setDate(firstDay.getDate() - offset);\n\n for (let i = 0; i < 42; i++) {\n days.push(new Date(current));\n current.setDate(current.getDate() + 1);\n }\n\n return days;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/logical_scroll.ts","../../src/utils/arrow_step.ts","../../src/utils/dates.ts","../../src/utils/safe_timeout.ts","../../src/controllers/calendar_controller.ts"],"names":[],"mappings":"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","file":"calendar_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 * 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 * 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","import { Controller } from \"@hotwired/stimulus\";\nimport { isReservedArrowChord, logicalArrowKey } from \"../utils/arrow_step\";\nimport {\n parseISODateString,\n parseISOMonthString,\n toISODateString,\n toISOMonthString,\n} from \"../utils/dates\";\nimport { SafeTimeout } from \"../utils/safe_timeout\";\n\n/**\n * Marks an `aria-disabled` this controller wrote, so a re-paint takes back only\n * its own. A consumer marks holidays and booked days with the same attribute;\n * without the marker a paint would clear their intent.\n *\n * The marker is scoped to the date the cell currently shows, not to the cell: the\n * 42 cells are recycled every month, so a value that outlived its date would\n * disable a different day. A consumer that marks specific dates applies them once\n * for the month the grid opens on, then re-applies after\n * `stimeo--calendar:monthchange`, which reports a move to a different month.\n */\nconst OWNED_DISABLED = \"data-stimeo--calendar-owns-disabled\";\n\n/**\n * Headless, highly accessible calendar grid behavior.\n *\n * Markup contract (identifier: `stimeo--calendar`):\n * <div data-controller=\"stimeo--calendar\"\n * data-stimeo--calendar-month-value=\"2026-05\"\n * data-stimeo--calendar-selected-value=\"2026-05-31\">\n * <button data-action=\"stimeo--calendar#prev\">Previous</button>\n * <span data-stimeo--calendar-target=\"label\">May 2026</span>\n * <button data-action=\"stimeo--calendar#next\">Next</button>\n * <table role=\"grid\">\n * <tbody data-stimeo--calendar-target=\"grid\"\n * data-action=\"keydown->stimeo--calendar#onKeydown\n * click->stimeo--calendar#selectByClick\">\n * <!-- Markup must contain exactly 42 day targets (7 days x 6 rows) -->\n * <tr role=\"row\">\n * <td role=\"gridcell\" data-stimeo--calendar-target=\"day\" tabindex=\"-1\"></td>\n * </tr>\n * </tbody>\n * </table>\n * </div>\n *\n * Implements the WAI-ARIA APG **Date Picker Dialog** grid navigation pattern:\n * - Local-aware month/year labels using native `Intl.DateTimeFormat`.\n * - Roving tabindex focus tracking (exactly one focusable day at any time).\n * - Full grid keyboard controls (arrows, PageUp/Down, Home/End, Shift+PageUp/Down).\n * - Automatic month wrapping and date clamping for missing dates (e.g. leap years, 31st to 30th).\n *\n * `monthchange` dispatches `{ month: string }`; `select` dispatches `{ date: string }`.\n *\n * @remarks\n * Behavior only. The controller updates classes, attributes (aria-selected, data-outside, etc.),\n * and text contents dynamically on 42 pre-allocated `day` targets.\n */\nexport class CalendarController extends Controller<HTMLElement> {\n static override targets = [\"label\", \"grid\", \"day\"];\n static override values = {\n month: { type: String, default: \"\" },\n selected: { type: String, default: \"\" },\n min: { type: String, default: \"\" },\n max: { type: String, default: \"\" },\n weekStart: { type: Number, default: 0 }, // 0 = Sunday, 1 = Monday, etc.\n };\n static actions = [\"next\", \"onKeydown\", \"prev\", \"selectByClick\"] as const;\n static events = [\"monthchange\", \"select\"] as const;\n\n declare readonly labelTarget: HTMLElement;\n declare readonly gridTarget: HTMLElement;\n declare readonly dayTargets: HTMLElement[];\n declare readonly hasLabelTarget: boolean;\n declare readonly hasGridTarget: boolean;\n\n declare monthValue: string;\n declare selectedValue: string;\n declare minValue: string;\n declare maxValue: string;\n declare weekStartValue: number;\n\n /** The date currently receiving focus in the grid (local time). */\n focusedDate: Date = new Date();\n\n /**\n * Deferred focus moves scheduled after an asynchronous month transition.\n * Tracked so {@link disconnect} can cancel any pending move and a detached\n * controller never steals focus after the element leaves the DOM (Turbo).\n */\n #focusTimer = new SafeTimeout();\n\n /**\n * The painted month the last `monthchange` reported, or `null` before the first\n * paint. Settling on the initial month — whether it comes from the attribute or\n * is derived here — is the grid describing itself, not a navigation, so it must\n * not reach a listener that refetches inventory or pushes history.\n */\n #announcedMonth: string | null = null;\n\n override connect(): void {\n // Initialize monthValue to current month if not provided\n if (!this.monthValue) {\n const today = new Date();\n const monthStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, \"0\")}`;\n this.monthValue = monthStr;\n return;\n }\n\n this.#initializeFocusedDate();\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.#focusTimer.clearAll();\n }\n\n /**\n * Stimulus lifecycle callback triggered automatically when the monthValue changes.\n * Forces a re-render of the date grid and updates labels.\n */\n monthValueChanged(): void {\n if (!this.monthValue) return;\n this.#syncFocusedDateWithMonth();\n this.render();\n }\n\n /**\n * Stimulus lifecycle callback triggered automatically when the selectedValue changes.\n * Re-renders grid cells to update `aria-selected` indicators.\n */\n selectedValueChanged(): void {\n if (this.selectedValue) {\n const selected = parseISODateString(this.selectedValue);\n if (selected) {\n this.focusedDate = selected;\n }\n }\n this.render();\n }\n\n /** Navigates to the previous month. */\n prev(event?: Event): void {\n if (event) event.preventDefault();\n this.#shiftMonth(-1);\n }\n\n /** Navigates to the next month. */\n next(event?: Event): void {\n if (event) event.preventDefault();\n this.#shiftMonth(1);\n }\n\n /** Handles day selection when a gridcell is clicked. */\n selectByClick(event: MouseEvent): void {\n const dayElement = (event.target as HTMLElement | null)?.closest<HTMLElement>(\n \"[data-stimeo--calendar-target='day']\",\n );\n if (!dayElement) return;\n\n this.selectDayElement(dayElement);\n }\n\n /** Handles grid cell keyboard navigation and triggers selection. */\n onKeydown(event: KeyboardEvent): void {\n // A widget that already claimed the key (a nested control, an enclosing\n // composite) must not ALSO move the roving focus or select a day.\n if (event.defaultPrevented) return;\n if (isReservedArrowChord(event)) return;\n const dayElement = (event.target as HTMLElement | null)?.closest<HTMLElement>(\n \"[data-stimeo--calendar-target='day']\",\n );\n if (!dayElement) return;\n\n // A cell the paint never reached carries no `data-date`, and an empty string\n // parses to null — one exit covers both.\n const date = parseISODateString(dayElement.getAttribute(\"data-date\") ?? \"\");\n if (!date) return;\n\n let handled = true;\n let nextDate = new Date(date);\n\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 nextDate.setDate(nextDate.getDate() - 1);\n break;\n case \"ArrowRight\":\n nextDate.setDate(nextDate.getDate() + 1);\n break;\n case \"ArrowUp\":\n nextDate.setDate(nextDate.getDate() - 7);\n break;\n case \"ArrowDown\":\n nextDate.setDate(nextDate.getDate() + 7);\n break;\n case \"PageUp\":\n if (event.shiftKey) {\n nextDate = this.#calculateShiftedYearDate(date, -1);\n } else {\n nextDate = this.#calculateShiftedMonthDate(date, -1);\n }\n break;\n case \"PageDown\":\n if (event.shiftKey) {\n nextDate = this.#calculateShiftedYearDate(date, 1);\n } else {\n nextDate = this.#calculateShiftedMonthDate(date, 1);\n }\n break;\n case \"Home\":\n nextDate = this.#getStartOfWeekDate(date);\n break;\n case \"End\":\n nextDate = this.#getEndOfWeekDate(date);\n break;\n case \"t\":\n case \"T\": {\n // A single printable key must not be claimed out of a modifier chord:\n // Ctrl/Cmd/Alt+T belongs to the browser, not to the grid.\n if (event.ctrlKey || event.metaKey || event.altKey) {\n handled = false;\n break;\n }\n const now = new Date();\n nextDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n break;\n }\n case \"Enter\":\n case \" \":\n event.preventDefault();\n this.selectDayElement(dayElement);\n return;\n default:\n handled = false;\n break;\n }\n\n if (handled) {\n event.preventDefault();\n this.#focusAndNavigateToDate(nextDate);\n }\n }\n\n /**\n * First day of the month the grid paints: the `month` Value when it parses,\n * otherwise the focused date's month.\n *\n * A malformed `month` falls back instead of stopping the paint: every cell\n * keeps its `aria-selected` and the grid keeps its tab stop, so a Value typo\n * still leaves the grid reachable by Tab and the author can see what they\n * typed. Every consumer of \"which month is on screen\" reads it from here, so\n * the paint and the `monthchange` report cannot name different months.\n */\n #paintedMonthStart(): Date {\n const monthInfo = parseISOMonthString(this.monthValue);\n return monthInfo\n ? new Date(monthInfo.year, monthInfo.month - 1, 1)\n : new Date(this.focusedDate.getFullYear(), this.focusedDate.getMonth(), 1);\n }\n\n /**\n * Renders the grid days and updates the month/year label, then reports the\n * painted month once it differs from the one already announced.\n *\n * The report belongs to the paint, not to the `month` Value: the Value is only\n * one of the things that decide the month on screen. While a malformed `month`\n * falls back, changing `selected` and selecting a neighbouring month's cell\n * move the painted month too, and both repaint from here. Reading the report\n * off the paint keeps the event naming the month the grid shows, in the\n * `YYYY-MM` the detail contract promises, whichever route repainted.\n */\n render(): void {\n const monthStart = this.#paintedMonthStart();\n const year = monthStart.getFullYear();\n const month = monthStart.getMonth() + 1;\n\n // Update label with localized month/year\n if (this.hasLabelTarget) {\n const lang = document.documentElement.lang || \"en\";\n const formatter = new Intl.DateTimeFormat(lang, { month: \"long\", year: \"numeric\" });\n this.labelTarget.textContent = formatter.format(monthStart);\n }\n\n const days = this.#calculateGridDays(year, month);\n const dayElements = this.dayTargets;\n\n // Driven by the dates, so every iteration has one. A short `day` target set\n // is the consumer's markup contradicting the documented 42 cells: paint the\n // ones that exist rather than dropping the grid out of the tab order.\n for (const [index, date] of days.entries()) {\n const el = dayElements[index];\n if (!el) continue;\n\n const dateStr = toISODateString(date);\n // The 42 cells are recycled across months, so an `aria-disabled` the\n // consumer wrote describes the date the cell showed before this paint.\n // Carrying it over would silently disable an unrelated day, so a date change\n // resets the attribute to whatever this render decides below.\n if (el.getAttribute(\"data-date\") !== dateStr) {\n el.removeAttribute(\"aria-disabled\");\n el.removeAttribute(OWNED_DISABLED);\n }\n el.setAttribute(\"data-date\", dateStr);\n el.textContent = String(date.getDate());\n\n // outside current month\n const isOutside = date.getFullYear() !== year || date.getMonth() !== month - 1;\n el.setAttribute(\"data-outside\", String(isOutside));\n\n // today\n const todayStr = toISODateString(new Date());\n el.setAttribute(\"data-today\", String(dateStr === todayStr));\n\n // selection state\n const isSelected = dateStr === this.selectedValue;\n el.setAttribute(\"aria-selected\", String(isSelected));\n\n // roving tabindex\n const isFocused = toISODateString(this.focusedDate) === dateStr;\n el.setAttribute(\"tabindex\", isFocused ? \"0\" : \"-1\");\n\n // min/max limits. Only the value this controller wrote comes back off: a\n // consumer marks holidays and booked days with the same attribute, and\n // clearing it on every paint would silently throw their intent away.\n const isDisabled = this.#isDateOutOfBounds(dateStr);\n if (isDisabled) {\n if (!el.hasAttribute(\"aria-disabled\")) el.setAttribute(OWNED_DISABLED, \"\");\n el.setAttribute(\"aria-disabled\", \"true\");\n } else if (el.hasAttribute(OWNED_DISABLED)) {\n el.removeAttribute(\"aria-disabled\");\n el.removeAttribute(OWNED_DISABLED);\n }\n }\n\n // Roving contract: exactly one focusable cell, always. `focusedDate` can sit\n // outside the rendered range — `selected` names a day in another month, and\n // nothing forces the two Values to agree — in which case no cell matched\n // above and the grid would be unreachable by Tab. Fall back to the first day\n // of the shown month so there is always a way in; arrow navigation reads the\n // date off the focused cell, so it continues from wherever the tab stop is.\n if (!dayElements.some((el) => el.getAttribute(\"tabindex\") === \"0\")) {\n const fallback =\n dayElements.find((el) => el.getAttribute(\"data-outside\") === \"false\") ?? dayElements[0];\n fallback?.setAttribute(\"tabindex\", \"0\");\n }\n\n // Post-paint, so a listener that re-marks holidays and booked days sees the\n // cells of the month it is being told about.\n const painted = toISOMonthString(monthStart);\n const previous = this.#announcedMonth;\n this.#announcedMonth = painted;\n if (previous !== null && previous !== painted) {\n this.dispatch(\"monthchange\", { detail: { month: painted } });\n }\n }\n\n selectDayElement(dayElement: HTMLElement): void {\n if (dayElement.getAttribute(\"aria-disabled\") === \"true\") return;\n\n const dateStr = dayElement.getAttribute(\"data-date\");\n if (!dateStr) return;\n\n this.selectedValue = dateStr;\n // Reflect the selection synchronously (move roving focus to the selected day and\n // repaint aria-selected) instead of waiting on the async value observer, so a\n // click or Enter updates the grid in the same tick — consistent with how the\n // navigation handler re-renders directly. `selectedValueChanged` covers\n // external (consumer-driven) value changes.\n const selected = parseISODateString(dateStr);\n if (selected) this.focusedDate = selected;\n this.render();\n this.dispatch(\"select\", { detail: { date: dateStr } });\n }\n\n #focusAndNavigateToDate(date: Date): void {\n this.focusedDate = date;\n const targetMonthStr = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, \"0\")}`;\n const isMonthTransition = targetMonthStr !== this.monthValue;\n\n if (isMonthTransition) {\n // Automatic month transition: assigning monthValue triggers\n // `monthValueChanged`, which re-renders the grid and keeps the already-set\n // focusedDate (it sits in the target month, so `#syncFocusedDateWithMonth`\n // is a no-op). Do NOT render synchronously here too — that double-renders;\n // focus is deferred below until after that async re-render lands.\n this.monthValue = targetMonthStr;\n } else {\n this.render();\n }\n\n const focusTarget = () => {\n const dateStr = toISODateString(date);\n const targetEl = this.dayTargets.find((el) => el.getAttribute(\"data-date\") === dateStr);\n targetEl?.focus();\n };\n\n if (isMonthTransition) {\n // Defer focus until Stimulus async lifecycle (monthValueChanged) has fully resolved\n this.#focusTimer.set(focusTarget, 0);\n } else {\n focusTarget();\n }\n }\n\n #isDateOutOfBounds(dateStr: string): boolean {\n if (this.minValue && dateStr < this.minValue) return true;\n if (this.maxValue && dateStr > this.maxValue) return true;\n return false;\n }\n\n #shiftMonth(delta: number): void {\n const monthInfo = parseISOMonthString(this.monthValue);\n if (!monthInfo) return;\n\n const nextMonthDate = new Date(monthInfo.year, monthInfo.month - 1 + delta, 1);\n this.monthValue = `${nextMonthDate.getFullYear()}-${String(nextMonthDate.getMonth() + 1).padStart(2, \"0\")}`;\n }\n\n #calculateShiftedMonthDate(baseDate: Date, delta: number): Date {\n const targetDate = new Date(baseDate.getFullYear(), baseDate.getMonth() + delta, 1);\n const lastDayInTarget = new Date(\n targetDate.getFullYear(),\n targetDate.getMonth() + 1,\n 0,\n ).getDate();\n const clampedDay = Math.min(baseDate.getDate(), lastDayInTarget);\n targetDate.setDate(clampedDay);\n return targetDate;\n }\n\n #calculateShiftedYearDate(baseDate: Date, delta: number): Date {\n const targetDate = new Date(baseDate.getFullYear() + delta, baseDate.getMonth(), 1);\n const lastDayInTarget = new Date(\n targetDate.getFullYear(),\n targetDate.getMonth() + 1,\n 0,\n ).getDate();\n const clampedDay = Math.min(baseDate.getDate(), lastDayInTarget);\n targetDate.setDate(clampedDay);\n return targetDate;\n }\n\n #getStartOfWeekDate(date: Date): Date {\n const currentDay = date.getDay();\n const shift = (currentDay - this.weekStartValue + 7) % 7;\n const target = new Date(date);\n target.setDate(date.getDate() - shift);\n return target;\n }\n\n #getEndOfWeekDate(date: Date): Date {\n const start = this.#getStartOfWeekDate(date);\n const target = new Date(start);\n target.setDate(start.getDate() + 6);\n return target;\n }\n\n #initializeFocusedDate(): void {\n if (this.selectedValue) {\n const selected = parseISODateString(this.selectedValue);\n if (selected) {\n this.focusedDate = selected;\n return;\n }\n }\n\n const monthInfo = parseISOMonthString(this.monthValue);\n if (monthInfo) {\n const today = new Date();\n if (today.getFullYear() === monthInfo.year && today.getMonth() === monthInfo.month - 1) {\n this.focusedDate = today;\n } else {\n this.focusedDate = new Date(monthInfo.year, monthInfo.month - 1, 1);\n }\n }\n }\n\n #syncFocusedDateWithMonth(): void {\n const monthInfo = parseISOMonthString(this.monthValue);\n if (!monthInfo) return;\n\n // Only align if focusedDate is outside current monthValue\n if (\n this.focusedDate.getFullYear() !== monthInfo.year ||\n this.focusedDate.getMonth() !== monthInfo.month - 1\n ) {\n const today = new Date();\n if (today.getFullYear() === monthInfo.year && today.getMonth() === monthInfo.month - 1) {\n this.focusedDate = today;\n } else {\n // Keep same day if possible, otherwise clamp to end of target month\n const targetDate = new Date(monthInfo.year, monthInfo.month - 1, 1);\n const lastDayInTarget = new Date(monthInfo.year, monthInfo.month, 0).getDate();\n const clampedDay = Math.min(this.focusedDate.getDate(), lastDayInTarget);\n targetDate.setDate(clampedDay);\n this.focusedDate = targetDate;\n }\n }\n }\n\n #calculateGridDays(year: number, month: number): Date[] {\n const firstDay = new Date(year, month - 1, 1);\n const dayOfWeek = firstDay.getDay();\n\n // calculate offset days based on weekStartValue\n const offset = (dayOfWeek - this.weekStartValue + 7) % 7;\n\n const days: Date[] = [];\n const current = new Date(firstDay);\n current.setDate(firstDay.getDate() - offset);\n\n for (let i = 0; i < 42; i++) {\n days.push(new Date(current));\n current.setDate(current.getDate() + 1);\n }\n\n return days;\n }\n}\n"]}
|
|
@@ -8,43 +8,56 @@ import { Controller } from '@hotwired/stimulus';
|
|
|
8
8
|
* aria-label="Featured"
|
|
9
9
|
* data-stimeo--carousel-autoplay-value="false"
|
|
10
10
|
* data-stimeo--carousel-interval-value="5000"
|
|
11
|
-
* data-stimeo--carousel-loop-value="true"
|
|
12
|
-
*
|
|
13
|
-
* mouseleave->stimeo--carousel#resume
|
|
14
|
-
* focusin->stimeo--carousel#pause
|
|
15
|
-
* focusout->stimeo--carousel#resume">
|
|
16
|
-
* <button data-stimeo--carousel-target="playToggle"
|
|
17
|
-
* data-action="stimeo--carousel#togglePlay">…</button>
|
|
11
|
+
* data-stimeo--carousel-loop-value="true">
|
|
12
|
+
* <button data-stimeo--carousel-target="playToggle">…</button>
|
|
18
13
|
* <div data-stimeo--carousel-target="viewport">
|
|
19
14
|
* <div role="tabpanel" data-stimeo--carousel-target="slide">…</div>
|
|
20
|
-
* <div role="tabpanel" data-stimeo--carousel-target="slide" hidden>…</div>
|
|
15
|
+
* <div role="tabpanel" data-stimeo--carousel-target="slide" hidden inert>…</div>
|
|
21
16
|
* </div>
|
|
22
|
-
* <button data-stimeo--carousel-target="prev"
|
|
23
|
-
* <button data-stimeo--carousel-target="next"
|
|
17
|
+
* <button data-stimeo--carousel-target="prev">‹</button>
|
|
18
|
+
* <button data-stimeo--carousel-target="next">›</button>
|
|
24
19
|
* <div role="tablist">
|
|
25
|
-
* <button role="tab" data-stimeo--carousel-target="picker"
|
|
26
|
-
* data-action="stimeo--carousel#goto
|
|
27
|
-
* keydown->stimeo--carousel#onPickerKeydown"></button>
|
|
20
|
+
* <button role="tab" data-stimeo--carousel-target="picker"></button>
|
|
28
21
|
* </div>
|
|
29
22
|
* </section>
|
|
30
23
|
*
|
|
31
|
-
* Implements the WAI-ARIA APG **Carousel**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* `
|
|
35
|
-
* `
|
|
24
|
+
* Implements the WAI-ARIA APG **Carousel** pattern. With pickers it is the tabbed
|
|
25
|
+
* variant: each picker is a `tab` carrying `aria-selected` and the single roving
|
|
26
|
+
* `tabindex`, and each slide is its `tabpanel`. Without pickers the slides are
|
|
27
|
+
* `group`s and `prev`/`next` drive them. The current slide is exposed through
|
|
28
|
+
* `data-state` (`active`/`inactive`); the rest carry `hidden` **and** `inert`, so
|
|
29
|
+
* they stay out of the focus order and the accessibility tree even when consumer
|
|
30
|
+
* CSS overrides `display` to lay the slides out as a track.
|
|
36
31
|
*
|
|
37
32
|
* @remarks
|
|
38
33
|
* Behavior only — transitions, layout, and visuals are the consumer's CSS.
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* the
|
|
34
|
+
*
|
|
35
|
+
* **The controller owns its own wiring.** Clicks, picker keys, hover, and focus
|
|
36
|
+
* are delegated from the controller element, so no `data-action` is required and
|
|
37
|
+
* a target added at runtime works the moment it appears. Explicit `data-action`
|
|
38
|
+
* bindings to the declared actions still work and coexist with the delegated
|
|
39
|
+
* path: the binding runs first and marks the event, and the delegated listener
|
|
40
|
+
* stands down, so one interaction is never handled twice.
|
|
41
|
+
*
|
|
42
|
+
* **`autoplay` is the single source of truth for the rotation intent.** The
|
|
43
|
+
* toggle writes back to it, so the state survives a Turbo Drive cache restore
|
|
44
|
+
* without a second, competing signal; `aria-pressed` is a pure output the
|
|
45
|
+
* controller owns. Rotation is suspended — not cancelled — while the pointer
|
|
46
|
+
* rests on the carousel, while focus is inside it, and while the tab is hidden;
|
|
47
|
+
* each suspension lifts on its own (WCAG 2.2.2 is met by the toggle, which is
|
|
48
|
+
* the one control that stops rotation for good). A carousel with nothing left to
|
|
49
|
+
* advance to (one slide, or the last slide of a non-looping set) normalizes
|
|
50
|
+
* `autoplay` to `false` and marks the toggle `aria-disabled`. `prefers-reduced-motion`
|
|
51
|
+
* does the same at connect, leaving an explicit press free to start rotation.
|
|
52
|
+
*
|
|
53
|
+
* The interval is cleared on `disconnect()` (Turbo navigation included), and the
|
|
54
|
+
* leased ARIA is returned before Turbo caches the page. Picker arrow keys, `Home`,
|
|
55
|
+
* and `End` move focus only (manual activation); slide changes never steal focus
|
|
56
|
+
* from the control the user operated. A slide change the user drove — including an
|
|
57
|
+
* autoplay tick they started — is reported as `stimeo--carousel:change` with
|
|
58
|
+
* `{ index, total }`; the same detail arrives as `stimeo--carousel:reconcile` when
|
|
59
|
+
* the controller re-derives the position itself, whether a target came or went or
|
|
60
|
+
* a retained element's state attributes were rewritten in place.
|
|
48
61
|
*/
|
|
49
62
|
declare class CarouselController extends Controller<HTMLElement> {
|
|
50
63
|
#private;
|
|
@@ -67,18 +80,27 @@ declare class CarouselController extends Controller<HTMLElement> {
|
|
|
67
80
|
static events: readonly ["change", "pause", "play", "reconcile"];
|
|
68
81
|
readonly slideTargets: HTMLElement[];
|
|
69
82
|
readonly pickerTargets: HTMLElement[];
|
|
70
|
-
readonly
|
|
71
|
-
readonly
|
|
83
|
+
readonly viewportTarget: HTMLElement;
|
|
84
|
+
readonly hasViewportTarget: boolean;
|
|
85
|
+
readonly prevTargets: HTMLElement[];
|
|
86
|
+
readonly nextTargets: HTMLElement[];
|
|
87
|
+
readonly playToggleTargets: HTMLElement[];
|
|
72
88
|
autoplayValue: boolean;
|
|
73
89
|
intervalValue: number;
|
|
74
90
|
loopValue: boolean;
|
|
75
91
|
/**
|
|
76
|
-
* Renders the initial slide and starts autoplay
|
|
92
|
+
* Renders the initial slide, wires the delegated listeners, and starts autoplay
|
|
93
|
+
* when requested.
|
|
77
94
|
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
95
|
+
* Every suspension is re-derived from the environment rather than carried, so an
|
|
96
|
+
* in-page move — which Stimulus delivers to the *same* controller instance as
|
|
97
|
+
* `disconnect()` then `connect()` — cannot strand the carousel in a suspension
|
|
98
|
+
* whose lifting event will never arrive. The attribute observer starts after the
|
|
99
|
+
* first render so the controller's own opening writes are not fed back to it.
|
|
80
100
|
*/
|
|
81
101
|
connect(): void;
|
|
102
|
+
/** Releases every listener and observer, returns the leased ARIA, drops the suspensions. */
|
|
103
|
+
disconnect(): void;
|
|
82
104
|
/**
|
|
83
105
|
* Re-establishes the single selected picker when one is added after connect.
|
|
84
106
|
*
|
|
@@ -95,29 +117,41 @@ declare class CarouselController extends Controller<HTMLElement> {
|
|
|
95
117
|
slideTargetConnected(): void;
|
|
96
118
|
/** Re-clamps the active index after a slide is removed. */
|
|
97
119
|
slideTargetDisconnected(): void;
|
|
98
|
-
/**
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
|
|
120
|
+
/** Follows a rotation intent the page changed at runtime. */
|
|
121
|
+
autoplayValueChanged(): void;
|
|
122
|
+
/** Re-arms the live interval at the new delay without reporting a state change. */
|
|
123
|
+
intervalValueChanged(): void;
|
|
124
|
+
/** Re-publishes the step controls and re-evaluates the non-looping end. */
|
|
125
|
+
loopValueChanged(): void;
|
|
126
|
+
/** Advances to the next slide. Delegated; `data-action` wiring is optional. */
|
|
127
|
+
next(event?: Event): void;
|
|
128
|
+
/** Returns to the previous slide. Delegated; `data-action` wiring is optional. */
|
|
129
|
+
prev(event?: Event): void;
|
|
104
130
|
/** Jumps to the slide whose picker was activated (click / Enter / Space). */
|
|
105
131
|
goto(event: Event): void;
|
|
106
|
-
/** Toggles autoplay on the user's explicit request and syncs the timer. */
|
|
107
|
-
togglePlay(): void;
|
|
108
132
|
/**
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
133
|
+
* Flips the rotation intent on the user's explicit request.
|
|
134
|
+
*
|
|
135
|
+
* The intent is written back to the `autoplay` Value, which is where every other
|
|
136
|
+
* path reads it from. A carousel with nothing to advance to has no intent to
|
|
137
|
+
* flip: the toggle is marked `aria-disabled` and does nothing.
|
|
138
|
+
*/
|
|
139
|
+
togglePlay(event?: Event): void;
|
|
140
|
+
/**
|
|
141
|
+
* Suspends rotation. A `focus`-family event records that focus is inside the
|
|
142
|
+
* carousel; anything else — hover, or a bare programmatic call — records the
|
|
143
|
+
* pointer suspension. Both lift through the matching {@link resume}, and
|
|
144
|
+
* neither touches the rotation intent.
|
|
112
145
|
*/
|
|
113
146
|
pause(event?: Event): void;
|
|
114
147
|
/**
|
|
115
|
-
* Lifts
|
|
116
|
-
*
|
|
117
|
-
*
|
|
148
|
+
* Lifts the matching suspension. A `focusout` whose `relatedTarget` is still
|
|
149
|
+
* inside the carousel is focus moving between its own controls, which leaves the
|
|
150
|
+
* focus suspension in place — releasing it there would stop and restart the
|
|
151
|
+
* interval on every Tab press.
|
|
118
152
|
*/
|
|
119
153
|
resume(event?: Event): void;
|
|
120
|
-
/** Picker roving
|
|
154
|
+
/** Picker roving for authored bindings; the delegated path is `#onKeydown`. */
|
|
121
155
|
onPickerKeydown(event: KeyboardEvent): void;
|
|
122
156
|
}
|
|
123
157
|
|