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,13 +1,9 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/time_picker_controller.ts
4
-
5
- // src/utils/logical_scroll.ts
6
3
  function isRtl(element) {
7
4
  return window.getComputedStyle(element).direction === "rtl";
8
5
  }
9
6
 
10
- // src/utils/arrow_step.ts
11
7
  function logicalArrowKey(key, element) {
12
8
  if (key !== "ArrowRight" && key !== "ArrowLeft") return key;
13
9
  if (!isRtl(element)) return key;
@@ -17,8 +13,108 @@ function isReservedArrowChord(event, allow = []) {
17
13
  if (!event.key.startsWith("Arrow")) return false;
18
14
  return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
19
15
  }
16
+ function hasModifierChord(event) {
17
+ return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
18
+ }
19
+
20
+ function setAttributeIfChanged(element, name, value, beforeWrite) {
21
+ if (element.getAttribute(name) === value) return false;
22
+ beforeWrite?.();
23
+ if (value === null) element.removeAttribute(name);
24
+ else element.setAttribute(name, value);
25
+ return true;
26
+ }
27
+
28
+ var AuthoredMutationWatcher = class {
29
+ #onAuthored;
30
+ #claims = null;
31
+ #observer = null;
32
+ constructor(onAuthored) {
33
+ this.#onAuthored = onAuthored;
34
+ }
35
+ observe(root, options) {
36
+ this.disconnect();
37
+ const observer = new MutationObserver((records) => {
38
+ if (this.#observer !== observer) return;
39
+ const authored = this.#filter(records);
40
+ if (authored.length > 0) this.#onAuthored(authored);
41
+ });
42
+ this.#observer = observer;
43
+ this.#claims = { attributes: /* @__PURE__ */ new Map(), children: /* @__PURE__ */ new Map() };
44
+ observer.observe(root, {
45
+ attributes: true,
46
+ attributeFilter: [...options.attributes],
47
+ subtree: options.subtree ?? false,
48
+ childList: options.childList ?? false
49
+ });
50
+ if (options.ancestorAttributes) {
51
+ let ancestor = root.parentElement;
52
+ while (ancestor) {
53
+ observer.observe(ancestor, {
54
+ attributes: true,
55
+ attributeFilter: [...options.ancestorAttributes]
56
+ });
57
+ ancestor = ancestor.parentElement;
58
+ }
59
+ }
60
+ }
61
+ claim(target, name, value) {
62
+ const claims = this.#claims?.attributes;
63
+ let attributes = claims?.get(target);
64
+ if (!attributes) {
65
+ attributes = /* @__PURE__ */ new Map();
66
+ claims?.set(target, attributes);
67
+ }
68
+ const pending = attributes.get(name);
69
+ attributes.set(name, { value, count: (pending?.count ?? 0) + 1 });
70
+ }
71
+ claimCurrent(target, name) {
72
+ this.claim(target, name, target.getAttribute(name));
73
+ }
74
+ claimChildList(target, added, removed) {
75
+ const claims = this.#claims?.children;
76
+ const pending = claims?.get(target) ?? { added: /* @__PURE__ */ new Map(), removed: /* @__PURE__ */ new Map() };
77
+ for (const node of added) pending.added.set(node, (pending.added.get(node) ?? 0) + 1);
78
+ for (const node of removed) pending.removed.set(node, (pending.removed.get(node) ?? 0) + 1);
79
+ claims?.set(target, pending);
80
+ }
81
+ take() {
82
+ return this.#filter(this.#observer?.takeRecords() ?? []);
83
+ }
84
+ disconnect() {
85
+ this.#observer?.disconnect();
86
+ this.#observer = null;
87
+ this.#claims = null;
88
+ }
89
+ #filter(records) {
90
+ const authored = records.filter((record) => !this.#consume(record));
91
+ this.#claims?.attributes.clear();
92
+ this.#claims?.children.clear();
93
+ return authored;
94
+ }
95
+ #consume(record) {
96
+ if (record.type === "attributes") {
97
+ const target = record.target;
98
+ const pending2 = this.#claims?.attributes.get(target)?.get(record.attributeName);
99
+ if (!pending2 || pending2.count === 0 || target.getAttribute(record.attributeName) !== pending2.value) {
100
+ return false;
101
+ }
102
+ pending2.count -= 1;
103
+ return true;
104
+ }
105
+ const pending = this.#claims?.children.get(record.target);
106
+ if (!pending) return false;
107
+ const added = [...record.addedNodes];
108
+ const removed = [...record.removedNodes];
109
+ if (added.some((node) => !pending.added.get(node)) || removed.some((node) => !pending.removed.get(node))) {
110
+ return false;
111
+ }
112
+ for (const node of added) pending.added.set(node, (pending.added.get(node) ?? 0) - 1);
113
+ for (const node of removed) pending.removed.set(node, (pending.removed.get(node) ?? 0) - 1);
114
+ return true;
115
+ }
116
+ };
20
117
 
21
- // src/utils/field_mirror.ts
22
118
  function writeField(field, value) {
23
119
  if (field.value === value) return false;
24
120
  field.value = value;
@@ -28,27 +124,36 @@ function commitField(target) {
28
124
  target.dispatchEvent(new Event("change", { bubbles: true }));
29
125
  }
30
126
 
31
- // src/utils/microtask_coalescer.ts
127
+ var ListenerSet = class {
128
+ #abort = new AbortController();
129
+ add(target, type, handler, options) {
130
+ target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
131
+ }
132
+ dispose() {
133
+ this.#abort.abort();
134
+ this.#abort = new AbortController();
135
+ }
136
+ };
137
+
32
138
  var MicrotaskCoalescer = class {
33
139
  #run;
34
140
  #queued = false;
35
141
  #active = false;
36
142
  #generation = 0;
37
- /** @param run - the single reconciliation pass, invoked at most once per batch. */
38
143
  constructor(run) {
39
144
  this.#run = run;
40
145
  }
41
- /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
42
146
  activate() {
43
147
  this.#active = true;
44
148
  }
45
- /** Closes the window and drops any pending pass; call from `disconnect()`. */
46
149
  cancel() {
47
150
  this.#active = false;
48
151
  this.#queued = false;
49
152
  this.#generation += 1;
50
153
  }
51
- /** Requests one pass after the batch settles. Idempotent; inert outside the window. */
154
+ get pending() {
155
+ return this.#queued;
156
+ }
52
157
  schedule() {
53
158
  if (!this.#active || this.#queued) return;
54
159
  this.#queued = true;
@@ -61,93 +166,183 @@ var MicrotaskCoalescer = class {
61
166
  }
62
167
  };
63
168
 
64
- // src/utils/target_selector.ts
169
+ var MorphRenderWatcher = class {
170
+ #listeners = new ListenerSet();
171
+ #pass;
172
+ #element = null;
173
+ #onMorph = () => this.#pass.schedule();
174
+ constructor(run) {
175
+ this.#pass = new MicrotaskCoalescer(run);
176
+ }
177
+ observe(element) {
178
+ if (this.#element === element) return;
179
+ this.disconnect();
180
+ this.#element = element;
181
+ this.#pass.activate();
182
+ this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
183
+ }
184
+ schedule() {
185
+ this.#pass.schedule();
186
+ }
187
+ get pending() {
188
+ return this.#pass.pending;
189
+ }
190
+ disconnect() {
191
+ this.#listeners.dispose();
192
+ this.#pass.cancel();
193
+ this.#element = null;
194
+ }
195
+ };
196
+
197
+ var MoveCounter = class {
198
+ #sequence = 0;
199
+ record() {
200
+ this.#sequence += 1;
201
+ return this.#sequence;
202
+ }
203
+ isLatest(token) {
204
+ return token === this.#sequence;
205
+ }
206
+ };
207
+
208
+ var NUMBER_BOUNDS = {
209
+ positive: { finite: true, exclusiveMin: 0 }};
210
+ function matchesNumberBounds(value, bounds) {
211
+ if (!Number.isFinite(value)) {
212
+ const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
213
+ if (direction === null) return false;
214
+ if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
215
+ }
216
+ if (bounds.min !== void 0 && value < bounds.min) return false;
217
+ if (bounds.max !== void 0 && value > bounds.max) return false;
218
+ if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
219
+ if (bounds.integer && !Number.isInteger(value)) return false;
220
+ if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
221
+ return true;
222
+ }
223
+
224
+ function readNumber(raw, fallback, bounds) {
225
+ return matchesNumberBounds(raw, bounds) ? raw : fallback;
226
+ }
227
+
228
+ var NumberValueReader = class {
229
+ #lastRejected = /* @__PURE__ */ new Map();
230
+ read(owner, name, raw, fallback, bounds) {
231
+ const resolved = readNumber(raw, fallback, bounds);
232
+ if (matchesNumberBounds(raw, bounds)) {
233
+ this.#lastRejected.delete(name);
234
+ return resolved;
235
+ }
236
+ const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
237
+ const literal = owner.element.getAttribute(attribute);
238
+ if (literal === null) {
239
+ this.#lastRejected.delete(name);
240
+ return resolved;
241
+ }
242
+ if (this.#lastRejected.get(name) !== literal) {
243
+ this.#lastRejected.set(name, literal);
244
+ console.warn(
245
+ `Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
246
+ );
247
+ }
248
+ return resolved;
249
+ }
250
+ };
251
+
65
252
  function targetSelector(identifier, name) {
66
253
  return `[data-${identifier}-target~="${name}"]`;
67
254
  }
68
255
 
69
- // src/controllers/time_picker_controller.ts
70
256
  var AM = 0;
71
257
  var PM = 1;
72
258
  var SECONDS_PER_MINUTE = 60;
73
259
  var SECONDS_PER_HOUR = 60 * SECONDS_PER_MINUTE;
74
260
  var SECONDS_PER_DAY = 24 * SECONDS_PER_HOUR;
75
- var hasModifier = (event) => event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
76
- var TimePickerController = class extends Controller {
261
+ var TimePickerController = class _TimePickerController extends Controller {
262
+ #numbers = new NumberValueReader();
263
+ #moves = new MoveCounter();
264
+ #connectionGeneration = 0;
265
+ #move = 0;
77
266
  static targets = ["segment", "field"];
78
267
  static values = {
79
268
  hourCycle: { type: Number, default: 24 },
269
+ hour12ZeroBased: { type: Boolean, default: false },
80
270
  step: { type: Number, default: 1 },
81
271
  seconds: { type: Boolean, default: false },
82
- wrap: { type: Boolean, default: true }
272
+ wrap: { type: Boolean, default: true },
273
+ amLabel: { type: String, default: "AM" },
274
+ pmLabel: { type: String, default: "PM" }
275
+ };
276
+ static valueConstraints = {
277
+ hourCycle: { finite: true, allowedValues: [12, 24] },
278
+ step: NUMBER_BOUNDS.positive
83
279
  };
84
280
  static actions = ["onKeydown"];
85
281
  static events = ["change", "reconcile"];
86
- /**
87
- * Collapses target, Value, and retained-attribute morphs into one render that
88
- * dispatches no `change`.
89
- */
90
- #reconcile = new MicrotaskCoalescer(() => this.#reconcileDom());
91
- /** Canonical state; the displayed hour and meridiem are derived from this value. */
282
+ #reconcile = new MorphRenderWatcher(() => this.#reconcileDom());
92
283
  #state = { hour: 0, minute: 0, second: 0 };
93
- /** Direct-entry digit buffer and the segment it belongs to. */
94
284
  #typeBuffer = "";
95
285
  #typeSegment = null;
96
- /** Last composed value, used to suppress duplicate user notifications. */
97
286
  #lastValue = "";
98
- #observer = null;
99
- #connected = false;
287
+ #renderedHourMode = null;
288
+ #renderedSegments = /* @__PURE__ */ new WeakSet();
289
+ #authoredSegments = /* @__PURE__ */ new Set();
290
+ #observer = new AuthoredMutationWatcher((records) => {
291
+ if (!this.#recordAuthoredSegments(records)) return;
292
+ this.#reconcile.schedule();
293
+ });
100
294
  #domDirty = false;
101
- /** Seeds state from the DOM, renders canonical ARIA, and starts morph observation. */
295
+ #listeners = new ListenerSet();
102
296
  connect() {
103
- this.#connected = true;
104
- this.#reconcile.activate();
105
- this.element.addEventListener("focusout", this.#onFocusOut);
297
+ this.#reconcile.observe(this.element);
298
+ this.#listeners.add(this.element, "focusout", this.#onFocusOut);
106
299
  this.#domDirty = false;
107
300
  this.#adoptDomState();
108
301
  this.#render();
109
302
  this.#observeMutations();
110
303
  }
111
- /** Releases the observer, listener, queued reconciliation, and transient input state. */
112
304
  disconnect() {
113
- this.#connected = false;
114
- this.#reconcile.cancel();
115
- this.element.removeEventListener("focusout", this.#onFocusOut);
116
- this.#observer?.disconnect();
117
- this.#observer = null;
305
+ this.#connectionGeneration += 1;
306
+ this.#reconcile.disconnect();
307
+ this.#listeners.dispose();
308
+ this.#observer.disconnect();
118
309
  this.#domDirty = false;
310
+ this.#renderedHourMode = null;
311
+ this.#renderedSegments = /* @__PURE__ */ new WeakSet();
312
+ this.#authoredSegments.clear();
119
313
  this.#clearTypeBuffer();
120
314
  this.#lastValue = "";
121
315
  }
122
- /** Re-renders the canonical instant when 12/24-hour presentation changes at runtime. */
123
316
  hourCycleValueChanged() {
124
317
  this.#reconcile.schedule();
125
318
  }
126
- /** Recomposes the optional seconds portion after a runtime Value change. */
319
+ hour12ZeroBasedValueChanged() {
320
+ this.#reconcile.schedule();
321
+ }
127
322
  secondsValueChanged() {
128
323
  this.#reconcile.schedule();
129
324
  }
130
- /** Adopts a segment inserted or replaced by a Turbo morph. */
325
+ amLabelValueChanged() {
326
+ this.#reconcile.schedule();
327
+ }
328
+ pmLabelValueChanged() {
329
+ this.#reconcile.schedule();
330
+ }
131
331
  segmentTargetConnected() {
132
332
  this.#domDirty = true;
133
- this.#clearTypeBuffer();
134
333
  this.#reconcile.schedule();
135
334
  }
136
- /** Rebuilds state after a segment leaves the retained controller element. */
137
- segmentTargetDisconnected() {
335
+ segmentTargetDisconnected(segment) {
336
+ if (segment && !this.segmentTargets.includes(segment)) this.#renderedSegments.delete(segment);
138
337
  this.#domDirty = true;
139
- this.#clearTypeBuffer();
140
338
  this.#reconcile.schedule();
141
339
  }
142
- /** Reflects the current composed value into a field added or replaced at runtime. */
143
340
  fieldTargetConnected() {
144
341
  this.#reconcile.schedule();
145
342
  }
146
- /** Reconciles silently when the optional field leaves at runtime. */
147
343
  fieldTargetDisconnected() {
148
344
  this.#reconcile.schedule();
149
345
  }
150
- /** Handles APG stepping, inter-segment focus moves, jumps, and direct entry. */
151
346
  onKeydown(event) {
152
347
  if (isReservedArrowChord(event)) return;
153
348
  const segment = event.target?.closest(
@@ -157,7 +352,9 @@ var TimePickerController = class extends Controller {
157
352
  const kind = this.#kindOf(segment);
158
353
  if (!kind) return;
159
354
  const key = logicalArrowKey(event.key, this.element);
160
- if ((key === "Home" || key === "End") && hasModifier(event)) return;
355
+ if ((key === "Home" || key === "End") && hasModifierChord(event)) return;
356
+ if (this.#adoptPendingDom()) this.#reconcile.schedule();
357
+ if (this.#renderedHourMode !== this.#hourMode) this.#clearTypeBuffer();
161
358
  switch (key) {
162
359
  case "ArrowUp":
163
360
  event.preventDefault();
@@ -186,7 +383,7 @@ var TimePickerController = class extends Controller {
186
383
  this.#commitRender();
187
384
  break;
188
385
  default:
189
- if (kind !== "meridiem" && /^[0-9]$/.test(event.key) && !hasModifier(event)) {
386
+ if (kind !== "meridiem" && /^[0-9]$/.test(event.key) && !event.ctrlKey && !event.altKey && !event.metaKey) {
190
387
  event.preventDefault();
191
388
  this.#typeDigit(segment, kind, event.key);
192
389
  return;
@@ -195,7 +392,6 @@ var TimePickerController = class extends Controller {
195
392
  }
196
393
  this.#clearTypeBuffer();
197
394
  }
198
- /** Clears direct-entry state when Tab, Shift+Tab, or pointer focus leaves a segment. */
199
395
  #onFocusOut = (event) => {
200
396
  const segment = event.target?.closest(
201
397
  targetSelector(this.identifier, "segment")
@@ -203,13 +399,11 @@ var TimePickerController = class extends Controller {
203
399
  if (!segment || !this.segmentTargets.includes(segment)) return;
204
400
  this.#clearTypeBuffer();
205
401
  };
206
- /** Uses the normalized positive-integer minute step; other segments step by one. */
207
402
  #delta(kind) {
208
403
  if (kind !== "minute") return 1;
209
- const step = Math.trunc(this.stepValue);
210
- return Number.isFinite(step) && step > 0 ? step : 1;
404
+ const step = Math.trunc(this.#safeStep);
405
+ return step > 0 ? step : 1;
211
406
  }
212
- /** Mutates one complete action and then renders/notifies its final value once. */
213
407
  #step(kind, delta) {
214
408
  if (kind === "meridiem" && this.wrapValue) {
215
409
  this.#state.hour = modulo(this.#state.hour + 12, 24);
@@ -225,7 +419,6 @@ var TimePickerController = class extends Controller {
225
419
  }
226
420
  this.#commitRender();
227
421
  }
228
- /** Accumulates a typed digit, rendering once and advancing after completion. */
229
422
  #typeDigit(segment, kind, digit) {
230
423
  if (this.#typeSegment !== kind) this.#typeBuffer = "";
231
424
  this.#typeSegment = kind;
@@ -233,34 +426,46 @@ var TimePickerController = class extends Controller {
233
426
  const candidate = Number(`${this.#typeBuffer}${digit}`);
234
427
  this.#typeBuffer = candidate <= max ? `${this.#typeBuffer}${digit}` : digit;
235
428
  this.#setDisplayed(kind, Number(this.#typeBuffer));
236
- this.#commitRender();
429
+ this.#commitRender(true);
237
430
  if (this.#typeBuffer.length >= 2 || Number(this.#typeBuffer) * 10 > max) {
238
431
  this.#clearTypeBuffer();
239
432
  this.#focusSibling(segment, 1);
240
433
  }
241
434
  }
242
- /** Moves focus to the previous/next valid segment, if one exists. */
243
435
  #focusSibling(segment, direction) {
244
436
  const segments = this.segmentTargets.filter((candidate) => this.#kindOf(candidate) !== null);
245
437
  const index = segments.indexOf(segment);
246
438
  segments[index + direction]?.focus();
247
439
  }
248
- /** Clears the direct-entry buffer and its owning segment together. */
249
440
  #clearTypeBuffer() {
250
441
  this.#typeBuffer = "";
251
442
  this.#typeSegment = null;
252
443
  }
253
- /** Reconciles one coalesced target, Value, or retained-attribute mutation batch. */
254
- #reconcileDom() {
255
- if (this.#domDirty) {
256
- this.#domDirty = false;
257
- this.#clearTypeBuffer();
258
- this.#adoptDomState();
444
+ #adoptPendingDom() {
445
+ this.#recordAuthoredSegments(this.#observer.take());
446
+ if (!this.#domDirty) return false;
447
+ this.#domDirty = false;
448
+ this.#clearTypeBuffer();
449
+ this.#adoptDomState();
450
+ return true;
451
+ }
452
+ #recordAuthoredSegments(records) {
453
+ let changed = false;
454
+ for (const { target } of records) {
455
+ if (!(target instanceof HTMLElement) || !this.segmentTargets.includes(target)) continue;
456
+ this.#authoredSegments.add(target);
457
+ changed = true;
259
458
  }
459
+ if (changed) this.#domDirty = true;
460
+ return changed;
461
+ }
462
+ #reconcileDom() {
463
+ this.#adoptPendingDom();
260
464
  this.#render();
261
465
  }
262
- /** Rebuilds canonical state from the targets; an absent hour represents midnight. */
263
466
  #adoptDomState() {
467
+ const mode = this.#hourMode;
468
+ const presentationChanged = this.#renderedHourMode !== null && this.#renderedHourMode !== mode;
264
469
  let displayedHour = 0;
265
470
  let meridiem = AM;
266
471
  let minute = 0;
@@ -268,58 +473,56 @@ var TimePickerController = class extends Controller {
268
473
  for (const segment of this.segmentTargets) {
269
474
  const kind = this.#kindOf(segment);
270
475
  if (!kind) continue;
271
- const value = this.#authoredValue(segment, kind);
476
+ const retained = presentationChanged && this.#renderedSegments.has(segment) && !this.#authoredSegments.has(segment);
477
+ let value;
478
+ if (retained && kind === "hour") {
479
+ value = mode === "h23" ? this.#state.hour : this.#state.hour % 12;
480
+ } else if (retained && kind === "meridiem") {
481
+ value = this.#state.hour >= 12 ? PM : AM;
482
+ } else {
483
+ value = this.#authoredValue(segment, kind);
484
+ }
272
485
  if (kind === "hour") displayedHour = value;
273
486
  else if (kind === "minute") minute = value;
274
487
  else if (kind === "second") second = value;
275
488
  else meridiem = value;
276
489
  }
277
490
  this.#state = {
278
- hour: this.hourCycleValue === 12 ? displayedHour % 12 + (meridiem === PM ? 12 : 0) : displayedHour,
491
+ hour: this.#safeHourCycle === 12 ? displayedHour % 12 + (meridiem === PM ? 12 : 0) : displayedHour,
279
492
  minute,
280
493
  second
281
494
  };
495
+ this.#authoredSegments.clear();
282
496
  }
283
- /** Reads and integer-clamps one authored `aria-valuenow`. */
284
497
  #authoredValue(segment, kind) {
285
498
  const raw = Number(segment.getAttribute("aria-valuenow"));
286
499
  const { min, max } = this.#bounds(kind);
287
500
  if (!Number.isFinite(raw)) return min;
288
501
  return Math.min(max, Math.max(min, Math.trunc(raw)));
289
502
  }
290
- /** Writes a displayed segment value back into canonical state without rendering. */
291
503
  #setDisplayed(kind, raw) {
292
504
  const { min, max } = this.#bounds(kind);
293
505
  const value = Math.min(max, Math.max(min, Math.trunc(raw)));
294
506
  if (kind === "hour") {
295
- this.#state.hour = this.hourCycleValue === 12 ? value % 12 + (this.#state.hour >= 12 ? 12 : 0) : value;
507
+ this.#state.hour = this.#safeHourCycle === 12 ? value % 12 + (this.#state.hour >= 12 ? 12 : 0) : value;
296
508
  } else if (kind === "minute" || kind === "second") {
297
509
  this.#state[kind] = value;
298
510
  } else {
299
511
  this.#state.hour = this.#state.hour % 12 + (value === PM ? 12 : 0);
300
512
  }
301
513
  }
302
- /** Converts seconds with day wrapping into the canonical three-unit state. */
303
514
  #setFromSeconds(raw) {
304
515
  const seconds = modulo(raw, SECONDS_PER_DAY);
305
516
  this.#state.hour = Math.floor(seconds / SECONDS_PER_HOUR);
306
517
  this.#state.minute = Math.floor(seconds % SECONDS_PER_HOUR / SECONDS_PER_MINUTE);
307
518
  this.#state.second = seconds % SECONDS_PER_MINUTE;
308
519
  }
309
- /** Reflects canonical state to every segment without dispatching user events. */
310
- #renderSegments() {
311
- this.#withoutObservation(() => {
312
- for (const segment of this.segmentTargets) this.#renderSegment(segment);
313
- });
520
+ #renderSegments(preserveTypeBuffer = false) {
521
+ const mode = this.#hourMode;
522
+ if (this.#renderedHourMode !== mode && !preserveTypeBuffer) this.#clearTypeBuffer();
523
+ this.#renderedHourMode = mode;
524
+ for (const segment of this.segmentTargets) this.#renderSegment(segment);
314
525
  }
315
- /**
316
- * Reflects canonical state during connection or DOM reconciliation.
317
- *
318
- * No user edit reaches here, so `change` never fires from this path. A pass
319
- * that moves the committed value reports `reconcile` instead.
320
- *
321
- * @stimeoRenderRoot
322
- */
323
526
  #render() {
324
527
  this.#renderSegments();
325
528
  const value = this.#composedValue;
@@ -327,53 +530,61 @@ var TimePickerController = class extends Controller {
327
530
  this.#writeField(value);
328
531
  this.#lastValue = value;
329
532
  if (previous !== "" && value !== previous) {
533
+ this.#move = this.#moves.record();
330
534
  this.dispatch("reconcile", { detail: { value } });
331
535
  }
332
536
  }
333
- /** Reflects one completed user action and dispatches its final change exactly once. */
334
- #commitRender() {
335
- this.#renderSegments();
537
+ #commitRender(preserveTypeBuffer = false) {
538
+ const generation = this.#connectionGeneration;
539
+ this.#renderSegments(preserveTypeBuffer);
336
540
  const value = this.#composedValue;
337
- if (this.#writeField(value)) commitField(this.fieldTarget);
338
- if (value !== this.#lastValue) this.dispatch("change", { detail: { value } });
541
+ const changed = value !== this.#lastValue;
339
542
  this.#lastValue = value;
543
+ if (changed) this.#move = this.#moves.record();
544
+ const move = this.#move;
545
+ if (this.#writeField(value)) commitField(this.fieldTarget);
546
+ if (generation !== this.#connectionGeneration || !this.#moves.isLatest(move)) return;
547
+ if (changed) this.dispatch("change", { detail: { value } });
340
548
  }
341
- /** Reflects one segment's value and controller-owned ARIA bounds/text. */
342
549
  #renderSegment(segment) {
343
550
  const kind = this.#kindOf(segment);
344
551
  if (!kind) return;
552
+ this.#renderedSegments.add(segment);
345
553
  const value = this.#displayValue(kind);
346
- const text = kind === "meridiem" ? value === PM ? "PM" : "AM" : pad(value);
554
+ const text = kind === "meridiem" ? value === PM ? this.pmLabelValue : this.amLabelValue : pad(value);
347
555
  const { min, max } = this.#bounds(kind);
348
- segment.setAttribute("aria-valuenow", String(value));
556
+ const serialized = String(value);
557
+ setAttributeIfChanged(segment, "aria-valuenow", serialized, () => {
558
+ this.#observer.claim(segment, "aria-valuenow", serialized);
559
+ });
349
560
  segment.setAttribute("aria-valuetext", text);
350
561
  segment.setAttribute("aria-valuemin", String(min));
351
562
  segment.setAttribute("aria-valuemax", String(max));
352
563
  segment.textContent = text;
353
564
  }
354
- /** Writes a composed value to the optional form field and reports whether it changed. */
355
565
  #writeField(value) {
356
566
  return this.hasFieldTarget && writeField(this.fieldTarget, value);
357
567
  }
358
- /** The canonical form value composed as `HH:MM[:SS]`. */
359
568
  get #composedValue() {
360
569
  const parts = [pad(this.#state.hour), pad(this.#state.minute)];
361
570
  if (this.secondsValue) parts.push(pad(this.#state.second));
362
571
  return parts.join(":");
363
572
  }
364
- /** Returns a canonical unit in the presentation form exposed by its segment. */
365
573
  #displayValue(kind) {
366
574
  if (kind === "hour") {
367
- return this.hourCycleValue === 12 ? this.#state.hour % 12 || 12 : this.#state.hour;
575
+ const mode = this.#hourMode;
576
+ if (mode === "h23") return this.#state.hour;
577
+ const hour = this.#state.hour % 12;
578
+ return mode === "h11" ? hour : hour || 12;
368
579
  }
369
580
  if (kind === "meridiem") return this.#state.hour >= 12 ? PM : AM;
370
581
  return this.#state[kind];
371
582
  }
372
- /** The inclusive controller-owned bounds for a segment kind. */
373
583
  #bounds(kind) {
374
584
  switch (kind) {
375
585
  case "hour":
376
- return this.hourCycleValue === 12 ? { min: 1, max: 12 } : { min: 0, max: 23 };
586
+ if (this.#hourMode === "h23") return { min: 0, max: 23 };
587
+ return this.#hourMode === "h11" ? { min: 0, max: 11 } : { min: 1, max: 12 };
377
588
  case "minute":
378
589
  case "second":
379
590
  return { min: 0, max: 59 };
@@ -381,39 +592,12 @@ var TimePickerController = class extends Controller {
381
592
  return { min: AM, max: PM };
382
593
  }
383
594
  }
384
- /** Watches retained segment state while excluding this controller's own reflections. */
385
595
  #observeMutations() {
386
- const observer = new MutationObserver((records) => {
387
- const changed = records.some(
388
- ({ target }) => target instanceof HTMLElement && this.segmentTargets.includes(target)
389
- );
390
- if (!changed) return;
391
- this.#domDirty = true;
392
- this.#clearTypeBuffer();
393
- this.#reconcile.schedule();
394
- });
395
- this.#observer = observer;
396
- this.#observeWith(observer);
397
- }
398
- /** Registers retained attribute observation on the controller subtree. */
399
- #observeWith(observer) {
400
- observer.observe(this.element, {
596
+ this.#observer.observe(this.element, {
401
597
  subtree: true,
402
- attributes: true,
403
- attributeFilter: ["aria-valuenow", "data-segment"]
598
+ attributes: ["aria-valuenow", "data-segment"]
404
599
  });
405
600
  }
406
- /** Temporarily pauses observation so derived ARIA writes cannot become DOM input. */
407
- #withoutObservation(run) {
408
- const observer = this.#observer;
409
- observer?.disconnect();
410
- try {
411
- run();
412
- } finally {
413
- if (observer && this.#connected) this.#observeWith(observer);
414
- }
415
- }
416
- /** Reads a segment's declared kind, or null when absent/invalid. */
417
601
  #kindOf(segment) {
418
602
  const kind = segment.getAttribute("data-segment");
419
603
  if (kind === "hour" || kind === "minute" || kind === "second" || kind === "meridiem") {
@@ -421,10 +605,31 @@ var TimePickerController = class extends Controller {
421
605
  }
422
606
  return null;
423
607
  }
424
- /** Canonical state as seconds since the start of its nominal day. */
425
608
  get #secondsOfDay() {
426
609
  return this.#state.hour * SECONDS_PER_HOUR + this.#state.minute * SECONDS_PER_MINUTE + this.#state.second;
427
610
  }
611
+ get #hourMode() {
612
+ if (this.#safeHourCycle !== 12) return "h23";
613
+ return this.hour12ZeroBasedValue ? "h11" : "h12";
614
+ }
615
+ get #safeHourCycle() {
616
+ return this.#numbers.read(
617
+ this,
618
+ "hourCycle",
619
+ this.hourCycleValue,
620
+ _TimePickerController.values.hourCycle.default,
621
+ _TimePickerController.valueConstraints.hourCycle
622
+ );
623
+ }
624
+ get #safeStep() {
625
+ return this.#numbers.read(
626
+ this,
627
+ "step",
628
+ this.stepValue,
629
+ _TimePickerController.values.step.default,
630
+ _TimePickerController.valueConstraints.step
631
+ );
632
+ }
428
633
  };
429
634
  function modulo(value, modulus) {
430
635
  return (value % modulus + modulus) % modulus;
@@ -434,5 +639,4 @@ function pad(value) {
434
639
  }
435
640
 
436
641
  export { TimePickerController };
437
- //# sourceMappingURL=time_picker_controller.js.map
438
642
  //# sourceMappingURL=time_picker_controller.js.map