stimeo-ui 0.15.0 → 0.16.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 (267) hide show
  1. package/CHANGELOG.md +178 -0
  2. package/README.md +120 -0
  3. package/dist/cable/index.js +63 -15
  4. package/dist/cable/index.js.map +1 -1
  5. package/dist/controllers/accordion_controller.d.ts +30 -3
  6. package/dist/controllers/accordion_controller.js +98 -9
  7. package/dist/controllers/accordion_controller.js.map +1 -1
  8. package/dist/controllers/alert_dialog_controller.d.ts +8 -7
  9. package/dist/controllers/alert_dialog_controller.js.map +1 -1
  10. package/dist/controllers/announcer_controller.d.ts +3 -2
  11. package/dist/controllers/announcer_controller.js +8 -1
  12. package/dist/controllers/announcer_controller.js.map +1 -1
  13. package/dist/controllers/auto_submit_controller.js +43 -2
  14. package/dist/controllers/auto_submit_controller.js.map +1 -1
  15. package/dist/controllers/avatar_controller.js +1 -1
  16. package/dist/controllers/avatar_controller.js.map +1 -1
  17. package/dist/controllers/breadcrumb_controller.d.ts +10 -7
  18. package/dist/controllers/breadcrumb_controller.js +9 -8
  19. package/dist/controllers/breadcrumb_controller.js.map +1 -1
  20. package/dist/controllers/bulk_select_controller.d.ts +4 -4
  21. package/dist/controllers/bulk_select_controller.js +7 -6
  22. package/dist/controllers/bulk_select_controller.js.map +1 -1
  23. package/dist/controllers/calendar_controller.d.ts +85 -23
  24. package/dist/controllers/calendar_controller.js +323 -123
  25. package/dist/controllers/calendar_controller.js.map +1 -1
  26. package/dist/controllers/carousel_controller.d.ts +67 -22
  27. package/dist/controllers/carousel_controller.js +263 -38
  28. package/dist/controllers/carousel_controller.js.map +1 -1
  29. package/dist/controllers/character_counter_controller.d.ts +1 -1
  30. package/dist/controllers/character_counter_controller.js +40 -2
  31. package/dist/controllers/character_counter_controller.js.map +1 -1
  32. package/dist/controllers/checkbox_controller.js +54 -10
  33. package/dist/controllers/checkbox_controller.js.map +1 -1
  34. package/dist/controllers/clipboard_controller.d.ts +28 -2
  35. package/dist/controllers/clipboard_controller.js +63 -5
  36. package/dist/controllers/clipboard_controller.js.map +1 -1
  37. package/dist/controllers/collapsible_controller.d.ts +25 -1
  38. package/dist/controllers/collapsible_controller.js +99 -14
  39. package/dist/controllers/collapsible_controller.js.map +1 -1
  40. package/dist/controllers/color_picker_controller.d.ts +29 -8
  41. package/dist/controllers/color_picker_controller.js +80 -34
  42. package/dist/controllers/color_picker_controller.js.map +1 -1
  43. package/dist/controllers/combobox_controller.d.ts +10 -1
  44. package/dist/controllers/combobox_controller.js +106 -16
  45. package/dist/controllers/combobox_controller.js.map +1 -1
  46. package/dist/controllers/command_palette_controller.d.ts +3 -3
  47. package/dist/controllers/command_palette_controller.js +35 -3
  48. package/dist/controllers/command_palette_controller.js.map +1 -1
  49. package/dist/controllers/conditional_fields_controller.js +56 -11
  50. package/dist/controllers/conditional_fields_controller.js.map +1 -1
  51. package/dist/controllers/confirm_controller.js +3 -0
  52. package/dist/controllers/confirm_controller.js.map +1 -1
  53. package/dist/controllers/context_menu_controller.d.ts +6 -0
  54. package/dist/controllers/context_menu_controller.js +32 -12
  55. package/dist/controllers/context_menu_controller.js.map +1 -1
  56. package/dist/controllers/countdown_controller.d.ts +30 -1
  57. package/dist/controllers/countdown_controller.js +129 -26
  58. package/dist/controllers/countdown_controller.js.map +1 -1
  59. package/dist/controllers/currency_input_controller.d.ts +74 -15
  60. package/dist/controllers/currency_input_controller.js +205 -58
  61. package/dist/controllers/currency_input_controller.js.map +1 -1
  62. package/dist/controllers/data_grid_controller.d.ts +63 -18
  63. package/dist/controllers/data_grid_controller.js +195 -29
  64. package/dist/controllers/data_grid_controller.js.map +1 -1
  65. package/dist/controllers/date_range_picker_controller.d.ts +34 -6
  66. package/dist/controllers/date_range_picker_controller.js +139 -27
  67. package/dist/controllers/date_range_picker_controller.js.map +1 -1
  68. package/dist/controllers/dialog_controller.d.ts +10 -3
  69. package/dist/controllers/dialog_controller.js +35 -8
  70. package/dist/controllers/dialog_controller.js.map +1 -1
  71. package/dist/controllers/direct_upload_controller.js +22 -4
  72. package/dist/controllers/direct_upload_controller.js.map +1 -1
  73. package/dist/controllers/dirty_form_controller.d.ts +2 -2
  74. package/dist/controllers/dirty_form_controller.js +14 -1
  75. package/dist/controllers/dirty_form_controller.js.map +1 -1
  76. package/dist/controllers/dismissible_controller.js +1 -0
  77. package/dist/controllers/dismissible_controller.js.map +1 -1
  78. package/dist/controllers/drawer_controller.d.ts +18 -10
  79. package/dist/controllers/drawer_controller.js +54 -19
  80. package/dist/controllers/drawer_controller.js.map +1 -1
  81. package/dist/controllers/dropdown_controller.d.ts +9 -3
  82. package/dist/controllers/dropdown_controller.js +36 -9
  83. package/dist/controllers/dropdown_controller.js.map +1 -1
  84. package/dist/controllers/editable_controller.js +34 -0
  85. package/dist/controllers/editable_controller.js.map +1 -1
  86. package/dist/controllers/file_dropzone_controller.js +144 -51
  87. package/dist/controllers/file_dropzone_controller.js.map +1 -1
  88. package/dist/controllers/filter_controller.d.ts +10 -4
  89. package/dist/controllers/filter_controller.js +20 -6
  90. package/dist/controllers/filter_controller.js.map +1 -1
  91. package/dist/controllers/flash_controller.d.ts +26 -6
  92. package/dist/controllers/flash_controller.js +305 -46
  93. package/dist/controllers/flash_controller.js.map +1 -1
  94. package/dist/controllers/focus_controller.js +1 -0
  95. package/dist/controllers/focus_controller.js.map +1 -1
  96. package/dist/controllers/form_field_controller.js +7 -5
  97. package/dist/controllers/form_field_controller.js.map +1 -1
  98. package/dist/controllers/form_validation_controller.js +19 -13
  99. package/dist/controllers/form_validation_controller.js.map +1 -1
  100. package/dist/controllers/frame_loading_controller.js +16 -2
  101. package/dist/controllers/frame_loading_controller.js.map +1 -1
  102. package/dist/controllers/highlight_controller.js +19 -2
  103. package/dist/controllers/highlight_controller.js.map +1 -1
  104. package/dist/controllers/hover_card_controller.d.ts +10 -2
  105. package/dist/controllers/hover_card_controller.js +40 -14
  106. package/dist/controllers/hover_card_controller.js.map +1 -1
  107. package/dist/controllers/idle_controller.d.ts +16 -3
  108. package/dist/controllers/idle_controller.js +90 -5
  109. package/dist/controllers/idle_controller.js.map +1 -1
  110. package/dist/controllers/input_mask_controller.d.ts +5 -2
  111. package/dist/controllers/input_mask_controller.js +65 -9
  112. package/dist/controllers/input_mask_controller.js.map +1 -1
  113. package/dist/controllers/intersection_controller.js +3 -0
  114. package/dist/controllers/intersection_controller.js.map +1 -1
  115. package/dist/controllers/lazy_frame_controller.js +11 -2
  116. package/dist/controllers/lazy_frame_controller.js.map +1 -1
  117. package/dist/controllers/listbox_controller.d.ts +50 -8
  118. package/dist/controllers/listbox_controller.js +203 -45
  119. package/dist/controllers/listbox_controller.js.map +1 -1
  120. package/dist/controllers/masonry_controller.js +0 -2
  121. package/dist/controllers/masonry_controller.js.map +1 -1
  122. package/dist/controllers/menu_controller.d.ts +9 -3
  123. package/dist/controllers/menu_controller.js +45 -16
  124. package/dist/controllers/menu_controller.js.map +1 -1
  125. package/dist/controllers/menubar_controller.d.ts +11 -0
  126. package/dist/controllers/menubar_controller.js +58 -24
  127. package/dist/controllers/menubar_controller.js.map +1 -1
  128. package/dist/controllers/meter_controller.js +9 -5
  129. package/dist/controllers/meter_controller.js.map +1 -1
  130. package/dist/controllers/multi_select_controller.d.ts +18 -3
  131. package/dist/controllers/multi_select_controller.js +278 -104
  132. package/dist/controllers/multi_select_controller.js.map +1 -1
  133. package/dist/controllers/navigation_menu_controller.d.ts +11 -0
  134. package/dist/controllers/navigation_menu_controller.js +48 -15
  135. package/dist/controllers/navigation_menu_controller.js.map +1 -1
  136. package/dist/controllers/nested_form_controller.js +37 -8
  137. package/dist/controllers/nested_form_controller.js.map +1 -1
  138. package/dist/controllers/network_status_controller.js +9 -1
  139. package/dist/controllers/network_status_controller.js.map +1 -1
  140. package/dist/controllers/number_input_controller.d.ts +36 -8
  141. package/dist/controllers/number_input_controller.js +124 -21
  142. package/dist/controllers/number_input_controller.js.map +1 -1
  143. package/dist/controllers/optimistic_controller.js +14 -1
  144. package/dist/controllers/optimistic_controller.js.map +1 -1
  145. package/dist/controllers/otp_controller.d.ts +22 -7
  146. package/dist/controllers/otp_controller.js +198 -55
  147. package/dist/controllers/otp_controller.js.map +1 -1
  148. package/dist/controllers/overflow_indicator_controller.d.ts +8 -12
  149. package/dist/controllers/overflow_indicator_controller.js +84 -13
  150. package/dist/controllers/overflow_indicator_controller.js.map +1 -1
  151. package/dist/controllers/overflow_menu_controller.d.ts +26 -6
  152. package/dist/controllers/overflow_menu_controller.js +112 -41
  153. package/dist/controllers/overflow_menu_controller.js.map +1 -1
  154. package/dist/controllers/pagination_controller.d.ts +19 -11
  155. package/dist/controllers/pagination_controller.js +74 -28
  156. package/dist/controllers/pagination_controller.js.map +1 -1
  157. package/dist/controllers/password_reveal_controller.d.ts +15 -1
  158. package/dist/controllers/password_reveal_controller.js +59 -2
  159. package/dist/controllers/password_reveal_controller.js.map +1 -1
  160. package/dist/controllers/persist_controller.js +30 -8
  161. package/dist/controllers/persist_controller.js.map +1 -1
  162. package/dist/controllers/pointer_drag_controller.js +131 -52
  163. package/dist/controllers/pointer_drag_controller.js.map +1 -1
  164. package/dist/controllers/popover_controller.d.ts +9 -3
  165. package/dist/controllers/popover_controller.js +45 -11
  166. package/dist/controllers/popover_controller.js.map +1 -1
  167. package/dist/controllers/portal_controller.d.ts +1 -1
  168. package/dist/controllers/portal_controller.js +6 -2
  169. package/dist/controllers/portal_controller.js.map +1 -1
  170. package/dist/controllers/preview_guard_controller.js +16 -1
  171. package/dist/controllers/preview_guard_controller.js.map +1 -1
  172. package/dist/controllers/progress_controller.js +8 -4
  173. package/dist/controllers/progress_controller.js.map +1 -1
  174. package/dist/controllers/radio_group_controller.d.ts +6 -4
  175. package/dist/controllers/radio_group_controller.js +42 -17
  176. package/dist/controllers/radio_group_controller.js.map +1 -1
  177. package/dist/controllers/range_slider_controller.d.ts +49 -1
  178. package/dist/controllers/range_slider_controller.js +88 -42
  179. package/dist/controllers/range_slider_controller.js.map +1 -1
  180. package/dist/controllers/rating_controller.d.ts +14 -3
  181. package/dist/controllers/rating_controller.js +39 -15
  182. package/dist/controllers/rating_controller.js.map +1 -1
  183. package/dist/controllers/read_more_controller.d.ts +24 -2
  184. package/dist/controllers/read_more_controller.js +69 -2
  185. package/dist/controllers/read_more_controller.js.map +1 -1
  186. package/dist/controllers/resizable_controller.d.ts +16 -2
  187. package/dist/controllers/resizable_controller.js +82 -22
  188. package/dist/controllers/resizable_controller.js.map +1 -1
  189. package/dist/controllers/scroll_area_controller.js +5 -1
  190. package/dist/controllers/scroll_area_controller.js.map +1 -1
  191. package/dist/controllers/scroll_visibility_controller.js +0 -1
  192. package/dist/controllers/scroll_visibility_controller.js.map +1 -1
  193. package/dist/controllers/scrollspy_controller.d.ts +3 -2
  194. package/dist/controllers/scrollspy_controller.js +6 -0
  195. package/dist/controllers/scrollspy_controller.js.map +1 -1
  196. package/dist/controllers/separator_controller.d.ts +41 -14
  197. package/dist/controllers/separator_controller.js +66 -37
  198. package/dist/controllers/separator_controller.js.map +1 -1
  199. package/dist/controllers/sidebar_controller.d.ts +20 -3
  200. package/dist/controllers/sidebar_controller.js +77 -18
  201. package/dist/controllers/sidebar_controller.js.map +1 -1
  202. package/dist/controllers/skeleton_controller.js +6 -1
  203. package/dist/controllers/skeleton_controller.js.map +1 -1
  204. package/dist/controllers/slider_controller.d.ts +45 -7
  205. package/dist/controllers/slider_controller.js +82 -47
  206. package/dist/controllers/slider_controller.js.map +1 -1
  207. package/dist/controllers/smart_sticky_header_controller.js +11 -1
  208. package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
  209. package/dist/controllers/sortable_controller.js +17 -2
  210. package/dist/controllers/sortable_controller.js.map +1 -1
  211. package/dist/controllers/spinner_controller.js +10 -2
  212. package/dist/controllers/spinner_controller.js.map +1 -1
  213. package/dist/controllers/step_indicator_controller.d.ts +19 -17
  214. package/dist/controllers/step_indicator_controller.js +18 -17
  215. package/dist/controllers/step_indicator_controller.js.map +1 -1
  216. package/dist/controllers/stepper_controller.d.ts +34 -9
  217. package/dist/controllers/stepper_controller.js +101 -19
  218. package/dist/controllers/stepper_controller.js.map +1 -1
  219. package/dist/controllers/stick_to_bottom_controller.d.ts +19 -0
  220. package/dist/controllers/stick_to_bottom_controller.js +75 -5
  221. package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
  222. package/dist/controllers/submit_once_controller.d.ts +3 -2
  223. package/dist/controllers/submit_once_controller.js +16 -3
  224. package/dist/controllers/submit_once_controller.js.map +1 -1
  225. package/dist/controllers/switch_controller.d.ts +29 -7
  226. package/dist/controllers/switch_controller.js +101 -10
  227. package/dist/controllers/switch_controller.js.map +1 -1
  228. package/dist/controllers/tabs_controller.d.ts +12 -0
  229. package/dist/controllers/tabs_controller.js +21 -2
  230. package/dist/controllers/tabs_controller.js.map +1 -1
  231. package/dist/controllers/tags_input_controller.d.ts +15 -3
  232. package/dist/controllers/tags_input_controller.js +209 -59
  233. package/dist/controllers/tags_input_controller.js.map +1 -1
  234. package/dist/controllers/theme_controller.d.ts +20 -3
  235. package/dist/controllers/theme_controller.js +64 -14
  236. package/dist/controllers/theme_controller.js.map +1 -1
  237. package/dist/controllers/time_picker_controller.js +23 -8
  238. package/dist/controllers/time_picker_controller.js.map +1 -1
  239. package/dist/controllers/toast_controller.d.ts +52 -15
  240. package/dist/controllers/toast_controller.js +337 -54
  241. package/dist/controllers/toast_controller.js.map +1 -1
  242. package/dist/controllers/toggle_group_controller.d.ts +49 -7
  243. package/dist/controllers/toggle_group_controller.js +159 -23
  244. package/dist/controllers/toggle_group_controller.js.map +1 -1
  245. package/dist/controllers/toolbar_controller.js +32 -0
  246. package/dist/controllers/toolbar_controller.js.map +1 -1
  247. package/dist/controllers/tooltip_controller.d.ts +8 -0
  248. package/dist/controllers/tooltip_controller.js +39 -13
  249. package/dist/controllers/tooltip_controller.js.map +1 -1
  250. package/dist/controllers/transition_controller.js +4 -0
  251. package/dist/controllers/transition_controller.js.map +1 -1
  252. package/dist/controllers/tree_view_controller.d.ts +39 -8
  253. package/dist/controllers/tree_view_controller.js +169 -16
  254. package/dist/controllers/tree_view_controller.js.map +1 -1
  255. package/dist/index.d.ts +28 -1
  256. package/dist/index.js +4588 -1535
  257. package/dist/index.js.map +1 -1
  258. package/dist/inspector/cli.d.ts +72 -6
  259. package/dist/inspector/cli.js +262 -51
  260. package/dist/inspector/cli.js.map +1 -1
  261. package/dist/inspector/cli_bin.js +309 -51
  262. package/dist/inspector/cli_bin.js.map +1 -1
  263. package/dist/inspector/examples.json +40 -40
  264. package/dist/inspector/manifest.json +525 -59
  265. package/dist/positioning/index.js +2 -0
  266. package/dist/positioning/index.js.map +1 -1
  267. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/safe_timeout.ts","../../src/utils/keyed_timers.ts","../../src/utils/pausable_timers.ts","../../src/utils/transition_completion.ts","../../src/controllers/toast_controller.ts"],"names":[],"mappings":"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","file":"toast_controller.js","sourcesContent":["/**\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 * Largest delay a timer can hold: the platform stores it in a 32-bit signed\n * integer, and anything larger overflows to `1`, so a delay meant to be far in\n * the future fires almost immediately. A declared delay above this bound names\n * no delay at all, and a controller reading one falls back to its default.\n */\nexport const MAX_TIMER_DELAY_MS = 2_147_483_647;\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 { SafeTimeout } from \"./safe_timeout\";\n\n/**\n * Keeps at most one pending timer per key, and releases them all together.\n *\n * A region, a row, a message or a speaker that is armed again while its earlier\n * timer is still pending must end up with exactly one timer deciding when its\n * state ends. Two timers on one key means the earlier deadline wins: it cuts the\n * new emphasis short, clears text written after it, or drops a speaker who is\n * still typing — and then reports an ending for a state that is already gone.\n * Arming through this registry cancels the key's earlier timer in the same step,\n * and no timer id ever reaches the caller.\n *\n * An entry lives exactly as long as its timer: it goes as the timer fires, and\n * the whole ledger goes on `clearAll()`. That is a correctness rule, not\n * tidiness — a platform may hand an id released by `clearTimeout` to the next\n * timer it creates, so an entry that outlived its timer would let a later\n * `clear()` on that key cancel whatever timer now holds the id, on some other\n * key entirely.\n *\n * The ledger is a plain `Map`, and the key may be anything. Weak keys would\n * retain nothing less: while a timer is pending the platform already holds the\n * key through the callback, and the entry is gone the moment the timer is.\n *\n * Scope is the one-per-key timer only. What the timer means, and the roster of\n * keys it is armed for, stay with the consumer, so a second kind of timer on the\n * same keys (a transition wait, an animation frame) is a second registry, and a\n * timer that belongs to no key stays on a plain `SafeTimeout`.\n *\n * @example\n * ```ts\n * readonly #expiry = new KeyedTimers<string>();\n *\n * #onSignal(name: string): void {\n * this.#expiry.set(name, () => this.#drop(name), this.#timeout);\n * }\n *\n * disconnect(): void {\n * this.#expiry.clearAll();\n * }\n * ```\n */\nexport class KeyedTimers<K> {\n readonly #timers = new SafeTimeout();\n\n /** The pending timer of each key; an entry lives exactly as long as its timer. */\n readonly #pending = new Map<K, number>();\n\n /**\n * Arms `callback` after `delay` ms for `key`, cancelling the timer `key` had\n * pending. The entry is dropped before the callback runs, so the callback sees\n * the key unarmed and may arm it again for the next round.\n */\n set(key: K, callback: () => void, delay: number): void {\n this.clear(key);\n const id = this.#timers.set(() => {\n this.#pending.delete(key);\n callback();\n }, delay);\n this.#pending.set(key, id);\n }\n\n /**\n * Cancels `key`'s pending timer, if it has one.\n *\n * A timer id is a positive integer, so `-1` stands for \"nothing pending\" and\n * the registry ignores an id it does not own — the unarmed case needs no\n * branch of its own, and no other key's timer can be reached from here.\n */\n clear(key: K): void {\n this.#timers.clear(this.#pending.get(key) ?? -1);\n this.#pending.delete(key);\n }\n\n /**\n * Cancels every pending timer and forgets every key. Call this from a\n * controller's `disconnect()` so no timer, and no entry, outlives the element.\n */\n clearAll(): void {\n this.#timers.clearAll();\n this.#pending.clear();\n }\n\n /** Whether `key` has a timer pending. */\n has(key: K): boolean {\n return this.#pending.has(key);\n }\n}\n","import { KeyedTimers } from \"./keyed_timers\";\n\n/** What a key needs to carry on: the work, when it was last armed, and who is holding it. */\ninterface Entry {\n callback: () => void;\n /** Epoch ms the running timer was armed at; written only where the timer is armed. */\n startedAt: number;\n remaining: number;\n reasons: Set<string>;\n}\n\n/**\n * Keeps one self-dismissing timer per key that a person can hold open.\n *\n * A notification that takes itself away has to stop while the pointer is over it\n * or the focus is inside it, and pick up where it left off once both have gone\n * (WAI-ARIA and WCAG 2.2 call this being able to pause a time limit). Each reason\n * to hold is tracked on its own, because a pointer leaving while focus stays is\n * not a release: the time left is banked when the first reason arrives, and the\n * timer is armed again with that bank only after the last one is released.\n *\n * **Holding never dismisses.** A deadline that passed while the timer sat queued\n * — a throttled tab, a long task — is banked as one millisecond, so the\n * notification goes right after the last reason is released rather than during\n * the event that holds it. Taking it away there would remove the element under\n * the pointer, or the control that has focus, and focus would fall to the body.\n *\n * Arming a held key keeps the hold and banks the new delay for the resume, so a\n * duration that changes at runtime reaches a held notification without\n * dismissing it or releasing it.\n *\n * Scope is the timer and its hold. Whether a key may be held at all, and the\n * state hook that shows it is held, stay with the consumer.\n *\n * @example\n * ```ts\n * readonly #dismiss = new PausableTimers<HTMLElement>();\n *\n * pause(event: Event): void {\n * const item = this.#itemFromEvent(event);\n * if (item && this.#dismiss.pause(item, this.#pauseReason(event))) {\n * item.setAttribute(\"data-paused\", \"true\");\n * }\n * }\n * ```\n */\nexport class PausableTimers<K> {\n readonly #timers = new KeyedTimers<K>();\n\n /** Every key armed or held; an entry goes as its timer fires, or with the key. */\n readonly #entries = new Map<K, Entry>();\n\n /**\n * Arms `callback` after `delay` ms for `key`, replacing whatever `key` had.\n * A held key stays held and banks `delay` for its resume.\n */\n set(key: K, callback: () => void, delay: number): void {\n const reasons = this.#entries.get(key)?.reasons ?? new Set<string>();\n const entry: Entry = { callback, startedAt: 0, remaining: delay, reasons };\n this.#entries.set(key, entry);\n if (reasons.size === 0) this.#arm(key, entry);\n }\n\n /**\n * Holds `key` for `reason` and banks the time left, with a floor of one\n * millisecond. Reports whether this call is the one that stopped a running\n * timer, so the caller can write its held-state hook exactly once.\n */\n pause(key: K, reason: string): boolean {\n const entry = this.#entries.get(key);\n if (entry === undefined) return false;\n entry.reasons.add(reason);\n if (!this.#timers.has(key)) return false;\n this.#timers.clear(key);\n entry.remaining = Math.max(1, entry.remaining - (Date.now() - entry.startedAt));\n return true;\n }\n\n /**\n * Releases `reason` on `key`, arming the banked time again once no reason is\n * left. Reports whether this call is the one that started the timer again.\n */\n resume(key: K, reason: string): boolean {\n const entry = this.#entries.get(key);\n if (entry === undefined) return false;\n entry.reasons.delete(reason);\n if (entry.reasons.size > 0 || this.#timers.has(key)) return false;\n this.#arm(key, entry);\n return true;\n }\n\n /** Whether `key` is armed or held — that is, whether this registry drives it at all. */\n tracks(key: K): boolean {\n return this.#entries.has(key);\n }\n\n /** Cancels `key`'s timer and drops its hold. */\n clear(key: K): void {\n this.#timers.clear(key);\n this.#entries.delete(key);\n }\n\n /**\n * Cancels every timer and forgets every key. Call this from a controller's\n * `disconnect()` so neither a timer nor a hold outlives the element.\n */\n clearAll(): void {\n this.#timers.clearAll();\n this.#entries.clear();\n }\n\n /** Starts `entry`'s banked time running for `key`, and drops it as it fires. */\n #arm(key: K, entry: Entry): void {\n entry.startedAt = Date.now();\n this.#timers.set(\n key,\n () => {\n this.#entries.delete(key);\n entry.callback();\n },\n entry.remaining,\n );\n }\n}\n","import { SafeTimeout } from \"./safe_timeout\";\n\n/** Computed transition fields needed to determine when an element has settled. */\nexport type TransitionStyle = Pick<\n CSSStyleDeclaration,\n \"transitionProperty\" | \"transitionDuration\" | \"transitionDelay\"\n>;\n\n/** Parsed transition property paired with its effective duration and delay. */\ninterface TransitionTiming {\n property: string;\n totalMs: number;\n}\n\n/** Parses a CSS `<time>` into milliseconds, returning `0` for malformed values. */\nfunction timeMs(value: string): number {\n const trimmed = value.trim();\n const amount = Number.parseFloat(trimmed);\n if (!Number.isFinite(amount)) return 0;\n if (trimmed.endsWith(\"ms\")) return amount;\n if (trimmed.endsWith(\"s\")) return amount * 1000;\n return 0;\n}\n\n/** Splits a computed comma-separated CSS list into normalized, non-empty items. */\nfunction cssList(value: string): string[] {\n return value\n .split(\",\")\n .map((item) => item.trim())\n .filter(Boolean);\n}\n\n/**\n * Pairs transition properties, durations, and delays using CSS list repetition.\n *\n * The `transition-property` list determines the number of transitions. Shorter\n * duration/delay lists repeat, while extra values are ignored. A negative delay\n * shortens the remaining wall-clock time, and a non-positive total is settled.\n */\nfunction transitionTimings(style: TransitionStyle): TransitionTiming[] {\n const properties = cssList(style.transitionProperty);\n const durations = cssList(style.transitionDuration).map(timeMs);\n const delays = cssList(style.transitionDelay).map(timeMs);\n const effectiveProperties =\n properties.length > 0\n ? properties\n : Array.from({ length: Math.max(durations.length, delays.length, 1) }, () => \"all\");\n const effectiveDurations = durations.length > 0 ? durations : [0];\n const effectiveDelays = delays.length > 0 ? delays : [0];\n\n return effectiveProperties\n .filter((property) => property !== \"none\")\n .map((property, index) => ({\n property,\n totalMs: Math.max(\n 0,\n (effectiveDurations[index % effectiveDurations.length] ?? 0) +\n (effectiveDelays[index % effectiveDelays.length] ?? 0),\n ),\n }));\n}\n\n/** Maximum total over already-parsed timings (0 when the list is empty). */\nfunction maxTotalMs(timings: TransitionTiming[]): number {\n return timings.reduce((max, { totalMs }) => Math.max(max, totalMs), 0);\n}\n\n/** Maximum effective transition duration plus delay, in milliseconds. */\nexport function maxTransitionTotalMs(style: TransitionStyle): number {\n return maxTotalMs(transitionTimings(style));\n}\n\n/** Optional tuning for a single {@link TransitionCompletion.wait} call. */\nexport interface TransitionWaitOptions {\n /**\n * Positive wall-clock override (ms) for the bounded fallback, replacing the\n * auto-computed `max + 50ms` timer verbatim. It also keeps the wait armed for\n * a computed 0ms transition (no synchronous completion): the consumer asserts\n * a transition budget that computed styles cannot see. Non-positive and\n * non-finite (`NaN` / `Infinity`) values are ignored.\n */\n timeoutMs?: number;\n}\n\n/**\n * Owns one cancellable wait for an element's CSS transitions to settle.\n *\n * When available, active CSS transitions provide their expanded property names.\n * Tracking those names lets shorthand declarations settle from their longhand\n * terminal events. A terminal event from an interrupted phase is ignored while a\n * replacement transition for the same property is still active. Because that set\n * is sampled when the wait is armed, a property whose transition only starts a\n * frame later would otherwise be settled over; the still-running set is therefore\n * re-read before completing and adopted when it is not yet empty. Without Web\n * Animations data, explicit transition properties retain the declared-property\n * behavior and the ambiguous `transition-property: all` form waits until the\n * computed maximum wall-clock time. A `max + 50ms` timeout is always armed\n * because browsers emit no terminal event when a property never transitions, an\n * ancestor disappears, or rendering is otherwise interrupted; a consumer with\n * better knowledge can replace that fallback via\n * {@link TransitionWaitOptions.timeoutMs}.\n */\nexport class TransitionCompletion {\n readonly #timers = new SafeTimeout();\n #element: HTMLElement | null = null;\n #complete: (() => void) | null = null;\n #pendingProperties: Set<string> | null = null;\n #deadline = 0;\n\n /**\n * Replaces any prior wait and invokes `complete` synchronously for a 0ms\n * transition (including when `getComputedStyle` is unavailable).\n *\n * With a positive `options.timeoutMs` the synchronous fast-path is skipped and\n * the override replaces the auto-computed fallback (see {@link TransitionWaitOptions}).\n */\n wait(element: HTMLElement, complete: () => void, options: TransitionWaitOptions = {}): void {\n this.cancel();\n\n const requested = options.timeoutMs ?? 0;\n const override = Number.isFinite(requested) && requested > 0 ? requested : 0;\n // A non-browser / partial-DOM environment cannot report a computable\n // transition, which is indistinguishable from a 0ms one.\n const timings =\n typeof window.getComputedStyle === \"function\"\n ? transitionTimings(window.getComputedStyle(element))\n : [];\n const maximum = maxTotalMs(timings);\n if (maximum <= 0 && override <= 0) {\n complete();\n return;\n }\n\n this.#element = element;\n this.#complete = complete;\n this.#deadline = Date.now() + maximum;\n const activeProperties = this.#activeTransitionProperties(element);\n this.#pendingProperties =\n activeProperties.size > 0 ? activeProperties : this.#explicitPendingProperties(timings);\n element.addEventListener(\"transitionend\", this.#onTerminal);\n element.addEventListener(\"transitioncancel\", this.#onTerminal);\n this.#timers.set(() => this.#finish(), override > 0 ? override : maximum + 50);\n }\n\n /** Cancels the pending wait without invoking its completion callback. */\n cancel(): void {\n this.#complete = null;\n this.#teardown();\n }\n\n /**\n * Handles terminal events from the observed element only.\n *\n * For explicit property lists, every declared positive-time property must\n * settle. For `all`, no reliable property set exists, so an event can finish\n * only after the computed maximum time; the safety timeout owns the usual path.\n */\n readonly #onTerminal = (event: Event): void => {\n if (event.target !== this.#element) return;\n const transitionEvent = event as TransitionEvent;\n // A pseudo-element's transition is reported with its originating element\n // as `target`; it must not settle the element's own transition.\n if (transitionEvent.pseudoElement) return;\n\n if (this.#pendingProperties) {\n const propertyName = transitionEvent.propertyName;\n const active = this.#activeTransitionProperties(this.#element);\n // An interrupted transition queues its cancel event before the replacement\n // phase starts, but dispatch can happen after the new wait is armed. The\n // replacement is then the active transition for this property, so the stale\n // terminal event must not settle the new phase.\n if (active.has(propertyName)) return;\n if (!this.#pendingProperties.delete(propertyName)) return;\n if (this.#pendingProperties.size > 0) return;\n // The tracked set is an arm-time snapshot, so a transition the phase starts\n // one frame later is absent from it. Re-reading the still-running set before\n // settling adopts those stragglers instead of completing over them; the\n // fallback timer stays armed, so this cannot extend the wait unboundedly.\n if (active.size > 0) {\n this.#pendingProperties = active;\n return;\n }\n this.#finish();\n return;\n }\n\n if (Date.now() >= this.#deadline) this.#finish();\n };\n\n /**\n * Returns active CSS transition properties expanded to the names reported by\n * terminal events. CSS animations and pseudo-element effects are excluded.\n */\n #activeTransitionProperties(element: HTMLElement | null): Set<string> {\n if (!element || typeof element.getAnimations !== \"function\") return new Set();\n\n try {\n const properties = element.getAnimations().flatMap((animation) => {\n if (animation.playState === \"idle\" || animation.playState === \"finished\") return [];\n const effect = animation.effect as KeyframeEffect | null;\n // A pseudo-element effect names the originating element as its target, so\n // `target` alone cannot separate it. Its terminal events are ignored, so\n // tracking its properties would only strand the wait on the fallback.\n if (effect?.pseudoElement) return [];\n const target = effect?.target;\n if (target && target !== element) return [];\n const property = (animation as Partial<CSSTransition>).transitionProperty;\n return typeof property === \"string\" && property.length > 0 ? [property] : [];\n });\n return new Set(properties);\n } catch {\n // Partial DOM implementations can expose getAnimations without supporting\n // it. The declared-property tracker and bounded timer remain safe fallbacks.\n return new Set();\n }\n }\n\n /** Returns explicit positive-time properties, or `null` for the ambiguous `all`. */\n #explicitPendingProperties(timings: TransitionTiming[]): Set<string> | null {\n if (timings.some(({ property }) => property === \"all\")) return null;\n const pending = new Set(\n timings.filter(({ totalMs }) => totalMs > 0).map(({ property }) => property),\n );\n // An empty set is only reachable through a timeout override (a 0ms transition\n // otherwise completes synchronously). With nothing to track, fall back to the\n // deadline rule so any terminal event can settle the wait, exactly like `all`.\n return pending.size > 0 ? pending : null;\n }\n\n /** Completes exactly once, releasing listeners and the fallback before the callback. */\n #finish(): void {\n const complete = this.#complete;\n if (!complete) return;\n this.#complete = null;\n this.#teardown();\n complete();\n }\n\n /** Releases the exact element listeners and timer owned by the current wait. */\n #teardown(): void {\n this.#timers.clearAll();\n this.#element?.removeEventListener(\"transitionend\", this.#onTerminal);\n this.#element?.removeEventListener(\"transitioncancel\", this.#onTerminal);\n this.#element = null;\n this.#pendingProperties = null;\n this.#deadline = 0;\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { PausableTimers } from \"../utils/pausable_timers\";\nimport { SafeTimeout } from \"../utils/safe_timeout\";\nimport { maxTransitionTotalMs } from \"../utils/transition_completion\";\n\nconst DELEGATED_EVENTS = [\"click\", \"focusin\", \"focusout\", \"keydown\", \"mouseover\", \"mouseout\"];\n\n/**\n * Headless, highly accessible toast notification behavior.\n *\n * Markup contract (identifier: `stimeo--toast`):\n * <div data-controller=\"stimeo--toast\"\n * data-stimeo--toast-duration-value=\"5000\"\n * data-stimeo--toast-max-value=\"3\">\n * <!-- Attribute-only trigger: no hand-written JS required. -->\n * <button data-action=\"click->stimeo--toast#show\"\n * data-stimeo--toast-body-param=\"Saved\"\n * data-stimeo--toast-type-param=\"status\">Show</button>\n * <!-- The live region is a descendant; the controller element only needs\n * to enclose both the trigger(s) and the list/template targets. -->\n * <div role=\"region\" aria-label=\"Notifications\">\n * <ol data-stimeo--toast-target=\"list\"></ol>\n * <template data-stimeo--toast-target=\"template\">\n * <li data-stimeo--toast-target=\"item\" tabindex=\"0\">\n * <span role=\"status\" data-toast-slot=\"body\"></span>\n * <button type=\"button\" data-toast-dismiss>Dismiss</button>\n * </li>\n * </template>\n * </div>\n * </div>\n *\n * Implements WAI-ARIA live region status/alert announcements, limits simultaneous\n * elements, and pauses dismiss timeouts on hover or focus to comply with WCAG 2.2.1.\n * Pausing never dismisses: a deadline that lapsed while the timer sat queued settles\n * once the last of hover and focus is released, so the pointer's target and the\n * focused control stay where they are.\n *\n * `dismiss` dispatches `{ item: HTMLElement, reason: \"timeout\" | \"user\" }`.\n *\n * `show` dispatches `{ item: HTMLElement }`.\n *\n * @remarks\n * Behavior only. The controller handles state updates via `data-state` and lifecycle events\n * while leaving visual styling completely to the client's CSS transitions.\n */\nexport class ToastController extends Controller<HTMLElement> {\n static override targets = [\"list\", \"template\", \"item\"];\n static override values = {\n duration: { type: Number, default: 0 },\n max: { type: Number, default: 3 },\n };\n static actions = [\"dismiss\", \"onKeydown\", \"pause\", \"resume\", \"show\"] as const;\n static events = [\"dismiss\", \"show\"] as const;\n\n declare readonly listTarget: HTMLElement;\n declare readonly templateTarget: HTMLTemplateElement;\n declare readonly itemTargets: HTMLElement[];\n declare readonly hasListTarget: boolean;\n declare readonly hasTemplateTarget: boolean;\n\n declare durationValue: number;\n declare maxValue: number;\n\n /** Removal timers for the leaving transition; the auto-dismiss ones live below. */\n #timers = new SafeTimeout();\n\n /** Per-toast auto-dismiss, held open while the toast is hovered or focused. */\n readonly #dismiss = new PausableTimers<HTMLElement>();\n\n /**\n * Pending one-shot `requestAnimationFrame` handles (the entering→visible flip).\n * Tracked so {@link disconnect} can cancel any that have not fired, preventing a\n * detached element from being mutated after it leaves the DOM (Turbo).\n */\n #rafHandles = new Map<HTMLElement, number>();\n\n /** The stable list that owns delegated listeners for dynamically added items. */\n #delegatedList: HTMLElement | null = null;\n\n override connect(): void {\n this.#connectDelegatedEvents();\n this.enforceMaxLimit();\n for (const item of this.itemTargets) {\n if (!this.#dismiss.tracks(item) && item.dataset.state !== \"leaving\") {\n this.#startTimer(item);\n }\n }\n }\n\n override disconnect(): void {\n // Both registries own every timer the controller schedules, so a call each\n // leaves none to fire against the detached controller.\n this.#disconnectDelegatedEvents();\n this.#timers.clearAll();\n this.#dismiss.clearAll();\n for (const handle of this.#rafHandles.values()) {\n window.cancelAnimationFrame(handle);\n }\n this.#rafHandles.clear();\n }\n\n /** Rebinds delegated interaction when Turbo replaces the list target in place. */\n listTargetConnected(element: HTMLElement): void {\n if (this.#delegatedList !== element) this.#connectDelegatedEvents(element);\n }\n\n /** Releases delegation only when the removed target is its current owner. */\n listTargetDisconnected(element: HTMLElement): void {\n if (this.#delegatedList === element) this.#disconnectDelegatedEvents();\n }\n\n durationValueChanged(): void {\n for (const item of this.itemTargets) {\n if (item.dataset.state === \"leaving\") continue;\n\n if (this.durationValue <= 0) {\n this.#dismiss.clear(item);\n item.removeAttribute(\"data-paused\");\n } else {\n // A toast held by hover or focus keeps its hold and banks the new\n // duration, so the change reaches it without dismissing it.\n this.#startTimer(item);\n }\n }\n }\n\n maxValueChanged(): void {\n this.enforceMaxLimit();\n }\n\n /**\n * Stimulus lifecycle callback triggered automatically when a new item target\n * enters the DOM, from a client-side injection or a Turbo Stream append alike. An\n * item already leaving, or parented outside `list`, is skipped.\n */\n itemTargetConnected(element: HTMLElement): void {\n this.enforceMaxLimit();\n if (element.dataset.state === \"leaving\" || element.parentNode !== this.listTarget) return;\n\n this.#startTimer(element);\n element.setAttribute(\"data-state\", \"entering\");\n this.#cancelAnimation(element);\n const handle = window.requestAnimationFrame(() => {\n this.#rafHandles.delete(element);\n if (element.parentNode !== this.listTarget || element.dataset.state === \"leaving\") return;\n element.setAttribute(\"data-state\", \"visible\");\n });\n this.#rafHandles.set(element, handle);\n }\n\n /** Clears any active timer when a toast is removed from the DOM. */\n itemTargetDisconnected(element: HTMLElement): void {\n this.#dismiss.clear(element);\n this.#cancelAnimation(element);\n }\n\n /**\n * Shows a new toast. Accepts its content from either a Stimulus action param\n * (attribute-only trigger) or a programmatic `show` CustomEvent `detail`\n * (remote / Turbo trigger); the action param wins when both are present.\n *\n * <button data-action=\"click->stimeo--toast#show\"\n * data-stimeo--toast-body-param=\"Saved\"\n * data-stimeo--toast-type-param=\"status\">Show</button>\n *\n * element.dispatchEvent(new CustomEvent(\"show\", { detail: { body, type } }))\n *\n * Clones the template slot, interpolates the body text, and appends to the list.\n */\n show(event: Event): void {\n if (!this.hasTemplateTarget || !this.hasListTarget) return;\n\n const body = this.#readField(event, \"body\");\n if (!body) return;\n\n const clone = this.templateTarget.content.cloneNode(true) as DocumentFragment;\n const item = clone.querySelector(\"[data-stimeo--toast-target='item']\") as HTMLElement | null;\n if (!item) return;\n\n const bodySlot = item.querySelector<HTMLElement>(\"[data-toast-slot='body']\");\n if (!bodySlot) return;\n bodySlot.textContent = body;\n\n // Validate the live-region role at runtime; untrusted params/detail could\n // otherwise write an invalid ARIA role. Anything but \"alert\" stays polite.\n bodySlot.setAttribute(\"role\", this.#readField(event, \"type\") === \"alert\" ? \"alert\" : \"status\");\n\n this.listTarget.appendChild(item);\n this.dispatch(\"show\", { detail: { item } });\n }\n\n /**\n * Reads a string field from a Stimulus action param or a CustomEvent `detail`,\n * preferring the action param. Returns null unless a non-empty string is found,\n * so untrusted runtime payloads cannot inject non-string values.\n */\n #readField(event: Event, key: \"body\" | \"type\"): string | null {\n const params = (event as { params?: Record<string, unknown> }).params;\n const fromParams = params?.[key];\n if (typeof fromParams === \"string\" && fromParams.length > 0) return fromParams;\n\n const detail = (event as CustomEvent<unknown>).detail;\n if (detail && typeof detail === \"object\" && key in detail) {\n const value = (detail as Record<string, unknown>)[key];\n if (typeof value === \"string\" && value.length > 0) return value;\n }\n return null;\n }\n\n /** Dismisses the toast that contained the trigger. */\n dismiss(event: Event): void {\n const item = this.#itemFromEvent(event);\n if (!item) return;\n\n this.#removeWithTransition(item, \"user\");\n }\n\n /** Dismisses the focused toast when Escape is pressed. */\n onKeydown(event: KeyboardEvent): void {\n if (event.key === \"Escape\") {\n // Leave a press an inner handler already owned.\n // A press during IME composition (a text field inside the toast) cancels\n // the conversion, never the toast.\n if (event.defaultPrevented || event.isComposing) return;\n const item = this.#itemFromEvent(event);\n if (!item) return;\n\n event.preventDefault();\n this.#removeWithTransition(item, \"user\");\n }\n }\n\n /**\n * Pauses the auto-dismiss timer on mouse entry or keyboard focus.\n *\n * Hover and focus are tracked as independent reasons: the timer is only\n * snapshotted on the first active reason, and only resumed once *every*\n * reason has been released (see {@link resume}). This keeps a toast paused\n * while it is still hovered *or* focused, per WCAG 2.2.1.\n */\n pause(event: Event): void {\n const item = this.#itemFromEvent(event);\n if (item && this.#dismiss.pause(item, this.#pauseReason(event))) {\n item.setAttribute(\"data-paused\", \"true\");\n }\n }\n\n /** Resumes the auto-dismiss timer once both hover and focus have been released. */\n resume(event: Event): void {\n const item = this.#itemFromEvent(event);\n if (item && this.#dismiss.resume(item, this.#pauseReason(event))) {\n item.removeAttribute(\"data-paused\");\n }\n }\n\n /** Resolves the toast item element a pause/resume event targets. */\n #itemFromEvent(event: Event): HTMLElement | null {\n const target = event.target instanceof Element ? event.target : event.currentTarget;\n if (!(target instanceof Element) || !this.hasListTarget) return null;\n const item = target.closest<HTMLElement>(\"[data-stimeo--toast-target='item']\");\n return item && this.listTarget.contains(item) ? item : null;\n }\n\n /** Classifies a pause/resume event as a hover or focus reason. */\n #pauseReason(event: Event): \"focus\" | \"hover\" {\n return event.type === \"focusin\" || event.type === \"focusout\" ? \"focus\" : \"hover\";\n }\n\n /** Arms a toast's auto-dismiss; a non-positive `duration` means it never expires. */\n #startTimer(element: HTMLElement): void {\n if (\n this.durationValue <= 0 ||\n element.dataset.state === \"leaving\" ||\n element.parentNode !== this.listTarget\n ) {\n return;\n }\n\n this.#dismiss.set(\n element,\n () => this.#removeWithTransition(element, \"timeout\"),\n this.durationValue,\n );\n }\n\n #removeWithTransition(element: HTMLElement, reason: \"timeout\" | \"user\"): void {\n if (element.dataset.state === \"leaving\" || element.parentNode !== this.listTarget) return;\n\n this.#dismiss.clear(element);\n this.#cancelAnimation(element);\n element.setAttribute(\"data-state\", \"leaving\");\n\n const finalize = () => {\n if (element.parentNode !== this.listTarget) return;\n this.listTarget.removeChild(element);\n this.dispatch(\"dismiss\", { detail: { item: element, reason } });\n };\n\n const duration = maxTransitionTotalMs(window.getComputedStyle(element));\n if (duration > 0) {\n this.#timers.set(finalize, duration);\n } else {\n finalize();\n }\n }\n\n /**\n * Removes the oldest toasts when the list exceeds `maxValue`.\n *\n * Public (not `#private`) as a deterministic seam: enforcement normally runs\n * from `itemTargetConnected`, a Stimulus callback delivered through a\n * MutationObserver, which a DOM-only environment does not reliably fire — so\n * it can also be invoked directly. It is not a user-wired action.\n */\n enforceMaxLimit(): void {\n const currentItems = this.itemTargets;\n const max = Math.max(0, this.maxValue);\n if (currentItems.length > max) {\n const excessCount = currentItems.length - max;\n for (let i = 0; i < excessCount; i++) {\n const oldest = currentItems[i];\n if (oldest) this.#removeWithTransition(oldest, \"timeout\");\n }\n }\n }\n\n /** Wires stable-container delegation so newly appended items work immediately. */\n #connectDelegatedEvents(list = this.hasListTarget ? this.listTarget : null): void {\n this.#disconnectDelegatedEvents();\n if (!list) return;\n\n this.#delegatedList = list;\n for (const type of DELEGATED_EVENTS) {\n this.#delegatedList.addEventListener(type, this.#onListEvent);\n }\n }\n\n /** Releases every delegated listener from the exact list that owns it. */\n #disconnectDelegatedEvents(): void {\n if (!this.#delegatedList) return;\n\n for (const type of DELEGATED_EVENTS) {\n this.#delegatedList.removeEventListener(type, this.#onListEvent);\n }\n this.#delegatedList = null;\n }\n\n /** Routes every delegated item interaction from the stable list. */\n readonly #onListEvent = (event: Event): void => {\n if (event.type === \"click\") {\n const target = event.target instanceof Element ? event.target : null;\n const trigger = target?.closest<HTMLElement>(\"[data-toast-dismiss]\");\n if (trigger && this.#delegatedList?.contains(trigger)) this.dismiss(event);\n } else if (event.type === \"keydown\") {\n this.onKeydown(event as KeyboardEvent);\n } else if (this.#crossesItemBoundary(event)) {\n if (event.type === \"focusin\" || event.type === \"mouseover\") this.pause(event);\n else this.resume(event);\n }\n };\n\n /** Whether a bubbling focus/pointer event enters or leaves a toast boundary. */\n #crossesItemBoundary(event: Event): boolean {\n const item = this.#itemFromEvent(event);\n if (!item) return false;\n const related = \"relatedTarget\" in event ? event.relatedTarget : null;\n return !(related instanceof Node && item.contains(related));\n }\n\n /** Cancels the pending entering-to-visible frame owned by one item. */\n #cancelAnimation(element: HTMLElement): void {\n const handle = this.#rafHandles.get(element);\n if (handle === undefined) return;\n window.cancelAnimationFrame(handle);\n this.#rafHandles.delete(element);\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/utils/event_owner.ts","../../src/utils/listener_set.ts","../../src/utils/microtask_coalescer.ts","../../src/utils/safe_timeout.ts","../../src/utils/keyed_timers.ts","../../src/utils/pausable_timers.ts","../../src/utils/target_selector.ts","../../src/utils/template_row.ts","../../src/utils/transition_completion.ts","../../src/controllers/toast_controller.ts"],"names":[],"mappings":"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","file":"toast_controller.js","sourcesContent":["/**\n * Resolves which of a controller's elements owns a node.\n *\n * A delegated listener hears events from a whole subtree, so the handler's first\n * job is almost always the same question: which item, handle, or control does\n * this `event.target` belong to? The same question comes up for a\n * `MutationRecord.target`, for `document.activeElement`, and for a\n * `relatedTarget` on the way out of a hover region.\n *\n * The answer is `Node.contains()`, which is **inclusive** — an element contains\n * itself — so testing the candidate for identity as well would be redundant.\n *\n * **The guard is what makes this safe to call with a raw event target.**\n * `event.target` is typed `EventTarget | null`, and `contains()` takes a `Node?`:\n * browsers throw `TypeError` for anything else, and `window` — the everyday\n * `EventTarget` that is not a `Node` — is what an event dispatched at it carries.\n * Narrowing here means a caller never has to cast, and the rule cannot drift\n * between the places that ask the question.\n *\n * Scope stays with the caller. These helpers say *which candidate owns the node*,\n * not *whether the node belongs to this controller at all* — a component with\n * nested instances of itself decides that first (by comparing the closest\n * annotated ancestor) and passes the candidates it owns.\n */\n\n/**\n * Index in `candidates` of the first one that is, or contains, `node`.\n *\n * `-1` when none does, when `node` is absent, and when it is an `EventTarget`\n * that is not a `Node`. Candidates are tested in array order, so a nested pair\n * resolves to whichever the caller listed first.\n */\nexport function ownerIndex<T extends Element>(\n candidates: readonly T[],\n node: EventTarget | null | undefined,\n): number {\n if (!(node instanceof Node)) return -1;\n return candidates.findIndex((candidate) => candidate.contains(node));\n}\n\n/**\n * The first candidate that is, or contains, `node`; `null` when none does.\n *\n * A miss indexes the array at `-1`, which reads as `undefined` and lands on the\n * same `null` the absent cases produce.\n */\nexport function ownerOf<T extends Element>(\n candidates: readonly T[],\n node: EventTarget | null | undefined,\n): T | null {\n return candidates[ownerIndex(candidates, node)] ?? null;\n}\n","/**\n * Owns every listener a controller attaches for one connected lifetime and\n * releases them together, so an event name is spelled once and the release\n * cannot drift from the registration.\n *\n * Detaching by hand repeats three things at the release site — the type, the\n * handler reference and the capture flag — and any one of them drifting leaves\n * a listener alive on an element the controller no longer drives. Aborting the\n * signal a registration was created with releases it whatever it was made of,\n * so the release site names nothing.\n *\n * One set per lifetime, held as a field and never rebuilt. {@link\n * ListenerSet.dispose} is the only thing that closes a generation, and it opens\n * the next one in the same step, so the lifecycle hooks can call `add` and\n * `dispose` in any order any number of times, and no `add` ever meets an\n * already aborted signal — a DOM that registers a listener on such a signal\n * would keep it forever. Rebuilding the set instead would leak:\n * `addEventListener` matches an existing registration on target, type, callback\n * and capture alone, so re-adding the same handler while the first registration\n * is live is discarded, and that live registration keeps the signal it was\n * attached with — a set built by a second `connect()` can never release what it\n * appears to own.\n *\n * Scope is the registration only. Timers, observers, leases and the order they\n * are unwound in stay with the controller, so `dispose()` belongs exactly where\n * the `removeEventListener` block stood. A receiver that changes at runtime (a\n * swapped target) is rebound by calling `dispose()` and then `add()` again from\n * the rebind, not by a second set.\n *\n * The set must own every registration of a tuple it holds: a listener the same\n * target already carries for the same type, callback and capture flag keeps the\n * right to remove it, and this set's `add` for that tuple is discarded. A\n * subscription shared between instances behind a participant count, or one that\n * lives for less than the connection, keeps its own pair of calls.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #listeners = new ListenerSet();\n *\n * connect(): void {\n * this.#listeners.add(this.element, \"submit\", this.#onNativeSubmit, { capture: true });\n * this.#listeners.add(this.element, \"turbo:submit-start\", this.#onSubmitStart);\n * this.#listeners.add(this.element, \"turbo:submit-end\", this.#onSubmitEnd);\n * }\n *\n * disconnect(): void {\n * this.#listeners.dispose();\n * }\n * ```\n */\nexport class ListenerSet {\n /** The generation every `add` joins until the next `dispose()`. */\n #abort = new AbortController();\n\n /**\n * Attaches `handler` to the open generation, exactly as the caller spelled it.\n *\n * The set supplies the signal, so `options` carries everything else the DOM\n * accepts — `capture` included, which has to match at release time and no\n * longer has a second place to drift from.\n */\n add(\n target: EventTarget,\n type: string,\n handler: EventListener,\n options?: Omit<AddEventListenerOptions, \"signal\">,\n ): void {\n target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });\n }\n\n /**\n * Releases every listener of the open generation, synchronously, and opens the\n * next one. Idempotent, and safe before anything has been added.\n */\n dispose(): void {\n this.#abort.abort();\n this.#abort = new AbortController();\n }\n}\n","/**\n * Collapses many Stimulus lifecycle callbacks from one DOM mutation into a\n * single pass.\n *\n * Stimulus fires `<name>TargetConnected` / `Disconnected` once per element and\n * `<name>ValueChanged` once per changed attribute. Replacing a list of N options\n * or morphing several render Values therefore delivers N callbacks — but the\n * useful unit of work is \"reconcile against the resulting declarative input\",\n * once, after the batch has settled. Every controller with reconcilable targets\n * or render Values needs the same shape: a `queued` flag plus `queueMicrotask`.\n *\n * **A microtask is the right horizon, and the reason is specific.** Stimulus\n * drives these callbacks from a `MutationObserver`, whose own callback already\n * runs as a microtask with the whole batch in hand; scheduling one more lands\n * after the last sibling callback of that batch and still before paint or any\n * event handler. A timer would be later than it needs to be, and reconciling\n * synchronously would run once per element against a half-applied DOM.\n *\n * **The two guards are not the same guard.** Scheduling is refused before the\n * controller connects, and running is refused after it disconnects:\n *\n * - **Before `connect()`** — Stimulus delivers initial target and Value callbacks\n * ahead of `connect()`. Reconciling there would compute output against a\n * controller whose own state has not been initialised, and `connect()` is\n * about to do a full pass anyway.\n * - **After `disconnect()`** — Stimulus fires a callback for **every** target\n * during teardown, and a microtask queued just before it would otherwise run\n * against a detached tree. {@link MicrotaskCoalescer.cancel} exists for the\n * teardown path to drop the pending pass outright.\n *\n * Both guards are part of one contract here rather than something each consumer\n * has to remember separately.\n *\n * Scope is the scheduling only. *What* to reconcile — keep the surviving active\n * option, fall back to the next / previous / first visible one, rebuild derived\n * chips or hidden fields — stays in the controller, because no two consumers\n * answer it the same way.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileOptions());\n *\n * connect() { this.#reconcile.activate(); }\n * disconnect() { this.#reconcile.cancel(); }\n *\n * optionTargetConnected() { this.#reconcile.schedule(); }\n * optionTargetDisconnected() { this.#reconcile.schedule(); }\n * ```\n */\nexport class MicrotaskCoalescer {\n readonly #run: () => void;\n #queued = false;\n #active = false;\n #generation = 0;\n\n /** @param run - the single reconciliation pass, invoked at most once per batch. */\n constructor(run: () => void) {\n this.#run = run;\n }\n\n /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */\n activate(): void {\n this.#active = true;\n }\n\n /** Closes the window and drops any pending pass; call from `disconnect()`. */\n cancel(): void {\n this.#active = false;\n this.#queued = false;\n this.#generation += 1;\n }\n\n /** Requests one pass after the batch settles. Idempotent; inert outside the window. */\n schedule(): void {\n if (!this.#active || this.#queued) return;\n this.#queued = true;\n const generation = this.#generation;\n queueMicrotask(() => {\n // A cancelled callback must not consume a pass queued after reconnect.\n if (generation !== this.#generation || !this.#queued || !this.#active) return;\n this.#queued = false;\n this.#run();\n });\n }\n}\n","/**\n * Self-cleaning timer registries shared by Stimeo controllers.\n *\n * Stimulus controllers frequently schedule `setTimeout` / `setInterval` work\n * (auto-dismiss, debouncing, polling). When the element leaves the DOM — a\n * Turbo Drive navigation, a Turbo Stream replacement, or any `disconnect()` —\n * orphaned timers keep firing against a detached controller, leaking memory and\n * mutating stale state. {@link SafeTimeout} and {@link SafeInterval} track every\n * timer they create so a single {@link TimerRegistry.clearAll | clearAll()} call\n * in `disconnect()` tears them all down.\n *\n * These are intentionally low-level primitives: they own *registration and\n * cleanup only*. Higher-level policy (pause/resume, remaining-time accounting)\n * stays in the individual controllers so per-widget semantics are not flattened\n * into a lowest-common-denominator helper.\n */\n\n/**\n * Largest delay a timer can hold: the platform stores it in a 32-bit signed\n * integer, and anything larger overflows to `1`, so a delay meant to be far in\n * the future fires almost immediately. A declared delay above this bound names\n * no delay at all, and a controller reading one falls back to its default.\n */\nexport const MAX_TIMER_DELAY_MS = 2_147_483_647;\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 { SafeTimeout } from \"./safe_timeout\";\n\n/**\n * Keeps at most one pending timer per key, and releases them all together.\n *\n * A region, a row, a message or a speaker that is armed again while its earlier\n * timer is still pending must end up with exactly one timer deciding when its\n * state ends. Two timers on one key means the earlier deadline wins: it cuts the\n * new emphasis short, clears text written after it, or drops a speaker who is\n * still typing — and then reports an ending for a state that is already gone.\n * Arming through this registry cancels the key's earlier timer in the same step,\n * and no timer id ever reaches the caller.\n *\n * An entry lives exactly as long as its timer: it goes as the timer fires, and\n * the whole ledger goes on `clearAll()`. That is a correctness rule, not\n * tidiness — a platform may hand an id released by `clearTimeout` to the next\n * timer it creates, so an entry that outlived its timer would let a later\n * `clear()` on that key cancel whatever timer now holds the id, on some other\n * key entirely.\n *\n * The ledger is a plain `Map`, and the key may be anything. Weak keys would\n * retain nothing less: while a timer is pending the platform already holds the\n * key through the callback, and the entry is gone the moment the timer is.\n *\n * Scope is the one-per-key timer only. What the timer means, and the roster of\n * keys it is armed for, stay with the consumer, so a second kind of timer on the\n * same keys (a transition wait, an animation frame) is a second registry, and a\n * timer that belongs to no key stays on a plain `SafeTimeout`.\n *\n * @example\n * ```ts\n * readonly #expiry = new KeyedTimers<string>();\n *\n * #onSignal(name: string): void {\n * this.#expiry.set(name, () => this.#drop(name), this.#timeout);\n * }\n *\n * disconnect(): void {\n * this.#expiry.clearAll();\n * }\n * ```\n */\nexport class KeyedTimers<K> {\n readonly #timers = new SafeTimeout();\n\n /** The pending timer of each key; an entry lives exactly as long as its timer. */\n readonly #pending = new Map<K, number>();\n\n /**\n * Arms `callback` after `delay` ms for `key`, cancelling the timer `key` had\n * pending. The entry is dropped before the callback runs, so the callback sees\n * the key unarmed and may arm it again for the next round.\n */\n set(key: K, callback: () => void, delay: number): void {\n this.clear(key);\n const id = this.#timers.set(() => {\n this.#pending.delete(key);\n callback();\n }, delay);\n this.#pending.set(key, id);\n }\n\n /**\n * Cancels `key`'s pending timer, if it has one.\n *\n * A timer id is a positive integer, so `-1` stands for \"nothing pending\" and\n * the registry ignores an id it does not own — the unarmed case needs no\n * branch of its own, and no other key's timer can be reached from here.\n */\n clear(key: K): void {\n this.#timers.clear(this.#pending.get(key) ?? -1);\n this.#pending.delete(key);\n }\n\n /**\n * Cancels every pending timer and forgets every key. Call this from a\n * controller's `disconnect()` so no timer, and no entry, outlives the element.\n */\n clearAll(): void {\n this.#timers.clearAll();\n this.#pending.clear();\n }\n\n /** Whether `key` has a timer pending. */\n has(key: K): boolean {\n return this.#pending.has(key);\n }\n}\n","import { KeyedTimers } from \"./keyed_timers\";\n\n/** What a key needs to carry on: the work, when it was last armed, and who is holding it. */\ninterface Entry {\n /** The work to run once the time is up; `null` while the key is held with no timer. */\n callback: (() => void) | null;\n /** Epoch ms the running timer was armed at; written only where the timer is armed. */\n startedAt: number;\n remaining: number;\n reasons: Set<string>;\n}\n\n/**\n * Keeps one self-dismissing timer per key that a person can hold open.\n *\n * A notification that takes itself away has to stop while the pointer is over it\n * or the focus is inside it, and pick up where it left off once both have gone\n * (WAI-ARIA and WCAG 2.2 call this being able to pause a time limit). Each reason\n * to hold is tracked on its own, because a pointer leaving while focus stays is\n * not a release: the time left is banked when the first reason arrives, and the\n * timer is armed again with that bank only after the last one is released.\n *\n * **Holding never dismisses.** A deadline that passed while the timer sat queued\n * — a throttled tab, a long task — is banked as one millisecond, so the\n * notification goes right after the last reason is released rather than during\n * the event that holds it. Taking it away there would remove the element under\n * the pointer, or the control that has focus, and focus would fall to the body.\n *\n * Arming a held key keeps the hold and banks the new delay for the resume, so a\n * duration that changes at runtime reaches a held notification without\n * dismissing it or releasing it.\n *\n * A hold is recorded whether or not the key has a timer: one that arrives before\n * the timer is set holds that timer back, and one on a key that never\n * auto-dismisses still answers {@link PausableTimers.isHeld}. That answer is what\n * a consumer that removes keys for reasons of its own — a cap on how many show\n * at once — reads to leave a held one in place. {@link PausableTimers.disarm}\n * drops a timer and keeps its hold, and a key with neither is forgotten.\n *\n * Scope is the timer and its hold. Whether a key may be held at all, and the\n * state hook that shows it is held, stay with the consumer.\n *\n * @example\n * ```ts\n * readonly #dismiss = new PausableTimers<HTMLElement>();\n *\n * pause(event: Event): void {\n * const item = this.#itemFromEvent(event);\n * if (item && this.#dismiss.pause(item, this.#pauseReason(event))) {\n * item.setAttribute(\"data-paused\", \"true\");\n * }\n * }\n * ```\n */\nexport class PausableTimers<K> {\n readonly #timers = new KeyedTimers<K>();\n\n /** Every key armed or held; an entry goes as its timer fires, or with the key. */\n readonly #entries = new Map<K, Entry>();\n\n /**\n * Arms `callback` after `delay` ms for `key`, replacing whatever `key` had.\n * A held key stays held and banks `delay` for its resume.\n */\n set(key: K, callback: () => void, delay: number): void {\n const reasons = this.#entries.get(key)?.reasons ?? new Set<string>();\n const entry: Entry = { callback, startedAt: 0, remaining: delay, reasons };\n this.#entries.set(key, entry);\n if (reasons.size === 0) this.#arm(key, entry, callback);\n }\n\n /**\n * Holds `key` for `reason` and banks the time left, with a floor of one\n * millisecond. A key with no timer is held all the same. Reports whether this\n * call is the one that stopped a running timer, so the caller can write its\n * held-state hook exactly once.\n */\n pause(key: K, reason: string): boolean {\n let entry = this.#entries.get(key);\n if (entry === undefined) {\n entry = { callback: null, startedAt: 0, remaining: 0, reasons: new Set<string>() };\n this.#entries.set(key, entry);\n }\n entry.reasons.add(reason);\n if (!this.#timers.has(key)) return false;\n this.#timers.clear(key);\n entry.remaining = Math.max(1, entry.remaining - (Date.now() - entry.startedAt));\n return true;\n }\n\n /**\n * Releases `reason` on `key`, arming the banked time again once no reason is\n * left; a key released with no timer is forgotten. Reports whether this call\n * is the one that started the timer again.\n */\n resume(key: K, reason: string): boolean {\n const entry = this.#entries.get(key);\n if (entry === undefined) return false;\n entry.reasons.delete(reason);\n if (entry.reasons.size > 0 || this.#timers.has(key)) return false;\n const { callback } = entry;\n if (callback === null) {\n this.#entries.delete(key);\n return false;\n }\n this.#arm(key, entry, callback);\n return true;\n }\n\n /** Whether any reason holds `key`, with or without a timer. */\n isHeld(key: K): boolean {\n return (this.#entries.get(key)?.reasons.size ?? 0) > 0;\n }\n\n /** Whether `key` is armed or held — that is, whether this registry drives it at all. */\n tracks(key: K): boolean {\n return this.#entries.has(key);\n }\n\n /**\n * Cancels `key`'s timer and keeps its hold, so a release arms nothing; a key\n * nothing holds is forgotten.\n */\n disarm(key: K): void {\n this.#timers.clear(key);\n const entry = this.#entries.get(key);\n if (entry?.reasons.size) entry.callback = null;\n else this.#entries.delete(key);\n }\n\n /** Cancels `key`'s timer and drops its hold. */\n clear(key: K): void {\n this.#timers.clear(key);\n this.#entries.delete(key);\n }\n\n /**\n * Cancels every timer and forgets every key. Call this from a controller's\n * `disconnect()` so neither a timer nor a hold outlives the element.\n */\n clearAll(): void {\n this.#timers.clearAll();\n this.#entries.clear();\n }\n\n /** Starts `entry`'s banked time running for `key`, and drops it as `callback` fires. */\n #arm(key: K, entry: Entry, callback: () => void): void {\n entry.startedAt = Date.now();\n this.#timers.set(\n key,\n () => {\n this.#entries.delete(key);\n callback();\n },\n entry.remaining,\n );\n }\n}\n","/**\n * The attribute selector for one declared target, in a controller's own namespace.\n *\n * Stimulus reads `data-<identifier>-target` as a **space-separated token list**, so a\n * single element can carry several target names at once. Matching the attribute value\n * whole would reach only the elements that declare exactly one name, which is why the\n * name is paired with `~=`.\n *\n * `identifier` is the name the controller is registered under, so the selector reaches\n * the markup that registration renders rather than one fixed spelling.\n */\nexport function targetSelector(identifier: string, name: string): string {\n return `[data-${identifier}-target~=\"${name}\"]`;\n}\n","import { fillTemplate } from \"./announce\";\nimport { matchingPart } from \"./element_part\";\nimport { targetSelector } from \"./target_selector\";\n\n/**\n * Clones the first element of a `<template>`, and nothing else.\n *\n * A template is authored across lines, so its content holds whitespace text nodes\n * around that element — and a second element, where one is written. Cloning the\n * element on its own makes it the whole unit the caller appends, so the same node\n * a later `remove()` takes back is everything that went in, and the parent's child\n * list stays equal to its element list.\n *\n * `null` when the content has no element at all.\n */\nexport function cloneTemplateRoot(template: HTMLTemplateElement): HTMLElement | null {\n const root = template.content.firstElementChild;\n return root instanceof HTMLElement ? (root.cloneNode(true) as HTMLElement) : null;\n}\n\n/** What a consumer declares once about the rows it builds from a `<template>`. */\nexport interface TemplateRowOptions<R extends string, O extends string> {\n /** The controller identifier the row's parts are declared against. */\n readonly identifier: string;\n /** Target name the row itself carries. */\n readonly root: string;\n /** Target names the row must contain; the first one missing is the one reported. */\n readonly required: readonly R[];\n /** Target names the row may contain; a missing one resolves to `null`. */\n readonly optional?: readonly O[];\n /** Target name of the `<button>` whose authored `aria-label` names the row. */\n readonly button: string;\n /** What the widget did not do, e.g. `\"added no tag\"`. */\n readonly outcome: string;\n /** What the author wrote it in, e.g. `\"chip template\"`. */\n readonly noun: string;\n}\n\n/** One row: the element to append, the parts inside it, and its named button. */\nexport interface TemplateRowParts<R extends string, O extends string> {\n readonly root: HTMLElement;\n readonly slots: Readonly<Record<R, HTMLElement> & Record<O, HTMLElement | null>>;\n readonly button: HTMLButtonElement;\n}\n\n/**\n * Builds one row from an authored `<template>`, naming an unusable one once per connection.\n *\n * **The row is the template's only element, and it carries {@link\n * TemplateRowOptions.root} itself.** Cloning it alone ({@link cloneTemplateRoot})\n * makes what the caller appends exactly what a later `remove()` takes back; a row\n * wrapped in another element, or standing beside a second one, would leave that\n * other element behind on every removal — or never be rendered at all — so such a\n * template is refused rather than half-built.\n *\n * Parts resolve through the caller's own namespace, derived from the identifier\n * the controller is registered under, so a registration under any name reaches\n * the attributes that registration renders.\n *\n * A template that cannot produce a row yields `null` and changes nothing: what a\n * refused row means for the selection, the field, or the announcement stays with\n * the caller. The diagnostic names what is wrong — the element count, or the first\n * missing part — because the only other symptom is a widget that silently adds\n * nothing, and the causes a static check cannot see — a server-rendered template,\n * a name that renders empty from a missing translation — would have no diagnostic\n * anywhere. It is written once per connection, so one authoring mistake cannot\n * flood the console.\n *\n * @example\n * ```ts\n * readonly #rows = new TemplateRow({\n * identifier: this.identifier,\n * root: \"tag\",\n * required: [\"label\"],\n * button: \"remove\",\n * outcome: \"added no tag\",\n * noun: \"chip template\",\n * });\n *\n * connect(): void {\n * this.#rows.connect();\n * }\n * ```\n */\nexport class TemplateRow<R extends string, O extends string = never> {\n readonly #options: TemplateRowOptions<R, O>;\n #warned = false;\n\n constructor(options: TemplateRowOptions<R, O>) {\n this.#options = options;\n }\n\n /** The attribute selector for one declared part, in this controller's namespace. */\n selector(name: string): string {\n return targetSelector(this.#options.identifier, name);\n }\n\n /** Re-arms the once-per-connection diagnostic. */\n connect(): void {\n this.#warned = false;\n }\n\n /**\n * Names one missing part on the console, at most once per connection, and\n * returns `null` so a caller can hand it straight back.\n */\n report(missing: string): null {\n return this.#say(`lacks ${missing}`);\n }\n\n /** Writes one diagnostic per connection, saying what the template got wrong. */\n #say(problem: string): null {\n if (this.#warned) return null;\n this.#warned = true;\n const { identifier, outcome, noun } = this.#options;\n console.warn(`Stimeo UI: \"${identifier}\" ${outcome} because its ${noun} ${problem}.`);\n return null;\n }\n\n /**\n * Clones the row and resolves its parts, or names what the template got wrong\n * and returns `null`. `values` fills the button's authored `aria-label`.\n */\n instantiate(\n template: HTMLTemplateElement,\n values: Record<string, string | number>,\n ): TemplateRowParts<R, O> | null {\n const { root: rootName, required, optional, button: buttonName } = this.#options;\n const root = cloneTemplateRoot(template);\n if (!root?.matches(this.selector(rootName))) {\n return this.report(`${this.#article(rootName)} \"${rootName}\" root`);\n }\n // One element, and it is the row: anything beside it would be left behind by\n // a removal that takes the row back, which is the accumulation this contract\n // exists to stop. The row here is the one that was asked for, so the count is\n // what the diagnostic names — a missing part would point at the wrong element.\n const count = template.content.children.length;\n if (count !== 1) {\n return this.#say(`holds ${count} elements, and the row has to be its only one`);\n }\n // Required parts are resolved before they are written, so the declared shape\n // holds for every row returned at all — a missing one leaves through `report`\n // instead. The accumulator is keyed loosely because that ordering is what\n // makes the narrower return type true, and no index signature can say so.\n const slots: Record<string, HTMLElement | null> = {};\n for (const name of required) {\n const part = this.#resolve(root, name);\n if (!part) return this.report(`${this.#article(name)} \"${name}\" target`);\n slots[name] = part;\n }\n for (const name of optional ?? []) slots[name] = this.#resolve(root, name);\n const named = this.#resolve(root, buttonName);\n if (!(named instanceof HTMLButtonElement)) {\n return this.report(`${this.#article(buttonName)} \"${buttonName}\" target <button>`);\n }\n const button = named;\n const name = button.getAttribute(\"aria-label\")?.trim() ?? \"\";\n if (name === \"\") return this.report(`a non-empty aria-label on its \"${buttonName}\" target`);\n button.setAttribute(\"aria-label\", fillTemplate(name, values));\n return { root, slots, button } as TemplateRowParts<R, O>;\n }\n\n /** The row may be its own part; otherwise the first descendant carrying the target. */\n #resolve(root: HTMLElement, name: string): HTMLElement | null {\n return matchingPart(root, this.selector(name));\n }\n\n #article(name: string): string {\n return /^[aeiou]/i.test(name) ? \"an\" : \"a\";\n }\n}\n","import { SafeTimeout } from \"./safe_timeout\";\n\n/** Computed transition fields needed to determine when an element has settled. */\nexport type TransitionStyle = Pick<\n CSSStyleDeclaration,\n \"transitionProperty\" | \"transitionDuration\" | \"transitionDelay\"\n>;\n\n/** Parsed transition property paired with its effective duration and delay. */\ninterface TransitionTiming {\n property: string;\n totalMs: number;\n}\n\n/** Parses a CSS `<time>` into milliseconds, returning `0` for malformed values. */\nfunction timeMs(value: string): number {\n const trimmed = value.trim();\n const amount = Number.parseFloat(trimmed);\n if (!Number.isFinite(amount)) return 0;\n if (trimmed.endsWith(\"ms\")) return amount;\n if (trimmed.endsWith(\"s\")) return amount * 1000;\n return 0;\n}\n\n/** Splits a computed comma-separated CSS list into normalized, non-empty items. */\nfunction cssList(value: string): string[] {\n return value\n .split(\",\")\n .map((item) => item.trim())\n .filter(Boolean);\n}\n\n/**\n * Pairs transition properties, durations, and delays using CSS list repetition.\n *\n * The `transition-property` list determines the number of transitions. Shorter\n * duration/delay lists repeat, while extra values are ignored. A negative delay\n * shortens the remaining wall-clock time, and a non-positive total is settled.\n */\nfunction transitionTimings(style: TransitionStyle): TransitionTiming[] {\n const properties = cssList(style.transitionProperty);\n const durations = cssList(style.transitionDuration).map(timeMs);\n const delays = cssList(style.transitionDelay).map(timeMs);\n const effectiveProperties =\n properties.length > 0\n ? properties\n : Array.from({ length: Math.max(durations.length, delays.length, 1) }, () => \"all\");\n const effectiveDurations = durations.length > 0 ? durations : [0];\n const effectiveDelays = delays.length > 0 ? delays : [0];\n\n return effectiveProperties\n .filter((property) => property !== \"none\")\n .map((property, index) => ({\n property,\n totalMs: Math.max(\n 0,\n (effectiveDurations[index % effectiveDurations.length] ?? 0) +\n (effectiveDelays[index % effectiveDelays.length] ?? 0),\n ),\n }));\n}\n\n/** Maximum total over already-parsed timings (0 when the list is empty). */\nfunction maxTotalMs(timings: TransitionTiming[]): number {\n return timings.reduce((max, { totalMs }) => Math.max(max, totalMs), 0);\n}\n\n/** Maximum effective transition duration plus delay, in milliseconds. */\nexport function maxTransitionTotalMs(style: TransitionStyle): number {\n return maxTotalMs(transitionTimings(style));\n}\n\n/** Optional tuning for a single {@link TransitionCompletion.wait} call. */\nexport interface TransitionWaitOptions {\n /**\n * Positive wall-clock override (ms) for the bounded fallback, replacing the\n * auto-computed `max + 50ms` timer verbatim. It also keeps the wait armed for\n * a computed 0ms transition (no synchronous completion): the consumer asserts\n * a transition budget that computed styles cannot see. Non-positive and\n * non-finite (`NaN` / `Infinity`) values are ignored.\n */\n timeoutMs?: number;\n}\n\n/**\n * Owns one cancellable wait for an element's CSS transitions to settle.\n *\n * When available, active CSS transitions provide their expanded property names.\n * Tracking those names lets shorthand declarations settle from their longhand\n * terminal events. A terminal event from an interrupted phase is ignored while a\n * replacement transition for the same property is still active. Because that set\n * is sampled when the wait is armed, a property whose transition only starts a\n * frame later would otherwise be settled over; the still-running set is therefore\n * re-read before completing and adopted when it is not yet empty. Without Web\n * Animations data, explicit transition properties retain the declared-property\n * behavior and the ambiguous `transition-property: all` form waits until the\n * computed maximum wall-clock time. A `max + 50ms` timeout is always armed\n * because browsers emit no terminal event when a property never transitions, an\n * ancestor disappears, or rendering is otherwise interrupted; a consumer with\n * better knowledge can replace that fallback via\n * {@link TransitionWaitOptions.timeoutMs}.\n */\nexport class TransitionCompletion {\n readonly #timers = new SafeTimeout();\n #element: HTMLElement | null = null;\n #complete: (() => void) | null = null;\n #pendingProperties: Set<string> | null = null;\n #deadline = 0;\n\n /**\n * Replaces any prior wait and invokes `complete` synchronously for a 0ms\n * transition (including when `getComputedStyle` is unavailable).\n *\n * With a positive `options.timeoutMs` the synchronous fast-path is skipped and\n * the override replaces the auto-computed fallback (see {@link TransitionWaitOptions}).\n */\n wait(element: HTMLElement, complete: () => void, options: TransitionWaitOptions = {}): void {\n this.cancel();\n\n const requested = options.timeoutMs ?? 0;\n const override = Number.isFinite(requested) && requested > 0 ? requested : 0;\n // A non-browser / partial-DOM environment cannot report a computable\n // transition, which is indistinguishable from a 0ms one.\n const timings =\n typeof window.getComputedStyle === \"function\"\n ? transitionTimings(window.getComputedStyle(element))\n : [];\n const maximum = maxTotalMs(timings);\n if (maximum <= 0 && override <= 0) {\n complete();\n return;\n }\n\n this.#element = element;\n this.#complete = complete;\n this.#deadline = Date.now() + maximum;\n const activeProperties = this.#activeTransitionProperties(element);\n this.#pendingProperties =\n activeProperties.size > 0 ? activeProperties : this.#explicitPendingProperties(timings);\n element.addEventListener(\"transitionend\", this.#onTerminal);\n element.addEventListener(\"transitioncancel\", this.#onTerminal);\n this.#timers.set(() => this.#finish(), override > 0 ? override : maximum + 50);\n }\n\n /** Cancels the pending wait without invoking its completion callback. */\n cancel(): void {\n this.#complete = null;\n this.#teardown();\n }\n\n /**\n * Handles terminal events from the observed element only.\n *\n * For explicit property lists, every declared positive-time property must\n * settle. For `all`, no reliable property set exists, so an event can finish\n * only after the computed maximum time; the safety timeout owns the usual path.\n */\n readonly #onTerminal = (event: Event): void => {\n if (event.target !== this.#element) return;\n const transitionEvent = event as TransitionEvent;\n // A pseudo-element's transition is reported with its originating element\n // as `target`; it must not settle the element's own transition.\n if (transitionEvent.pseudoElement) return;\n\n if (this.#pendingProperties) {\n const propertyName = transitionEvent.propertyName;\n const active = this.#activeTransitionProperties(this.#element);\n // An interrupted transition queues its cancel event before the replacement\n // phase starts, but dispatch can happen after the new wait is armed. The\n // replacement is then the active transition for this property, so the stale\n // terminal event must not settle the new phase.\n if (active.has(propertyName)) return;\n if (!this.#pendingProperties.delete(propertyName)) return;\n if (this.#pendingProperties.size > 0) return;\n // The tracked set is an arm-time snapshot, so a transition the phase starts\n // one frame later is absent from it. Re-reading the still-running set before\n // settling adopts those stragglers instead of completing over them; the\n // fallback timer stays armed, so this cannot extend the wait unboundedly.\n if (active.size > 0) {\n this.#pendingProperties = active;\n return;\n }\n this.#finish();\n return;\n }\n\n if (Date.now() >= this.#deadline) this.#finish();\n };\n\n /**\n * Returns active CSS transition properties expanded to the names reported by\n * terminal events. CSS animations and pseudo-element effects are excluded.\n */\n #activeTransitionProperties(element: HTMLElement | null): Set<string> {\n if (!element || typeof element.getAnimations !== \"function\") return new Set();\n\n try {\n const properties = element.getAnimations().flatMap((animation) => {\n if (animation.playState === \"idle\" || animation.playState === \"finished\") return [];\n const effect = animation.effect as KeyframeEffect | null;\n // A pseudo-element effect names the originating element as its target, so\n // `target` alone cannot separate it. Its terminal events are ignored, so\n // tracking its properties would only strand the wait on the fallback.\n if (effect?.pseudoElement) return [];\n const target = effect?.target;\n if (target && target !== element) return [];\n const property = (animation as Partial<CSSTransition>).transitionProperty;\n return typeof property === \"string\" && property.length > 0 ? [property] : [];\n });\n return new Set(properties);\n } catch {\n // Partial DOM implementations can expose getAnimations without supporting\n // it. The declared-property tracker and bounded timer remain safe fallbacks.\n return new Set();\n }\n }\n\n /** Returns explicit positive-time properties, or `null` for the ambiguous `all`. */\n #explicitPendingProperties(timings: TransitionTiming[]): Set<string> | null {\n if (timings.some(({ property }) => property === \"all\")) return null;\n const pending = new Set(\n timings.filter(({ totalMs }) => totalMs > 0).map(({ property }) => property),\n );\n // An empty set is only reachable through a timeout override (a 0ms transition\n // otherwise completes synchronously). With nothing to track, fall back to the\n // deadline rule so any terminal event can settle the wait, exactly like `all`.\n return pending.size > 0 ? pending : null;\n }\n\n /** Completes exactly once, releasing listeners and the fallback before the callback. */\n #finish(): void {\n const complete = this.#complete;\n if (!complete) return;\n this.#complete = null;\n this.#teardown();\n complete();\n }\n\n /** Releases the exact element listeners and timer owned by the current wait. */\n #teardown(): void {\n this.#timers.clearAll();\n this.#element?.removeEventListener(\"transitionend\", this.#onTerminal);\n this.#element?.removeEventListener(\"transitioncancel\", this.#onTerminal);\n this.#element = null;\n this.#pendingProperties = null;\n this.#deadline = 0;\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { ownerOf } from \"../utils/event_owner\";\nimport { ListenerSet } from \"../utils/listener_set\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\nimport { PausableTimers } from \"../utils/pausable_timers\";\nimport { SafeTimeout } from \"../utils/safe_timeout\";\nimport { targetSelector } from \"../utils/target_selector\";\nimport { cloneTemplateRoot } from \"../utils/template_row\";\nimport { maxTransitionTotalMs } from \"../utils/transition_completion\";\n\nconst DELEGATED_EVENTS = [\"click\", \"focusin\", \"focusout\", \"keydown\", \"mouseover\", \"mouseout\"];\n\n/**\n * Headless, highly accessible toast notification behavior.\n *\n * Markup contract (identifier: `stimeo--toast`):\n * <div data-controller=\"stimeo--toast\"\n * data-stimeo--toast-duration-value=\"5000\"\n * data-stimeo--toast-max-value=\"3\">\n * <!-- Attribute-only trigger: no hand-written JS required. -->\n * <button data-action=\"click->stimeo--toast#show\"\n * data-stimeo--toast-message-param=\"Saved\"\n * data-stimeo--toast-type-param=\"status\">Show</button>\n * <!-- The live region is a descendant; the controller element only needs\n * to enclose both the trigger(s) and the list/template targets. -->\n * <div role=\"region\" aria-label=\"Notifications\">\n * <ol data-stimeo--toast-target=\"list\"></ol>\n * <template data-stimeo--toast-target=\"template\">\n * <li data-stimeo--toast-target=\"item\" tabindex=\"0\">\n * <span role=\"status\" data-toast-slot=\"message\"></span>\n * <button type=\"button\" data-toast-dismiss>Dismiss</button>\n * </li>\n * </template>\n * </div>\n * </div>\n *\n * Implements WAI-ARIA live region status/alert announcements, limits simultaneous\n * elements, and pauses dismiss timeouts on hover or focus to comply with WCAG 2.2.1.\n * Pausing never dismisses: a deadline that lapsed while the timer sat queued settles\n * once the last of hover and focus is released, so the pointer's target and the\n * focused control stay where they are.\n *\n * The `max` limit (`0` or less, or not a finite number, means none) keeps them there too.\n * Past it the oldest toasts go with reason `limit`, passing over every toast the pointer\n * is over or focus is inside — whether or not a timer runs — the toast just taken on, and\n * the one the pointer or focus is moving into. While nothing else can go the list stays\n * over the limit, and the limit is applied again once hover and focus have both left a\n * toast, or a toast they held leaves the list.\n *\n * `dismiss` dispatches `{ item: HTMLElement, reason: \"timeout\" | \"user\" | \"limit\" }`.\n *\n * `show` dispatches `{ item: HTMLElement }`.\n *\n * @remarks\n * Behavior only. The controller handles state updates via `data-state` and lifecycle events\n * while leaving visual styling completely to the client's CSS transitions.\n */\nexport class ToastController extends Controller<HTMLElement> {\n static override targets = [\"list\", \"template\", \"item\"];\n static override values = {\n duration: { type: Number, default: 0 },\n max: { type: Number, default: 3 },\n };\n static actions = [\"dismiss\", \"onKeydown\", \"pause\", \"resume\", \"show\"] as const;\n static events = [\"dismiss\", \"show\"] as const;\n\n declare readonly listTarget: HTMLElement;\n declare readonly templateTarget: HTMLTemplateElement;\n declare readonly itemTargets: HTMLElement[];\n declare readonly hasListTarget: boolean;\n declare readonly hasTemplateTarget: boolean;\n\n declare durationValue: number;\n declare maxValue: number;\n\n /** Removal timers for the leaving transition; the auto-dismiss ones live below. */\n #timers = new SafeTimeout();\n\n /** Per-toast auto-dismiss, held open while the toast is hovered or focused. */\n readonly #dismiss = new PausableTimers<HTMLElement>();\n\n /** Toasts taken on and not let go; a move within the list keeps a toast here. */\n readonly #taken = new Set<HTMLElement>();\n\n /** Applies the `max` limit again once the event that released a hold has run its course. */\n readonly #reapply = new MicrotaskCoalescer(() => this.#reapplyLimit());\n\n /** Toasts the pointer or focus moved into since the limit was last applied again. */\n #spared: HTMLElement[] = [];\n\n /** The next pointer movement, listened for while a hover hold waits on it. */\n readonly #pointer = new ListenerSet();\n\n /** Toasts whose hover hold waits for the next pointer movement to be confirmed. */\n readonly #awaitingPointer = new Set<HTMLElement>();\n\n /**\n * Pending one-shot `requestAnimationFrame` handles (the entering→visible flip).\n * Tracked so {@link disconnect} can cancel any that have not fired, preventing a\n * detached element from being mutated after it leaves the DOM (Turbo).\n */\n #rafHandles = new Map<HTMLElement, number>();\n\n /** The stable list that owns delegated listeners for dynamically added items. */\n #delegatedList: HTMLElement | null = null;\n\n /** Whether the controller is between `connect()` and `disconnect()`. */\n #connected = false;\n\n /**\n * The `max` the list was last held to, or `null` before the first time. `connect()`\n * applies the limit only when `max` is not that one, so a reconnect of the same instance\n * leaves the list as it was unless `max` changed while it was away.\n */\n #appliedMax: number | null = null;\n\n /**\n * Stimulus reports every toast the list already holds before this runs, and each is\n * taken on then with its holds, meeting no limit. The limit is applied here once, over\n * all of them, unless the list was already held to the current `max`.\n */\n override connect(): void {\n this.#connected = true;\n this.#reapply.activate();\n this.#connectDelegatedEvents();\n for (const item of this.itemTargets) {\n if (!this.#dismiss.tracks(item) && item.dataset.state !== \"leaving\") {\n this.#startTimer(item);\n }\n }\n if (!Object.is(this.#appliedMax, this.maxValue)) {\n this.#appliedMax = this.maxValue;\n this.#enforceMax();\n }\n }\n\n override disconnect(): void {\n this.#connected = false;\n // Both registries own every timer the controller schedules, so a call each\n // leaves none to fire against the detached controller.\n this.#disconnectDelegatedEvents();\n this.#timers.clearAll();\n this.#dismiss.clearAll();\n this.#taken.clear();\n this.#reapply.cancel();\n this.#spared = [];\n this.#pointer.dispose();\n this.#awaitingPointer.clear();\n for (const handle of this.#rafHandles.values()) {\n window.cancelAnimationFrame(handle);\n }\n this.#rafHandles.clear();\n }\n\n /** Rebinds delegated interaction when Turbo replaces the list target in place. */\n listTargetConnected(element: HTMLElement): void {\n if (this.#delegatedList !== element) this.#connectDelegatedEvents(element);\n }\n\n /** Releases delegation only when the removed target is its current owner. */\n listTargetDisconnected(element: HTMLElement): void {\n if (this.#delegatedList === element) this.#disconnectDelegatedEvents();\n }\n\n durationValueChanged(): void {\n for (const item of this.itemTargets) {\n if (item.dataset.state === \"leaving\") continue;\n\n if (this.durationValue <= 0) {\n // The timer goes and the hold stays, so the limit still passes over a held toast.\n this.#dismiss.disarm(item);\n item.removeAttribute(\"data-paused\");\n } else {\n // A toast held by hover or focus keeps its hold and banks the new\n // duration, so the change reaches it without dismissing it.\n this.#startTimer(item);\n }\n }\n }\n\n /**\n * Holds the list to a changed `max`. Stimulus can also call this ahead of `connect()` —\n * for an attribute that changed while the controller was away, and on every connect\n * for an undeclared `max`, with its default; `connect()` decides then.\n */\n maxValueChanged(): void {\n if (!this.#connected) return;\n this.#appliedMax = this.maxValue;\n this.enforceMaxLimit();\n }\n\n /**\n * Stimulus lifecycle callback triggered automatically when a new item target\n * enters the DOM, from a client-side injection or a Turbo Stream append alike, and for\n * every toast the list already holds ahead of `connect()`. An item already leaving,\n * parented outside `list`, or already taken on (a move within the list) is skipped; any\n * other is taken on with the holds it already has. On a connected controller the `max`\n * limit is then applied, never to the arrival itself; the toasts reported ahead of\n * `connect()` are left to it.\n */\n itemTargetConnected(element: HTMLElement): void {\n if (this.#taken.has(element)) return;\n if (element.dataset.state === \"leaving\" || element.parentNode !== this.listTarget) return;\n\n this.#taken.add(element);\n this.#readHolds(element);\n this.#startTimer(element);\n element.setAttribute(\"data-state\", \"entering\");\n this.#cancelAnimation(element);\n const handle = window.requestAnimationFrame(() => {\n this.#rafHandles.delete(element);\n if (element.parentNode !== this.listTarget || element.dataset.state === \"leaving\") return;\n element.setAttribute(\"data-state\", \"visible\");\n });\n this.#rafHandles.set(element, handle);\n if (this.#connected) this.#enforceMax([element]);\n }\n\n /**\n * Lets go of a toast that left the list or stopped being an item: its timer, holds,\n * `data-paused` and pending frame. After a move within the list the node is already\n * back, still an item, when Stimulus reports it, so it keeps all of those, and only the\n * holds the move may have ended are read again.\n */\n itemTargetDisconnected(element: HTMLElement): void {\n const moved =\n this.#isShown(element) && element.matches(targetSelector(this.identifier, \"item\"));\n if (moved) {\n this.#afterMove(element);\n return;\n }\n this.#taken.delete(element);\n element.removeAttribute(\"data-paused\");\n this.#letGo(element);\n this.#cancelAnimation(element);\n }\n\n /**\n * Shows a new toast. Accepts its content from either a Stimulus action param\n * (attribute-only trigger) or a programmatic `show` CustomEvent `detail`\n * (remote / Turbo trigger); the action param wins when both are present.\n *\n * <button data-action=\"click->stimeo--toast#show\"\n * data-stimeo--toast-message-param=\"Saved\"\n * data-stimeo--toast-type-param=\"status\">Show</button>\n *\n * element.dispatchEvent(new CustomEvent(\"show\", { detail: { message, type } }))\n *\n * Clones the template slot, interpolates the message, and appends to the list.\n * `message` is the wording key the rest of the library dispatches under, so a\n * part that already carries its own wording — `stimeo--clipboard:copy`,\n * `stimeo--auto-submit:done` — wires straight into this action.\n */\n show(event: Event): void {\n if (!this.hasTemplateTarget || !this.hasListTarget) return;\n\n const message = this.#readField(event, \"message\");\n if (!message) return;\n\n // The toast is the template's only element, cloned on its own, so the node\n // appended here is exactly the one a later dismissal takes back and the list\n // holds nothing but toasts. Anything standing beside it would never be shown.\n const template = this.templateTarget;\n const item = cloneTemplateRoot(template);\n if (template.content.children.length !== 1) return;\n if (!item?.matches(targetSelector(this.identifier, \"item\"))) return;\n\n const messageSlot = item.querySelector<HTMLElement>(\"[data-toast-slot='message']\");\n if (!messageSlot) return;\n messageSlot.textContent = message;\n\n // Validate the live-region role at runtime; untrusted params/detail could\n // otherwise write an invalid ARIA role. Anything but \"alert\" stays polite.\n messageSlot.setAttribute(\n \"role\",\n this.#readField(event, \"type\") === \"alert\" ? \"alert\" : \"status\",\n );\n\n this.listTarget.appendChild(item);\n this.dispatch(\"show\", { detail: { item } });\n }\n\n /**\n * Reads a string field from a Stimulus action param or a CustomEvent `detail`,\n * preferring the action param. Returns null unless a non-empty string is found,\n * so untrusted runtime payloads cannot inject non-string values.\n */\n #readField(event: Event, key: \"message\" | \"type\"): string | null {\n const params = (event as { params?: Record<string, unknown> }).params;\n const fromParams = params?.[key];\n if (typeof fromParams === \"string\" && fromParams.length > 0) return fromParams;\n\n const detail = (event as CustomEvent<unknown>).detail;\n if (detail && typeof detail === \"object\" && key in detail) {\n const value = (detail as Record<string, unknown>)[key];\n if (typeof value === \"string\" && value.length > 0) return value;\n }\n return null;\n }\n\n /** Dismisses the toast that contained the trigger. */\n dismiss(event: Event): void {\n const item = this.#itemFromEvent(event);\n if (!item) return;\n\n this.#removeWithTransition(item, \"user\");\n }\n\n /** Dismisses the focused toast when Escape is pressed. */\n onKeydown(event: KeyboardEvent): void {\n if (event.key === \"Escape\") {\n // Leave a press an inner handler already owned.\n // A press during IME composition (a text field inside the toast) cancels\n // the conversion, never the toast.\n if (event.defaultPrevented || event.isComposing) return;\n const item = this.#itemFromEvent(event);\n if (!item) return;\n\n event.preventDefault();\n this.#removeWithTransition(item, \"user\");\n }\n }\n\n /**\n * Pauses the auto-dismiss timer on mouse entry or keyboard focus.\n *\n * Hover and focus are tracked as independent reasons: the timer is only\n * snapshotted on the first active reason, and only resumed once *every*\n * reason has been released (see {@link resume}). This keeps a toast paused\n * while it is still hovered *or* focused, per WCAG 2.2.1. The hold is recorded\n * whether or not a timer runs, so the `max` limit passes over the toast either\n * way; `data-paused` marks a timer that stopped, and only that.\n */\n pause(event: Event): void {\n const item = this.#itemFromEvent(event);\n if (item && this.#dismiss.pause(item, this.#pauseReason(event))) {\n item.setAttribute(\"data-paused\", \"true\");\n }\n }\n\n /**\n * Resumes the auto-dismiss timer once both hover and focus have been released,\n * and then applies the `max` limit again, sparing the toast the pointer or focus is\n * moving into: its own hold only arrives after this event.\n */\n resume(event: Event): void {\n const item = this.#itemFromEvent(event);\n if (item) {\n this.#release(\n item,\n this.#pauseReason(event),\n ownerOf(this.itemTargets, (event as Partial<FocusEvent>).relatedTarget),\n );\n }\n }\n\n /** Releases one reason on `item`; releasing the last one applies the limit again. */\n #release(item: HTMLElement, reason: \"focus\" | \"hover\", spare: HTMLElement | null): void {\n const held = this.#dismiss.isHeld(item);\n if (this.#dismiss.resume(item, reason)) item.removeAttribute(\"data-paused\");\n if (held && !this.#dismiss.isHeld(item)) this.#limitLater(spare);\n }\n\n /**\n * Applies the limit again once the current event is over, sparing `spare`. A hold can\n * end in a `focusout` the engine fires while it is itself taking the node out for a\n * script's move or removal, and taking the toast away inside that event would pull\n * the node from under the caller's own call.\n */\n #limitLater(spare: HTMLElement | null): void {\n if (spare) this.#spared.push(spare);\n this.#reapply.schedule();\n }\n\n /** Applies the limit again, sparing every toast gathered since the last pass. */\n #reapplyLimit(): void {\n const spared = this.#spared;\n this.#spared = [];\n this.#enforceMax(spared);\n }\n\n /**\n * Reads the holds of a toast that moved within the list. Focus is read at once: an\n * ordinary move ends it with a `focusout` and `moveBefore` keeps it. Where the pointer\n * is, nothing says until it moves again: no `mouseout` reaches a moved node, and\n * `:hover` can answer from before the move. A toast still held waits for that movement.\n */\n #afterMove(item: HTMLElement): void {\n if (!item.contains(document.activeElement)) this.#release(item, \"focus\", null);\n if (this.#dismiss.isHeld(item)) this.#awaitPointer(item);\n }\n\n /**\n * Takes the holds a toast already has as it is taken on: focus inside it, and the pointer\n * over it by `:hover`. That answer can date from before the toast came here, so a hover\n * hold taken on it waits for the next pointer movement to be confirmed.\n */\n #readHolds(item: HTMLElement): void {\n if (item.contains(document.activeElement)) this.#dismiss.pause(item, \"focus\");\n if (!item.matches(\":hover\")) return;\n this.#dismiss.pause(item, \"hover\");\n this.#awaitPointer(item);\n }\n\n /** Leaves `item`'s hover hold to be confirmed or let go on the next pointer movement. */\n #awaitPointer(item: HTMLElement): void {\n this.#awaitingPointer.add(item);\n this.#pointer.add(document, \"pointermove\", this.#onPointerMove, {\n capture: true,\n passive: true,\n });\n }\n\n /**\n * Reads `:hover` once the pointer has moved, when the answer is current, and lets go of\n * the hover hold of every waiting toast the pointer is not over. Listens once.\n */\n readonly #onPointerMove = (): void => {\n this.#pointer.dispose();\n const waiting = [...this.#awaitingPointer];\n this.#awaitingPointer.clear();\n for (const item of waiting) {\n if (!item.matches(\":hover\")) this.#release(item, \"hover\", null);\n }\n };\n\n /**\n * Drops a toast's timer and holds as it leaves, and stops waiting on the pointer for it.\n * A toast something still held counts as released: the limit is applied again.\n */\n #letGo(item: HTMLElement): void {\n if (this.#dismiss.isHeld(item)) this.#limitLater(null);\n this.#dismiss.clear(item);\n this.#awaitingPointer.delete(item);\n if (this.#awaitingPointer.size === 0) this.#pointer.dispose();\n }\n\n /** Resolves the toast item element a pause/resume event targets. */\n #itemFromEvent(event: Event): HTMLElement | null {\n const target = event.target instanceof Element ? event.target : event.currentTarget;\n if (!(target instanceof Element) || !this.hasListTarget) return null;\n const item = target.closest<HTMLElement>(targetSelector(this.identifier, \"item\"));\n return item && this.listTarget.contains(item) ? item : null;\n }\n\n /** Classifies a pause/resume event as a hover or focus reason. */\n #pauseReason(event: Event): \"focus\" | \"hover\" {\n return event.type === \"focusin\" || event.type === \"focusout\" ? \"focus\" : \"hover\";\n }\n\n /**\n * Arms a toast's auto-dismiss; a non-positive `duration` means it never expires.\n * On a toast hover or focus already holds, the timer waits for the release.\n * `data-paused` is written from that state, so a mark the toast carried in with it,\n * from a restored page, does not outlive it.\n *\n * @stimeoRuntimeOnly `duration` is the delay of the one dismissal timer this call arms.\n */\n #startTimer(element: HTMLElement): void {\n if (element.dataset.state === \"leaving\" || element.parentNode !== this.listTarget) return;\n\n const armed = this.durationValue > 0;\n if (armed) {\n this.#dismiss.set(\n element,\n () => this.#removeWithTransition(element, \"timeout\"),\n this.durationValue,\n );\n }\n if (armed && this.#dismiss.isHeld(element)) element.setAttribute(\"data-paused\", \"true\");\n else element.removeAttribute(\"data-paused\");\n }\n\n #removeWithTransition(element: HTMLElement, reason: \"timeout\" | \"user\" | \"limit\"): void {\n if (element.dataset.state === \"leaving\" || element.parentNode !== this.listTarget) return;\n\n this.#letGo(element);\n this.#cancelAnimation(element);\n element.setAttribute(\"data-state\", \"leaving\");\n\n const finalize = () => {\n if (element.parentNode !== this.listTarget) return;\n this.listTarget.removeChild(element);\n this.dispatch(\"dismiss\", { detail: { item: element, reason } });\n };\n\n const duration = maxTransitionTotalMs(window.getComputedStyle(element));\n if (duration > 0) {\n this.#timers.set(finalize, duration);\n } else {\n finalize();\n }\n }\n\n /**\n * Removes the oldest toasts while the list shows more than `maxValue`, passing\n * over every toast hover or focus holds.\n *\n * Public (not `#private`) as a deterministic seam: enforcement normally runs\n * as each toast is taken on in `itemTargetConnected`, a Stimulus callback delivered\n * through a MutationObserver, which a DOM-only environment does not reliably fire —\n * so it can also be invoked directly. It counts only the toasts taken on. It is not a\n * user-wired action.\n */\n enforceMaxLimit(): void {\n this.#enforceMax();\n }\n\n /**\n * Removes the oldest toasts with reason `limit` while the list shows more than `max`\n * (`0` or less, or not a finite number, means no limit), passing over every toast hover\n * or focus holds and those in `spared` — the toast just taken on, or the ones the\n * pointer or focus moved into. Only toasts taken on count or go, so one Stimulus has\n * yet to report is neither; a toast already leaving does not count. With nothing else\n * left to go the list stays over the limit. The count is read again on every step,\n * because a `dismiss` listener may already have changed it.\n *\n * @stimeoRenderRoot\n */\n #enforceMax(spared: readonly HTMLElement[] = []): void {\n if (!Number.isFinite(this.maxValue) || this.maxValue <= 0) return;\n for (const item of this.itemTargets) {\n if (this.#shownCount() <= this.maxValue) return;\n if (this.#isShown(item) && !spared.includes(item) && !this.#dismiss.isHeld(item)) {\n this.#removeWithTransition(item, \"limit\");\n }\n }\n }\n\n /** How many toasts the list shows: the ones taken on that are still shown. */\n #shownCount(): number {\n return this.itemTargets.filter((item) => this.#isShown(item)).length;\n }\n\n /** Whether the list shows `item`: a toast taken on, a child of `list`, not leaving. */\n #isShown(item: HTMLElement): boolean {\n return (\n this.#taken.has(item) &&\n this.hasListTarget &&\n item.parentNode === this.listTarget &&\n item.dataset.state !== \"leaving\"\n );\n }\n\n /** Wires stable-container delegation so newly appended items work immediately. */\n #connectDelegatedEvents(list = this.hasListTarget ? this.listTarget : null): void {\n this.#disconnectDelegatedEvents();\n if (!list) return;\n\n this.#delegatedList = list;\n for (const type of DELEGATED_EVENTS) {\n this.#delegatedList.addEventListener(type, this.#onListEvent);\n }\n }\n\n /** Releases every delegated listener from the exact list that owns it. */\n #disconnectDelegatedEvents(): void {\n if (!this.#delegatedList) return;\n\n for (const type of DELEGATED_EVENTS) {\n this.#delegatedList.removeEventListener(type, this.#onListEvent);\n }\n this.#delegatedList = null;\n }\n\n /** Routes every delegated item interaction from the stable list. */\n readonly #onListEvent = (event: Event): void => {\n if (event.type === \"click\") {\n const target = event.target instanceof Element ? event.target : null;\n const trigger = target?.closest<HTMLElement>(\"[data-toast-dismiss]\");\n if (trigger && this.#delegatedList?.contains(trigger)) this.dismiss(event);\n } else if (event.type === \"keydown\") {\n this.onKeydown(event as KeyboardEvent);\n } else if (this.#crossesItemBoundary(event)) {\n if (event.type === \"focusin\" || event.type === \"mouseover\") this.pause(event);\n else this.resume(event);\n }\n };\n\n /** Whether a bubbling focus/pointer event enters or leaves a toast boundary. */\n #crossesItemBoundary(event: Event): boolean {\n const item = this.#itemFromEvent(event);\n if (!item) return false;\n const related = \"relatedTarget\" in event ? event.relatedTarget : null;\n return !(related instanceof Node && item.contains(related));\n }\n\n /** Cancels the pending entering-to-visible frame owned by one item. */\n #cancelAnimation(element: HTMLElement): void {\n const handle = this.#rafHandles.get(element);\n if (handle === undefined) return;\n window.cancelAnimationFrame(handle);\n this.#rafHandles.delete(element);\n }\n}\n"]}
@@ -6,7 +6,9 @@ import { Controller } from '@hotwired/stimulus';
6
6
  * Markup contract (identifier: `stimeo--toggle-group`):
7
7
  * <div data-controller="stimeo--toggle-group"
8
8
  * data-stimeo--toggle-group-mode-value="single"
9
+ * data-stimeo--toggle-group-name-value="styles[]"
9
10
  * role="group" aria-label="Text style">
11
+ * <div data-stimeo--toggle-group-target="fields"></div>
10
12
  * <button type="button" aria-pressed="true" tabindex="0" data-value="bold"
11
13
  * data-stimeo--toggle-group-target="item">Bold</button>
12
14
  * <!-- more items; exactly one navigable item has tabindex=0 -->
@@ -18,7 +20,8 @@ import { Controller } from '@hotwired/stimulus';
18
20
  * exclusive selection with radio semantics, use
19
21
  * {@link RadioGroupController | Radio Group} instead.
20
22
  *
21
- * `change` dispatches `{ value: string, pressed: boolean, values: string[] }`.
23
+ * `change` dispatches `{ value: string, pressed: boolean, values: string[] }`;
24
+ * `reconcile` dispatches `{ values: string[] }`.
22
25
  *
23
26
  * @remarks
24
27
  * Behavior only — the consumer styles off `[aria-pressed="true"]`. A supported
@@ -40,7 +43,25 @@ import { Controller } from '@hotwired/stimulus';
40
43
  * items remain discoverable in the roving order but cannot be activated.
41
44
  * - `stimeo--toggle-group:change` is dispatched only for user activation. Its
42
45
  * detail is `{ value: string, pressed: boolean, values: string[] }`, where
43
- * `values` is the DOM-ordered value list of every item left pressed.
46
+ * `values` is the DOM-ordered value list of every item left pressed. A press
47
+ * that a listener of its native `change` replaces with a press of its own
48
+ * dispatches no `change`: the newer press reports itself, so every `change`
49
+ * describes the set as it is when it goes out.
50
+ * - `stimeo--toggle-group:reconcile` reports a pressed set the page moved
51
+ * instead — items arriving or leaving, a `mode` change, an in-place
52
+ * `aria-pressed` or `data-value` write, first-wins in `single` mode, a host
53
+ * the group stands down on — once per batch and never on connect. Its detail
54
+ * is `{ values: string[] }` alone, unlike `change`: a page-driven move changes
55
+ * the set, not one item's press.
56
+ * - With a `fields` target the pressed values are mirrored into `name`d hidden
57
+ * inputs so the group can be submitted and read server-side — one per pressed
58
+ * item in DOM order, so `single` mode submits 0 or 1. `form` points them at a
59
+ * `<form>` by id when the group sits outside it. A toggle the user made emits
60
+ * a native bubbling `change` from the container, the way a form control does,
61
+ * so `stimeo--auto-submit` and form-level validation hear it. The mirror is
62
+ * refreshed silently on connect, on item churn, whenever `mode`, `name` or
63
+ * `form` changes, and — through the group's own mutation observer — when the
64
+ * container itself is replaced.
44
65
  */
45
66
  declare class ToggleGroupController extends Controller<HTMLElement> {
46
67
  #private;
@@ -50,25 +71,46 @@ declare class ToggleGroupController extends Controller<HTMLElement> {
50
71
  type: StringConstructor;
51
72
  default: string;
52
73
  };
74
+ name: {
75
+ type: StringConstructor;
76
+ default: string;
77
+ };
78
+ form: {
79
+ type: StringConstructor;
80
+ default: string;
81
+ };
53
82
  };
54
83
  static actions: readonly ["onKeydown", "toggle"];
55
- static events: readonly ["change"];
84
+ static events: readonly ["change", "reconcile"];
56
85
  readonly itemTargets: HTMLElement[];
86
+ readonly fieldsTarget: HTMLElement;
87
+ readonly hasFieldsTarget: boolean;
57
88
  modeValue: string;
89
+ nameValue: string;
90
+ formValue: string;
58
91
  /**
59
92
  * Normalizes state and establishes one roving entry point. A single authored
60
93
  * `tabindex="0"` survives reconnect; otherwise the first pressed, navigable
61
- * item wins, falling back to the first navigable item.
94
+ * item wins, falling back to the first navigable item. The pressed set it
95
+ * settles on is the one a later move is measured from; connecting reports
96
+ * nothing.
62
97
  */
63
98
  connect(): void;
64
- /** Releases every listener and observer while retaining DOM state for Turbo cache/reconnect. */
99
+ /**
100
+ * Releases every listener, the observer, and a pass still queued, while
101
+ * retaining DOM state for Turbo cache/reconnect.
102
+ */
65
103
  disconnect(): void;
66
- /** Drops a newly connected item from the Tab sequence before reconciling the group. */
104
+ /** Drops a newly connected item from the Tab sequence before the batch is reconciled. */
67
105
  itemTargetConnected(item: HTMLElement): void;
68
- /** Restores attributes owned only while an element is an item and repairs the Tab stop. */
106
+ /** Restores attributes owned only while an element is an item, then reconciles the batch. */
69
107
  itemTargetDisconnected(item: HTMLElement): void;
70
108
  /** Reconciles the single-selection invariant when the Stimulus Value changes. */
71
109
  modeValueChanged(): void;
110
+ /** Rebuilds the submitted fields when the public name changes at runtime. */
111
+ nameValueChanged(): void;
112
+ /** Repoints the submitted fields when the owning form changes at runtime. */
113
+ formValueChanged(): void;
72
114
  /**
73
115
  * Toggles the action's item. Per-item action wiring is optional because click
74
116
  * is also delegated from the group.