stimeo-ui 0.16.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (328) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +8 -1
  3. package/dist/cable/index.d.ts +79 -23
  4. package/dist/cable/index.js +363 -436
  5. package/dist/cable/index.js.map +1 -1
  6. package/dist/controllers/accordion_controller.d.ts +4 -2
  7. package/dist/controllers/accordion_controller.js +166 -55
  8. package/dist/controllers/accordion_controller.js.map +1 -1
  9. package/dist/controllers/alert_dialog_controller.d.ts +12 -2
  10. package/dist/controllers/alert_dialog_controller.js +862 -221
  11. package/dist/controllers/alert_dialog_controller.js.map +1 -1
  12. package/dist/controllers/announcer_controller.d.ts +35 -5
  13. package/dist/controllers/announcer_controller.js +135 -198
  14. package/dist/controllers/announcer_controller.js.map +1 -1
  15. package/dist/controllers/aspect_ratio_controller.js +0 -10
  16. package/dist/controllers/aspect_ratio_controller.js.map +1 -1
  17. package/dist/controllers/auto_submit_controller.d.ts +30 -6
  18. package/dist/controllers/auto_submit_controller.js +271 -127
  19. package/dist/controllers/auto_submit_controller.js.map +1 -1
  20. package/dist/controllers/avatar_controller.js +171 -105
  21. package/dist/controllers/avatar_controller.js.map +1 -1
  22. package/dist/controllers/breadcrumb_controller.js +0 -130
  23. package/dist/controllers/breadcrumb_controller.js.map +1 -1
  24. package/dist/controllers/bulk_select_controller.d.ts +18 -0
  25. package/dist/controllers/bulk_select_controller.js +262 -52
  26. package/dist/controllers/bulk_select_controller.js.map +1 -1
  27. package/dist/controllers/calendar_controller.d.ts +24 -5
  28. package/dist/controllers/calendar_controller.js +175 -209
  29. package/dist/controllers/calendar_controller.js.map +1 -1
  30. package/dist/controllers/carousel_controller.d.ts +34 -7
  31. package/dist/controllers/carousel_controller.js +461 -399
  32. package/dist/controllers/carousel_controller.js.map +1 -1
  33. package/dist/controllers/character_counter_controller.d.ts +17 -1
  34. package/dist/controllers/character_counter_controller.js +246 -156
  35. package/dist/controllers/character_counter_controller.js.map +1 -1
  36. package/dist/controllers/checkbox_controller.d.ts +7 -2
  37. package/dist/controllers/checkbox_controller.js +32 -74
  38. package/dist/controllers/checkbox_controller.js.map +1 -1
  39. package/dist/controllers/clipboard_controller.d.ts +16 -5
  40. package/dist/controllers/clipboard_controller.js +168 -147
  41. package/dist/controllers/clipboard_controller.js.map +1 -1
  42. package/dist/controllers/collapsible_controller.d.ts +16 -4
  43. package/dist/controllers/collapsible_controller.js +301 -120
  44. package/dist/controllers/collapsible_controller.js.map +1 -1
  45. package/dist/controllers/color_picker_controller.d.ts +18 -6
  46. package/dist/controllers/color_picker_controller.js +149 -139
  47. package/dist/controllers/color_picker_controller.js.map +1 -1
  48. package/dist/controllers/combobox_controller.d.ts +23 -5
  49. package/dist/controllers/combobox_controller.js +360 -133
  50. package/dist/controllers/combobox_controller.js.map +1 -1
  51. package/dist/controllers/command_palette_controller.d.ts +45 -14
  52. package/dist/controllers/command_palette_controller.js +970 -358
  53. package/dist/controllers/command_palette_controller.js.map +1 -1
  54. package/dist/controllers/conditional_fields_controller.d.ts +15 -2
  55. package/dist/controllers/conditional_fields_controller.js +166 -124
  56. package/dist/controllers/conditional_fields_controller.js.map +1 -1
  57. package/dist/controllers/confirm_controller.d.ts +49 -12
  58. package/dist/controllers/confirm_controller.js +939 -248
  59. package/dist/controllers/confirm_controller.js.map +1 -1
  60. package/dist/controllers/context_menu_controller.d.ts +31 -4
  61. package/dist/controllers/context_menu_controller.js +256 -128
  62. package/dist/controllers/context_menu_controller.js.map +1 -1
  63. package/dist/controllers/count_up_controller.d.ts +13 -1
  64. package/dist/controllers/count_up_controller.js +73 -21
  65. package/dist/controllers/count_up_controller.js.map +1 -1
  66. package/dist/controllers/countdown_controller.d.ts +45 -1
  67. package/dist/controllers/countdown_controller.js +183 -148
  68. package/dist/controllers/countdown_controller.js.map +1 -1
  69. package/dist/controllers/currency_input_controller.d.ts +21 -2
  70. package/dist/controllers/currency_input_controller.js +134 -158
  71. package/dist/controllers/currency_input_controller.js.map +1 -1
  72. package/dist/controllers/data_grid_controller.d.ts +15 -4
  73. package/dist/controllers/data_grid_controller.js +114 -186
  74. package/dist/controllers/data_grid_controller.js.map +1 -1
  75. package/dist/controllers/date_range_picker_controller.d.ts +30 -5
  76. package/dist/controllers/date_range_picker_controller.js +288 -206
  77. package/dist/controllers/date_range_picker_controller.js.map +1 -1
  78. package/dist/controllers/dialog_controller.d.ts +13 -1
  79. package/dist/controllers/dialog_controller.js +858 -223
  80. package/dist/controllers/dialog_controller.js.map +1 -1
  81. package/dist/controllers/direct_upload_controller.d.ts +24 -7
  82. package/dist/controllers/direct_upload_controller.js +73 -153
  83. package/dist/controllers/direct_upload_controller.js.map +1 -1
  84. package/dist/controllers/dirty_form_controller.js +14 -48
  85. package/dist/controllers/dirty_form_controller.js.map +1 -1
  86. package/dist/controllers/dismissible_controller.d.ts +19 -0
  87. package/dist/controllers/dismissible_controller.js +175 -21
  88. package/dist/controllers/dismissible_controller.js.map +1 -1
  89. package/dist/controllers/drawer_controller.d.ts +39 -11
  90. package/dist/controllers/drawer_controller.js +933 -341
  91. package/dist/controllers/drawer_controller.js.map +1 -1
  92. package/dist/controllers/dropdown_controller.d.ts +31 -1
  93. package/dist/controllers/dropdown_controller.js +312 -82
  94. package/dist/controllers/dropdown_controller.js.map +1 -1
  95. package/dist/controllers/editable_controller.d.ts +12 -1
  96. package/dist/controllers/editable_controller.js +158 -68
  97. package/dist/controllers/editable_controller.js.map +1 -1
  98. package/dist/controllers/empty_state_controller.js +67 -53
  99. package/dist/controllers/empty_state_controller.js.map +1 -1
  100. package/dist/controllers/file_dropzone_controller.d.ts +60 -18
  101. package/dist/controllers/file_dropzone_controller.js +311 -207
  102. package/dist/controllers/file_dropzone_controller.js.map +1 -1
  103. package/dist/controllers/filter_controller.js +67 -39
  104. package/dist/controllers/filter_controller.js.map +1 -1
  105. package/dist/controllers/flash_controller.d.ts +31 -8
  106. package/dist/controllers/flash_controller.js +172 -314
  107. package/dist/controllers/flash_controller.js.map +1 -1
  108. package/dist/controllers/focus_controller.d.ts +12 -3
  109. package/dist/controllers/focus_controller.js +654 -240
  110. package/dist/controllers/focus_controller.js.map +1 -1
  111. package/dist/controllers/form_field_controller.js +147 -132
  112. package/dist/controllers/form_field_controller.js.map +1 -1
  113. package/dist/controllers/form_validation_controller.js +13 -86
  114. package/dist/controllers/form_validation_controller.js.map +1 -1
  115. package/dist/controllers/frame_loading_controller.d.ts +41 -9
  116. package/dist/controllers/frame_loading_controller.js +264 -213
  117. package/dist/controllers/frame_loading_controller.js.map +1 -1
  118. package/dist/controllers/highlight_controller.d.ts +22 -2
  119. package/dist/controllers/highlight_controller.js +107 -75
  120. package/dist/controllers/highlight_controller.js.map +1 -1
  121. package/dist/controllers/hover_card_controller.d.ts +56 -3
  122. package/dist/controllers/hover_card_controller.js +309 -118
  123. package/dist/controllers/hover_card_controller.js.map +1 -1
  124. package/dist/controllers/idle_controller.d.ts +42 -1
  125. package/dist/controllers/idle_controller.js +267 -101
  126. package/dist/controllers/idle_controller.js.map +1 -1
  127. package/dist/controllers/input_mask_controller.js +71 -72
  128. package/dist/controllers/input_mask_controller.js.map +1 -1
  129. package/dist/controllers/intersection_controller.d.ts +32 -13
  130. package/dist/controllers/intersection_controller.js +147 -106
  131. package/dist/controllers/intersection_controller.js.map +1 -1
  132. package/dist/controllers/lazy_frame_controller.d.ts +16 -0
  133. package/dist/controllers/lazy_frame_controller.js +9 -65
  134. package/dist/controllers/lazy_frame_controller.js.map +1 -1
  135. package/dist/controllers/listbox_controller.d.ts +34 -2
  136. package/dist/controllers/listbox_controller.js +306 -204
  137. package/dist/controllers/listbox_controller.js.map +1 -1
  138. package/dist/controllers/local_time_controller.d.ts +1 -1
  139. package/dist/controllers/local_time_controller.js +54 -64
  140. package/dist/controllers/local_time_controller.js.map +1 -1
  141. package/dist/controllers/masonry_controller.d.ts +11 -3
  142. package/dist/controllers/masonry_controller.js +70 -93
  143. package/dist/controllers/masonry_controller.js.map +1 -1
  144. package/dist/controllers/menu_controller.d.ts +32 -7
  145. package/dist/controllers/menu_controller.js +214 -156
  146. package/dist/controllers/menu_controller.js.map +1 -1
  147. package/dist/controllers/menubar_controller.d.ts +4 -4
  148. package/dist/controllers/menubar_controller.js +170 -329
  149. package/dist/controllers/menubar_controller.js.map +1 -1
  150. package/dist/controllers/meter_controller.d.ts +20 -0
  151. package/dist/controllers/meter_controller.js +151 -67
  152. package/dist/controllers/meter_controller.js.map +1 -1
  153. package/dist/controllers/multi_select_controller.d.ts +32 -4
  154. package/dist/controllers/multi_select_controller.js +593 -358
  155. package/dist/controllers/multi_select_controller.js.map +1 -1
  156. package/dist/controllers/navigation_menu_controller.d.ts +8 -1
  157. package/dist/controllers/navigation_menu_controller.js +124 -232
  158. package/dist/controllers/navigation_menu_controller.js.map +1 -1
  159. package/dist/controllers/nested_form_controller.d.ts +10 -0
  160. package/dist/controllers/nested_form_controller.js +352 -182
  161. package/dist/controllers/nested_form_controller.js.map +1 -1
  162. package/dist/controllers/network_status_controller.d.ts +23 -0
  163. package/dist/controllers/network_status_controller.js +242 -54
  164. package/dist/controllers/network_status_controller.js.map +1 -1
  165. package/dist/controllers/number_input_controller.d.ts +26 -2
  166. package/dist/controllers/number_input_controller.js +320 -263
  167. package/dist/controllers/number_input_controller.js.map +1 -1
  168. package/dist/controllers/optimistic_controller.js +16 -76
  169. package/dist/controllers/optimistic_controller.js.map +1 -1
  170. package/dist/controllers/otp_controller.d.ts +20 -4
  171. package/dist/controllers/otp_controller.js +198 -193
  172. package/dist/controllers/otp_controller.js.map +1 -1
  173. package/dist/controllers/overflow_indicator_controller.d.ts +5 -0
  174. package/dist/controllers/overflow_indicator_controller.js +116 -113
  175. package/dist/controllers/overflow_indicator_controller.js.map +1 -1
  176. package/dist/controllers/overflow_menu_controller.d.ts +48 -11
  177. package/dist/controllers/overflow_menu_controller.js +343 -283
  178. package/dist/controllers/overflow_menu_controller.js.map +1 -1
  179. package/dist/controllers/pagination_controller.d.ts +35 -6
  180. package/dist/controllers/pagination_controller.js +295 -119
  181. package/dist/controllers/pagination_controller.js.map +1 -1
  182. package/dist/controllers/password_reveal_controller.d.ts +45 -8
  183. package/dist/controllers/password_reveal_controller.js +389 -121
  184. package/dist/controllers/password_reveal_controller.js.map +1 -1
  185. package/dist/controllers/password_strength_controller.d.ts +14 -5
  186. package/dist/controllers/password_strength_controller.js +99 -153
  187. package/dist/controllers/password_strength_controller.js.map +1 -1
  188. package/dist/controllers/persist_controller.d.ts +11 -4
  189. package/dist/controllers/persist_controller.js +237 -103
  190. package/dist/controllers/persist_controller.js.map +1 -1
  191. package/dist/controllers/pointer_drag_controller.d.ts +19 -7
  192. package/dist/controllers/pointer_drag_controller.js +185 -165
  193. package/dist/controllers/pointer_drag_controller.js.map +1 -1
  194. package/dist/controllers/popover_controller.d.ts +38 -2
  195. package/dist/controllers/popover_controller.js +236 -97
  196. package/dist/controllers/popover_controller.js.map +1 -1
  197. package/dist/controllers/portal_controller.d.ts +44 -4
  198. package/dist/controllers/portal_controller.js +209 -76
  199. package/dist/controllers/portal_controller.js.map +1 -1
  200. package/dist/controllers/preview_guard_controller.d.ts +10 -4
  201. package/dist/controllers/preview_guard_controller.js +232 -116
  202. package/dist/controllers/preview_guard_controller.js.map +1 -1
  203. package/dist/controllers/progress_controller.d.ts +11 -0
  204. package/dist/controllers/progress_controller.js +125 -56
  205. package/dist/controllers/progress_controller.js.map +1 -1
  206. package/dist/controllers/radio_group_controller.d.ts +14 -5
  207. package/dist/controllers/radio_group_controller.js +117 -137
  208. package/dist/controllers/radio_group_controller.js.map +1 -1
  209. package/dist/controllers/range_slider_controller.d.ts +43 -3
  210. package/dist/controllers/range_slider_controller.js +192 -105
  211. package/dist/controllers/range_slider_controller.js.map +1 -1
  212. package/dist/controllers/rating_controller.d.ts +20 -4
  213. package/dist/controllers/rating_controller.js +418 -207
  214. package/dist/controllers/rating_controller.js.map +1 -1
  215. package/dist/controllers/read_more_controller.d.ts +2 -0
  216. package/dist/controllers/read_more_controller.js +134 -63
  217. package/dist/controllers/read_more_controller.js.map +1 -1
  218. package/dist/controllers/reading_progress_controller.d.ts +1 -1
  219. package/dist/controllers/reading_progress_controller.js +147 -135
  220. package/dist/controllers/reading_progress_controller.js.map +1 -1
  221. package/dist/controllers/relative_time_controller.d.ts +18 -4
  222. package/dist/controllers/relative_time_controller.js +145 -110
  223. package/dist/controllers/relative_time_controller.js.map +1 -1
  224. package/dist/controllers/reset_on_restore_controller.d.ts +85 -0
  225. package/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +97 -38
  226. package/dist/controllers/reset_on_restore_controller.js.map +1 -0
  227. package/dist/controllers/resizable_controller.d.ts +28 -2
  228. package/dist/controllers/resizable_controller.js +255 -139
  229. package/dist/controllers/resizable_controller.js.map +1 -1
  230. package/dist/controllers/roving_controller.js +39 -84
  231. package/dist/controllers/roving_controller.js.map +1 -1
  232. package/dist/controllers/scroll_area_controller.d.ts +7 -3
  233. package/dist/controllers/scroll_area_controller.js +428 -225
  234. package/dist/controllers/scroll_area_controller.js.map +1 -1
  235. package/dist/controllers/scroll_restore_controller.js +0 -53
  236. package/dist/controllers/scroll_restore_controller.js.map +1 -1
  237. package/dist/controllers/scroll_visibility_controller.d.ts +28 -12
  238. package/dist/controllers/scroll_visibility_controller.js +395 -145
  239. package/dist/controllers/scroll_visibility_controller.js.map +1 -1
  240. package/dist/controllers/scrollspy_controller.d.ts +6 -1
  241. package/dist/controllers/scrollspy_controller.js +181 -242
  242. package/dist/controllers/scrollspy_controller.js.map +1 -1
  243. package/dist/controllers/separator_controller.d.ts +19 -4
  244. package/dist/controllers/separator_controller.js +267 -140
  245. package/dist/controllers/separator_controller.js.map +1 -1
  246. package/dist/controllers/sidebar_controller.d.ts +64 -7
  247. package/dist/controllers/sidebar_controller.js +1023 -386
  248. package/dist/controllers/sidebar_controller.js.map +1 -1
  249. package/dist/controllers/skeleton_controller.d.ts +23 -0
  250. package/dist/controllers/skeleton_controller.js +248 -97
  251. package/dist/controllers/skeleton_controller.js.map +1 -1
  252. package/dist/controllers/slider_controller.d.ts +27 -1
  253. package/dist/controllers/slider_controller.js +159 -79
  254. package/dist/controllers/slider_controller.js.map +1 -1
  255. package/dist/controllers/smart_sticky_header_controller.d.ts +21 -3
  256. package/dist/controllers/smart_sticky_header_controller.js +162 -63
  257. package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
  258. package/dist/controllers/sortable_controller.js +0 -112
  259. package/dist/controllers/sortable_controller.js.map +1 -1
  260. package/dist/controllers/spinner_controller.d.ts +39 -4
  261. package/dist/controllers/spinner_controller.js +277 -169
  262. package/dist/controllers/spinner_controller.js.map +1 -1
  263. package/dist/controllers/step_indicator_controller.d.ts +5 -0
  264. package/dist/controllers/step_indicator_controller.js +99 -46
  265. package/dist/controllers/step_indicator_controller.js.map +1 -1
  266. package/dist/controllers/stepper_controller.d.ts +12 -3
  267. package/dist/controllers/stepper_controller.js +114 -73
  268. package/dist/controllers/stepper_controller.js.map +1 -1
  269. package/dist/controllers/stick_to_bottom_controller.d.ts +6 -0
  270. package/dist/controllers/stick_to_bottom_controller.js +262 -138
  271. package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
  272. package/dist/controllers/sticky_observer_controller.d.ts +11 -0
  273. package/dist/controllers/sticky_observer_controller.js +214 -49
  274. package/dist/controllers/sticky_observer_controller.js.map +1 -1
  275. package/dist/controllers/submit_once_controller.d.ts +23 -8
  276. package/dist/controllers/submit_once_controller.js +294 -205
  277. package/dist/controllers/submit_once_controller.js.map +1 -1
  278. package/dist/controllers/switch_controller.d.ts +12 -1
  279. package/dist/controllers/switch_controller.js +33 -60
  280. package/dist/controllers/switch_controller.js.map +1 -1
  281. package/dist/controllers/tabs_controller.d.ts +2 -2
  282. package/dist/controllers/tabs_controller.js +35 -29
  283. package/dist/controllers/tabs_controller.js.map +1 -1
  284. package/dist/controllers/tags_input_controller.d.ts +12 -0
  285. package/dist/controllers/tags_input_controller.js +136 -145
  286. package/dist/controllers/tags_input_controller.js.map +1 -1
  287. package/dist/controllers/textarea_autosize_controller.d.ts +10 -0
  288. package/dist/controllers/textarea_autosize_controller.js +71 -58
  289. package/dist/controllers/textarea_autosize_controller.js.map +1 -1
  290. package/dist/controllers/theme_controller.d.ts +21 -9
  291. package/dist/controllers/theme_controller.js +130 -112
  292. package/dist/controllers/theme_controller.js.map +1 -1
  293. package/dist/controllers/time_picker_controller.d.ts +18 -1
  294. package/dist/controllers/time_picker_controller.js +146 -80
  295. package/dist/controllers/time_picker_controller.js.map +1 -1
  296. package/dist/controllers/toast_controller.d.ts +36 -11
  297. package/dist/controllers/toast_controller.js +186 -297
  298. package/dist/controllers/toast_controller.js.map +1 -1
  299. package/dist/controllers/toggle_group_controller.d.ts +12 -3
  300. package/dist/controllers/toggle_group_controller.js +95 -136
  301. package/dist/controllers/toggle_group_controller.js.map +1 -1
  302. package/dist/controllers/toolbar_controller.js +68 -98
  303. package/dist/controllers/toolbar_controller.js.map +1 -1
  304. package/dist/controllers/tooltip_controller.d.ts +45 -3
  305. package/dist/controllers/tooltip_controller.js +158 -124
  306. package/dist/controllers/tooltip_controller.js.map +1 -1
  307. package/dist/controllers/transition_controller.d.ts +22 -4
  308. package/dist/controllers/transition_controller.js +123 -119
  309. package/dist/controllers/transition_controller.js.map +1 -1
  310. package/dist/controllers/tree_view_controller.d.ts +21 -11
  311. package/dist/controllers/tree_view_controller.js +150 -345
  312. package/dist/controllers/tree_view_controller.js.map +1 -1
  313. package/dist/index.d.ts +8 -5
  314. package/dist/index.js +6370 -9346
  315. package/dist/index.js.map +1 -1
  316. package/dist/inspector/cli.d.ts +23 -3
  317. package/dist/inspector/cli.js +92 -37
  318. package/dist/inspector/cli.js.map +1 -1
  319. package/dist/inspector/cli_bin.js +92 -56
  320. package/dist/inspector/cli_bin.js.map +1 -1
  321. package/dist/inspector/examples.json +8 -8
  322. package/dist/inspector/manifest.json +787 -100
  323. package/dist/positioning/index.d.ts +8 -0
  324. package/dist/positioning/index.js +148 -47
  325. package/dist/positioning/index.js.map +1 -1
  326. package/package.json +6 -6
  327. package/dist/controllers/reset_before_cache_controller.d.ts +0 -76
  328. package/dist/controllers/reset_before_cache_controller.js.map +0 -1
@@ -1,13 +1,31 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/date_range_picker_controller.ts
3
+ var FOCUS_EVENTS = /* @__PURE__ */ new Set(["blur", "focus", "focusin", "focusout"]);
4
+ var POINTER_EVENTS = /* @__PURE__ */ new Set(["mouseenter", "mouseleave", "pointerenter", "pointerleave"]);
5
+ function stateReasonFor(event) {
6
+ if (!event) return "api";
7
+ if (FOCUS_EVENTS.has(event.type)) return "focus";
8
+ if (POINTER_EVENTS.has(event.type)) return "pointer";
9
+ return "user";
10
+ }
11
+
12
+ function actionSource(source) {
13
+ if (source instanceof HTMLElement) {
14
+ return { event: null, host: source, origin: source, reason: "api" };
15
+ }
16
+ const event = source ?? null;
17
+ return {
18
+ event,
19
+ host: event?.currentTarget instanceof Element ? event.currentTarget : null,
20
+ origin: event?.target instanceof Element ? event.target : null,
21
+ reason: stateReasonFor(event)
22
+ };
23
+ }
4
24
 
5
- // src/utils/logical_scroll.ts
6
25
  function isRtl(element) {
7
26
  return window.getComputedStyle(element).direction === "rtl";
8
27
  }
9
28
 
10
- // src/utils/arrow_step.ts
11
29
  function logicalArrowKey(key, element) {
12
30
  if (key !== "ArrowRight" && key !== "ArrowLeft") return key;
13
31
  if (!isRtl(element)) return key;
@@ -18,36 +36,153 @@ function isReservedArrowChord(event, allow = []) {
18
36
  return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
19
37
  }
20
38
 
21
- // src/utils/before_cache_reset.ts
22
- var BeforeCacheReset = class _BeforeCacheReset {
23
- /** Every subscribed instance, iterated by the one shared document listener. */
24
- static #subscribers = /* @__PURE__ */ new Set();
25
- /** The shared listener; installed while at least one instance is subscribed. */
26
- static #onBeforeCache = () => {
27
- for (const subscriber of _BeforeCacheReset.#subscribers) subscriber.#rewind();
28
- };
29
- #rewind;
30
- /** @param rewind - the pass that returns this controller's state to its initial form. */
31
- constructor(rewind) {
32
- this.#rewind = rewind;
39
+ function sharedRegistry(key, create) {
40
+ const symbol = Symbol.for(key);
41
+ const scope = globalThis;
42
+ const existing = scope[symbol];
43
+ if (existing !== void 0) return existing;
44
+ const registry = create();
45
+ Object.defineProperty(globalThis, symbol, { value: registry });
46
+ return registry;
47
+ }
48
+
49
+ function isAttributeValue(value) {
50
+ return value === null || typeof value === "string";
51
+ }
52
+ function readLeaseRecord(element, record) {
53
+ try {
54
+ const parsed = JSON.parse(element.getAttribute(record) ?? "null");
55
+ if (!Array.isArray(parsed)) return void 0;
56
+ const [original, written, ...rest] = parsed;
57
+ const linked = rest[0] !== false;
58
+ const beneath = linked ? rest : rest.slice(1);
59
+ if (!beneath.every((under) => typeof under === "string")) return void 0;
60
+ return isAttributeValue(original) && isAttributeValue(written) ? { original, written, linked, beneath } : void 0;
61
+ } catch {
62
+ return void 0;
33
63
  }
34
- /** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */
35
- activate() {
36
- const first = _BeforeCacheReset.#subscribers.size === 0;
37
- _BeforeCacheReset.#subscribers.add(this);
38
- if (first) {
39
- document.addEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
64
+ }
65
+ var AttributeLease = class _AttributeLease {
66
+ static #registry = sharedRegistry(
67
+ "stimeo-ui.attribute-lease.registry.v1",
68
+ () => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
69
+ );
70
+ #attribute;
71
+ #record;
72
+ #base;
73
+ #held = /* @__PURE__ */ new Set();
74
+ constructor(attribute, owner, options = {}) {
75
+ this.#attribute = attribute;
76
+ this.#record = `data-${owner}-${attribute}-lease`;
77
+ this.#base = options.base === true;
78
+ const names = _AttributeLease.#registry.names;
79
+ names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
80
+ }
81
+ write(element, value) {
82
+ const stack = this.#stack(element);
83
+ const hold = this.#take(stack) ?? this.#acquire(element, stack);
84
+ this.#held.add(element);
85
+ const shows = !this.#covered(element, stack, hold);
86
+ hold.written = value;
87
+ this.#mark(element, stack);
88
+ if (shows) this.#reflect(element, value);
89
+ }
90
+ return(element) {
91
+ const held = this.#held.delete(element);
92
+ const known = _AttributeLease.#registry.stacks.get(element)?.has(this.#attribute);
93
+ const stack = held || known || element.hasAttribute(this.#record) ? this.#stack(element) : [];
94
+ const hold = this.#take(stack);
95
+ if (!hold) return false;
96
+ const carries = element.getAttribute(this.#attribute) === hold.written;
97
+ const owns = carries && !this.#covered(element, stack, hold);
98
+ const index = stack.indexOf(hold);
99
+ stack.splice(index, 1);
100
+ const above = stack[index];
101
+ if (above) above.linked &&= hold.linked;
102
+ this.#mark(element, stack);
103
+ if (!owns) return true;
104
+ const below = hold.linked ? stack[index - 1] : void 0;
105
+ this.#reflect(element, below ? below.written : hold.original);
106
+ return true;
107
+ }
108
+ returnAll() {
109
+ for (const element of Array.from(this.#held)) this.return(element);
110
+ }
111
+ #stack(element) {
112
+ const stacks = _AttributeLease.#registry.stacks;
113
+ const byAttribute = stacks.get(element) ?? /* @__PURE__ */ new Map();
114
+ stacks.set(element, byAttribute);
115
+ const stack = byAttribute.get(this.#attribute) ?? this.#seed(element);
116
+ byAttribute.set(this.#attribute, stack);
117
+ return stack;
118
+ }
119
+ #seed(element) {
120
+ const found = [];
121
+ for (const record of _AttributeLease.#registry.names.get(this.#attribute) ?? []) {
122
+ const read = readLeaseRecord(element, record);
123
+ if (read) found.push({ ...read, record });
124
+ }
125
+ const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
126
+ return found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
127
+ lease: null,
128
+ record,
129
+ written,
130
+ original,
131
+ linked: linked && index > 0
132
+ }));
133
+ }
134
+ #take(stack) {
135
+ const hold = stack.find((held) => held.lease === this) ?? stack.find((held) => held.lease === null && held.record === this.#record);
136
+ if (hold) hold.lease = this;
137
+ return hold;
138
+ }
139
+ #acquire(element, stack) {
140
+ const current = element.getAttribute(this.#attribute);
141
+ const top = stack.at(-1);
142
+ const bottom = stack[0];
143
+ const over = top?.written === current ? top : void 0;
144
+ const from = this.#base ? bottom : over;
145
+ const hold = {
146
+ lease: this,
147
+ record: this.#record,
148
+ written: current,
149
+ original: from ? from.original : current,
150
+ linked: !this.#base && over !== void 0
151
+ };
152
+ if (this.#base && bottom) {
153
+ bottom.linked = true;
154
+ stack.unshift(hold);
155
+ } else stack.push(hold);
156
+ return hold;
157
+ }
158
+ #covered(element, stack, hold) {
159
+ const current = element.getAttribute(this.#attribute);
160
+ return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current);
161
+ }
162
+ #mark(element, stack) {
163
+ const records = /* @__PURE__ */ new Map([[this.#record, null]]);
164
+ stack.forEach((hold, index) => {
165
+ const names = stack.slice(0, index).map((under) => under.record);
166
+ const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
167
+ const marker = hold.linked || beneath.length === 0 ? [] : [false];
168
+ records.set(
169
+ hold.record,
170
+ hold.written === hold.original && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([hold.original, hold.written, ...marker, ...beneath])
171
+ );
172
+ });
173
+ for (const [name, recorded] of records) {
174
+ if (element.getAttribute(name) === recorded) continue;
175
+ if (recorded === null) element.removeAttribute(name);
176
+ else element.setAttribute(name, recorded);
40
177
  }
41
178
  }
42
- /** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */
43
- deactivate() {
44
- _BeforeCacheReset.#subscribers.delete(this);
45
- if (_BeforeCacheReset.#subscribers.size > 0) return;
46
- document.removeEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
179
+ #reflect(element, value) {
180
+ if (element.getAttribute(this.#attribute) === value) return;
181
+ if (value === null) element.removeAttribute(this.#attribute);
182
+ else element.setAttribute(this.#attribute, value);
47
183
  }
48
184
  };
49
185
 
50
- // src/utils/intl_format.ts
51
186
  var formatters = /* @__PURE__ */ new WeakMap();
52
187
  function intlFormatter(factory, locale, options, fallbackLocale) {
53
188
  const cache = cacheFor(factory);
@@ -76,7 +211,6 @@ function construct(factory, locale, options, fallbackLocale) {
76
211
  }
77
212
  }
78
213
 
79
- // src/utils/dates.ts
80
214
  function toISODateString(date) {
81
215
  const year = date.getFullYear();
82
216
  const month = String(date.getMonth() + 1).padStart(2, "0");
@@ -114,7 +248,6 @@ function monthLabelFormatter(locale) {
114
248
  return intlFormatter(Intl.DateTimeFormat, locale, MONTH_LABEL_OPTIONS, "en");
115
249
  }
116
250
 
117
- // src/utils/field_mirror.ts
118
251
  function writeField(field, value) {
119
252
  if (field.value === value) return false;
120
253
  field.value = value;
@@ -124,32 +257,37 @@ function commitField(target) {
124
257
  target.dispatchEvent(new Event("change", { bubbles: true }));
125
258
  }
126
259
 
127
- // src/utils/locale.ts
128
260
  function resolveLocale(element, declared = "") {
129
261
  return declared || element.closest("[lang]")?.getAttribute("lang") || void 0;
130
262
  }
131
263
 
132
- // src/utils/microtask_coalescer.ts
264
+ var ListenerSet = class {
265
+ #abort = new AbortController();
266
+ add(target, type, handler, options) {
267
+ target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
268
+ }
269
+ dispose() {
270
+ this.#abort.abort();
271
+ this.#abort = new AbortController();
272
+ }
273
+ };
274
+
133
275
  var MicrotaskCoalescer = class {
134
276
  #run;
135
277
  #queued = false;
136
278
  #active = false;
137
279
  #generation = 0;
138
- /** @param run - the single reconciliation pass, invoked at most once per batch. */
139
280
  constructor(run) {
140
281
  this.#run = run;
141
282
  }
142
- /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
143
283
  activate() {
144
284
  this.#active = true;
145
285
  }
146
- /** Closes the window and drops any pending pass; call from `disconnect()`. */
147
286
  cancel() {
148
287
  this.#active = false;
149
288
  this.#queued = false;
150
289
  this.#generation += 1;
151
290
  }
152
- /** Requests one pass after the batch settles. Idempotent; inert outside the window. */
153
291
  schedule() {
154
292
  if (!this.#active || this.#queued) return;
155
293
  this.#queued = true;
@@ -162,43 +300,49 @@ var MicrotaskCoalescer = class {
162
300
  }
163
301
  };
164
302
 
165
- // src/utils/safe_timeout.ts
303
+ var MorphRenderWatcher = class {
304
+ #listeners = new ListenerSet();
305
+ #pass;
306
+ #element = null;
307
+ #onMorph = () => this.#pass.schedule();
308
+ constructor(run) {
309
+ this.#pass = new MicrotaskCoalescer(run);
310
+ }
311
+ observe(element) {
312
+ if (this.#element === element) return;
313
+ this.disconnect();
314
+ this.#element = element;
315
+ this.#pass.activate();
316
+ this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
317
+ }
318
+ schedule() {
319
+ this.#pass.schedule();
320
+ }
321
+ disconnect() {
322
+ this.#listeners.dispose();
323
+ this.#pass.cancel();
324
+ this.#element = null;
325
+ }
326
+ };
327
+
166
328
  var TimerRegistry = class {
167
- /** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
168
329
  ids = /* @__PURE__ */ new Set();
169
- /**
170
- * Cancels a single tracked timer.
171
- *
172
- * No-ops if the id is unknown (already cleared, fired, or never owned by this
173
- * registry), so callers can clear defensively without guarding.
174
- */
175
330
  clear(id) {
176
331
  if (this.ids.delete(id)) {
177
332
  this.cancel(id);
178
333
  }
179
334
  }
180
- /**
181
- * Cancels every tracked timer. Call this from a controller's `disconnect()`
182
- * to guarantee no timer outlives the element.
183
- */
184
335
  clearAll() {
185
336
  for (const id of this.ids) {
186
337
  this.cancel(id);
187
338
  }
188
339
  this.ids.clear();
189
340
  }
190
- /** Number of timers currently tracked (pending). */
191
341
  get size() {
192
342
  return this.ids.size;
193
343
  }
194
344
  };
195
345
  var SafeTimeout = class extends TimerRegistry {
196
- /**
197
- * Schedules `callback` after `delay` ms and returns the timer id.
198
- *
199
- * The id is removed from the registry automatically when the timeout fires,
200
- * so {@link TimerRegistry.size | size} reflects only still-pending timers.
201
- */
202
346
  set(callback, delay) {
203
347
  const id = this.schedule(() => {
204
348
  this.ids.delete(id);
@@ -215,7 +359,6 @@ var SafeTimeout = class extends TimerRegistry {
215
359
  }
216
360
  };
217
361
 
218
- // src/utils/string_list.ts
219
362
  function parseStringList(raw, fallback = []) {
220
363
  const text = raw.trim();
221
364
  if (text.length === 0) return [...fallback];
@@ -229,67 +372,42 @@ function parseStringList(raw, fallback = []) {
229
372
  return parsed.filter((entry) => typeof entry === "string");
230
373
  }
231
374
 
232
- // src/utils/target_selector.ts
233
375
  function targetSelector(identifier, name) {
234
376
  return `[data-${identifier}-target~="${name}"]`;
235
377
  }
236
378
 
237
- // src/controllers/date_range_picker_controller.ts
238
379
  var GRID_SIZE = 42;
239
380
  var DateRangePickerController = class extends Controller {
381
+ #fieldWrites = /* @__PURE__ */ new WeakMap();
240
382
  static targets = ["grid", "monthLabel", "cell", "status", "startField", "endField"];
241
383
  static values = {
242
384
  min: { type: String, default: "" },
243
385
  max: { type: String, default: "" },
244
- // A JSON list read through `parseStringList` rather than Stimulus's `Array`
245
- // type: that reader throws out of the value observer before any callback
246
- // runs, so one malformed attribute would stop the picker from connecting.
247
386
  disabledDates: { type: String, default: "" },
248
387
  locale: { type: String, default: "" }
249
388
  };
250
389
  static actions = ["applyPreset", "next", "onKeydown", "prev", "previewTo", "selectDate"];
251
390
  static events = ["change", "monthchange", "reconcile"];
252
- /** The month currently rendered, as `YYYY-MM`. */
253
391
  #viewMonth = "";
254
- /** The confirmed range endpoints (ISO), or "" when unset. */
255
392
  #startDate = "";
256
393
  #endDate = "";
257
- /** The first endpoint of an in-progress selection (ISO), or "" when idle. */
258
394
  #pendingStart = "";
259
- /** The hovered/focused date previewed while selecting (ISO), or "". */
260
395
  #previewDate = "";
261
- /** The roving-focus date in the grid (local time). */
262
396
  #focusedDate = /* @__PURE__ */ new Date();
263
- /** Deferred focus after an async month transition (cancelled on teardown). */
264
397
  #focusTimer = new SafeTimeout();
265
- /**
266
- * How many times the confirmed range has moved — a commit or a narrowing — so
267
- * a report still pending for a range a listener has since replaced can tell.
268
- */
269
398
  #rangeMoves = 0;
270
- /** How many month transitions have started, so one a listener starts mid-paint keeps its focus. */
271
399
  #transitions = 0;
272
- /** The declared unavailable dates, indexed for the per-cell paint lookup. */
273
400
  #disabledDates = /* @__PURE__ */ new Set();
274
- /** Rewinds an unfinished selection before Turbo snapshots the page. */
275
- #beforeCache = new BeforeCacheReset(() => this.#rewindForCache());
276
- /** Last painted month, or `null` until the initial paint has settled. */
277
401
  #announcedMonth = null;
278
- /**
279
- * Collapses a morph that swaps render inputs into one repaint, and refuses the
280
- * pass Stimulus delivers before `connect()`.
281
- */
282
- #repaint = new MicrotaskCoalescer(() => {
402
+ #multiselectable = new AttributeLease(
403
+ "aria-multiselectable",
404
+ this.identifier
405
+ );
406
+ #repaint = new MorphRenderWatcher(() => {
283
407
  this.#render();
284
408
  });
285
- /**
286
- * Seeds the range from optional hidden fields — ordered, and narrowed to the
287
- * days that can be chosen — then paints the grid, which writes the range back
288
- * to the fields silently.
289
- */
290
409
  connect() {
291
- this.#repaint.activate();
292
- this.#beforeCache.activate();
410
+ this.#repaint.observe(this.element);
293
411
  const authoredStart = this.hasStartFieldTarget ? normalizeISO(this.startFieldTarget.value) : "";
294
412
  const authoredEnd = this.hasEndFieldTarget ? normalizeISO(this.endFieldTarget.value) : "";
295
413
  [this.#startDate, this.#endDate] = this.#selectableRange(
@@ -301,58 +419,78 @@ var DateRangePickerController = class extends Controller {
301
419
  const anchor = parseISODateString(this.#startDate) ?? this.#clampToBounds(/* @__PURE__ */ new Date()) ?? /* @__PURE__ */ new Date();
302
420
  this.#focusedDate = anchor;
303
421
  this.#viewMonth = toISOMonthString(anchor);
304
- if (this.hasGridTarget) this.gridTarget.setAttribute("aria-multiselectable", "true");
305
422
  this.#render();
306
423
  }
307
- /** Cancels any pending deferred focus so it never fires on a detached element. */
308
424
  disconnect() {
309
- this.#repaint.cancel();
310
- this.#beforeCache.deactivate();
425
+ this.#repaint.disconnect();
311
426
  this.#focusTimer.clearAll();
312
427
  }
313
- /** Repaints the label when application code changes `locale` at runtime. */
314
428
  localeValueChanged() {
315
429
  this.#repaint.schedule();
316
430
  }
317
- /** Repaints when application code (or a Turbo morph) changes `min` at runtime. */
318
431
  minValueChanged() {
319
432
  this.#repaint.schedule();
320
433
  }
321
- /** Repaints when application code (or a Turbo morph) changes `max` at runtime. */
322
434
  maxValueChanged() {
323
435
  this.#repaint.schedule();
324
436
  }
325
- /** Re-indexes the unavailable dates and repaints when the declared set changes. */
326
437
  disabledDatesValueChanged() {
327
438
  this.#disabledDates = new Set(parseStringList(this.disabledDatesValue));
328
439
  this.#repaint.schedule();
329
440
  }
330
- /** Navigates to the previous month. */
441
+ gridTargetConnected() {
442
+ this.#repaint.schedule();
443
+ }
444
+ gridTargetDisconnected(grid) {
445
+ if (!this.gridTargets.includes(grid)) this.#multiselectable.return(grid);
446
+ this.#repaint.schedule();
447
+ }
448
+ monthLabelTargetConnected() {
449
+ this.#repaint.schedule();
450
+ }
451
+ monthLabelTargetDisconnected() {
452
+ this.#repaint.schedule();
453
+ }
454
+ startFieldTargetConnected() {
455
+ this.#repaint.schedule();
456
+ }
457
+ startFieldTargetDisconnected() {
458
+ this.#repaint.schedule();
459
+ }
460
+ endFieldTargetConnected() {
461
+ this.#repaint.schedule();
462
+ }
463
+ endFieldTargetDisconnected() {
464
+ this.#repaint.schedule();
465
+ }
331
466
  prev(event) {
332
467
  event?.preventDefault();
333
468
  this.#shiftMonth(-1);
334
469
  }
335
- /** Navigates to the next month. */
336
470
  next(event) {
337
471
  event?.preventDefault();
338
472
  this.#shiftMonth(1);
339
473
  }
340
- /** Confirms a range endpoint from a clicked cell. */
341
- selectDate(event) {
342
- const cell = this.#cellFrom(event.target);
474
+ selectDate(source) {
475
+ const { origin, reason } = actionSource(source);
476
+ if (origin && origin.closest(`[data-controller~="${this.identifier}"]`) !== this.element)
477
+ return;
478
+ const cell = this.#cellFrom(origin);
343
479
  if (!cell) return;
344
480
  const date = cell.getAttribute("data-date");
345
481
  if (!date || !this.#isSelectable(date)) return;
346
- this.#choose(date);
482
+ this.#choose(date, reason);
347
483
  }
348
- /** Previews the range up to a hovered/focused cell while selecting. */
349
- previewTo(event) {
350
- const cell = this.#cellFrom(event.target);
484
+ previewTo(source) {
485
+ const { event, origin } = actionSource(source);
486
+ if (origin && origin.closest(`[data-controller~="${this.identifier}"]`) !== this.element)
487
+ return;
488
+ const cell = this.#cellFrom(origin);
351
489
  if (!cell) return;
352
490
  const date = cell.getAttribute("data-date");
353
491
  if (!date) return;
354
492
  let shouldRender = false;
355
- if (event.type.startsWith("focus")) {
493
+ if (event?.type.startsWith("focus")) {
356
494
  const parsed = parseISODateString(date);
357
495
  if (parsed) this.#focusedDate = parsed;
358
496
  shouldRender = cell.getAttribute("tabindex") !== "0";
@@ -363,9 +501,11 @@ var DateRangePickerController = class extends Controller {
363
501
  }
364
502
  if (shouldRender) this.#render();
365
503
  }
366
- /** Applies a named preset (`today` / `last7` / `last30` / `thisMonth`). */
367
- applyPreset(event) {
368
- const button = event.target?.closest("[data-range]");
504
+ applyPreset(source) {
505
+ const { event, origin, reason } = actionSource(source);
506
+ const button = origin?.closest("[data-range]");
507
+ if (!button || !this.element.contains(button)) return;
508
+ const focus = event !== null || this.element.contains(document.activeElement);
369
509
  const range = computePreset(button?.getAttribute("data-range") ?? "");
370
510
  if (!range) return;
371
511
  const intersection = this.#intersectRange(range);
@@ -375,10 +515,14 @@ var DateRangePickerController = class extends Controller {
375
515
  const move = this.#setConfirmed(start, end);
376
516
  const endDate = parseISODateString(end);
377
517
  if (endDate) this.#focusedDate = endDate;
378
- this.#transitionTo(toISOMonthString(parseISODateString(end) ?? /* @__PURE__ */ new Date()), end, true);
379
- this.#reportConfirmed(move);
518
+ this.#transitionTo(
519
+ toISOMonthString(parseISODateString(end) ?? /* @__PURE__ */ new Date()),
520
+ end,
521
+ true,
522
+ () => focus && (event !== null || this.element.contains(document.activeElement))
523
+ );
524
+ this.#reportConfirmed(move, reason);
380
525
  }
381
- /** Grid keyboard navigation, selection (Enter/Space), and Escape-to-cancel. */
382
526
  onKeydown(event) {
383
527
  if (event.defaultPrevented) return;
384
528
  if (isReservedArrowChord(event)) return;
@@ -433,8 +577,7 @@ var DateRangePickerController = class extends Controller {
433
577
  event.preventDefault();
434
578
  this.#moveFocusTo(next);
435
579
  }
436
- /** Records a chosen date as either the pending start or the confirmed end. */
437
- #choose(date) {
580
+ #choose(date, reason = "user") {
438
581
  if (!this.#pendingStart || !this.#isSelectable(this.#pendingStart)) {
439
582
  this.#pendingStart = date;
440
583
  this.#previewDate = date;
@@ -446,54 +589,38 @@ var DateRangePickerController = class extends Controller {
446
589
  const [start, end] = date < this.#pendingStart ? [date, this.#pendingStart] : [this.#pendingStart, date];
447
590
  const move = this.#setConfirmed(start, end);
448
591
  this.#render(true);
449
- this.#reportConfirmed(move);
450
- }
451
- /**
452
- * Makes `start`–`end` the confirmed range, ending any selection in progress,
453
- * ahead of the paint that shows it.
454
- *
455
- * @returns The move count the range is now at, which its `change` checks.
456
- */
592
+ this.#reportConfirmed(move, reason);
593
+ }
457
594
  #setConfirmed(start, end) {
595
+ const changed = start !== this.#startDate || end !== this.#endDate;
458
596
  this.#startDate = start;
459
597
  this.#endDate = end;
460
598
  this.#pendingStart = "";
461
599
  this.#previewDate = "";
600
+ if (!changed) return null;
462
601
  this.#rangeMoves += 1;
463
602
  return this.#rangeMoves;
464
603
  }
465
- /**
466
- * Dispatches `change` for the range confirmed at `move`, once its paint has
467
- * reported it through the fields. A listener of those reports that moved the
468
- * range on has had the range it moved to reported instead.
469
- */
470
- #reportConfirmed(move) {
471
- if (move !== this.#rangeMoves) return;
472
- this.dispatch("change", { detail: { start: this.#startDate, end: this.#endDate } });
604
+ #reportConfirmed(move, reason) {
605
+ if (move === null || move !== this.#rangeMoves) return;
606
+ this.dispatch("change", { detail: { start: this.#startDate, end: this.#endDate, reason } });
473
607
  }
474
- /** Moves roving focus to `date`, transitioning the month when needed. */
475
608
  #moveFocusTo(date) {
476
609
  this.#focusedDate = date;
477
610
  const iso = toISODateString(date);
478
611
  if (this.#pendingStart && this.#isSelectable(iso)) this.#previewDate = iso;
479
612
  this.#transitionTo(toISOMonthString(date), iso);
480
613
  }
481
- /**
482
- * Renders `month`, then focuses the cell for `dateStr` (deferred if async).
483
- * A listener of the paint's reports that started another move has placed
484
- * focus itself, so this one leaves it there.
485
- *
486
- * @param confirmed - Whether the paint shows a range the user has just confirmed.
487
- */
488
- #transitionTo(month, dateStr, confirmed = false) {
614
+ #transitionTo(month, dateStr, confirmed = false, canFocus = () => true) {
489
615
  const isTransition = month !== this.#viewMonth;
490
616
  this.#focusTimer.clearAll();
491
617
  this.#viewMonth = month;
492
618
  this.#transitions += 1;
493
619
  const transition = this.#transitions;
494
620
  this.#render(confirmed);
495
- if (transition !== this.#transitions) return;
621
+ if (transition !== this.#transitions || !canFocus()) return;
496
622
  const focusCell = () => {
623
+ if (!canFocus()) return;
497
624
  this.cellTargets.find((c) => c.getAttribute("data-date") === dateStr)?.focus();
498
625
  };
499
626
  if (isTransition) {
@@ -502,7 +629,6 @@ var DateRangePickerController = class extends Controller {
502
629
  focusCell();
503
630
  }
504
631
  }
505
- /** Shifts the displayed month by `delta`, keeping focus within it. */
506
632
  #shiftMonth(delta) {
507
633
  const info = parseISOMonthString(this.#viewMonth);
508
634
  if (!info) return;
@@ -513,17 +639,8 @@ var DateRangePickerController = class extends Controller {
513
639
  this.#focusedDate = target;
514
640
  this.#render();
515
641
  }
516
- /**
517
- * Builds the six-week grid and binds range/roving/disabled state per cell,
518
- * mirrors the confirmed range to the hidden fields, then reports what the
519
- * paint moved.
520
- *
521
- * @param confirmed - Whether the paint shows a range the user has just
522
- * confirmed, which the status then announces and each moved field reports.
523
- *
524
- * @stimeoRenderRoot
525
- */
526
642
  #render(confirmed = false) {
643
+ if (this.hasGridTarget) this.#multiselectable.write(this.gridTarget, "true");
527
644
  const info = parseISOMonthString(this.#viewMonth);
528
645
  if (!info) return;
529
646
  const { year, month } = info;
@@ -576,8 +693,8 @@ var DateRangePickerController = class extends Controller {
576
693
  const moved = this.#mirrorFields();
577
694
  if (confirmed) {
578
695
  this.#announce();
579
- for (const [field, value] of moved) {
580
- if (field.value === value) commitField(field);
696
+ for (const [field, value, write] of moved) {
697
+ if (field.value === value && this.#fieldWrites.get(field) === write) commitField(field);
581
698
  }
582
699
  }
583
700
  const previous = this.#announcedMonth;
@@ -589,12 +706,6 @@ var DateRangePickerController = class extends Controller {
589
706
  this.dispatch("reconcile", { detail: { start: this.#startDate, end: this.#endDate } });
590
707
  }
591
708
  }
592
- /**
593
- * Narrows the confirmed range to days that can still be chosen. The paint
594
- * mirrors it to the fields without reporting a commit.
595
- *
596
- * @returns Whether the range moved.
597
- */
598
709
  #narrowConfirmedRange() {
599
710
  const [start, end] = this.#selectableRange(this.#startDate, this.#endDate);
600
711
  if (start === this.#startDate && end === this.#endDate) return false;
@@ -603,11 +714,6 @@ var DateRangePickerController = class extends Controller {
603
714
  this.#rangeMoves += 1;
604
715
  return true;
605
716
  }
606
- /**
607
- * The range `start`–`end` with each end moved inward to the nearest day that
608
- * can be chosen, or two empty strings when none of its days can be. A lone
609
- * endpoint is the one-day range it names, and stays lone.
610
- */
611
717
  #selectableRange(start, end) {
612
718
  let from = parseISODateString(start || end);
613
719
  let to = parseISODateString(end || start);
@@ -621,7 +727,6 @@ var DateRangePickerController = class extends Controller {
621
727
  if (from.getTime() > to.getTime()) return ["", ""];
622
728
  return [start ? toISODateString(from) : "", end ? toISODateString(to) : ""];
623
729
  }
624
- /** The ordered [start, end] pair to paint: the preview while selecting, else confirmed. */
625
730
  #visualRange() {
626
731
  if (this.#pendingStart) {
627
732
  const other = this.#previewDate || this.#pendingStart;
@@ -629,81 +734,59 @@ var DateRangePickerController = class extends Controller {
629
734
  }
630
735
  return [this.#startDate, this.#endDate];
631
736
  }
632
- /**
633
- * Writes the confirmed range to the hidden fields.
634
- *
635
- * @returns Each field whose value moved, with the value written to it.
636
- */
737
+ #writeField(field, value) {
738
+ if (!writeField(field, value)) return false;
739
+ this.#fieldWrites.set(field, (this.#fieldWrites.get(field) ?? 0) + 1);
740
+ return true;
741
+ }
637
742
  #mirrorFields() {
638
743
  const moved = [];
639
- if (this.hasStartFieldTarget && writeField(this.startFieldTarget, this.#startDate)) {
640
- moved.push([this.startFieldTarget, this.#startDate]);
744
+ if (this.hasStartFieldTarget && this.#writeField(this.startFieldTarget, this.#startDate)) {
745
+ moved.push([
746
+ this.startFieldTarget,
747
+ this.#startDate,
748
+ this.#fieldWrites.get(this.startFieldTarget) ?? 0
749
+ ]);
641
750
  }
642
- if (this.hasEndFieldTarget && writeField(this.endFieldTarget, this.#endDate)) {
643
- moved.push([this.endFieldTarget, this.#endDate]);
751
+ if (this.hasEndFieldTarget && this.#writeField(this.endFieldTarget, this.#endDate)) {
752
+ moved.push([
753
+ this.endFieldTarget,
754
+ this.#endDate,
755
+ this.#fieldWrites.get(this.endFieldTarget) ?? 0
756
+ ]);
644
757
  }
645
758
  return moved;
646
759
  }
647
- /** Announces the confirmed range in the live status region. */
648
760
  #announce() {
649
761
  if (this.hasStatusTarget && this.#startDate && this.#endDate) {
650
762
  this.statusTarget.textContent = `${this.#startDate} \u2013 ${this.#endDate}`;
651
763
  }
652
764
  }
653
- /**
654
- * True when `iso` may be chosen as a range endpoint.
655
- *
656
- * The single availability question in the controller: the grid paint, the
657
- * preview, and both commit paths ask it, so a cell's `aria-disabled` and what
658
- * a click on that cell does are the same decision rather than two that have to
659
- * be kept in step.
660
- */
661
765
  #isSelectable(iso) {
662
766
  return !this.#outOfBounds(iso) && !this.#disabledDates.has(iso);
663
767
  }
664
- /** True when `iso` falls outside the `[min, max]` bounds. */
665
768
  #outOfBounds(iso) {
666
769
  if (this.minValue && iso < this.minValue) return true;
667
770
  if (this.maxValue && iso > this.maxValue) return true;
668
771
  return false;
669
772
  }
670
- /** Clamps a generated ISO date string into `[min, max]`. */
671
773
  #clampISO(iso) {
672
774
  if (this.minValue && iso < this.minValue) return this.minValue;
673
775
  if (this.maxValue && iso > this.maxValue) return this.maxValue;
674
776
  return iso;
675
777
  }
676
- /** Clamps a Date into `[min, max]`, returning null only when unparseable. */
677
778
  #clampToBounds(date) {
678
779
  const clamped = this.#clampISO(toISODateString(date));
679
780
  return parseISODateString(clamped);
680
781
  }
681
- /**
682
- * Intersects a preset with `[min, max]`, rejecting a disjoint interval.
683
- *
684
- * Only the bounds narrow a preset here: `disabledDates` excludes single days,
685
- * not sub-intervals, so it cannot shrink one to a still-contiguous range. A
686
- * day it excludes is still refused as an endpoint — the caller checks that —
687
- * but a preset that merely spans one keeps its span.
688
- */
689
782
  #intersectRange(range) {
690
783
  const start = this.minValue && range.start < this.minValue ? this.minValue : range.start;
691
784
  const end = this.maxValue && range.end > this.maxValue ? this.maxValue : range.end;
692
785
  return start <= end ? { start, end } : null;
693
786
  }
694
- /** Removes provisional range state before Turbo freezes a cached snapshot. */
695
- #rewindForCache() {
696
- this.#focusTimer.clearAll();
697
- if (!this.#pendingStart && !this.#previewDate) return;
698
- this.#pendingStart = "";
699
- this.#previewDate = "";
700
- this.#render();
701
- }
702
- /** Resolves the cell element from an event target, or null. */
703
787
  #cellFrom(target) {
704
- return target?.closest(
705
- targetSelector(this.identifier, "cell")
706
- ) ?? null;
788
+ const cell = target instanceof Element ? target.closest(targetSelector(this.identifier, "cell")) : null;
789
+ return cell && this.cellTargets.includes(cell) ? cell : null;
707
790
  }
708
791
  };
709
792
  function addDays(date, n) {
@@ -763,5 +846,4 @@ function computePreset(name) {
763
846
  }
764
847
 
765
848
  export { DateRangePickerController };
766
- //# sourceMappingURL=date_range_picker_controller.js.map
767
849
  //# sourceMappingURL=date_range_picker_controller.js.map