stimeo-ui 0.6.0 → 0.7.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.
Files changed (199) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/dist/controllers/alert_dialog_controller.d.ts +2 -0
  3. package/dist/controllers/alert_dialog_controller.js +75 -4
  4. package/dist/controllers/alert_dialog_controller.js.map +1 -1
  5. package/dist/controllers/auto_submit_controller.d.ts +2 -0
  6. package/dist/controllers/auto_submit_controller.js.map +1 -1
  7. package/dist/controllers/avatar_controller.js +47 -5
  8. package/dist/controllers/avatar_controller.js.map +1 -1
  9. package/dist/controllers/breadcrumb_controller.d.ts +2 -0
  10. package/dist/controllers/breadcrumb_controller.js.map +1 -1
  11. package/dist/controllers/bulk_select_controller.d.ts +2 -0
  12. package/dist/controllers/bulk_select_controller.js.map +1 -1
  13. package/dist/controllers/calendar_controller.d.ts +2 -0
  14. package/dist/controllers/calendar_controller.js.map +1 -1
  15. package/dist/controllers/character_counter_controller.d.ts +52 -20
  16. package/dist/controllers/character_counter_controller.js +338 -63
  17. package/dist/controllers/character_counter_controller.js.map +1 -1
  18. package/dist/controllers/checkbox_controller.d.ts +3 -0
  19. package/dist/controllers/checkbox_controller.js.map +1 -1
  20. package/dist/controllers/color_picker_controller.d.ts +3 -0
  21. package/dist/controllers/color_picker_controller.js.map +1 -1
  22. package/dist/controllers/combobox_controller.d.ts +2 -0
  23. package/dist/controllers/combobox_controller.js.map +1 -1
  24. package/dist/controllers/command_palette_controller.d.ts +2 -0
  25. package/dist/controllers/command_palette_controller.js +75 -4
  26. package/dist/controllers/command_palette_controller.js.map +1 -1
  27. package/dist/controllers/conditional_fields_controller.d.ts +42 -14
  28. package/dist/controllers/conditional_fields_controller.js +345 -51
  29. package/dist/controllers/conditional_fields_controller.js.map +1 -1
  30. package/dist/controllers/confirm_controller.d.ts +2 -0
  31. package/dist/controllers/confirm_controller.js +75 -4
  32. package/dist/controllers/confirm_controller.js.map +1 -1
  33. package/dist/controllers/count_up_controller.d.ts +2 -0
  34. package/dist/controllers/count_up_controller.js.map +1 -1
  35. package/dist/controllers/countdown_controller.d.ts +4 -0
  36. package/dist/controllers/countdown_controller.js.map +1 -1
  37. package/dist/controllers/currency_input_controller.d.ts +2 -0
  38. package/dist/controllers/currency_input_controller.js.map +1 -1
  39. package/dist/controllers/data_grid_controller.d.ts +3 -0
  40. package/dist/controllers/data_grid_controller.js.map +1 -1
  41. package/dist/controllers/dialog_controller.js +75 -4
  42. package/dist/controllers/dialog_controller.js.map +1 -1
  43. package/dist/controllers/direct_upload_controller.d.ts +56 -24
  44. package/dist/controllers/direct_upload_controller.js +201 -45
  45. package/dist/controllers/direct_upload_controller.js.map +1 -1
  46. package/dist/controllers/dirty_form_controller.d.ts +14 -6
  47. package/dist/controllers/dirty_form_controller.js +192 -29
  48. package/dist/controllers/dirty_form_controller.js.map +1 -1
  49. package/dist/controllers/dismissible_controller.d.ts +2 -0
  50. package/dist/controllers/dismissible_controller.js +83 -18
  51. package/dist/controllers/dismissible_controller.js.map +1 -1
  52. package/dist/controllers/drawer_controller.js +75 -4
  53. package/dist/controllers/drawer_controller.js.map +1 -1
  54. package/dist/controllers/empty_state_controller.d.ts +2 -0
  55. package/dist/controllers/empty_state_controller.js.map +1 -1
  56. package/dist/controllers/file_dropzone_controller.d.ts +2 -0
  57. package/dist/controllers/file_dropzone_controller.js.map +1 -1
  58. package/dist/controllers/filter_controller.d.ts +2 -0
  59. package/dist/controllers/filter_controller.js.map +1 -1
  60. package/dist/controllers/flash_controller.d.ts +4 -0
  61. package/dist/controllers/flash_controller.js.map +1 -1
  62. package/dist/controllers/focus_controller.d.ts +2 -0
  63. package/dist/controllers/focus_controller.js +75 -4
  64. package/dist/controllers/focus_controller.js.map +1 -1
  65. package/dist/controllers/form_field_controller.d.ts +50 -10
  66. package/dist/controllers/form_field_controller.js +280 -62
  67. package/dist/controllers/form_field_controller.js.map +1 -1
  68. package/dist/controllers/form_validation_controller.d.ts +10 -8
  69. package/dist/controllers/form_validation_controller.js +208 -83
  70. package/dist/controllers/form_validation_controller.js.map +1 -1
  71. package/dist/controllers/frame_loading_controller.d.ts +2 -0
  72. package/dist/controllers/frame_loading_controller.js.map +1 -1
  73. package/dist/controllers/highlight_controller.d.ts +2 -0
  74. package/dist/controllers/highlight_controller.js.map +1 -1
  75. package/dist/controllers/idle_controller.d.ts +2 -0
  76. package/dist/controllers/idle_controller.js.map +1 -1
  77. package/dist/controllers/input_mask_controller.d.ts +2 -0
  78. package/dist/controllers/input_mask_controller.js.map +1 -1
  79. package/dist/controllers/lazy_frame_controller.d.ts +2 -0
  80. package/dist/controllers/lazy_frame_controller.js.map +1 -1
  81. package/dist/controllers/listbox_controller.d.ts +2 -0
  82. package/dist/controllers/listbox_controller.js.map +1 -1
  83. package/dist/controllers/local_time_controller.d.ts +2 -0
  84. package/dist/controllers/local_time_controller.js.map +1 -1
  85. package/dist/controllers/masonry_controller.d.ts +2 -0
  86. package/dist/controllers/masonry_controller.js.map +1 -1
  87. package/dist/controllers/meter_controller.d.ts +2 -0
  88. package/dist/controllers/meter_controller.js.map +1 -1
  89. package/dist/controllers/multi_select_controller.d.ts +2 -0
  90. package/dist/controllers/multi_select_controller.js.map +1 -1
  91. package/dist/controllers/nested_form_controller.d.ts +2 -0
  92. package/dist/controllers/nested_form_controller.js.map +1 -1
  93. package/dist/controllers/network_status_controller.d.ts +2 -0
  94. package/dist/controllers/network_status_controller.js.map +1 -1
  95. package/dist/controllers/number_input_controller.d.ts +2 -0
  96. package/dist/controllers/number_input_controller.js +47 -5
  97. package/dist/controllers/number_input_controller.js.map +1 -1
  98. package/dist/controllers/otp_controller.d.ts +3 -0
  99. package/dist/controllers/otp_controller.js.map +1 -1
  100. package/dist/controllers/overflow_indicator_controller.d.ts +2 -0
  101. package/dist/controllers/overflow_indicator_controller.js.map +1 -1
  102. package/dist/controllers/overflow_menu_controller.d.ts +2 -0
  103. package/dist/controllers/overflow_menu_controller.js +2 -1
  104. package/dist/controllers/overflow_menu_controller.js.map +1 -1
  105. package/dist/controllers/pagination_controller.d.ts +2 -0
  106. package/dist/controllers/pagination_controller.js +2 -1
  107. package/dist/controllers/pagination_controller.js.map +1 -1
  108. package/dist/controllers/password_reveal_controller.d.ts +2 -0
  109. package/dist/controllers/password_reveal_controller.js.map +1 -1
  110. package/dist/controllers/password_strength_controller.d.ts +2 -0
  111. package/dist/controllers/password_strength_controller.js.map +1 -1
  112. package/dist/controllers/persist_controller.d.ts +30 -16
  113. package/dist/controllers/persist_controller.js +432 -122
  114. package/dist/controllers/persist_controller.js.map +1 -1
  115. package/dist/controllers/pointer_drag_controller.d.ts +3 -0
  116. package/dist/controllers/pointer_drag_controller.js.map +1 -1
  117. package/dist/controllers/popover_controller.js +77 -4
  118. package/dist/controllers/popover_controller.js.map +1 -1
  119. package/dist/controllers/portal_controller.d.ts +2 -0
  120. package/dist/controllers/portal_controller.js.map +1 -1
  121. package/dist/controllers/preview_guard_controller.d.ts +2 -0
  122. package/dist/controllers/preview_guard_controller.js.map +1 -1
  123. package/dist/controllers/progress_controller.d.ts +3 -0
  124. package/dist/controllers/progress_controller.js.map +1 -1
  125. package/dist/controllers/radio_group_controller.d.ts +3 -0
  126. package/dist/controllers/radio_group_controller.js.map +1 -1
  127. package/dist/controllers/rating_controller.d.ts +2 -0
  128. package/dist/controllers/rating_controller.js +9 -5
  129. package/dist/controllers/rating_controller.js.map +1 -1
  130. package/dist/controllers/reading_progress_controller.d.ts +2 -0
  131. package/dist/controllers/reading_progress_controller.js.map +1 -1
  132. package/dist/controllers/resizable_controller.d.ts +2 -0
  133. package/dist/controllers/resizable_controller.js.map +1 -1
  134. package/dist/controllers/roving_controller.d.ts +2 -0
  135. package/dist/controllers/roving_controller.js.map +1 -1
  136. package/dist/controllers/scroll_area_controller.d.ts +23 -15
  137. package/dist/controllers/scroll_area_controller.js +462 -162
  138. package/dist/controllers/scroll_area_controller.js.map +1 -1
  139. package/dist/controllers/scroll_visibility_controller.d.ts +2 -0
  140. package/dist/controllers/scroll_visibility_controller.js.map +1 -1
  141. package/dist/controllers/scrollspy_controller.d.ts +2 -0
  142. package/dist/controllers/scrollspy_controller.js.map +1 -1
  143. package/dist/controllers/separator_controller.d.ts +54 -11
  144. package/dist/controllers/separator_controller.js +354 -38
  145. package/dist/controllers/separator_controller.js.map +1 -1
  146. package/dist/controllers/sidebar_controller.js +83 -10
  147. package/dist/controllers/sidebar_controller.js.map +1 -1
  148. package/dist/controllers/skeleton_controller.d.ts +2 -0
  149. package/dist/controllers/skeleton_controller.js.map +1 -1
  150. package/dist/controllers/slider_controller.d.ts +2 -0
  151. package/dist/controllers/slider_controller.js.map +1 -1
  152. package/dist/controllers/smart_sticky_header_controller.d.ts +2 -0
  153. package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
  154. package/dist/controllers/spinner_controller.d.ts +2 -0
  155. package/dist/controllers/spinner_controller.js.map +1 -1
  156. package/dist/controllers/step_indicator_controller.d.ts +2 -0
  157. package/dist/controllers/step_indicator_controller.js.map +1 -1
  158. package/dist/controllers/stepper_controller.d.ts +2 -0
  159. package/dist/controllers/stepper_controller.js.map +1 -1
  160. package/dist/controllers/stick_to_bottom_controller.d.ts +2 -0
  161. package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
  162. package/dist/controllers/sticky_observer_controller.d.ts +2 -0
  163. package/dist/controllers/sticky_observer_controller.js.map +1 -1
  164. package/dist/controllers/submit_once_controller.d.ts +94 -38
  165. package/dist/controllers/submit_once_controller.js +399 -121
  166. package/dist/controllers/submit_once_controller.js.map +1 -1
  167. package/dist/controllers/switch_controller.d.ts +2 -0
  168. package/dist/controllers/switch_controller.js.map +1 -1
  169. package/dist/controllers/tags_input_controller.d.ts +2 -0
  170. package/dist/controllers/tags_input_controller.js.map +1 -1
  171. package/dist/controllers/textarea_autosize_controller.d.ts +2 -0
  172. package/dist/controllers/textarea_autosize_controller.js.map +1 -1
  173. package/dist/controllers/theme_controller.d.ts +2 -0
  174. package/dist/controllers/theme_controller.js +8 -6
  175. package/dist/controllers/theme_controller.js.map +1 -1
  176. package/dist/controllers/time_picker_controller.d.ts +2 -0
  177. package/dist/controllers/time_picker_controller.js.map +1 -1
  178. package/dist/controllers/toast_controller.d.ts +4 -0
  179. package/dist/controllers/toast_controller.js.map +1 -1
  180. package/dist/controllers/toggle_group_controller.d.ts +2 -0
  181. package/dist/controllers/toggle_group_controller.js.map +1 -1
  182. package/dist/controllers/toolbar_controller.js.map +1 -1
  183. package/dist/controllers/transition_controller.d.ts +2 -0
  184. package/dist/controllers/transition_controller.js.map +1 -1
  185. package/dist/controllers/tree_view_controller.d.ts +2 -0
  186. package/dist/controllers/tree_view_controller.js +2 -1
  187. package/dist/controllers/tree_view_controller.js.map +1 -1
  188. package/dist/index.js +2387 -861
  189. package/dist/index.js.map +1 -1
  190. package/dist/inspector/cli.d.ts +107 -3
  191. package/dist/inspector/cli.js +192 -14
  192. package/dist/inspector/cli.js.map +1 -1
  193. package/dist/inspector/cli_bin.js +254 -46
  194. package/dist/inspector/cli_bin.js.map +1 -1
  195. package/dist/inspector/examples.json +7 -7
  196. package/dist/inspector/manifest.json +434 -44
  197. package/dist/positioning/index.d.ts +2 -0
  198. package/dist/positioning/index.js.map +1 -1
  199. package/package.json +1 -1
@@ -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"]}
@@ -1,35 +1,44 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
+ type CharacterCounterField = HTMLInputElement | HTMLTextAreaElement;
3
4
  /**
4
5
  * Headless character-counter behavior for a text field (no dedicated APG
5
6
  * pattern; follows the WCAG 2.2 "status messages" practice, 4.1.3).
6
7
  *
7
8
  * Markup contract (identifier: `stimeo--character-counter`):
8
9
  * <div data-controller="stimeo--character-counter"
9
- * data-stimeo--character-counter-max-value="140">
10
+ * data-stimeo--character-counter-max-value="140"
11
+ * data-stimeo--character-counter-announce-text-value="{remaining} characters remaining">
10
12
  * <textarea data-stimeo--character-counter-target="input"
11
13
  * aria-describedby="cc"></textarea>
12
- * <span id="cc" data-stimeo--character-counter-target="output"
13
- * aria-live="polite"></span>
14
+ * <span id="cc" data-stimeo--character-counter-target="output"></span>
14
15
  * </div>
15
16
  *
16
- * Watches the field's length, writes the remaining/used count into `output`, and
17
- * toggles the `data-near-limit` / `data-over-limit` state hooks (plus
18
- * `aria-invalid` on the field once the limit is exceeded). The field is the
19
- * `input` target, or — when the controller is attached straight onto an
20
- * `<input>`/`<textarea>` — the controller element itself.
17
+ * Watches the field's UTF-16 code-unit length, writes the remaining/used count
18
+ * into `output`, and toggles the `data-near-limit` / `data-over-limit` state
19
+ * hooks. While over the limit it temporarily leases `aria-invalid="true"` on
20
+ * the field and returns the consumer's authored value on recovery or teardown.
21
+ * The field is the first `input` target, or — when the controller is attached
22
+ * straight onto an `<input>`/`<textarea>` — the controller element itself.
23
+ *
24
+ * `change` and `reconcile` dispatch
25
+ * `{ length: number, remaining: number | null, over: boolean }`.
21
26
  *
22
27
  * @remarks
23
- * Behavior only — the count text is updated, not styled. Outside IME composition
24
- * the non-text state (`data-*` hooks, `aria-invalid`, and the `change` event)
25
- * updates **immediately** on every input so styling and consumers stay responsive,
26
- * while the visible count — in the `aria-live="polite"` region — is written on a
27
- * short debounce so a screen reader is not flooded during fast typing (it hears the
28
- * settled count when the user pauses). During IME composition both are deferred to
29
- * `compositionend`, so they reflect the confirmed characters rather than the
30
- * intermediate (pre-conversion) kana. The debounce timer is owned by
31
- * {@link SafeTimeout} and torn down on `disconnect()` (Turbo navigation included);
32
- * `connect()` re-reads the field so the count is correct after a cache restore.
28
+ * Behavior only — count text and state update synchronously, with no styling.
29
+ * Confirmed user input dispatches `stimeo--character-counter:change` only when
30
+ * the measured length actually changes. Its detail is `{ length, remaining,
31
+ * over }`; `remaining` is `null` when `max` is disabled. IME intermediate input
32
+ * is ignored, and `compositionend` commits the confirmed value exactly once.
33
+ *
34
+ * Assistive notification is opt-in and i18n-neutral. `announceText` accepts
35
+ * `{count}`, `{length}`, `{remaining}`, `{max}`, and `{over}` placeholders and
36
+ * sends the settled message to the page's shared `stimeo--announcer` after a
37
+ * short debounce. The visible `output` is not itself required to be a live
38
+ * region. Initial reflection and Turbo restoration never dispatch or announce.
39
+ * Runtime target/Value reconciliation dispatches
40
+ * `stimeo--character-counter:reconcile` only when the public derived state
41
+ * changes, and never announces.
33
42
  */
34
43
  declare class CharacterCounterController extends Controller<HTMLElement> {
35
44
  #private;
@@ -47,17 +56,40 @@ declare class CharacterCounterController extends Controller<HTMLElement> {
47
56
  type: StringConstructor;
48
57
  default: string;
49
58
  };
59
+ announceText: {
60
+ type: StringConstructor;
61
+ default: string;
62
+ };
50
63
  };
51
- static events: readonly ["change"];
52
- readonly inputTarget: HTMLInputElement | HTMLTextAreaElement;
64
+ static events: readonly ["change", "reconcile"];
65
+ readonly inputTarget: CharacterCounterField;
53
66
  readonly outputTarget: HTMLElement;
54
67
  readonly hasInputTarget: boolean;
55
68
  readonly hasOutputTarget: boolean;
56
69
  maxValue: number;
57
70
  warnAtValue: number;
58
71
  modeValue: string;
72
+ announceTextValue: string;
73
+ /** Reflects the current DOM state and opens the mutation-reconciliation window. */
59
74
  connect(): void;
75
+ /** Releases listeners, timers, borrowed ARIA, and controller-owned state hooks. */
60
76
  disconnect(): void;
77
+ /** Rebinds and repaints after an input target is added or replaced at runtime. */
78
+ inputTargetConnected(): void;
79
+ /** Releases and repaints after an input target is removed or replaced at runtime. */
80
+ inputTargetDisconnected(): void;
81
+ /** Initializes a display target inserted after the controller connected. */
82
+ outputTargetConnected(): void;
83
+ /** Reconciles the optional display target set after a removal or replacement. */
84
+ outputTargetDisconnected(): void;
85
+ /** Repaints when application code or a Turbo morph changes `max`. */
86
+ maxValueChanged(): void;
87
+ /** Repaints when application code or a Turbo morph changes `warnAt`. */
88
+ warnAtValueChanged(): void;
89
+ /** Repaints when application code or a Turbo morph changes `mode`. */
90
+ modeValueChanged(): void;
91
+ /** Cancels a pending old message when its consumer-authored template changes. */
92
+ announceTextValueChanged(): void;
61
93
  }
62
94
 
63
95
  export { CharacterCounterController };