stimeo-ui 0.16.0 → 0.18.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 (337) hide show
  1. package/CHANGELOG.md +136 -0
  2. package/README.md +27 -11
  3. package/dist/cable/index.d.ts +88 -31
  4. package/dist/cable/index.js +384 -449
  5. package/dist/cable/index.js.map +1 -1
  6. package/dist/coerce-JtZVNG5h.d.ts +20 -0
  7. package/dist/controllers/accordion_controller.d.ts +4 -2
  8. package/dist/controllers/accordion_controller.js +174 -55
  9. package/dist/controllers/accordion_controller.js.map +1 -1
  10. package/dist/controllers/alert_dialog_controller.d.ts +12 -2
  11. package/dist/controllers/alert_dialog_controller.js +903 -235
  12. package/dist/controllers/alert_dialog_controller.js.map +1 -1
  13. package/dist/controllers/announcer_controller.d.ts +37 -5
  14. package/dist/controllers/announcer_controller.js +238 -205
  15. package/dist/controllers/announcer_controller.js.map +1 -1
  16. package/dist/controllers/aspect_ratio_controller.js +0 -10
  17. package/dist/controllers/aspect_ratio_controller.js.map +1 -1
  18. package/dist/controllers/auto_submit_controller.d.ts +30 -6
  19. package/dist/controllers/auto_submit_controller.js +414 -145
  20. package/dist/controllers/auto_submit_controller.js.map +1 -1
  21. package/dist/controllers/avatar_controller.js +185 -107
  22. package/dist/controllers/avatar_controller.js.map +1 -1
  23. package/dist/controllers/breadcrumb_controller.js +0 -130
  24. package/dist/controllers/breadcrumb_controller.js.map +1 -1
  25. package/dist/controllers/bulk_select_controller.d.ts +21 -3
  26. package/dist/controllers/bulk_select_controller.js +282 -58
  27. package/dist/controllers/bulk_select_controller.js.map +1 -1
  28. package/dist/controllers/calendar_controller.d.ts +38 -16
  29. package/dist/controllers/calendar_controller.js +228 -260
  30. package/dist/controllers/calendar_controller.js.map +1 -1
  31. package/dist/controllers/carousel_controller.d.ts +43 -12
  32. package/dist/controllers/carousel_controller.js +536 -436
  33. package/dist/controllers/carousel_controller.js.map +1 -1
  34. package/dist/controllers/character_counter_controller.d.ts +44 -7
  35. package/dist/controllers/character_counter_controller.js +493 -207
  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 +38 -74
  39. package/dist/controllers/checkbox_controller.js.map +1 -1
  40. package/dist/controllers/clipboard_controller.d.ts +16 -5
  41. package/dist/controllers/clipboard_controller.js +261 -149
  42. package/dist/controllers/clipboard_controller.js.map +1 -1
  43. package/dist/controllers/collapsible_controller.d.ts +17 -5
  44. package/dist/controllers/collapsible_controller.js +304 -120
  45. package/dist/controllers/collapsible_controller.js.map +1 -1
  46. package/dist/controllers/color_picker_controller.d.ts +18 -6
  47. package/dist/controllers/color_picker_controller.js +178 -146
  48. package/dist/controllers/color_picker_controller.js.map +1 -1
  49. package/dist/controllers/combobox_controller.d.ts +24 -6
  50. package/dist/controllers/combobox_controller.js +522 -156
  51. package/dist/controllers/combobox_controller.js.map +1 -1
  52. package/dist/controllers/command_palette_controller.d.ts +51 -20
  53. package/dist/controllers/command_palette_controller.js +1156 -395
  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 +300 -171
  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 +980 -262
  60. package/dist/controllers/confirm_controller.js.map +1 -1
  61. package/dist/controllers/context_menu_controller.d.ts +80 -18
  62. package/dist/controllers/context_menu_controller.js +346 -153
  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 +47 -3
  68. package/dist/controllers/countdown_controller.js +281 -158
  69. package/dist/controllers/countdown_controller.js.map +1 -1
  70. package/dist/controllers/currency_input_controller.d.ts +93 -10
  71. package/dist/controllers/currency_input_controller.js +575 -225
  72. package/dist/controllers/currency_input_controller.js.map +1 -1
  73. package/dist/controllers/data_grid_controller.d.ts +25 -12
  74. package/dist/controllers/data_grid_controller.js +248 -214
  75. package/dist/controllers/data_grid_controller.js.map +1 -1
  76. package/dist/controllers/date_range_picker_controller.d.ts +42 -14
  77. package/dist/controllers/date_range_picker_controller.js +338 -235
  78. package/dist/controllers/date_range_picker_controller.js.map +1 -1
  79. package/dist/controllers/dialog_controller.d.ts +17 -6
  80. package/dist/controllers/dialog_controller.js +899 -237
  81. package/dist/controllers/dialog_controller.js.map +1 -1
  82. package/dist/controllers/direct_upload_controller.d.ts +25 -8
  83. package/dist/controllers/direct_upload_controller.js +97 -167
  84. package/dist/controllers/direct_upload_controller.js.map +1 -1
  85. package/dist/controllers/dirty_form_controller.d.ts +6 -1
  86. package/dist/controllers/dirty_form_controller.js +72 -69
  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 +196 -24
  90. package/dist/controllers/dismissible_controller.js.map +1 -1
  91. package/dist/controllers/drawer_controller.d.ts +39 -11
  92. package/dist/controllers/drawer_controller.js +974 -355
  93. package/dist/controllers/drawer_controller.js.map +1 -1
  94. package/dist/controllers/dropdown_controller.d.ts +31 -1
  95. package/dist/controllers/dropdown_controller.js +339 -96
  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 +315 -88
  99. package/dist/controllers/editable_controller.js.map +1 -1
  100. package/dist/controllers/empty_state_controller.js +79 -58
  101. package/dist/controllers/empty_state_controller.js.map +1 -1
  102. package/dist/controllers/file_dropzone_controller.d.ts +63 -18
  103. package/dist/controllers/file_dropzone_controller.js +322 -211
  104. package/dist/controllers/file_dropzone_controller.js.map +1 -1
  105. package/dist/controllers/filter_controller.js +77 -42
  106. package/dist/controllers/filter_controller.js.map +1 -1
  107. package/dist/controllers/flash_controller.d.ts +35 -12
  108. package/dist/controllers/flash_controller.js +238 -347
  109. package/dist/controllers/flash_controller.js.map +1 -1
  110. package/dist/controllers/focus_controller.d.ts +15 -6
  111. package/dist/controllers/focus_controller.js +679 -240
  112. package/dist/controllers/focus_controller.js.map +1 -1
  113. package/dist/controllers/form_field_controller.js +156 -132
  114. package/dist/controllers/form_field_controller.js.map +1 -1
  115. package/dist/controllers/form_validation_controller.d.ts +3 -3
  116. package/dist/controllers/form_validation_controller.js +31 -97
  117. package/dist/controllers/form_validation_controller.js.map +1 -1
  118. package/dist/controllers/frame_loading_controller.d.ts +47 -14
  119. package/dist/controllers/frame_loading_controller.js +275 -217
  120. package/dist/controllers/frame_loading_controller.js.map +1 -1
  121. package/dist/controllers/highlight_controller.d.ts +27 -6
  122. package/dist/controllers/highlight_controller.js +107 -75
  123. package/dist/controllers/highlight_controller.js.map +1 -1
  124. package/dist/controllers/hover_card_controller.d.ts +60 -4
  125. package/dist/controllers/hover_card_controller.js +327 -130
  126. package/dist/controllers/hover_card_controller.js.map +1 -1
  127. package/dist/controllers/idle_controller.d.ts +48 -6
  128. package/dist/controllers/idle_controller.js +271 -101
  129. package/dist/controllers/idle_controller.js.map +1 -1
  130. package/dist/controllers/input_mask_controller.d.ts +30 -13
  131. package/dist/controllers/input_mask_controller.js +483 -97
  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 +150 -106
  135. package/dist/controllers/intersection_controller.js.map +1 -1
  136. package/dist/controllers/lazy_frame_controller.d.ts +19 -2
  137. package/dist/controllers/lazy_frame_controller.js +24 -68
  138. package/dist/controllers/lazy_frame_controller.js.map +1 -1
  139. package/dist/controllers/listbox_controller.d.ts +44 -9
  140. package/dist/controllers/listbox_controller.js +523 -240
  141. package/dist/controllers/listbox_controller.js.map +1 -1
  142. package/dist/controllers/local_time_controller.d.ts +9 -7
  143. package/dist/controllers/local_time_controller.js +102 -77
  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 +80 -96
  147. package/dist/controllers/masonry_controller.js.map +1 -1
  148. package/dist/controllers/menu_controller.d.ts +55 -11
  149. package/dist/controllers/menu_controller.js +302 -188
  150. package/dist/controllers/menu_controller.js.map +1 -1
  151. package/dist/controllers/menubar_controller.d.ts +51 -9
  152. package/dist/controllers/menubar_controller.js +232 -345
  153. package/dist/controllers/menubar_controller.js.map +1 -1
  154. package/dist/controllers/meter_controller.d.ts +33 -20
  155. package/dist/controllers/meter_controller.js +417 -87
  156. package/dist/controllers/meter_controller.js.map +1 -1
  157. package/dist/controllers/multi_select_controller.d.ts +48 -18
  158. package/dist/controllers/multi_select_controller.js +785 -393
  159. package/dist/controllers/multi_select_controller.js.map +1 -1
  160. package/dist/controllers/navigation_menu_controller.d.ts +27 -6
  161. package/dist/controllers/navigation_menu_controller.js +190 -250
  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 +396 -192
  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 +268 -62
  168. package/dist/controllers/network_status_controller.js.map +1 -1
  169. package/dist/controllers/number_input_controller.d.ts +50 -8
  170. package/dist/controllers/number_input_controller.js +610 -303
  171. package/dist/controllers/number_input_controller.js.map +1 -1
  172. package/dist/controllers/optimistic_controller.d.ts +8 -5
  173. package/dist/controllers/optimistic_controller.js +45 -87
  174. package/dist/controllers/optimistic_controller.js.map +1 -1
  175. package/dist/controllers/otp_controller.d.ts +55 -8
  176. package/dist/controllers/otp_controller.js +658 -255
  177. package/dist/controllers/otp_controller.js.map +1 -1
  178. package/dist/controllers/overflow_indicator_controller.d.ts +5 -0
  179. package/dist/controllers/overflow_indicator_controller.js +122 -113
  180. package/dist/controllers/overflow_indicator_controller.js.map +1 -1
  181. package/dist/controllers/overflow_menu_controller.d.ts +58 -20
  182. package/dist/controllers/overflow_menu_controller.js +470 -295
  183. package/dist/controllers/overflow_menu_controller.js.map +1 -1
  184. package/dist/controllers/pagination_controller.d.ts +37 -7
  185. package/dist/controllers/pagination_controller.js +332 -123
  186. package/dist/controllers/pagination_controller.js.map +1 -1
  187. package/dist/controllers/password_reveal_controller.d.ts +46 -8
  188. package/dist/controllers/password_reveal_controller.js +392 -121
  189. package/dist/controllers/password_reveal_controller.js.map +1 -1
  190. package/dist/controllers/password_strength_controller.d.ts +15 -6
  191. package/dist/controllers/password_strength_controller.js +111 -158
  192. package/dist/controllers/password_strength_controller.js.map +1 -1
  193. package/dist/controllers/persist_controller.d.ts +11 -4
  194. package/dist/controllers/persist_controller.js +165 -111
  195. package/dist/controllers/persist_controller.js.map +1 -1
  196. package/dist/controllers/pointer_drag_controller.d.ts +35 -12
  197. package/dist/controllers/pointer_drag_controller.js +434 -188
  198. package/dist/controllers/pointer_drag_controller.js.map +1 -1
  199. package/dist/controllers/popover_controller.d.ts +41 -5
  200. package/dist/controllers/popover_controller.js +269 -113
  201. package/dist/controllers/popover_controller.js.map +1 -1
  202. package/dist/controllers/portal_controller.d.ts +44 -4
  203. package/dist/controllers/portal_controller.js +215 -76
  204. package/dist/controllers/portal_controller.js.map +1 -1
  205. package/dist/controllers/preview_guard_controller.d.ts +10 -4
  206. package/dist/controllers/preview_guard_controller.js +243 -116
  207. package/dist/controllers/preview_guard_controller.js.map +1 -1
  208. package/dist/controllers/progress_controller.d.ts +20 -19
  209. package/dist/controllers/progress_controller.js +391 -78
  210. package/dist/controllers/progress_controller.js.map +1 -1
  211. package/dist/controllers/radio_group_controller.d.ts +21 -9
  212. package/dist/controllers/radio_group_controller.js +278 -211
  213. package/dist/controllers/radio_group_controller.js.map +1 -1
  214. package/dist/controllers/range_slider_controller.d.ts +47 -6
  215. package/dist/controllers/range_slider_controller.js +220 -113
  216. package/dist/controllers/range_slider_controller.js.map +1 -1
  217. package/dist/controllers/rating_controller.d.ts +20 -4
  218. package/dist/controllers/rating_controller.js +458 -211
  219. package/dist/controllers/rating_controller.js.map +1 -1
  220. package/dist/controllers/read_more_controller.d.ts +2 -0
  221. package/dist/controllers/read_more_controller.js +138 -63
  222. package/dist/controllers/read_more_controller.js.map +1 -1
  223. package/dist/controllers/reading_progress_controller.d.ts +1 -1
  224. package/dist/controllers/reading_progress_controller.js +166 -137
  225. package/dist/controllers/reading_progress_controller.js.map +1 -1
  226. package/dist/controllers/relative_time_controller.d.ts +20 -6
  227. package/dist/controllers/relative_time_controller.js +211 -112
  228. package/dist/controllers/relative_time_controller.js.map +1 -1
  229. package/dist/controllers/reset_on_restore_controller.d.ts +85 -0
  230. package/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +103 -38
  231. package/dist/controllers/reset_on_restore_controller.js.map +1 -0
  232. package/dist/controllers/resizable_controller.d.ts +31 -2
  233. package/dist/controllers/resizable_controller.js +299 -150
  234. package/dist/controllers/resizable_controller.js.map +1 -1
  235. package/dist/controllers/roving_controller.d.ts +3 -3
  236. package/dist/controllers/roving_controller.js +49 -88
  237. package/dist/controllers/roving_controller.js.map +1 -1
  238. package/dist/controllers/scroll_area_controller.d.ts +7 -3
  239. package/dist/controllers/scroll_area_controller.js +490 -246
  240. package/dist/controllers/scroll_area_controller.js.map +1 -1
  241. package/dist/controllers/scroll_restore_controller.d.ts +3 -3
  242. package/dist/controllers/scroll_restore_controller.js +14 -55
  243. package/dist/controllers/scroll_restore_controller.js.map +1 -1
  244. package/dist/controllers/scroll_visibility_controller.d.ts +28 -12
  245. package/dist/controllers/scroll_visibility_controller.js +432 -149
  246. package/dist/controllers/scroll_visibility_controller.js.map +1 -1
  247. package/dist/controllers/scrollspy_controller.d.ts +6 -1
  248. package/dist/controllers/scrollspy_controller.js +193 -248
  249. package/dist/controllers/scrollspy_controller.js.map +1 -1
  250. package/dist/controllers/separator_controller.d.ts +20 -5
  251. package/dist/controllers/separator_controller.js +285 -142
  252. package/dist/controllers/separator_controller.js.map +1 -1
  253. package/dist/controllers/sidebar_controller.d.ts +65 -8
  254. package/dist/controllers/sidebar_controller.js +1069 -404
  255. package/dist/controllers/sidebar_controller.js.map +1 -1
  256. package/dist/controllers/skeleton_controller.d.ts +23 -0
  257. package/dist/controllers/skeleton_controller.js +259 -101
  258. package/dist/controllers/skeleton_controller.js.map +1 -1
  259. package/dist/controllers/slider_controller.d.ts +29 -2
  260. package/dist/controllers/slider_controller.js +187 -86
  261. package/dist/controllers/slider_controller.js.map +1 -1
  262. package/dist/controllers/smart_sticky_header_controller.d.ts +22 -4
  263. package/dist/controllers/smart_sticky_header_controller.js +173 -66
  264. package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
  265. package/dist/controllers/sortable_controller.d.ts +4 -4
  266. package/dist/controllers/sortable_controller.js +26 -125
  267. package/dist/controllers/sortable_controller.js.map +1 -1
  268. package/dist/controllers/spinner_controller.d.ts +39 -4
  269. package/dist/controllers/spinner_controller.js +288 -173
  270. package/dist/controllers/spinner_controller.js.map +1 -1
  271. package/dist/controllers/step_indicator_controller.d.ts +9 -4
  272. package/dist/controllers/step_indicator_controller.js +105 -46
  273. package/dist/controllers/step_indicator_controller.js.map +1 -1
  274. package/dist/controllers/stepper_controller.d.ts +14 -6
  275. package/dist/controllers/stepper_controller.js +120 -73
  276. package/dist/controllers/stepper_controller.js.map +1 -1
  277. package/dist/controllers/stick_to_bottom_controller.d.ts +9 -1
  278. package/dist/controllers/stick_to_bottom_controller.js +275 -140
  279. package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
  280. package/dist/controllers/sticky_observer_controller.d.ts +11 -0
  281. package/dist/controllers/sticky_observer_controller.js +220 -49
  282. package/dist/controllers/sticky_observer_controller.js.map +1 -1
  283. package/dist/controllers/submit_once_controller.d.ts +24 -8
  284. package/dist/controllers/submit_once_controller.js +376 -227
  285. package/dist/controllers/submit_once_controller.js.map +1 -1
  286. package/dist/controllers/switch_controller.d.ts +18 -4
  287. package/dist/controllers/switch_controller.js +201 -84
  288. package/dist/controllers/switch_controller.js.map +1 -1
  289. package/dist/controllers/tabs_controller.d.ts +9 -6
  290. package/dist/controllers/tabs_controller.js +41 -30
  291. package/dist/controllers/tabs_controller.js.map +1 -1
  292. package/dist/controllers/tags_input_controller.d.ts +16 -3
  293. package/dist/controllers/tags_input_controller.js +293 -173
  294. package/dist/controllers/tags_input_controller.js.map +1 -1
  295. package/dist/controllers/textarea_autosize_controller.d.ts +11 -1
  296. package/dist/controllers/textarea_autosize_controller.js +108 -74
  297. package/dist/controllers/textarea_autosize_controller.js.map +1 -1
  298. package/dist/controllers/theme_controller.d.ts +24 -11
  299. package/dist/controllers/theme_controller.js +140 -116
  300. package/dist/controllers/theme_controller.js.map +1 -1
  301. package/dist/controllers/time_picker_controller.d.ts +55 -5
  302. package/dist/controllers/time_picker_controller.js +331 -127
  303. package/dist/controllers/time_picker_controller.js.map +1 -1
  304. package/dist/controllers/toast_controller.d.ts +40 -16
  305. package/dist/controllers/toast_controller.js +244 -324
  306. package/dist/controllers/toast_controller.js.map +1 -1
  307. package/dist/controllers/toggle_group_controller.d.ts +14 -6
  308. package/dist/controllers/toggle_group_controller.js +252 -191
  309. package/dist/controllers/toggle_group_controller.js.map +1 -1
  310. package/dist/controllers/toolbar_controller.d.ts +8 -6
  311. package/dist/controllers/toolbar_controller.js +219 -120
  312. package/dist/controllers/toolbar_controller.js.map +1 -1
  313. package/dist/controllers/tooltip_controller.d.ts +49 -4
  314. package/dist/controllers/tooltip_controller.js +158 -124
  315. package/dist/controllers/tooltip_controller.js.map +1 -1
  316. package/dist/controllers/transition_controller.d.ts +22 -4
  317. package/dist/controllers/transition_controller.js +123 -119
  318. package/dist/controllers/transition_controller.js.map +1 -1
  319. package/dist/controllers/tree_view_controller.d.ts +22 -12
  320. package/dist/controllers/tree_view_controller.js +283 -369
  321. package/dist/controllers/tree_view_controller.js.map +1 -1
  322. package/dist/index.d.ts +10 -5
  323. package/dist/index.js +8573 -10410
  324. package/dist/index.js.map +1 -1
  325. package/dist/inspector/cli.d.ts +38 -14
  326. package/dist/inspector/cli.js +108 -40
  327. package/dist/inspector/cli.js.map +1 -1
  328. package/dist/inspector/cli_bin.js +145 -64
  329. package/dist/inspector/cli_bin.js.map +1 -1
  330. package/dist/inspector/examples.json +20 -20
  331. package/dist/inspector/manifest.json +802 -101
  332. package/dist/positioning/index.d.ts +15 -7
  333. package/dist/positioning/index.js +154 -47
  334. package/dist/positioning/index.js.map +1 -1
  335. package/package.json +11 -10
  336. package/dist/controllers/reset_before_cache_controller.d.ts +0 -76
  337. package/dist/controllers/reset_before_cache_controller.js.map +0 -1
@@ -1,37 +1,52 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/relative_time_controller.ts
3
+ function setAttributeIfChanged(element, name, value, beforeWrite) {
4
+ if (element.getAttribute(name) === value) return false;
5
+ if (value === null) element.removeAttribute(name);
6
+ else element.setAttribute(name, value);
7
+ return true;
8
+ }
4
9
 
5
- // src/utils/before_cache_reset.ts
6
- var BeforeCacheReset = class _BeforeCacheReset {
7
- /** Every subscribed instance, iterated by the one shared document listener. */
8
- static #subscribers = /* @__PURE__ */ new Set();
9
- /** The shared listener; installed while at least one instance is subscribed. */
10
- static #onBeforeCache = () => {
11
- for (const subscriber of _BeforeCacheReset.#subscribers) subscriber.#rewind();
12
- };
13
- #rewind;
14
- /** @param rewind - the pass that returns this controller's state to its initial form. */
15
- constructor(rewind) {
16
- this.#rewind = rewind;
10
+ var DATETIME = /^([+-]\d{6}|\d{4})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?(Z|[+-]\d{2}:?\d{2})?)?$/;
11
+ function readDatetime(element) {
12
+ const raw = element.getAttribute("datetime");
13
+ if (raw === null) return null;
14
+ const match = DATETIME.exec(raw.trim());
15
+ if (match === null) return null;
16
+ const [
17
+ ,
18
+ yearText,
19
+ monthText,
20
+ dayText,
21
+ hourText = "00",
22
+ minuteText = "00",
23
+ secondText = "00",
24
+ fraction = "",
25
+ zone = "Z"
26
+ ] = match;
27
+ const year = Number(yearText);
28
+ const month = Number(monthText);
29
+ const day = Number(dayText);
30
+ const leap = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
31
+ const days = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
32
+ if (month < 1 || month > 12 || day < 1 || day > (days[month - 1] ?? 0)) return null;
33
+ const hour = Number(hourText);
34
+ const minute = Number(minuteText);
35
+ const second = Number(secondText);
36
+ if (hour === 24 && (minute !== 0 || second !== 0 || /[1-9]/.test(fraction))) return null;
37
+ let offset = zone;
38
+ if (zone !== "Z") {
39
+ const digits = zone.slice(1).replace(":", "");
40
+ const offsetHour = digits.slice(0, 2);
41
+ const offsetMinute = digits.slice(2);
42
+ offset = `${zone[0]}${offsetHour}:${offsetMinute}`;
17
43
  }
18
- /** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */
19
- activate() {
20
- const first = _BeforeCacheReset.#subscribers.size === 0;
21
- _BeforeCacheReset.#subscribers.add(this);
22
- if (first) {
23
- document.addEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
24
- }
25
- }
26
- /** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */
27
- deactivate() {
28
- _BeforeCacheReset.#subscribers.delete(this);
29
- if (_BeforeCacheReset.#subscribers.size > 0) return;
30
- document.removeEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
31
- }
32
- };
44
+ const milliseconds = fraction.slice(0, 3).padEnd(3, "0");
45
+ const canonical = `${yearText}-${monthText}-${dayText}T${hourText}:${minuteText}:${secondText}.${milliseconds}${offset}`;
46
+ const instant = Date.parse(canonical);
47
+ return Number.isNaN(instant) ? null : instant;
48
+ }
33
49
 
34
- // src/utils/intl_format.ts
35
50
  var formatters = /* @__PURE__ */ new WeakMap();
36
51
  function intlFormatter(factory, locale, options, fallbackLocale) {
37
52
  const cache = cacheFor(factory);
@@ -60,32 +75,40 @@ function construct(factory, locale, options, fallbackLocale) {
60
75
  }
61
76
  }
62
77
 
63
- // src/utils/locale.ts
64
78
  function resolveLocale(element, declared = "") {
65
79
  return declared || element.closest("[lang]")?.getAttribute("lang") || void 0;
66
80
  }
67
81
 
68
- // src/utils/microtask_coalescer.ts
82
+ var ListenerSet = class {
83
+ #abort = new AbortController();
84
+ add(target, type, handler, options) {
85
+ target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
86
+ }
87
+ dispose() {
88
+ this.#abort.abort();
89
+ this.#abort = new AbortController();
90
+ }
91
+ };
92
+
69
93
  var MicrotaskCoalescer = class {
70
94
  #run;
71
95
  #queued = false;
72
96
  #active = false;
73
97
  #generation = 0;
74
- /** @param run - the single reconciliation pass, invoked at most once per batch. */
75
98
  constructor(run) {
76
99
  this.#run = run;
77
100
  }
78
- /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
79
101
  activate() {
80
102
  this.#active = true;
81
103
  }
82
- /** Closes the window and drops any pending pass; call from `disconnect()`. */
83
104
  cancel() {
84
105
  this.#active = false;
85
106
  this.#queued = false;
86
107
  this.#generation += 1;
87
108
  }
88
- /** Requests one pass after the batch settles. Idempotent; inert outside the window. */
109
+ get pending() {
110
+ return this.#queued;
111
+ }
89
112
  schedule() {
90
113
  if (!this.#active || this.#queued) return;
91
114
  this.#queued = true;
@@ -98,43 +121,99 @@ var MicrotaskCoalescer = class {
98
121
  }
99
122
  };
100
123
 
101
- // src/utils/safe_timeout.ts
124
+ var MorphRenderWatcher = class {
125
+ #listeners = new ListenerSet();
126
+ #pass;
127
+ #element = null;
128
+ #onMorph = () => this.#pass.schedule();
129
+ constructor(run) {
130
+ this.#pass = new MicrotaskCoalescer(run);
131
+ }
132
+ observe(element) {
133
+ if (this.#element === element) return;
134
+ this.disconnect();
135
+ this.#element = element;
136
+ this.#pass.activate();
137
+ this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
138
+ }
139
+ schedule() {
140
+ this.#pass.schedule();
141
+ }
142
+ get pending() {
143
+ return this.#pass.pending;
144
+ }
145
+ disconnect() {
146
+ this.#listeners.dispose();
147
+ this.#pass.cancel();
148
+ this.#element = null;
149
+ }
150
+ };
151
+
152
+ var MAX_TIMER_DELAY_MS = 2147483647;
153
+
154
+ var NUMBER_BOUNDS = {
155
+ nonNegative: { finite: true, min: 0 },
156
+ timer: { finite: true, min: 0, max: MAX_TIMER_DELAY_MS }};
157
+ function matchesNumberBounds(value, bounds) {
158
+ if (!Number.isFinite(value)) {
159
+ const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
160
+ if (direction === null) return false;
161
+ if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
162
+ }
163
+ if (bounds.min !== void 0 && value < bounds.min) return false;
164
+ if (bounds.max !== void 0 && value > bounds.max) return false;
165
+ if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
166
+ if (bounds.integer && !Number.isInteger(value)) return false;
167
+ if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
168
+ return true;
169
+ }
170
+
171
+ function readNumber(raw, fallback, bounds) {
172
+ return matchesNumberBounds(raw, bounds) ? raw : fallback;
173
+ }
174
+
175
+ var NumberValueReader = class {
176
+ #lastRejected = /* @__PURE__ */ new Map();
177
+ read(owner, name, raw, fallback, bounds) {
178
+ const resolved = readNumber(raw, fallback, bounds);
179
+ if (matchesNumberBounds(raw, bounds)) {
180
+ this.#lastRejected.delete(name);
181
+ return resolved;
182
+ }
183
+ const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
184
+ const literal = owner.element.getAttribute(attribute);
185
+ if (literal === null) {
186
+ this.#lastRejected.delete(name);
187
+ return resolved;
188
+ }
189
+ if (this.#lastRejected.get(name) !== literal) {
190
+ this.#lastRejected.set(name, literal);
191
+ console.warn(
192
+ `Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
193
+ );
194
+ }
195
+ return resolved;
196
+ }
197
+ };
198
+
102
199
  var TimerRegistry = class {
103
- /** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
104
200
  ids = /* @__PURE__ */ new Set();
105
- /**
106
- * Cancels a single tracked timer.
107
- *
108
- * No-ops if the id is unknown (already cleared, fired, or never owned by this
109
- * registry), so callers can clear defensively without guarding.
110
- */
111
201
  clear(id) {
112
202
  if (this.ids.delete(id)) {
113
203
  this.cancel(id);
114
204
  }
115
205
  }
116
- /**
117
- * Cancels every tracked timer. Call this from a controller's `disconnect()`
118
- * to guarantee no timer outlives the element.
119
- */
120
206
  clearAll() {
121
207
  for (const id of this.ids) {
122
208
  this.cancel(id);
123
209
  }
124
210
  this.ids.clear();
125
211
  }
126
- /** Number of timers currently tracked (pending). */
127
212
  get size() {
128
213
  return this.ids.size;
129
214
  }
130
215
  };
131
216
  var SafeTimeout = class extends TimerRegistry {
132
- /**
133
- * Schedules `callback` after `delay` ms and returns the timer id.
134
- *
135
- * The id is removed from the registry automatically when the timeout fires,
136
- * so {@link TimerRegistry.size | size} reflects only still-pending timers.
137
- */
138
217
  set(callback, delay) {
139
218
  const id = this.schedule(() => {
140
219
  this.ids.delete(id);
@@ -151,7 +230,6 @@ var SafeTimeout = class extends TimerRegistry {
151
230
  }
152
231
  };
153
232
 
154
- // src/controllers/relative_time_controller.ts
155
233
  var YEAR_SCALE = { limit: Number.POSITIVE_INFINITY, unit: "year", ms: 315576e5 };
156
234
  var UNITS = [
157
235
  { limit: 60, unit: "second", ms: 1e3 },
@@ -163,112 +241,116 @@ var UNITS = [
163
241
  YEAR_SCALE
164
242
  ];
165
243
  var RELATIVE_OPTIONS = { numeric: "auto" };
166
- var RelativeTimeController = class extends Controller {
244
+ var TEXT_RECORD = "text";
245
+ var RelativeTimeController = class _RelativeTimeController extends Controller {
246
+ #numbers = new NumberValueReader();
167
247
  static values = {
168
248
  locale: { type: String, default: "" },
169
249
  threshold: { type: Number, default: 0 },
170
250
  tickInterval: { type: Number, default: 6e4 }
171
251
  };
252
+ static valueConstraints = {
253
+ threshold: NUMBER_BOUNDS.nonNegative,
254
+ tickInterval: NUMBER_BOUNDS.timer
255
+ };
172
256
  #timers = new SafeTimeout();
173
- /** Collapses a morph that swaps several render inputs at once into one repaint. */
174
- #resync = new MicrotaskCoalescer(() => this.#resyncToValues());
175
- #beforeCache = new BeforeCacheReset(() => this.#rewindForCache());
176
- /** Epoch ms parsed from `datetime`; `NaN` when absent or invalid. */
257
+ #resync = new MorphRenderWatcher(() => {
258
+ const target = readDatetime(this.element) ?? Number.NaN;
259
+ if (!Object.is(target, this.#targetMs)) {
260
+ this.#targetMs = target;
261
+ this.#adoptAuthoredText();
262
+ this.#valuesDirty = true;
263
+ }
264
+ if (this.#valuesDirty) {
265
+ this.#valuesDirty = false;
266
+ this.#resyncToValues();
267
+ } else if (!Number.isNaN(this.#targetMs)) {
268
+ this.#applyAndComputeDelay();
269
+ }
270
+ });
271
+ #valuesDirty = false;
272
+ #datetimeWatch = new MutationObserver(() => this.#resync.schedule());
177
273
  #targetMs = Number.NaN;
178
- /** The authored absolute text, restored when the threshold fallback kicks in. */
179
274
  #absoluteText = "";
180
275
  connect() {
181
- this.#resync.activate();
182
- this.#beforeCache.activate();
183
- if (this.element.getAttribute("data-state") !== "relative") {
184
- this.#absoluteText = (this.element.textContent ?? "").trim();
185
- }
186
- this.#targetMs = Date.parse(this.element.getAttribute("datetime") ?? "");
276
+ this.#timers.clearAll();
277
+ this.#valuesDirty = false;
278
+ this.#resync.observe(this.element);
279
+ this.#datetimeWatch.observe(this.element, { attributeFilter: ["datetime"] });
280
+ this.#adoptAuthoredText();
281
+ this.#targetMs = readDatetime(this.element) ?? Number.NaN;
187
282
  if (Number.isNaN(this.#targetMs)) return;
188
283
  this.#schedule();
189
284
  }
190
285
  disconnect() {
191
- this.#resync.cancel();
192
- this.#beforeCache.deactivate();
286
+ this.#resync.disconnect();
287
+ this.#datetimeWatch.disconnect();
193
288
  this.#timers.clearAll();
194
289
  }
195
- /** Repaints when application code (or a Turbo morph) changes `locale` at runtime. */
290
+ #adoptAuthoredText() {
291
+ if (this.element.getAttribute("data-state") !== "relative") {
292
+ this.#absoluteText = (this.element.textContent ?? "").trim();
293
+ } else {
294
+ const recorded = this.#recordedText();
295
+ if (recorded !== null) this.#absoluteText = recorded;
296
+ }
297
+ }
298
+ get #textRecord() {
299
+ return `data-${this.identifier}-${TEXT_RECORD}`;
300
+ }
301
+ #recordedText() {
302
+ try {
303
+ const parsed = JSON.parse(this.element.getAttribute(this.#textRecord) ?? "null");
304
+ return typeof parsed === "string" ? parsed : null;
305
+ } catch {
306
+ return null;
307
+ }
308
+ }
196
309
  localeValueChanged() {
310
+ this.#valuesDirty = true;
197
311
  this.#resync.schedule();
198
312
  }
199
- /** Repaints when application code (or a Turbo morph) changes `threshold` at runtime. */
200
313
  thresholdValueChanged() {
314
+ this.#valuesDirty = true;
201
315
  this.#resync.schedule();
202
316
  }
203
- /** Repaints when application code (or a Turbo morph) changes `tickInterval` at runtime. */
204
317
  tickIntervalValueChanged() {
318
+ this.#valuesDirty = true;
205
319
  this.#resync.schedule();
206
320
  }
207
- /**
208
- * Renders against the current Values and re-arms the poll from now.
209
- *
210
- * Render only: it emits no event, and clearing first keeps the single self-arming
211
- * timer single — scheduling on top of a pending one would double the poll rate for
212
- * the rest of the session. A stamp whose `datetime` never parsed has nothing to
213
- * render, and one that already reached its terminal fallback simply renders it
214
- * again and stops.
215
- */
216
321
  #resyncToValues() {
217
- if (Number.isNaN(this.#targetMs)) return;
218
322
  this.#timers.clearAll();
323
+ if (Number.isNaN(this.#targetMs)) return;
219
324
  this.#schedule();
220
325
  }
221
- /**
222
- * Restores the authored absolute text and the pre-render state for the snapshot
223
- * Turbo is about to take, leaving the live page's poll timer alone.
224
- *
225
- * With no authored text held there is nothing to restore, and `data-state` has to
226
- * stay as it is: that marker is what tells the next `connect()` the visible text is
227
- * a rendered relative form rather than an absolute fallback to hold on to.
228
- */
229
- #rewindForCache() {
230
- if (!this.#absoluteText) return;
231
- this.element.textContent = this.#absoluteText;
232
- this.element.removeAttribute("data-state");
233
- }
234
- /** Renders the current representation and reschedules unless polling can stop. */
235
326
  #schedule() {
236
327
  const nextDelay = this.#applyAndComputeDelay();
237
328
  if (nextDelay !== null) {
238
329
  this.#timers.set(() => this.#schedule(), nextDelay);
239
330
  }
240
331
  }
241
- /**
242
- * Updates the visible text and returns the next poll delay (ms), or `null` when
243
- * polling can stop: a *past* timestamp that fell back to the absolute text can
244
- * never leave it again, and a locale the runtime rejects has nothing to render
245
- * until that value is corrected.
246
- *
247
- * @stimeoRenderRoot
248
- */
249
332
  #applyAndComputeDelay() {
250
333
  const deltaMs = this.#targetMs - Date.now();
251
334
  const absSeconds = Math.abs(deltaMs) / 1e3;
252
335
  const scale = UNITS.find((u) => absSeconds < u.limit) ?? YEAR_SCALE;
253
336
  const unitFloor = scale.unit === "second" || scale.unit === "minute" ? 6e4 : scale.ms;
254
- const nextDelay = Math.max(this.tickIntervalValue, Math.min(unitFloor, 864e5));
255
- if (this.thresholdValue > 0 && absSeconds >= this.thresholdValue && this.#absoluteText) {
337
+ const nextDelay = Math.max(this.#safeTickInterval, Math.min(unitFloor, 864e5));
338
+ if (this.#safeThreshold > 0 && absSeconds >= this.#safeThreshold && this.#absoluteText) {
256
339
  this.element.textContent = this.#absoluteText;
257
340
  this.element.setAttribute("data-state", "absolute");
341
+ this.element.removeAttribute(this.#textRecord);
258
342
  if (deltaMs <= 0) return null;
259
- return Math.min(nextDelay, deltaMs - this.thresholdValue * 1e3 + 1);
343
+ return Math.max(1, Math.min(nextDelay, deltaMs - this.#safeThreshold * 1e3 + 1));
260
344
  }
261
345
  const formatter = this.#formatter;
262
346
  if (formatter === null) return null;
263
347
  const value = Math.round(deltaMs / scale.ms);
264
348
  this.element.textContent = formatter.format(value, scale.unit);
265
349
  this.element.setAttribute("data-state", "relative");
350
+ const record = JSON.stringify(this.#absoluteText);
351
+ setAttributeIfChanged(this.element, this.#textRecord, record);
266
352
  return nextDelay;
267
353
  }
268
- /**
269
- * A `RelativeTimeFormat` for the resolved locale (`numeric: "auto"`), or `null`
270
- * when the runtime rejects that locale.
271
- */
272
354
  get #formatter() {
273
355
  return intlFormatter(
274
356
  Intl.RelativeTimeFormat,
@@ -276,8 +358,25 @@ var RelativeTimeController = class extends Controller {
276
358
  RELATIVE_OPTIONS
277
359
  );
278
360
  }
361
+ get #safeThreshold() {
362
+ return this.#numbers.read(
363
+ this,
364
+ "threshold",
365
+ this.thresholdValue,
366
+ _RelativeTimeController.values.threshold.default,
367
+ _RelativeTimeController.valueConstraints.threshold
368
+ );
369
+ }
370
+ get #safeTickInterval() {
371
+ return this.#numbers.read(
372
+ this,
373
+ "tickInterval",
374
+ this.tickIntervalValue,
375
+ _RelativeTimeController.values.tickInterval.default,
376
+ _RelativeTimeController.valueConstraints.tickInterval
377
+ );
378
+ }
279
379
  };
280
380
 
281
381
  export { RelativeTimeController };
282
- //# sourceMappingURL=relative_time_controller.js.map
283
382
  //# sourceMappingURL=relative_time_controller.js.map