stimeo-ui 0.15.0 → 0.17.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 (332) hide show
  1. package/CHANGELOG.md +209 -0
  2. package/README.md +128 -1
  3. package/dist/cable/index.d.ts +79 -23
  4. package/dist/cable/index.js +392 -417
  5. package/dist/cable/index.js.map +1 -1
  6. package/dist/controllers/accordion_controller.d.ts +34 -5
  7. package/dist/controllers/accordion_controller.js +228 -28
  8. package/dist/controllers/accordion_controller.js.map +1 -1
  9. package/dist/controllers/alert_dialog_controller.d.ts +20 -9
  10. package/dist/controllers/alert_dialog_controller.js +862 -221
  11. package/dist/controllers/alert_dialog_controller.js.map +1 -1
  12. package/dist/controllers/announcer_controller.d.ts +38 -7
  13. package/dist/controllers/announcer_controller.js +135 -191
  14. package/dist/controllers/announcer_controller.js.map +1 -1
  15. package/dist/controllers/aspect_ratio_controller.js +0 -10
  16. package/dist/controllers/aspect_ratio_controller.js.map +1 -1
  17. package/dist/controllers/auto_submit_controller.d.ts +30 -6
  18. package/dist/controllers/auto_submit_controller.js +295 -110
  19. package/dist/controllers/auto_submit_controller.js.map +1 -1
  20. package/dist/controllers/avatar_controller.js +172 -106
  21. package/dist/controllers/avatar_controller.js.map +1 -1
  22. package/dist/controllers/breadcrumb_controller.d.ts +10 -7
  23. package/dist/controllers/breadcrumb_controller.js +0 -129
  24. package/dist/controllers/breadcrumb_controller.js.map +1 -1
  25. package/dist/controllers/bulk_select_controller.d.ts +22 -4
  26. package/dist/controllers/bulk_select_controller.js +264 -53
  27. package/dist/controllers/bulk_select_controller.js.map +1 -1
  28. package/dist/controllers/calendar_controller.d.ts +109 -28
  29. package/dist/controllers/calendar_controller.js +346 -180
  30. package/dist/controllers/calendar_controller.js.map +1 -1
  31. package/dist/controllers/carousel_controller.d.ts +99 -27
  32. package/dist/controllers/carousel_controller.js +587 -300
  33. package/dist/controllers/carousel_controller.js.map +1 -1
  34. package/dist/controllers/character_counter_controller.d.ts +18 -2
  35. package/dist/controllers/character_counter_controller.js +271 -143
  36. package/dist/controllers/character_counter_controller.js.map +1 -1
  37. package/dist/controllers/checkbox_controller.d.ts +7 -2
  38. package/dist/controllers/checkbox_controller.js +77 -75
  39. package/dist/controllers/checkbox_controller.js.map +1 -1
  40. package/dist/controllers/clipboard_controller.d.ts +44 -7
  41. package/dist/controllers/clipboard_controller.js +187 -108
  42. package/dist/controllers/clipboard_controller.js.map +1 -1
  43. package/dist/controllers/collapsible_controller.d.ts +41 -5
  44. package/dist/controllers/collapsible_controller.js +374 -108
  45. package/dist/controllers/collapsible_controller.js.map +1 -1
  46. package/dist/controllers/color_picker_controller.d.ts +47 -14
  47. package/dist/controllers/color_picker_controller.js +183 -127
  48. package/dist/controllers/color_picker_controller.js.map +1 -1
  49. package/dist/controllers/combobox_controller.d.ts +33 -6
  50. package/dist/controllers/combobox_controller.js +426 -109
  51. package/dist/controllers/combobox_controller.js.map +1 -1
  52. package/dist/controllers/command_palette_controller.d.ts +45 -14
  53. package/dist/controllers/command_palette_controller.js +994 -350
  54. package/dist/controllers/command_palette_controller.js.map +1 -1
  55. package/dist/controllers/conditional_fields_controller.d.ts +15 -2
  56. package/dist/controllers/conditional_fields_controller.js +212 -125
  57. package/dist/controllers/conditional_fields_controller.js.map +1 -1
  58. package/dist/controllers/confirm_controller.d.ts +49 -12
  59. package/dist/controllers/confirm_controller.js +939 -245
  60. package/dist/controllers/confirm_controller.js.map +1 -1
  61. package/dist/controllers/context_menu_controller.d.ts +36 -3
  62. package/dist/controllers/context_menu_controller.js +275 -127
  63. package/dist/controllers/context_menu_controller.js.map +1 -1
  64. package/dist/controllers/count_up_controller.d.ts +13 -1
  65. package/dist/controllers/count_up_controller.js +73 -21
  66. package/dist/controllers/count_up_controller.js.map +1 -1
  67. package/dist/controllers/countdown_controller.d.ts +75 -2
  68. package/dist/controllers/countdown_controller.js +235 -97
  69. package/dist/controllers/countdown_controller.js.map +1 -1
  70. package/dist/controllers/currency_input_controller.d.ts +93 -15
  71. package/dist/controllers/currency_input_controller.js +241 -118
  72. package/dist/controllers/currency_input_controller.js.map +1 -1
  73. package/dist/controllers/data_grid_controller.d.ts +78 -22
  74. package/dist/controllers/data_grid_controller.js +229 -135
  75. package/dist/controllers/data_grid_controller.js.map +1 -1
  76. package/dist/controllers/date_range_picker_controller.d.ts +64 -11
  77. package/dist/controllers/date_range_picker_controller.js +359 -165
  78. package/dist/controllers/date_range_picker_controller.js.map +1 -1
  79. package/dist/controllers/dialog_controller.d.ts +22 -3
  80. package/dist/controllers/dialog_controller.js +887 -225
  81. package/dist/controllers/dialog_controller.js.map +1 -1
  82. package/dist/controllers/direct_upload_controller.d.ts +24 -7
  83. package/dist/controllers/direct_upload_controller.js +80 -142
  84. package/dist/controllers/direct_upload_controller.js.map +1 -1
  85. package/dist/controllers/dirty_form_controller.d.ts +2 -2
  86. package/dist/controllers/dirty_form_controller.js +26 -47
  87. package/dist/controllers/dirty_form_controller.js.map +1 -1
  88. package/dist/controllers/dismissible_controller.d.ts +19 -0
  89. package/dist/controllers/dismissible_controller.js +175 -20
  90. package/dist/controllers/dismissible_controller.js.map +1 -1
  91. package/dist/controllers/drawer_controller.d.ts +52 -16
  92. package/dist/controllers/drawer_controller.js +963 -336
  93. package/dist/controllers/drawer_controller.js.map +1 -1
  94. package/dist/controllers/dropdown_controller.d.ts +39 -3
  95. package/dist/controllers/dropdown_controller.js +342 -85
  96. package/dist/controllers/dropdown_controller.js.map +1 -1
  97. package/dist/controllers/editable_controller.d.ts +12 -1
  98. package/dist/controllers/editable_controller.js +182 -58
  99. package/dist/controllers/editable_controller.js.map +1 -1
  100. package/dist/controllers/empty_state_controller.js +67 -53
  101. package/dist/controllers/empty_state_controller.js.map +1 -1
  102. package/dist/controllers/file_dropzone_controller.d.ts +60 -18
  103. package/dist/controllers/file_dropzone_controller.js +426 -229
  104. package/dist/controllers/file_dropzone_controller.js.map +1 -1
  105. package/dist/controllers/filter_controller.d.ts +10 -4
  106. package/dist/controllers/filter_controller.js +78 -36
  107. package/dist/controllers/filter_controller.js.map +1 -1
  108. package/dist/controllers/flash_controller.d.ts +57 -14
  109. package/dist/controllers/flash_controller.js +328 -211
  110. package/dist/controllers/flash_controller.js.map +1 -1
  111. package/dist/controllers/focus_controller.d.ts +12 -3
  112. package/dist/controllers/focus_controller.js +654 -239
  113. package/dist/controllers/focus_controller.js.map +1 -1
  114. package/dist/controllers/form_field_controller.js +153 -136
  115. package/dist/controllers/form_field_controller.js.map +1 -1
  116. package/dist/controllers/form_validation_controller.js +29 -96
  117. package/dist/controllers/form_validation_controller.js.map +1 -1
  118. package/dist/controllers/frame_loading_controller.d.ts +41 -9
  119. package/dist/controllers/frame_loading_controller.js +263 -198
  120. package/dist/controllers/frame_loading_controller.js.map +1 -1
  121. package/dist/controllers/highlight_controller.d.ts +22 -2
  122. package/dist/controllers/highlight_controller.js +119 -70
  123. package/dist/controllers/highlight_controller.js.map +1 -1
  124. package/dist/controllers/hover_card_controller.d.ts +65 -4
  125. package/dist/controllers/hover_card_controller.js +335 -118
  126. package/dist/controllers/hover_card_controller.js.map +1 -1
  127. package/dist/controllers/idle_controller.d.ts +58 -4
  128. package/dist/controllers/idle_controller.js +316 -65
  129. package/dist/controllers/idle_controller.js.map +1 -1
  130. package/dist/controllers/input_mask_controller.d.ts +5 -2
  131. package/dist/controllers/input_mask_controller.js +116 -61
  132. package/dist/controllers/input_mask_controller.js.map +1 -1
  133. package/dist/controllers/intersection_controller.d.ts +32 -13
  134. package/dist/controllers/intersection_controller.js +147 -103
  135. package/dist/controllers/intersection_controller.js.map +1 -1
  136. package/dist/controllers/lazy_frame_controller.d.ts +16 -0
  137. package/dist/controllers/lazy_frame_controller.js +9 -56
  138. package/dist/controllers/lazy_frame_controller.js.map +1 -1
  139. package/dist/controllers/listbox_controller.d.ts +84 -10
  140. package/dist/controllers/listbox_controller.js +413 -153
  141. package/dist/controllers/listbox_controller.js.map +1 -1
  142. package/dist/controllers/local_time_controller.d.ts +1 -1
  143. package/dist/controllers/local_time_controller.js +54 -64
  144. package/dist/controllers/local_time_controller.js.map +1 -1
  145. package/dist/controllers/masonry_controller.d.ts +11 -3
  146. package/dist/controllers/masonry_controller.js +70 -95
  147. package/dist/controllers/masonry_controller.js.map +1 -1
  148. package/dist/controllers/menu_controller.d.ts +40 -9
  149. package/dist/controllers/menu_controller.js +254 -167
  150. package/dist/controllers/menu_controller.js.map +1 -1
  151. package/dist/controllers/menubar_controller.d.ts +15 -4
  152. package/dist/controllers/menubar_controller.js +206 -331
  153. package/dist/controllers/menubar_controller.js.map +1 -1
  154. package/dist/controllers/meter_controller.d.ts +20 -0
  155. package/dist/controllers/meter_controller.js +159 -71
  156. package/dist/controllers/meter_controller.js.map +1 -1
  157. package/dist/controllers/multi_select_controller.d.ts +50 -7
  158. package/dist/controllers/multi_select_controller.js +797 -388
  159. package/dist/controllers/multi_select_controller.js.map +1 -1
  160. package/dist/controllers/navigation_menu_controller.d.ts +19 -1
  161. package/dist/controllers/navigation_menu_controller.js +156 -231
  162. package/dist/controllers/navigation_menu_controller.js.map +1 -1
  163. package/dist/controllers/nested_form_controller.d.ts +10 -0
  164. package/dist/controllers/nested_form_controller.js +373 -174
  165. package/dist/controllers/nested_form_controller.js.map +1 -1
  166. package/dist/controllers/network_status_controller.d.ts +23 -0
  167. package/dist/controllers/network_status_controller.js +241 -45
  168. package/dist/controllers/network_status_controller.js.map +1 -1
  169. package/dist/controllers/number_input_controller.d.ts +62 -10
  170. package/dist/controllers/number_input_controller.js +387 -227
  171. package/dist/controllers/number_input_controller.js.map +1 -1
  172. package/dist/controllers/optimistic_controller.js +28 -75
  173. package/dist/controllers/optimistic_controller.js.map +1 -1
  174. package/dist/controllers/otp_controller.d.ts +38 -7
  175. package/dist/controllers/otp_controller.js +344 -196
  176. package/dist/controllers/otp_controller.js.map +1 -1
  177. package/dist/controllers/overflow_indicator_controller.d.ts +13 -12
  178. package/dist/controllers/overflow_indicator_controller.js +167 -93
  179. package/dist/controllers/overflow_indicator_controller.js.map +1 -1
  180. package/dist/controllers/overflow_menu_controller.d.ts +66 -9
  181. package/dist/controllers/overflow_menu_controller.js +408 -277
  182. package/dist/controllers/overflow_menu_controller.js.map +1 -1
  183. package/dist/controllers/pagination_controller.d.ts +52 -15
  184. package/dist/controllers/pagination_controller.js +342 -120
  185. package/dist/controllers/pagination_controller.js.map +1 -1
  186. package/dist/controllers/password_reveal_controller.d.ts +60 -9
  187. package/dist/controllers/password_reveal_controller.js +424 -99
  188. package/dist/controllers/password_reveal_controller.js.map +1 -1
  189. package/dist/controllers/password_strength_controller.d.ts +14 -5
  190. package/dist/controllers/password_strength_controller.js +99 -153
  191. package/dist/controllers/password_strength_controller.js.map +1 -1
  192. package/dist/controllers/persist_controller.d.ts +11 -4
  193. package/dist/controllers/persist_controller.js +252 -96
  194. package/dist/controllers/persist_controller.js.map +1 -1
  195. package/dist/controllers/pointer_drag_controller.d.ts +19 -7
  196. package/dist/controllers/pointer_drag_controller.js +263 -164
  197. package/dist/controllers/pointer_drag_controller.js.map +1 -1
  198. package/dist/controllers/popover_controller.d.ts +46 -4
  199. package/dist/controllers/popover_controller.js +267 -94
  200. package/dist/controllers/popover_controller.js.map +1 -1
  201. package/dist/controllers/portal_controller.d.ts +44 -4
  202. package/dist/controllers/portal_controller.js +209 -72
  203. package/dist/controllers/portal_controller.js.map +1 -1
  204. package/dist/controllers/preview_guard_controller.d.ts +10 -4
  205. package/dist/controllers/preview_guard_controller.js +243 -112
  206. package/dist/controllers/preview_guard_controller.js.map +1 -1
  207. package/dist/controllers/progress_controller.d.ts +11 -0
  208. package/dist/controllers/progress_controller.js +132 -59
  209. package/dist/controllers/progress_controller.js.map +1 -1
  210. package/dist/controllers/radio_group_controller.d.ts +19 -8
  211. package/dist/controllers/radio_group_controller.js +138 -133
  212. package/dist/controllers/radio_group_controller.js.map +1 -1
  213. package/dist/controllers/range_slider_controller.d.ts +92 -4
  214. package/dist/controllers/range_slider_controller.js +245 -112
  215. package/dist/controllers/range_slider_controller.js.map +1 -1
  216. package/dist/controllers/rating_controller.d.ts +33 -6
  217. package/dist/controllers/rating_controller.js +429 -194
  218. package/dist/controllers/rating_controller.js.map +1 -1
  219. package/dist/controllers/read_more_controller.d.ts +26 -2
  220. package/dist/controllers/read_more_controller.js +185 -47
  221. package/dist/controllers/read_more_controller.js.map +1 -1
  222. package/dist/controllers/reading_progress_controller.d.ts +1 -1
  223. package/dist/controllers/reading_progress_controller.js +147 -135
  224. package/dist/controllers/reading_progress_controller.js.map +1 -1
  225. package/dist/controllers/relative_time_controller.d.ts +18 -4
  226. package/dist/controllers/relative_time_controller.js +145 -110
  227. package/dist/controllers/relative_time_controller.js.map +1 -1
  228. package/dist/controllers/reset_on_restore_controller.d.ts +85 -0
  229. package/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +97 -38
  230. package/dist/controllers/reset_on_restore_controller.js.map +1 -0
  231. package/dist/controllers/resizable_controller.d.ts +44 -4
  232. package/dist/controllers/resizable_controller.js +294 -118
  233. package/dist/controllers/resizable_controller.js.map +1 -1
  234. package/dist/controllers/roving_controller.js +39 -84
  235. package/dist/controllers/roving_controller.js.map +1 -1
  236. package/dist/controllers/scroll_area_controller.d.ts +7 -3
  237. package/dist/controllers/scroll_area_controller.js +428 -221
  238. package/dist/controllers/scroll_area_controller.js.map +1 -1
  239. package/dist/controllers/scroll_restore_controller.js +0 -53
  240. package/dist/controllers/scroll_restore_controller.js.map +1 -1
  241. package/dist/controllers/scroll_visibility_controller.d.ts +28 -12
  242. package/dist/controllers/scroll_visibility_controller.js +395 -146
  243. package/dist/controllers/scroll_visibility_controller.js.map +1 -1
  244. package/dist/controllers/scrollspy_controller.d.ts +9 -3
  245. package/dist/controllers/scrollspy_controller.js +181 -236
  246. package/dist/controllers/scrollspy_controller.js.map +1 -1
  247. package/dist/controllers/separator_controller.d.ts +59 -17
  248. package/dist/controllers/separator_controller.js +288 -132
  249. package/dist/controllers/separator_controller.js.map +1 -1
  250. package/dist/controllers/sidebar_controller.d.ts +81 -7
  251. package/dist/controllers/sidebar_controller.js +1071 -375
  252. package/dist/controllers/sidebar_controller.js.map +1 -1
  253. package/dist/controllers/skeleton_controller.d.ts +23 -0
  254. package/dist/controllers/skeleton_controller.js +248 -92
  255. package/dist/controllers/skeleton_controller.js.map +1 -1
  256. package/dist/controllers/slider_controller.d.ts +72 -8
  257. package/dist/controllers/slider_controller.js +211 -96
  258. package/dist/controllers/slider_controller.js.map +1 -1
  259. package/dist/controllers/smart_sticky_header_controller.d.ts +21 -3
  260. package/dist/controllers/smart_sticky_header_controller.js +163 -54
  261. package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
  262. package/dist/controllers/sortable_controller.js +13 -110
  263. package/dist/controllers/sortable_controller.js.map +1 -1
  264. package/dist/controllers/spinner_controller.d.ts +39 -4
  265. package/dist/controllers/spinner_controller.js +277 -161
  266. package/dist/controllers/spinner_controller.js.map +1 -1
  267. package/dist/controllers/step_indicator_controller.d.ts +24 -17
  268. package/dist/controllers/step_indicator_controller.js +107 -53
  269. package/dist/controllers/step_indicator_controller.js.map +1 -1
  270. package/dist/controllers/stepper_controller.d.ts +43 -9
  271. package/dist/controllers/stepper_controller.js +171 -48
  272. package/dist/controllers/stepper_controller.js.map +1 -1
  273. package/dist/controllers/stick_to_bottom_controller.d.ts +25 -0
  274. package/dist/controllers/stick_to_bottom_controller.js +310 -116
  275. package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
  276. package/dist/controllers/sticky_observer_controller.d.ts +11 -0
  277. package/dist/controllers/sticky_observer_controller.js +214 -49
  278. package/dist/controllers/sticky_observer_controller.js.map +1 -1
  279. package/dist/controllers/submit_once_controller.d.ts +22 -6
  280. package/dist/controllers/submit_once_controller.js +294 -192
  281. package/dist/controllers/submit_once_controller.js.map +1 -1
  282. package/dist/controllers/switch_controller.d.ts +40 -7
  283. package/dist/controllers/switch_controller.js +107 -43
  284. package/dist/controllers/switch_controller.js.map +1 -1
  285. package/dist/controllers/tabs_controller.d.ts +13 -1
  286. package/dist/controllers/tabs_controller.js +50 -25
  287. package/dist/controllers/tabs_controller.js.map +1 -1
  288. package/dist/controllers/tags_input_controller.d.ts +27 -3
  289. package/dist/controllers/tags_input_controller.js +290 -149
  290. package/dist/controllers/tags_input_controller.js.map +1 -1
  291. package/dist/controllers/textarea_autosize_controller.d.ts +10 -0
  292. package/dist/controllers/textarea_autosize_controller.js +71 -58
  293. package/dist/controllers/textarea_autosize_controller.js.map +1 -1
  294. package/dist/controllers/theme_controller.d.ts +37 -8
  295. package/dist/controllers/theme_controller.js +148 -80
  296. package/dist/controllers/theme_controller.js.map +1 -1
  297. package/dist/controllers/time_picker_controller.d.ts +18 -1
  298. package/dist/controllers/time_picker_controller.js +162 -81
  299. package/dist/controllers/time_picker_controller.js.map +1 -1
  300. package/dist/controllers/toast_controller.d.ts +85 -23
  301. package/dist/controllers/toast_controller.js +365 -193
  302. package/dist/controllers/toast_controller.js.map +1 -1
  303. package/dist/controllers/toggle_group_controller.d.ts +60 -9
  304. package/dist/controllers/toggle_group_controller.js +194 -99
  305. package/dist/controllers/toggle_group_controller.js.map +1 -1
  306. package/dist/controllers/toolbar_controller.js +92 -90
  307. package/dist/controllers/toolbar_controller.js.map +1 -1
  308. package/dist/controllers/tooltip_controller.d.ts +52 -2
  309. package/dist/controllers/tooltip_controller.js +185 -125
  310. package/dist/controllers/tooltip_controller.js.map +1 -1
  311. package/dist/controllers/transition_controller.d.ts +22 -4
  312. package/dist/controllers/transition_controller.js +123 -115
  313. package/dist/controllers/transition_controller.js.map +1 -1
  314. package/dist/controllers/tree_view_controller.d.ts +59 -18
  315. package/dist/controllers/tree_view_controller.js +248 -290
  316. package/dist/controllers/tree_view_controller.js.map +1 -1
  317. package/dist/index.d.ts +33 -3
  318. package/dist/index.js +8649 -8572
  319. package/dist/index.js.map +1 -1
  320. package/dist/inspector/cli.d.ts +95 -9
  321. package/dist/inspector/cli.js +343 -77
  322. package/dist/inspector/cli.js.map +1 -1
  323. package/dist/inspector/cli_bin.js +390 -96
  324. package/dist/inspector/cli_bin.js.map +1 -1
  325. package/dist/inspector/examples.json +45 -45
  326. package/dist/inspector/manifest.json +1308 -155
  327. package/dist/positioning/index.d.ts +8 -0
  328. package/dist/positioning/index.js +148 -45
  329. package/dist/positioning/index.js.map +1 -1
  330. package/package.json +7 -7
  331. package/dist/controllers/reset_before_cache_controller.d.ts +0 -76
  332. package/dist/controllers/reset_before_cache_controller.js.map +0 -1
@@ -24,6 +24,22 @@ import { Controller } from '@hotwired/stimulus';
24
24
  * slot free of live-region semantics: with `announceText` set it would say the
25
25
  * same thing twice.
26
26
  *
27
+ * The slot is shared with the consumer. Completion writes the label in force and
28
+ * marks it with `data-<identifier>-owns-status`, whose value is that text; while
29
+ * the slot still shows that text and nothing else, the controller keeps it on the
30
+ * current `completeLabel` and takes it back once the timer leaves the complete
31
+ * state — `reset`, `start()` counting on from it, or a completion the new reading
32
+ * does not settle (a deadline moved forward or a count turned `up`, in place or
33
+ * before a restore). All but `start()` leave it `paused`, so `resume()` counts
34
+ * again.
35
+ * An empty label puts no text there, so it never displaces what the slot already
36
+ * holds; completing with one claims an empty slot — no text and no element — with
37
+ * an empty marker, which owns the slot whenever it is empty. Text the consumer put
38
+ * there stays theirs while it is there, and so does a slot they put an element in,
39
+ * whatever its text: the label is neither followed into it nor taken back out of
40
+ * it, and its marker stays, until the element is gone. Only a completion with a
41
+ * label writes over either.
42
+ *
27
43
  * `complete` dispatches `{}`; `tick` dispatches
28
44
  * `{ remaining: number, direction: "down" | "up" }`, where `remaining` is in
29
45
  * milliseconds.
@@ -37,7 +53,10 @@ import { Controller } from '@hotwired/stimulus';
37
53
  * source of truth — `autostart` only decides the state of a timer whose markup does
38
54
  * not carry one. The interval is owned by `SafeInterval` and torn down on
39
55
  * `disconnect()` (Turbo navigation included); nothing else needs carrying across,
40
- * because every reading is re-derived from `deadline` and the wall clock.
56
+ * because every reading is re-derived from `deadline` and the wall clock. A change to
57
+ * `interval` while the timer runs re-arms the tick at the new period, keeping the run
58
+ * state, the reading and the completion; a paused or completed timer picks it up when
59
+ * it next runs.
41
60
  */
42
61
  declare class CountdownController extends Controller<HTMLElement> {
43
62
  #private;
@@ -68,6 +87,13 @@ declare class CountdownController extends Controller<HTMLElement> {
68
87
  default: string;
69
88
  };
70
89
  };
90
+ static valueConstraints: {
91
+ interval: {
92
+ readonly finite: true;
93
+ readonly exclusiveMin: 0;
94
+ readonly max: 2147483647;
95
+ };
96
+ };
71
97
  static actions: readonly ["pause", "reset", "resume", "start"];
72
98
  static events: readonly ["complete", "tick"];
73
99
  readonly daysTarget: HTMLElement;
@@ -75,6 +101,7 @@ declare class CountdownController extends Controller<HTMLElement> {
75
101
  readonly minutesTarget: HTMLElement;
76
102
  readonly secondsTarget: HTMLElement;
77
103
  readonly statusTarget: HTMLElement;
104
+ readonly statusTargets: HTMLElement[];
78
105
  readonly hasDaysTarget: boolean;
79
106
  readonly hasHoursTarget: boolean;
80
107
  readonly hasMinutesTarget: boolean;
@@ -88,11 +115,57 @@ declare class CountdownController extends Controller<HTMLElement> {
88
115
  announceTextValue: string;
89
116
  connect(): void;
90
117
  disconnect(): void;
118
+ /** Writes the reading on screen into a days slot that arrives at runtime. */
119
+ daysTargetConnected(): void;
120
+ /** Writes the reading on screen into the days slot that stays after another leaves. */
121
+ daysTargetDisconnected(): void;
122
+ /** Writes the reading on screen into an hours slot that arrives at runtime. */
123
+ hoursTargetConnected(): void;
124
+ /** Writes the reading on screen into the hours slot that stays after another leaves. */
125
+ hoursTargetDisconnected(): void;
126
+ /** Writes the reading on screen into a minutes slot that arrives at runtime. */
127
+ minutesTargetConnected(): void;
128
+ /** Writes the reading on screen into the minutes slot that stays after another leaves. */
129
+ minutesTargetDisconnected(): void;
130
+ /** Writes the reading on screen into a seconds slot that arrives at runtime. */
131
+ secondsTargetConnected(): void;
132
+ /** Writes the reading on screen into the seconds slot that stays after another leaves. */
133
+ secondsTargetDisconnected(): void;
134
+ /** Brings a status that arrives at runtime, when it shows this controller's text, in line. */
135
+ statusTargetConnected(): void;
136
+ /**
137
+ * Takes the claim off a status that no longer resolves, even after `disconnect()`, when
138
+ * it still shows this controller's text alone; the text stays. Brings the status that
139
+ * stays in line.
140
+ */
141
+ statusTargetDisconnected(status: HTMLElement): void;
91
142
  /** Re-derives the display when a morph swaps the deadline in place. */
92
143
  deadlineValueChanged(): void;
93
144
  /** Re-derives the display when a morph flips the counting direction in place. */
94
145
  directionValueChanged(): void;
95
- /** Starts (or restarts after pause) ticking toward the deadline. */
146
+ /**
147
+ * Follows a completion label swapped in place by a morph.
148
+ *
149
+ * Render only: `complete` is neither dispatched nor announced again. The status
150
+ * changes only after the countdown has completed, and only while it still shows
151
+ * the text this controller wrote there and nothing else, so text or an element
152
+ * the consumer put in the slot stays. A change delivered ahead of `connect()` is
153
+ * left to `connect()`.
154
+ */
155
+ completeLabelValueChanged(): void;
156
+ /**
157
+ * Follows a tick period changed at runtime. A running countdown swaps its one interval
158
+ * for one at the new period, starting from now; its run state, reading, deadline and
159
+ * completion are untouched, and nothing ticks or repaints until the next period ends. A
160
+ * paused or completed countdown starts nothing and uses the new period when it next
161
+ * runs, and a declaration that resolves to the period already running changes nothing.
162
+ * Stimulus also calls this ahead of `connect()`, when no interval runs.
163
+ */
164
+ intervalValueChanged(): void;
165
+ /**
166
+ * Starts (or restarts after pause) ticking toward the deadline. Counting on from a
167
+ * completion takes this controller's completion text back out of the status.
168
+ */
96
169
  start(): void;
97
170
  /** Pauses ticking, preserving the currently displayed amount. */
98
171
  pause(): void;
@@ -1,8 +1,5 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/countdown_controller.ts
4
-
5
- // src/utils/announce.ts
6
3
  function announce(message, options = {}) {
7
4
  const text = message.trim();
8
5
  if (text.length === 0) return;
@@ -19,27 +16,33 @@ function fillTemplate(template, values) {
19
16
  });
20
17
  }
21
18
 
22
- // src/utils/microtask_coalescer.ts
19
+ var ListenerSet = class {
20
+ #abort = new AbortController();
21
+ add(target, type, handler, options) {
22
+ target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
23
+ }
24
+ dispose() {
25
+ this.#abort.abort();
26
+ this.#abort = new AbortController();
27
+ }
28
+ };
29
+
23
30
  var MicrotaskCoalescer = class {
24
31
  #run;
25
32
  #queued = false;
26
33
  #active = false;
27
34
  #generation = 0;
28
- /** @param run - the single reconciliation pass, invoked at most once per batch. */
29
35
  constructor(run) {
30
36
  this.#run = run;
31
37
  }
32
- /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
33
38
  activate() {
34
39
  this.#active = true;
35
40
  }
36
- /** Closes the window and drops any pending pass; call from `disconnect()`. */
37
41
  cancel() {
38
42
  this.#active = false;
39
43
  this.#queued = false;
40
44
  this.#generation += 1;
41
45
  }
42
- /** Requests one pass after the batch settles. Idempotent; inert outside the window. */
43
46
  schedule() {
44
47
  if (!this.#active || this.#queued) return;
45
48
  this.#queued = true;
@@ -52,38 +55,96 @@ var MicrotaskCoalescer = class {
52
55
  }
53
56
  };
54
57
 
55
- // src/utils/safe_timeout.ts
58
+ var MorphRenderWatcher = class {
59
+ #listeners = new ListenerSet();
60
+ #pass;
61
+ #element = null;
62
+ #onMorph = () => this.#pass.schedule();
63
+ constructor(run) {
64
+ this.#pass = new MicrotaskCoalescer(run);
65
+ }
66
+ observe(element) {
67
+ if (this.#element === element) return;
68
+ this.disconnect();
69
+ this.#element = element;
70
+ this.#pass.activate();
71
+ this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
72
+ }
73
+ schedule() {
74
+ this.#pass.schedule();
75
+ }
76
+ disconnect() {
77
+ this.#listeners.dispose();
78
+ this.#pass.cancel();
79
+ this.#element = null;
80
+ }
81
+ };
82
+
83
+ var MAX_TIMER_DELAY_MS = 2147483647;
84
+
85
+ var NUMBER_BOUNDS = {
86
+ positiveTimer: { finite: true, exclusiveMin: 0, max: MAX_TIMER_DELAY_MS }
87
+ };
88
+ function matchesNumberBounds(value, bounds) {
89
+ if (!Number.isFinite(value)) {
90
+ const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
91
+ if (direction === null) return false;
92
+ if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
93
+ }
94
+ if (bounds.min !== void 0 && value < bounds.min) return false;
95
+ if (bounds.max !== void 0 && value > bounds.max) return false;
96
+ if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
97
+ if (bounds.integer && !Number.isInteger(value)) return false;
98
+ if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
99
+ return true;
100
+ }
101
+
102
+ function readNumber(raw, fallback, bounds) {
103
+ return matchesNumberBounds(raw, bounds) ? raw : fallback;
104
+ }
105
+
106
+ var NumberValueReader = class {
107
+ #lastRejected = /* @__PURE__ */ new Map();
108
+ read(owner, name, raw, fallback, bounds) {
109
+ const resolved = readNumber(raw, fallback, bounds);
110
+ if (matchesNumberBounds(raw, bounds)) {
111
+ this.#lastRejected.delete(name);
112
+ return resolved;
113
+ }
114
+ const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
115
+ const literal = owner.element.getAttribute(attribute);
116
+ if (literal === null) {
117
+ this.#lastRejected.delete(name);
118
+ return resolved;
119
+ }
120
+ if (this.#lastRejected.get(name) !== literal) {
121
+ this.#lastRejected.set(name, literal);
122
+ console.warn(
123
+ `Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
124
+ );
125
+ }
126
+ return resolved;
127
+ }
128
+ };
129
+
56
130
  var TimerRegistry = class {
57
- /** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
58
131
  ids = /* @__PURE__ */ new Set();
59
- /**
60
- * Cancels a single tracked timer.
61
- *
62
- * No-ops if the id is unknown (already cleared, fired, or never owned by this
63
- * registry), so callers can clear defensively without guarding.
64
- */
65
132
  clear(id) {
66
133
  if (this.ids.delete(id)) {
67
134
  this.cancel(id);
68
135
  }
69
136
  }
70
- /**
71
- * Cancels every tracked timer. Call this from a controller's `disconnect()`
72
- * to guarantee no timer outlives the element.
73
- */
74
137
  clearAll() {
75
138
  for (const id of this.ids) {
76
139
  this.cancel(id);
77
140
  }
78
141
  this.ids.clear();
79
142
  }
80
- /** Number of timers currently tracked (pending). */
81
143
  get size() {
82
144
  return this.ids.size;
83
145
  }
84
146
  };
85
147
  var SafeInterval = class extends TimerRegistry {
86
- /** Schedules a repeating `callback` every `delay` ms and returns the timer id. */
87
148
  set(callback, delay) {
88
149
  const id = this.schedule(callback, delay);
89
150
  this.ids.add(id);
@@ -97,9 +158,13 @@ var SafeInterval = class extends TimerRegistry {
97
158
  }
98
159
  };
99
160
 
100
- // src/controllers/countdown_controller.ts
101
161
  var SECOND_MS = 1e3;
102
- var CountdownController = class extends Controller {
162
+ var OWNED_STATUS = "owns-status";
163
+ var CountdownController = class _CountdownController extends Controller {
164
+ #numbers = new NumberValueReader();
165
+ get #ownedStatus() {
166
+ return `data-${this.identifier}-${OWNED_STATUS}`;
167
+ }
103
168
  static targets = ["days", "hours", "minutes", "seconds", "status"];
104
169
  static values = {
105
170
  deadline: { type: String, default: "" },
@@ -109,72 +174,122 @@ var CountdownController = class extends Controller {
109
174
  completeLabel: { type: String, default: "" },
110
175
  announceText: { type: String, default: "" }
111
176
  };
177
+ static valueConstraints = {
178
+ interval: NUMBER_BOUNDS.positiveTimer
179
+ };
112
180
  static actions = ["pause", "reset", "resume", "start"];
113
181
  static events = ["complete", "tick"];
114
182
  #intervals = new SafeInterval();
115
183
  #intervalId = null;
116
- /** Collapses a morph that swaps several render inputs at once into one re-derive. */
117
- #resync = new MicrotaskCoalescer(() => this.#resyncToValues());
118
- /** Epoch-ms anchor: the deadline (down) or the count-up origin (up). */
184
+ #armedPeriod = 0;
185
+ #resync = new MorphRenderWatcher(() => this.#resyncToValues());
186
+ #connected = false;
119
187
  #reference = 0;
120
- /** Amount (ms) captured at pause, so resume can restore the same display. */
121
188
  #pausedAmount = 0;
122
- /**
123
- * The amount the slots are currently showing, floored to the second they render.
124
- * It lags {@link #currentAmount} by up to one tick, and it — not the live reading —
125
- * is what a pause has to preserve: storing the fraction behind the display instead
126
- * makes the first tick after a resume step by two units.
127
- */
128
189
  #renderedAmount = 0;
190
+ #phase = "paused";
191
+ #valuesDirty = false;
192
+ #statusWrites = /* @__PURE__ */ new WeakMap();
129
193
  connect() {
130
- this.#resync.activate();
194
+ this.#connected = true;
195
+ this.#resync.observe(this.element);
196
+ this.#valuesDirty = false;
131
197
  this.#initReference();
132
198
  const amount = this.#currentAmount();
133
199
  this.#render(amount);
134
200
  this.#pausedAmount = this.#renderedAmount;
135
201
  const authored = this.element.getAttribute("data-state");
202
+ this.#phase = authored ?? "paused";
203
+ const settled = authored === "complete" && this.#isSettled(amount);
136
204
  if (authored === null) {
137
- if (this.autostartValue && this.#isValidDeadline) {
138
- this.start();
139
- return;
140
- }
141
- this.element.setAttribute("data-state", "paused");
142
- return;
205
+ if (this.autostartValue && this.#isValidDeadline) this.start();
206
+ else this.#setPhase("paused");
207
+ } else if (!settled) {
208
+ this.#setPhase("paused");
209
+ if (authored === "running") this.start();
143
210
  }
144
- if (authored === "complete" && this.#isDown && amount <= 0) {
145
- return;
146
- }
147
- const wasRunning = authored === "running";
148
- this.element.setAttribute("data-state", "paused");
149
- if (wasRunning) this.start();
211
+ this.#syncStatus();
150
212
  }
151
213
  disconnect() {
152
- this.#resync.cancel();
214
+ this.#connected = false;
215
+ this.#resync.disconnect();
153
216
  this.#intervals.clearAll();
154
217
  this.#intervalId = null;
155
218
  }
156
- /** Re-derives the display when a morph swaps the deadline in place. */
219
+ daysTargetConnected() {
220
+ this.#resync.schedule();
221
+ }
222
+ daysTargetDisconnected() {
223
+ this.#resync.schedule();
224
+ }
225
+ hoursTargetConnected() {
226
+ this.#resync.schedule();
227
+ }
228
+ hoursTargetDisconnected() {
229
+ this.#resync.schedule();
230
+ }
231
+ minutesTargetConnected() {
232
+ this.#resync.schedule();
233
+ }
234
+ minutesTargetDisconnected() {
235
+ this.#resync.schedule();
236
+ }
237
+ secondsTargetConnected() {
238
+ this.#resync.schedule();
239
+ }
240
+ secondsTargetDisconnected() {
241
+ this.#resync.schedule();
242
+ }
243
+ statusTargetConnected() {
244
+ this.#resync.schedule();
245
+ }
246
+ statusTargetDisconnected(status) {
247
+ if (!this.statusTargets.includes(status) && this.#ownsStatus(status)) {
248
+ status.removeAttribute(this.#ownedStatus);
249
+ this.#statusWrites.delete(status);
250
+ }
251
+ this.#resync.schedule();
252
+ }
157
253
  deadlineValueChanged() {
254
+ this.#valuesDirty = true;
158
255
  this.#resync.schedule();
159
256
  }
160
- /** Re-derives the display when a morph flips the counting direction in place. */
161
257
  directionValueChanged() {
258
+ this.#valuesDirty = true;
162
259
  this.#resync.schedule();
163
260
  }
164
- /**
165
- * Points the anchor at the current `deadline` / `direction` and repaints.
166
- *
167
- * Render only: it starts no interval and emits no event, so a morph cannot make a
168
- * paused timer run or replay a milestone. A running one needs no restart either —
169
- * every tick reads the anchor, so moving it is enough. While paused the stored
170
- * amount follows the new reading, or resume would continue from the old deadline.
171
- */
261
+ completeLabelValueChanged() {
262
+ if (this.#connected) this.#syncStatus();
263
+ }
264
+ intervalValueChanged() {
265
+ if (this.#intervalId === null || this.#armedPeriod === this.#safeInterval) return;
266
+ this.#teardownInterval();
267
+ this.#armTick();
268
+ }
269
+ #syncStatus() {
270
+ if (!this.hasStatusTarget || !this.#ownsStatus(this.statusTarget)) return;
271
+ if (this.#state === "complete") this.#writeStatus(this.statusTarget, this.completeLabelValue);
272
+ else this.#releaseStatus(this.statusTarget);
273
+ }
172
274
  #resyncToValues() {
275
+ this.#setPhase(this.#state);
276
+ if (!this.#valuesDirty) {
277
+ this.#render(this.#renderedAmount);
278
+ this.#syncStatus();
279
+ return;
280
+ }
281
+ this.#valuesDirty = false;
173
282
  this.#initReference();
174
- this.#render(this.#currentAmount());
283
+ const amount = this.#currentAmount();
284
+ this.#render(amount);
285
+ if (this.#state === "running" && !this.#isValidDeadline) {
286
+ this.#teardownInterval();
287
+ this.#setPhase("paused");
288
+ }
289
+ if (this.#state === "complete" && !this.#isSettled(amount)) this.#setPhase("paused");
175
290
  if (this.#state !== "running") this.#pausedAmount = this.#renderedAmount;
291
+ this.#syncStatus();
176
292
  }
177
- /** Starts (or restarts after pause) ticking toward the deadline. */
178
293
  start() {
179
294
  if (this.#state === "running" || !this.#isValidDeadline) return;
180
295
  if (this.#isDown && this.#currentAmount() <= 0) {
@@ -183,39 +298,26 @@ var CountdownController = class extends Controller {
183
298
  }
184
299
  this.#runInterval();
185
300
  }
186
- /** Pauses ticking, preserving the currently displayed amount. */
187
301
  pause() {
188
302
  if (this.#state !== "running") return;
189
303
  this.#pausedAmount = this.#renderedAmount;
190
304
  this.#teardownInterval();
191
- this.element.setAttribute("data-state", "paused");
305
+ this.#setPhase("paused");
192
306
  }
193
- /** Resumes from a pause, continuing from the preserved amount. */
194
307
  resume() {
195
308
  if (this.#state !== "paused" || !this.#isValidDeadline) return;
196
309
  const now = Date.now();
197
310
  this.#reference = this.#isDown ? now + this.#pausedAmount : now - this.#pausedAmount;
198
311
  this.start();
199
312
  }
200
- /**
201
- * Re-syncs to the deadline and clears any pause offset, **preserving the current
202
- * run state**: a running timer keeps counting down from the reset amount, while a
203
- * paused (or completed) one resets the displayed amount but stays paused until the
204
- * user resumes — it never silently restarts. The run state is read from the DOM,
205
- * not re-derived from the declarative `autostart` Value (which governs only markup
206
- * that states no run state at all); re-deriving it would override a user's pause —
207
- * the DOM, not a re-run of declarative config, is the source of truth.
208
- */
209
313
  reset() {
210
314
  const wasRunning = this.#state === "running";
211
315
  this.#teardownInterval();
212
316
  this.#initReference();
213
317
  const amount = this.#currentAmount();
214
318
  this.#render(amount);
215
- if (this.hasStatusTarget && this.statusTarget.textContent === this.completeLabelValue) {
216
- this.statusTarget.textContent = "";
217
- }
218
- this.element.setAttribute("data-state", "paused");
319
+ this.#setPhase("paused");
320
+ this.#syncStatus();
219
321
  if (wasRunning && this.#isValidDeadline) {
220
322
  this.#pausedAmount = 0;
221
323
  this.start();
@@ -223,19 +325,21 @@ var CountdownController = class extends Controller {
223
325
  this.#pausedAmount = this.#renderedAmount;
224
326
  }
225
327
  }
226
- /** Schedules the repeating tick and marks the timer running. */
227
328
  #runInterval() {
228
- this.element.setAttribute("data-state", "running");
229
- this.#intervalId = this.#intervals.set(() => this.#tick(), this.intervalValue);
329
+ this.#setPhase("running");
330
+ this.#syncStatus();
331
+ this.#armTick();
332
+ }
333
+ #armTick() {
334
+ this.#armedPeriod = this.#safeInterval;
335
+ this.#intervalId = this.#intervals.set(() => this.#tick(), this.#armedPeriod);
230
336
  }
231
- /** Cancels the repeating tick, if any. */
232
337
  #teardownInterval() {
233
338
  if (this.#intervalId !== null) {
234
339
  this.#intervals.clear(this.#intervalId);
235
340
  this.#intervalId = null;
236
341
  }
237
342
  }
238
- /** Recomputes, renders, emits `tick`, and completes when a countdown hits 0. */
239
343
  #tick() {
240
344
  const amount = this.#currentAmount();
241
345
  this.#render(amount);
@@ -246,33 +350,57 @@ var CountdownController = class extends Controller {
246
350
  this.#complete();
247
351
  }
248
352
  }
249
- /** Stops at zero, marks completion, announces it, and emits `complete`. */
250
353
  #complete() {
251
354
  this.#teardownInterval();
252
355
  this.#render(0);
253
- this.element.setAttribute("data-state", "complete");
254
- if (this.hasStatusTarget && this.completeLabelValue.length > 0) {
255
- this.statusTarget.textContent = this.completeLabelValue;
256
- }
356
+ this.#setPhase("complete");
357
+ this.#claimStatus();
257
358
  this.dispatch("complete", { detail: {} });
359
+ this.#announceCompletion();
360
+ }
361
+ #claimStatus() {
362
+ if (!this.hasStatusTarget) return;
363
+ const status = this.statusTarget;
364
+ const label = this.completeLabelValue;
365
+ if (label === "" && !this.#isEmpty(status) && !this.#ownsStatus(status)) return;
366
+ this.#writeStatus(status, label);
367
+ }
368
+ #ownsStatus(status) {
369
+ const held = this.#statusWrites.get(status);
370
+ if (!status.hasAttribute(this.#ownedStatus) && held && status.firstElementChild === null && (status.textContent === held.text || status.textContent === held.original))
371
+ return true;
372
+ return status.getAttribute(this.#ownedStatus) === status.textContent && status.firstElementChild === null;
373
+ }
374
+ #isEmpty(status) {
375
+ return status.textContent === "" && status.firstElementChild === null;
376
+ }
377
+ #writeStatus(status, text) {
378
+ const original = this.#statusWrites.get(status)?.original ?? status.textContent ?? "";
379
+ this.#statusWrites.set(status, { original, text });
380
+ if (status.textContent !== text) status.textContent = text;
381
+ if (status.getAttribute(this.#ownedStatus) !== text)
382
+ status.setAttribute(this.#ownedStatus, text);
383
+ }
384
+ #releaseStatus(status) {
385
+ status.textContent = "";
386
+ status.removeAttribute(this.#ownedStatus);
387
+ this.#statusWrites.delete(status);
388
+ }
389
+ #announceCompletion() {
258
390
  announce(fillTemplate(this.announceTextValue, {}));
259
391
  }
260
- /** Sets the time anchor from the `deadline` value. */
261
392
  #initReference() {
262
393
  this.#reference = Date.parse(this.deadlineValue);
263
394
  }
264
- /** Remaining (down) or elapsed (up) ms, never negative. */
395
+ #isSettled(amount) {
396
+ return this.#isDown && amount <= 0;
397
+ }
265
398
  #currentAmount() {
266
399
  if (!this.#isValidDeadline) return 0;
267
400
  const now = Date.now();
268
401
  const raw = this.#isDown ? this.#reference - now : now - this.#reference;
269
402
  return Math.max(0, raw);
270
403
  }
271
- /**
272
- * Writes the amount into the day/hour/minute/second slots.
273
- *
274
- * @stimeoRenderRoot
275
- */
276
404
  #render(amount) {
277
405
  const totalSeconds = Math.floor(amount / SECOND_MS);
278
406
  this.#renderedAmount = totalSeconds * SECOND_MS;
@@ -285,7 +413,6 @@ var CountdownController = class extends Controller {
285
413
  if (this.hasMinutesTarget) this.minutesTarget.textContent = this.#pad(minutes);
286
414
  if (this.hasSecondsTarget) this.secondsTarget.textContent = this.#pad(seconds);
287
415
  }
288
- /** Zero-pads a unit to two digits. */
289
416
  #pad(unit) {
290
417
  return String(unit).padStart(2, "0");
291
418
  }
@@ -295,12 +422,23 @@ var CountdownController = class extends Controller {
295
422
  get #isValidDeadline() {
296
423
  return !Number.isNaN(this.#reference);
297
424
  }
298
- /** Current lifecycle phase as reflected on `data-state`. */
425
+ #setPhase(phase) {
426
+ this.#phase = phase;
427
+ this.element.setAttribute("data-state", phase);
428
+ }
299
429
  get #state() {
300
- return this.element.getAttribute("data-state") ?? "paused";
430
+ return this.element.getAttribute("data-state") ?? this.#phase;
431
+ }
432
+ get #safeInterval() {
433
+ return this.#numbers.read(
434
+ this,
435
+ "interval",
436
+ this.intervalValue,
437
+ _CountdownController.values.interval.default,
438
+ _CountdownController.valueConstraints.interval
439
+ );
301
440
  }
302
441
  };
303
442
 
304
443
  export { CountdownController };
305
- //# sourceMappingURL=countdown_controller.js.map
306
444
  //# sourceMappingURL=countdown_controller.js.map