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,31 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/toggle_group_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 logicalArrowStep(key, element) {
12
30
  if (key === "ArrowDown") return 1;
13
31
  if (key === "ArrowUp") return -1;
@@ -19,8 +37,108 @@ function isReservedArrowChord(event, allow = []) {
19
37
  if (!event.key.startsWith("Arrow")) return false;
20
38
  return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
21
39
  }
40
+ function hasModifierChord(event) {
41
+ return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
42
+ }
43
+
44
+ function setAttributeIfChanged(element, name, value, beforeWrite) {
45
+ if (element.getAttribute(name) === value) return false;
46
+ beforeWrite?.();
47
+ if (value === null) element.removeAttribute(name);
48
+ else element.setAttribute(name, value);
49
+ return true;
50
+ }
51
+
52
+ var AuthoredMutationWatcher = class {
53
+ #onAuthored;
54
+ #claims = null;
55
+ #observer = null;
56
+ constructor(onAuthored) {
57
+ this.#onAuthored = onAuthored;
58
+ }
59
+ observe(root, options) {
60
+ this.disconnect();
61
+ const observer = new MutationObserver((records) => {
62
+ if (this.#observer !== observer) return;
63
+ const authored = this.#filter(records);
64
+ if (authored.length > 0) this.#onAuthored(authored);
65
+ });
66
+ this.#observer = observer;
67
+ this.#claims = { attributes: /* @__PURE__ */ new Map(), children: /* @__PURE__ */ new Map() };
68
+ observer.observe(root, {
69
+ attributes: true,
70
+ attributeFilter: [...options.attributes],
71
+ subtree: options.subtree ?? false,
72
+ childList: options.childList ?? false
73
+ });
74
+ if (options.ancestorAttributes) {
75
+ let ancestor = root.parentElement;
76
+ while (ancestor) {
77
+ observer.observe(ancestor, {
78
+ attributes: true,
79
+ attributeFilter: [...options.ancestorAttributes]
80
+ });
81
+ ancestor = ancestor.parentElement;
82
+ }
83
+ }
84
+ }
85
+ claim(target, name, value) {
86
+ const claims = this.#claims?.attributes;
87
+ let attributes = claims?.get(target);
88
+ if (!attributes) {
89
+ attributes = /* @__PURE__ */ new Map();
90
+ claims?.set(target, attributes);
91
+ }
92
+ const pending = attributes.get(name);
93
+ attributes.set(name, { value, count: (pending?.count ?? 0) + 1 });
94
+ }
95
+ claimCurrent(target, name) {
96
+ this.claim(target, name, target.getAttribute(name));
97
+ }
98
+ claimChildList(target, added, removed) {
99
+ const claims = this.#claims?.children;
100
+ const pending = claims?.get(target) ?? { added: /* @__PURE__ */ new Map(), removed: /* @__PURE__ */ new Map() };
101
+ for (const node of added) pending.added.set(node, (pending.added.get(node) ?? 0) + 1);
102
+ for (const node of removed) pending.removed.set(node, (pending.removed.get(node) ?? 0) + 1);
103
+ claims?.set(target, pending);
104
+ }
105
+ take() {
106
+ return this.#filter(this.#observer?.takeRecords() ?? []);
107
+ }
108
+ disconnect() {
109
+ this.#observer?.disconnect();
110
+ this.#observer = null;
111
+ this.#claims = null;
112
+ }
113
+ #filter(records) {
114
+ const authored = records.filter((record) => !this.#consume(record));
115
+ this.#claims?.attributes.clear();
116
+ this.#claims?.children.clear();
117
+ return authored;
118
+ }
119
+ #consume(record) {
120
+ if (record.type === "attributes") {
121
+ const target = record.target;
122
+ const pending2 = this.#claims?.attributes.get(target)?.get(record.attributeName);
123
+ if (!pending2 || pending2.count === 0 || target.getAttribute(record.attributeName) !== pending2.value) {
124
+ return false;
125
+ }
126
+ pending2.count -= 1;
127
+ return true;
128
+ }
129
+ const pending = this.#claims?.children.get(record.target);
130
+ if (!pending) return false;
131
+ const added = [...record.addedNodes];
132
+ const removed = [...record.removedNodes];
133
+ if (added.some((node) => !pending.added.get(node)) || removed.some((node) => !pending.removed.get(node))) {
134
+ return false;
135
+ }
136
+ for (const node of added) pending.added.set(node, (pending.added.get(node) ?? 0) - 1);
137
+ for (const node of removed) pending.removed.set(node, (pending.removed.get(node) ?? 0) - 1);
138
+ return true;
139
+ }
140
+ };
22
141
 
23
- // src/utils/event_owner.ts
24
142
  function ownerIndex(candidates, node) {
25
143
  if (!(node instanceof Node)) return -1;
26
144
  return candidates.findIndex((candidate) => candidate.contains(node));
@@ -29,7 +147,6 @@ function ownerOf(candidates, node) {
29
147
  return candidates[ownerIndex(candidates, node)] ?? null;
30
148
  }
31
149
 
32
- // src/utils/field_mirror.ts
33
150
  function writeFields(container, values, { name, form = "" }) {
34
151
  const current = [...container.children];
35
152
  const submits = current.length === values.length && current.every(
@@ -52,7 +169,6 @@ function commitField(target) {
52
169
  target.dispatchEvent(new Event("change", { bubbles: true }));
53
170
  }
54
171
 
55
- // src/utils/focus_candidate.ts
56
172
  function inheritsFieldsetDisabled(control) {
57
173
  let fieldset = control.closest("fieldset[disabled]");
58
174
  while (fieldset) {
@@ -63,7 +179,6 @@ function inheritsFieldsetDisabled(control) {
63
179
  return false;
64
180
  }
65
181
 
66
- // src/utils/interactive_host.ts
67
182
  var INTERACTIVE_HOST_SELECTOR = "button, input, select, textarea, label, a[href], area[href], summary, details, audio[controls], video[controls], iframe, object, embed";
68
183
  function isInteractiveHost(element) {
69
184
  if (element.matches(INTERACTIVE_HOST_SELECTOR)) return true;
@@ -80,27 +195,36 @@ function isInteractiveHost(element) {
80
195
  return false;
81
196
  }
82
197
 
83
- // src/utils/microtask_coalescer.ts
198
+ var ListenerSet = class {
199
+ #abort = new AbortController();
200
+ add(target, type, handler, options) {
201
+ target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
202
+ }
203
+ dispose() {
204
+ this.#abort.abort();
205
+ this.#abort = new AbortController();
206
+ }
207
+ };
208
+
84
209
  var MicrotaskCoalescer = class {
85
210
  #run;
86
211
  #queued = false;
87
212
  #active = false;
88
213
  #generation = 0;
89
- /** @param run - the single reconciliation pass, invoked at most once per batch. */
90
214
  constructor(run) {
91
215
  this.#run = run;
92
216
  }
93
- /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
94
217
  activate() {
95
218
  this.#active = true;
96
219
  }
97
- /** Closes the window and drops any pending pass; call from `disconnect()`. */
98
220
  cancel() {
99
221
  this.#active = false;
100
222
  this.#queued = false;
101
223
  this.#generation += 1;
102
224
  }
103
- /** Requests one pass after the batch settles. Idempotent; inert outside the window. */
225
+ get pending() {
226
+ return this.#queued;
227
+ }
104
228
  schedule() {
105
229
  if (!this.#active || this.#queued) return;
106
230
  this.#queued = true;
@@ -113,31 +237,53 @@ var MicrotaskCoalescer = class {
113
237
  }
114
238
  };
115
239
 
116
- // src/utils/roving_tabindex.ts
240
+ var MorphRenderWatcher = class {
241
+ #listeners = new ListenerSet();
242
+ #pass;
243
+ #element = null;
244
+ #onMorph = () => this.#pass.schedule();
245
+ constructor(run) {
246
+ this.#pass = new MicrotaskCoalescer(run);
247
+ }
248
+ observe(element) {
249
+ if (this.#element === element) return;
250
+ this.disconnect();
251
+ this.#element = element;
252
+ this.#pass.activate();
253
+ this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
254
+ }
255
+ schedule() {
256
+ this.#pass.schedule();
257
+ }
258
+ get pending() {
259
+ return this.#pass.pending;
260
+ }
261
+ disconnect() {
262
+ this.#listeners.dispose();
263
+ this.#pass.cancel();
264
+ this.#element = null;
265
+ }
266
+ };
267
+
268
+ var MoveCounter = class {
269
+ #sequence = 0;
270
+ record() {
271
+ this.#sequence += 1;
272
+ return this.#sequence;
273
+ }
274
+ isLatest(token) {
275
+ return token === this.#sequence;
276
+ }
277
+ };
278
+
117
279
  var RovingTabindex = class {
118
- /** Returns the current ordered item elements; called on every operation. */
119
280
  #getItems;
120
- /**
121
- * @param getItems - Returns the current ordered item elements. Called on every
122
- * operation so the live target list is always used.
123
- */
124
281
  constructor(getItems) {
125
282
  this.#getItems = getItems;
126
283
  }
127
- /** Index of the currently tabbable item (`tabindex="0"`), or `-1` if none. */
128
284
  get activeIndex() {
129
285
  return this.#getItems().findIndex((item) => item.tabIndex === 0);
130
286
  }
131
- /**
132
- * Makes exactly the item at `index` tabbable (`tabindex="0"`) and removes every
133
- * other item from the Tab sequence (`tabindex="-1"`). An out-of-range `index`
134
- * (e.g. `-1`) leaves all items at `-1`, which a controller can use to express
135
- * "nothing is currently tabbable".
136
- *
137
- * @param index - Position of the item to make tabbable.
138
- * @param options - Pass `{ focus: true }` to also move DOM focus to that item,
139
- * and `items` to reuse an event-scoped collection snapshot.
140
- */
141
287
  setActive(index, options = {}) {
142
288
  const { focus = false } = options;
143
289
  const items = options.items ?? this.#getItems();
@@ -153,7 +299,10 @@ function rovingMove(current, length, delta, wrap) {
153
299
  return (next + length) % length;
154
300
  }
155
301
 
156
- // src/controllers/toggle_group_controller.ts
302
+ function targetSelector(identifier, name) {
303
+ return `[data-${identifier}-target~="${name}"]`;
304
+ }
305
+
157
306
  var ITEM_ATTRIBUTES = [
158
307
  "aria-pressed",
159
308
  "data-value",
@@ -164,8 +313,9 @@ var ITEM_ATTRIBUTES = [
164
313
  "contenteditable",
165
314
  "controls"
166
315
  ];
167
- var hasModifier = (event) => event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
168
316
  var ToggleGroupController = class extends Controller {
317
+ #moves = new MoveCounter();
318
+ #connectionGeneration = 0;
169
319
  static targets = ["item", "fields"];
170
320
  static values = {
171
321
  mode: { type: String, default: "multiple" },
@@ -177,28 +327,18 @@ var ToggleGroupController = class extends Controller {
177
327
  #roving = new RovingTabindex(() => this.#managedTargets);
178
328
  #handledEvents = /* @__PURE__ */ new WeakSet();
179
329
  #managedItems = /* @__PURE__ */ new Set();
180
- #originalTabindex = /* @__PURE__ */ new Map();
181
- #ownedPressed = /* @__PURE__ */ new Set();
182
- #internalPressedValues = /* @__PURE__ */ new Map();
183
- /** One pass per batch of item, Value, and retained-element changes. */
184
- #pass = new MicrotaskCoalescer(() => this.#reconcileDom());
185
- #observer = null;
330
+ #originalTabindex = /* @__PURE__ */ new WeakMap();
331
+ #ownedPressed = /* @__PURE__ */ new Map();
332
+ #pass = new MorphRenderWatcher(() => this.#reconcileDom());
333
+ #observer = new AuthoredMutationWatcher((records) => {
334
+ this.#releaseAuthoredPressed(records);
335
+ this.#pass.schedule();
336
+ });
186
337
  #connected = false;
187
- /** The pressed set last published: read on connect, then committed or reported. */
188
338
  #committedValues = [];
189
- /**
190
- * How many presses the user has committed, so a press whose reports are still
191
- * going out can tell that a listener has committed a newer one meanwhile.
192
- */
193
- #presses = 0;
194
- /**
195
- * Normalizes state and establishes one roving entry point. A single authored
196
- * `tabindex="0"` survives reconnect; otherwise the first pressed, navigable
197
- * item wins, falling back to the first navigable item. The pressed set it
198
- * settles on is the one a later move is measured from; connecting reports
199
- * nothing.
200
- */
339
+ #listeners = new ListenerSet();
201
340
  connect() {
341
+ this.#releaseDefaultsRewrittenWhileAway();
202
342
  const currentItems = new Set(this.itemTargets);
203
343
  for (const item of this.#managedItems) {
204
344
  if (!currentItems.has(item)) this.#releaseItem(item);
@@ -212,84 +352,62 @@ var ToggleGroupController = class extends Controller {
212
352
  this.#ensureTabStop(preferred);
213
353
  this.#mirrorFields(false);
214
354
  this.#committedValues = this.#pressedValues();
215
- this.element.addEventListener("click", this.#onClickCapture, true);
216
- this.element.addEventListener("keydown", this.#onKeydownCapture, true);
217
- this.element.addEventListener("click", this.#onClick);
218
- this.element.addEventListener("keydown", this.#onKeydown);
219
- this.element.addEventListener("focusin", this.#onFocusin);
355
+ this.#listeners.add(this.element, "click", this.#onClickCapture, { capture: true });
356
+ this.#listeners.add(this.element, "keydown", this.#onKeydownCapture, { capture: true });
357
+ this.#listeners.add(this.element, "click", this.#onClick);
358
+ this.#listeners.add(this.element, "keydown", this.#onKeydown);
359
+ this.#listeners.add(this.element, "focusin", this.#onFocusin);
220
360
  this.#connected = true;
221
- this.#internalPressedValues.clear();
222
- this.#pass.activate();
361
+ this.#pass.observe(this.element);
223
362
  this.#observeMutations();
224
363
  }
225
- /**
226
- * Releases every listener, the observer, and a pass still queued, while
227
- * retaining DOM state for Turbo cache/reconnect.
228
- */
229
364
  disconnect() {
365
+ this.#connectionGeneration += 1;
230
366
  this.#connected = false;
231
- this.#pass.cancel();
232
- this.element.removeEventListener("click", this.#onClickCapture, true);
233
- this.element.removeEventListener("keydown", this.#onKeydownCapture, true);
234
- this.element.removeEventListener("click", this.#onClick);
235
- this.element.removeEventListener("keydown", this.#onKeydown);
236
- this.element.removeEventListener("focusin", this.#onFocusin);
237
- this.#observer?.disconnect();
238
- this.#observer = null;
239
- this.#internalPressedValues.clear();
367
+ this.#pass.disconnect();
368
+ this.#listeners.dispose();
369
+ this.#observer.disconnect();
240
370
  }
241
- /** Drops a newly connected item from the Tab sequence before the batch is reconciled. */
242
371
  itemTargetConnected(item) {
243
372
  if (!this.#connected) return;
244
373
  this.#reconcileHost(item, true);
245
374
  this.#pass.schedule();
246
375
  }
247
- /** Restores attributes owned only while an element is an item, then reconciles the batch. */
248
376
  itemTargetDisconnected(item) {
249
377
  if (!this.#connected) return;
250
378
  this.#releaseItem(item);
251
379
  this.#pass.schedule();
252
380
  }
253
- /** Reconciles the single-selection invariant when the Stimulus Value changes. */
254
381
  modeValueChanged() {
255
382
  this.#pass.schedule();
256
383
  }
257
- /** Rebuilds the submitted fields when the public name changes at runtime. */
258
384
  nameValueChanged() {
259
385
  this.#pass.schedule();
260
386
  }
261
- /** Repoints the submitted fields when the owning form changes at runtime. */
262
387
  formValueChanged() {
263
388
  this.#pass.schedule();
264
389
  }
265
- /**
266
- * Toggles the action's item. Per-item action wiring is optional because click
267
- * is also delegated from the group.
268
- */
269
- toggle(event) {
270
- if (event.defaultPrevented) return;
271
- const item = event.currentTarget;
390
+ toggle(source) {
391
+ const { event, host, origin, reason } = actionSource(source);
392
+ const item = host?.closest(targetSelector(this.identifier, "item"));
272
393
  if (!item || !this.itemTargets.includes(item)) return;
273
- this.#handledEvents.add(event);
274
- this.#toggleItem(item);
394
+ if (origin && origin.closest(`[data-controller~="${this.identifier}"]`) !== this.element)
395
+ return;
396
+ if (event?.defaultPrevented) return;
397
+ if (event) this.#handledEvents.add(event);
398
+ this.#toggleItem(item, reason);
275
399
  }
276
- /**
277
- * Moves focus or activates the action's item. Per-item action wiring is
278
- * optional because keydown is also delegated from the group.
279
- */
280
400
  onKeydown(event) {
281
401
  const item = event.currentTarget;
282
402
  if (!item || !this.itemTargets.includes(item)) return;
283
403
  this.#handleKeydown(event, item);
284
404
  }
285
- /** Blocks disabled activation before per-item or consumer event handlers run. */
286
405
  #onClickCapture = (event) => {
287
406
  const item = this.#itemForEventTarget(event.target);
288
407
  if (!item || !this.#isSupportedHost(item) || !this.#isActivationDisabled(item)) return;
289
408
  event.preventDefault();
290
409
  event.stopImmediatePropagation();
291
410
  };
292
- /** Blocks disabled keyboard activation while leaving navigation keys available. */
293
411
  #onKeydownCapture = (event) => {
294
412
  if (event.key !== " " && event.key !== "Enter") return;
295
413
  const item = this.#itemForEventTarget(event.target);
@@ -297,29 +415,25 @@ var ToggleGroupController = class extends Controller {
297
415
  event.preventDefault();
298
416
  event.stopImmediatePropagation();
299
417
  };
300
- /** Delegated click path for static and runtime-added items without actions. */
301
418
  #onClick = (event) => {
302
419
  if (this.#handledEvents.delete(event) || event.defaultPrevented) return;
303
420
  const item = this.#itemForEventTarget(event.target);
304
421
  if (item) this.#toggleItem(item);
305
422
  };
306
- /** Delegated keydown path for static and runtime-added items without actions. */
307
423
  #onKeydown = (event) => {
308
424
  const item = this.#itemForEventTarget(event.target);
309
425
  if (item) this.#handleKeydown(event, item);
310
426
  };
311
- /** Keeps programmatic and pointer focus as the group's next Tab entry point. */
312
427
  #onFocusin = (event) => {
313
428
  const item = this.#itemForEventTarget(event.target);
314
429
  if (!item || !this.#isNavigable(item)) return;
315
430
  this.#setActive(item);
316
431
  };
317
- /** Applies the APG navigation and activation key map to one supported item. */
318
432
  #handleKeydown(event, item) {
319
433
  if (event.defaultPrevented || !this.#isSupportedHost(item)) return;
320
434
  if (event.isComposing) return;
321
435
  if (isReservedArrowChord(event)) return;
322
- if ((event.key === "Home" || event.key === "End") && hasModifier(event)) return;
436
+ if ((event.key === "Home" || event.key === "End") && hasModifierChord(event)) return;
323
437
  if (!this.#managedItems.has(item)) this.#reconcileHost(item, true);
324
438
  this.#ensureTabStop();
325
439
  const items = this.#managedTargets;
@@ -353,19 +467,9 @@ var ToggleGroupController = class extends Controller {
353
467
  event.preventDefault();
354
468
  if (destination) this.#setActive(destination, true);
355
469
  }
356
- /**
357
- * Applies one user toggle and dispatches the documented change detail. The set
358
- * it leaves is taken as published before either report goes out, so a
359
- * listener that presses again or writes `aria-pressed` is measured from it. A
360
- * listener of the native `change` that presses again has had that newer press
361
- * reported, so this press's `change` would describe a set that is gone and is
362
- * not dispatched.
363
- *
364
- * @stimeoRuntimeOnly `mode` is the rule this one press follows; the lasting single-press
365
- * normalisation is a render root of its own.
366
- */
367
- #toggleItem(item) {
470
+ #toggleItem(item, reason = "user") {
368
471
  if (!this.#isSupportedHost(item) || this.#isActivationDisabled(item)) return;
472
+ const generation = this.#connectionGeneration;
369
473
  if (!this.#managedItems.has(item)) this.#reconcileHost(item, true);
370
474
  const willPress = !this.#isPressed(item);
371
475
  if (this.modeValue === "single") {
@@ -376,49 +480,40 @@ var ToggleGroupController = class extends Controller {
376
480
  }
377
481
  this.#setActive(item);
378
482
  const values = this.#pressedValues();
483
+ const previous = this.#committedValues;
484
+ const changed = values.length !== previous.length || values.some((value, index) => value !== previous[index]);
379
485
  this.#committedValues = values;
380
- this.#presses += 1;
381
- const press = this.#presses;
486
+ if (!changed) {
487
+ this.#mirrorFields(false);
488
+ return;
489
+ }
490
+ const token = this.#moves.record();
382
491
  this.#mirrorFields(true);
383
- if (press !== this.#presses) return;
492
+ if (generation !== this.#connectionGeneration || !this.#moves.isLatest(token)) return;
384
493
  this.dispatch("change", {
385
- detail: { value: this.#itemValue(item), pressed: willPress, values: [...values] }
494
+ detail: { value: this.#itemValue(item), pressed: willPress, values: [...values], reason }
386
495
  });
387
496
  }
388
- /**
389
- * Mirrors the pressed values into the optional fields container.
390
- *
391
- * @stimeoRenderRoot
392
- */
393
497
  #mirrorFields(notify) {
394
498
  if (!this.hasFieldsTarget) return;
395
499
  const options = { name: this.nameValue, form: this.formValue };
396
- if (writeFields(this.fieldsTarget, this.#pressedValues(), options) && notify) {
397
- commitField(this.fieldsTarget);
398
- }
500
+ const removed = [...this.fieldsTarget.childNodes];
501
+ const changed = writeFields(this.fieldsTarget, this.#pressedValues(), options);
502
+ if (changed)
503
+ this.#observer.claimChildList(this.fieldsTarget, [...this.fieldsTarget.childNodes], removed);
504
+ if (changed && notify) commitField(this.fieldsTarget);
399
505
  }
400
- /**
401
- * Reconciles supported hosts, pressed state, the roving invariant, and the
402
- * fields after the page changed the group, then reports a pressed set that
403
- * moved. Records still queued are read first, so an author's write is not lost
404
- * when observation is suspended for this pass's own writes; observation resumes
405
- * before the report, so an edit a listener makes is seen by the next pass.
406
- */
407
506
  #reconcileDom() {
408
- const observer = this.#observer;
409
- if (observer) {
410
- this.#releaseAuthoredPressed(observer.takeRecords());
411
- observer.disconnect();
412
- }
507
+ this.#releaseAuthoredPressed(this.#observer.take());
413
508
  for (const item of this.itemTargets) this.#reconcileHost(item, true);
414
509
  this.#normalizeSelection();
415
510
  this.#ensureTabStop();
416
511
  this.#mirrorFields(false);
417
- this.#internalPressedValues.clear();
418
- if (observer) this.#observeWith(observer);
512
+ const authored = this.#observer.take();
513
+ this.#releaseAuthoredPressed(authored);
514
+ if (authored.length > 0) this.#pass.schedule();
419
515
  this.#reportMove();
420
516
  }
421
- /** Reports a pressed set that moved since the one this group last published. */
422
517
  #reportMove() {
423
518
  const values = this.#pressedValues();
424
519
  const previous = this.#committedValues;
@@ -428,7 +523,6 @@ var ToggleGroupController = class extends Controller {
428
523
  this.#committedValues = values;
429
524
  this.dispatch("reconcile", { detail: { values: [...values] } });
430
525
  }
431
- /** Begins or ends ownership according to the item's current host semantics. */
432
526
  #reconcileHost(item, dropFromTabSequence) {
433
527
  if (!this.#isSupportedHost(item)) {
434
528
  this.#releaseItem(item);
@@ -441,34 +535,23 @@ var ToggleGroupController = class extends Controller {
441
535
  }
442
536
  this.#normalizePressed(item);
443
537
  }
444
- /** Restores only defaults owned because an element belonged to this group. */
445
538
  #releaseItem(item) {
446
539
  if (!this.#managedItems.delete(item)) return;
447
540
  const original = this.#originalTabindex.get(item);
448
541
  if (original === null) item.removeAttribute("tabindex");
449
542
  else if (original !== void 0) item.setAttribute("tabindex", original);
450
- this.#originalTabindex.delete(item);
451
- if (this.#ownedPressed.delete(item)) item.removeAttribute("aria-pressed");
452
- this.#internalPressedValues.delete(item);
543
+ if (this.#ownedPressed.delete(item)) this.#writePressed(item, null);
453
544
  }
454
- /** Supplies a missing pressed state and normalizes invalid ARIA tokens. */
455
545
  #normalizePressed(item) {
456
546
  const value = item.getAttribute("aria-pressed");
457
547
  if (value === null) {
458
- this.#ownedPressed.add(item);
459
- this.#internalPressedValues.set(item, "false");
460
- item.setAttribute("aria-pressed", "false");
548
+ this.#ownedPressed.set(item, "false");
549
+ this.#writePressed(item, "false");
461
550
  } else if (value !== "true" && value !== "false") {
462
- item.setAttribute("aria-pressed", "false");
551
+ this.#writePressed(item, "false");
463
552
  }
464
553
  }
465
- /**
466
- * Makes the first DOM-ordered pressed item the sole pressed item in single mode.
467
- *
468
- * @stimeoRenderRoot
469
- */
470
554
  #normalizeSelection() {
471
- for (const item of this.#managedTargets) this.#normalizePressed(item);
472
555
  if (this.modeValue !== "single") return;
473
556
  let found = false;
474
557
  for (const item of this.#managedTargets) {
@@ -477,7 +560,6 @@ var ToggleGroupController = class extends Controller {
477
560
  else this.#setPressed(item, false);
478
561
  }
479
562
  }
480
- /** Keeps one navigable Tab stop, preferring current DOM state after initial connect. */
481
563
  #ensureTabStop(initialPreference) {
482
564
  const navigable = this.#navigableItems;
483
565
  let active;
@@ -493,7 +575,6 @@ var ToggleGroupController = class extends Controller {
493
575
  active ??= navigable[0];
494
576
  this.#setActive(active ?? null);
495
577
  }
496
- /** Moves through the full item order until a navigable destination is found. */
497
578
  #nextNavigable(fromIndex, delta) {
498
579
  const items = this.#managedTargets;
499
580
  let index = fromIndex;
@@ -504,31 +585,25 @@ var ToggleGroupController = class extends Controller {
504
585
  }
505
586
  return void 0;
506
587
  }
507
- /** Assigns the single roving Tab stop and optionally moves DOM focus. */
508
588
  #setActive(item, focus = false) {
509
589
  this.#roving.setActive(this.#managedTargets.indexOf(item), { focus });
510
590
  }
511
- /** Finds this group's item containing an event target, excluding nested groups. */
512
591
  #itemForEventTarget(target) {
513
592
  if (!this.#ownsEventTarget(target)) return null;
514
593
  return ownerOf(this.itemTargets, target);
515
594
  }
516
- /** Whether the closest Toggle Group scope around a target is this instance. */
517
595
  #ownsEventTarget(target) {
518
596
  return target instanceof Element && target.closest(`[data-controller~="${this.identifier}"]`) === this.element;
519
597
  }
520
- /** Hosts whose activation model can be owned without conflicting native behavior. */
521
598
  #isSupportedHost(item) {
522
599
  if (item instanceof HTMLButtonElement) return item.type === "button";
523
600
  return !isInteractiveHost(item);
524
601
  }
525
- /** Items eligible for roving focus (ARIA-disabled deliberately remains eligible). */
526
602
  #isNavigable(item) {
527
603
  if (!this.#isSupportedHost(item) || this.#isHidden(item)) return false;
528
604
  if (!(item instanceof HTMLButtonElement)) return true;
529
605
  return !item.disabled && !inheritsFieldsetDisabled(item);
530
606
  }
531
- /** Whether hidden applies on the path from an item up to the group root. */
532
607
  #isHidden(item) {
533
608
  let current = item;
534
609
  while (current && current !== this.element) {
@@ -537,7 +612,6 @@ var ToggleGroupController = class extends Controller {
537
612
  }
538
613
  return false;
539
614
  }
540
- /** Whether ARIA, visibility, or native HTML semantics suppress activation. */
541
615
  #isActivationDisabled(item) {
542
616
  if (!this.#isNavigable(item)) return true;
543
617
  let current = item;
@@ -547,72 +621,59 @@ var ToggleGroupController = class extends Controller {
547
621
  }
548
622
  return false;
549
623
  }
550
- /** Releases default ownership when a Turbo morph authors `aria-pressed`. */
551
624
  #releaseAuthoredPressed(records) {
552
625
  for (const record of records) {
553
626
  if (record.attributeName !== "aria-pressed") continue;
554
627
  const item = record.target;
555
628
  const value = item.getAttribute("aria-pressed");
556
- if (value !== null && this.#internalPressedValues.get(item) !== value) {
629
+ if (value !== null) {
557
630
  this.#ownedPressed.delete(item);
558
631
  }
559
632
  }
560
- this.#internalPressedValues.clear();
561
633
  }
562
- /** Watches target membership, retained item hosts/state, and inherited host/fieldset state. */
563
634
  #observeMutations() {
564
- const observer = new MutationObserver((records) => {
565
- this.#releaseAuthoredPressed(records);
566
- this.#pass.schedule();
567
- });
568
- this.#observer = observer;
569
- this.#observeWith(observer);
570
- }
571
- /** Registers every root and ancestor observation on one observer instance. */
572
- #observeWith(observer) {
573
- observer.observe(this.element, {
635
+ this.#observer.observe(this.element, {
574
636
  subtree: true,
575
637
  childList: true,
576
- attributes: true,
577
- attributeFilter: ITEM_ATTRIBUTES
638
+ attributes: ITEM_ATTRIBUTES,
639
+ ancestorAttributes: ["contenteditable", "disabled"]
578
640
  });
579
- let ancestor = this.element.parentElement;
580
- while (ancestor) {
581
- observer.observe(ancestor, {
582
- attributes: true,
583
- attributeFilter: ["contenteditable", "disabled"]
584
- });
585
- ancestor = ancestor.parentElement;
641
+ }
642
+ #releaseDefaultsRewrittenWhileAway() {
643
+ for (const [item, written] of this.#ownedPressed) {
644
+ const current = item.getAttribute("aria-pressed");
645
+ if (current !== null && current !== written) this.#ownedPressed.delete(item);
586
646
  }
587
647
  }
588
- /** Supported targets currently managed by the roving primitive. */
589
648
  get #managedTargets() {
590
649
  return this.itemTargets.filter((item) => this.#managedItems.has(item));
591
650
  }
592
- /** Managed items eligible for the roving Tab stop. */
593
651
  get #navigableItems() {
594
652
  return this.#managedTargets.filter((item) => this.#isNavigable(item));
595
653
  }
596
- /** Whether an item is currently pressed. */
597
654
  #isPressed(item) {
598
655
  return item.getAttribute("aria-pressed") === "true";
599
656
  }
600
- /** Reflects pressed state while distinguishing controller writes from authored morphs. */
601
657
  #setPressed(item, pressed) {
602
658
  const value = pressed ? "true" : "false";
603
- this.#internalPressedValues.set(item, value);
604
- item.setAttribute("aria-pressed", value);
659
+ if (this.#ownedPressed.has(item)) this.#ownedPressed.set(item, value);
660
+ this.#writePressed(item, value);
605
661
  }
606
- /** The DOM-ordered values of every currently pressed managed item. */
607
662
  #pressedValues() {
608
663
  return this.#managedTargets.filter((item) => this.#isPressed(item)).map((item) => this.#itemValue(item));
609
664
  }
610
- /** An item's value (`data-value`, defaulting to empty). */
611
665
  #itemValue(item) {
612
666
  return item.getAttribute("data-value") ?? "";
613
667
  }
668
+ #writePressed(item, value) {
669
+ setAttributeIfChanged(
670
+ item,
671
+ "aria-pressed",
672
+ value,
673
+ () => this.#observer.claim(item, "aria-pressed", value)
674
+ );
675
+ }
614
676
  };
615
677
 
616
678
  export { ToggleGroupController };
617
- //# sourceMappingURL=toggle_group_controller.js.map
618
679
  //# sourceMappingURL=toggle_group_controller.js.map