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,14 +1,108 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/conditional_fields_controller.ts
3
+ function setAttributeIfChanged(element, name, value, beforeWrite) {
4
+ if (element.getAttribute(name) === value) return false;
5
+ beforeWrite?.();
6
+ if (value === null) element.removeAttribute(name);
7
+ else element.setAttribute(name, value);
8
+ return true;
9
+ }
10
+
11
+ var AuthoredMutationWatcher = class {
12
+ #onAuthored;
13
+ #claims = null;
14
+ #observer = null;
15
+ constructor(onAuthored) {
16
+ this.#onAuthored = onAuthored;
17
+ }
18
+ observe(root, options) {
19
+ this.disconnect();
20
+ const observer = new MutationObserver((records) => {
21
+ if (this.#observer !== observer) return;
22
+ const authored = this.#filter(records);
23
+ if (authored.length > 0) this.#onAuthored(authored);
24
+ });
25
+ this.#observer = observer;
26
+ this.#claims = { attributes: /* @__PURE__ */ new Map(), children: /* @__PURE__ */ new Map() };
27
+ observer.observe(root, {
28
+ attributes: true,
29
+ attributeFilter: [...options.attributes],
30
+ subtree: options.subtree ?? false,
31
+ childList: options.childList ?? false
32
+ });
33
+ if (options.ancestorAttributes) {
34
+ let ancestor = root.parentElement;
35
+ while (ancestor) {
36
+ observer.observe(ancestor, {
37
+ attributes: true,
38
+ attributeFilter: [...options.ancestorAttributes]
39
+ });
40
+ ancestor = ancestor.parentElement;
41
+ }
42
+ }
43
+ }
44
+ claim(target, name, value) {
45
+ const claims = this.#claims?.attributes;
46
+ let attributes = claims?.get(target);
47
+ if (!attributes) {
48
+ attributes = /* @__PURE__ */ new Map();
49
+ claims?.set(target, attributes);
50
+ }
51
+ const pending = attributes.get(name);
52
+ attributes.set(name, { value, count: (pending?.count ?? 0) + 1 });
53
+ }
54
+ claimCurrent(target, name) {
55
+ this.claim(target, name, target.getAttribute(name));
56
+ }
57
+ claimChildList(target, added, removed) {
58
+ const claims = this.#claims?.children;
59
+ const pending = claims?.get(target) ?? { added: /* @__PURE__ */ new Map(), removed: /* @__PURE__ */ new Map() };
60
+ for (const node of added) pending.added.set(node, (pending.added.get(node) ?? 0) + 1);
61
+ for (const node of removed) pending.removed.set(node, (pending.removed.get(node) ?? 0) + 1);
62
+ claims?.set(target, pending);
63
+ }
64
+ take() {
65
+ return this.#filter(this.#observer?.takeRecords() ?? []);
66
+ }
67
+ disconnect() {
68
+ this.#observer?.disconnect();
69
+ this.#observer = null;
70
+ this.#claims = null;
71
+ }
72
+ #filter(records) {
73
+ const authored = records.filter((record) => !this.#consume(record));
74
+ this.#claims?.attributes.clear();
75
+ this.#claims?.children.clear();
76
+ return authored;
77
+ }
78
+ #consume(record) {
79
+ if (record.type === "attributes") {
80
+ const target = record.target;
81
+ const pending2 = this.#claims?.attributes.get(target)?.get(record.attributeName);
82
+ if (!pending2 || pending2.count === 0 || target.getAttribute(record.attributeName) !== pending2.value) {
83
+ return false;
84
+ }
85
+ pending2.count -= 1;
86
+ return true;
87
+ }
88
+ const pending = this.#claims?.children.get(record.target);
89
+ if (!pending) return false;
90
+ const added = [...record.addedNodes];
91
+ const removed = [...record.removedNodes];
92
+ if (added.some((node) => !pending.added.get(node)) || removed.some((node) => !pending.removed.get(node))) {
93
+ return false;
94
+ }
95
+ for (const node of added) pending.added.set(node, (pending.added.get(node) ?? 0) - 1);
96
+ for (const node of removed) pending.removed.set(node, (pending.removed.get(node) ?? 0) - 1);
97
+ return true;
98
+ }
99
+ };
4
100
 
5
- // src/utils/event_owner.ts
6
101
  function ownerIndex(candidates, node) {
7
102
  if (!(node instanceof Node)) return -1;
8
103
  return candidates.findIndex((candidate) => candidate.contains(node));
9
104
  }
10
105
 
11
- // src/utils/focus_candidate.ts
12
106
  function inheritsFieldsetDisabled(control) {
13
107
  let fieldset = control.closest("fieldset[disabled]");
14
108
  while (fieldset) {
@@ -18,33 +112,42 @@ function inheritsFieldsetDisabled(control) {
18
112
  }
19
113
  return false;
20
114
  }
115
+ function unslotted(element) {
116
+ return element.assignedSlot === null && element.parentElement?.shadowRoot != null;
117
+ }
118
+ function flatTreeParent(element) {
119
+ if (unslotted(element)) return null;
120
+ const parent = element.assignedSlot ?? element.parentNode;
121
+ if (parent instanceof ShadowRoot) return parent.host;
122
+ return parent instanceof Element ? parent : null;
123
+ }
21
124
  function canTakeFocus(element) {
22
- if (element.closest("[hidden], [inert]")) return false;
125
+ for (let node = element; node; node = flatTreeParent(node)) {
126
+ if (unslotted(node) || node.matches("[hidden], [inert]")) return false;
127
+ }
23
128
  if (element instanceof HTMLInputElement && element.type === "hidden") return false;
24
129
  if (!("disabled" in element)) return true;
25
130
  if (element.disabled) return false;
26
131
  return !inheritsFieldsetDisabled(element);
27
132
  }
133
+ function deepActiveElement(ownerDocument) {
134
+ let active = ownerDocument.activeElement;
135
+ while (active?.shadowRoot?.activeElement) active = active.shadowRoot.activeElement;
136
+ return active;
137
+ }
28
138
 
29
- // src/utils/form_reset_watcher.ts
30
139
  var FormResetWatcher = class {
31
140
  #owns;
32
141
  #onReset;
33
142
  #frames = /* @__PURE__ */ new Set();
34
143
  #generation = 0;
35
- /**
36
- * @param owns - whether `form` owns a control this controller derives from.
37
- * @param onReset - the reconciliation pass, run once per honoured reset.
38
- */
39
144
  constructor(owns, onReset) {
40
145
  this.#owns = owns;
41
146
  this.#onReset = onReset;
42
147
  }
43
- /** Subscribes to `reset` at the document; call from `connect()`. Idempotent. */
44
148
  observe() {
45
149
  document.addEventListener("reset", this.#handleReset, true);
46
150
  }
47
- /** Unsubscribes and drops every pending pass; call from `disconnect()`. */
48
151
  disconnect() {
49
152
  document.removeEventListener("reset", this.#handleReset, true);
50
153
  this.#generation += 1;
@@ -68,57 +171,41 @@ var FormResetWatcher = class {
68
171
  this.#frames.add(frame);
69
172
  });
70
173
  };
71
- /** Runs the pass unless a listener cancelled the reset before it landed. */
72
174
  #settle(event) {
73
175
  if (!event.defaultPrevented) this.#onReset();
74
176
  }
75
177
  };
76
178
 
77
- // src/utils/listener_set.ts
78
179
  var ListenerSet = class {
79
- /** The generation every `add` joins until the next `dispose()`. */
80
180
  #abort = new AbortController();
81
- /**
82
- * Attaches `handler` to the open generation, exactly as the caller spelled it.
83
- *
84
- * The set supplies the signal, so `options` carries everything else the DOM
85
- * accepts — `capture` included, which has to match at release time and no
86
- * longer has a second place to drift from.
87
- */
88
181
  add(target, type, handler, options) {
89
182
  target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
90
183
  }
91
- /**
92
- * Releases every listener of the open generation, synchronously, and opens the
93
- * next one. Idempotent, and safe before anything has been added.
94
- */
95
184
  dispose() {
96
185
  this.#abort.abort();
97
186
  this.#abort = new AbortController();
98
187
  }
99
188
  };
100
189
 
101
- // src/utils/microtask_coalescer.ts
102
190
  var MicrotaskCoalescer = class {
103
191
  #run;
104
192
  #queued = false;
105
193
  #active = false;
106
194
  #generation = 0;
107
- /** @param run - the single reconciliation pass, invoked at most once per batch. */
108
195
  constructor(run) {
109
196
  this.#run = run;
110
197
  }
111
- /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
112
198
  activate() {
113
199
  this.#active = true;
114
200
  }
115
- /** Closes the window and drops any pending pass; call from `disconnect()`. */
116
201
  cancel() {
117
202
  this.#active = false;
118
203
  this.#queued = false;
119
204
  this.#generation += 1;
120
205
  }
121
- /** Requests one pass after the batch settles. Idempotent; inert outside the window. */
206
+ get pending() {
207
+ return this.#queued;
208
+ }
122
209
  schedule() {
123
210
  if (!this.#active || this.#queued) return;
124
211
  this.#queued = true;
@@ -131,68 +218,166 @@ var MicrotaskCoalescer = class {
131
218
  }
132
219
  };
133
220
 
134
- // src/utils/before_cache_reset.ts
135
- var BeforeCacheReset = class _BeforeCacheReset {
136
- /** Every subscribed instance, iterated by the one shared document listener. */
137
- static #subscribers = /* @__PURE__ */ new Set();
138
- /** The shared listener; installed while at least one instance is subscribed. */
139
- static #onBeforeCache = () => {
140
- for (const subscriber of _BeforeCacheReset.#subscribers) subscriber.#rewind();
141
- };
142
- #rewind;
143
- /** @param rewind - the pass that returns this controller's state to its initial form. */
144
- constructor(rewind) {
145
- this.#rewind = rewind;
221
+ var MorphRenderWatcher = class {
222
+ #listeners = new ListenerSet();
223
+ #pass;
224
+ #element = null;
225
+ #onMorph = () => this.#pass.schedule();
226
+ constructor(run) {
227
+ this.#pass = new MicrotaskCoalescer(run);
146
228
  }
147
- /** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */
148
- activate() {
149
- const first = _BeforeCacheReset.#subscribers.size === 0;
150
- _BeforeCacheReset.#subscribers.add(this);
151
- if (first) {
152
- document.addEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
153
- }
229
+ observe(element) {
230
+ if (this.#element === element) return;
231
+ this.disconnect();
232
+ this.#element = element;
233
+ this.#pass.activate();
234
+ this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
235
+ }
236
+ schedule() {
237
+ this.#pass.schedule();
238
+ }
239
+ get pending() {
240
+ return this.#pass.pending;
154
241
  }
155
- /** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */
156
- deactivate() {
157
- _BeforeCacheReset.#subscribers.delete(this);
158
- if (_BeforeCacheReset.#subscribers.size > 0) return;
159
- document.removeEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
242
+ disconnect() {
243
+ this.#listeners.dispose();
244
+ this.#pass.cancel();
245
+ this.#element = null;
160
246
  }
161
247
  };
162
248
 
163
- // src/utils/tabindex_loan.ts
164
- var TabindexLoan = class {
249
+ function queryOpenDescendants(root, selector) {
250
+ const matches = [];
251
+ const roots = [root];
252
+ for (const scope of roots) {
253
+ matches.push(...scope.querySelectorAll(selector));
254
+ if (scope.nodeType === Node.ELEMENT_NODE) {
255
+ const shadow = scope.shadowRoot;
256
+ if (shadow) roots.push(shadow);
257
+ }
258
+ for (const element of scope.querySelectorAll("*")) {
259
+ if (element.shadowRoot) roots.push(element.shadowRoot);
260
+ }
261
+ }
262
+ return matches;
263
+ }
264
+
265
+ function sharedRegistry(key, create) {
266
+ const symbol = Symbol.for(key);
267
+ const scope = globalThis;
268
+ const existing = scope[symbol];
269
+ if (existing !== void 0) return existing;
270
+ const registry = create();
271
+ Object.defineProperty(globalThis, symbol, { value: registry });
272
+ return registry;
273
+ }
274
+
275
+ function holdsFocus(element) {
276
+ return element.matches(":focus") || deepActiveElement(element.ownerDocument) === element;
277
+ }
278
+ var TabindexLoan = class _TabindexLoan {
279
+ static #registry = sharedRegistry(
280
+ "stimeo-ui.tabindex-loan.registry.v1",
281
+ () => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Set() })
282
+ );
165
283
  #value;
284
+ #record;
285
+ #preserveFocus;
166
286
  #lent = /* @__PURE__ */ new Set();
167
- /** Returns live loans before Turbo can copy them into its page snapshot. */
168
- #beforeCache = new BeforeCacheReset(() => this.returnAll());
169
- /**
170
- * @param value - the `tabindex` to lend. `"-1"` (the default) is
171
- * programmatically focusable but not a Tab stop; `"0"` is a real Tab stop,
172
- * which a scroll region with no focusable content of its own needs.
173
- */
174
- constructor(value = "-1") {
287
+ constructor(value, owner, options = {}) {
175
288
  this.#value = value;
176
- }
177
- /** Lends `element` the value; no-ops when it already carries a `tabindex`. */
178
- lend(element) {
179
- if (element.hasAttribute("tabindex")) return;
180
- element.setAttribute("tabindex", this.#value);
289
+ this.#record = `data-${owner}-tabindex-loan`;
290
+ this.#preserveFocus = options.preserveFocus === true;
291
+ _TabindexLoan.#registry.names.add(this.#record);
292
+ }
293
+ lend(element, options = {}) {
294
+ const stack = this.#stack(element);
295
+ const current = element.getAttribute("tabindex");
296
+ const held = stack.find((hold) => hold.loan === this) ?? stack.find(
297
+ (hold) => hold.loan === null && hold.record === this.#record && hold.value === this.#value
298
+ );
299
+ const linked = stack.at(-1)?.value === current;
300
+ if (!held && options.onlyIfUnfocusable && (current !== null || element.tabIndex >= 0)) return;
301
+ if (!held && current !== null && !linked) return;
181
302
  this.#lent.add(element);
182
- this.#beforeCache.activate();
303
+ if (held) held.loan = this;
304
+ else stack.push({ loan: this, record: this.#record, value: this.#value, linked });
305
+ this.#mark(element, stack);
306
+ if (current === null || !held && current !== this.#value) {
307
+ element.setAttribute("tabindex", this.#value);
308
+ }
309
+ }
310
+ return(element) {
311
+ const stack = this.#stack(element);
312
+ const hold = stack.find((held) => held.loan === this) ?? stack.find(
313
+ (held) => held.loan === null && held.record === this.#record && held.value === this.#value
314
+ );
315
+ if (!hold) return false;
316
+ if (!this.#release(element, stack, hold, this.#preserveFocus)) {
317
+ hold.loan = this;
318
+ this.#lent.add(element);
319
+ return false;
320
+ }
321
+ this.#lent.delete(element);
322
+ return true;
183
323
  }
184
- /** Takes back every loan whose value is still the one that was lent. */
185
324
  returnAll() {
186
- for (const element of this.#lent) {
187
- if (element.getAttribute("tabindex") === this.#value) element.removeAttribute("tabindex");
325
+ for (const element of Array.from(this.#lent)) this.return(element);
326
+ }
327
+ reclaim(element) {
328
+ if (element.getAttribute(this.#record) !== this.#value) return;
329
+ const stack = this.#stack(element);
330
+ const hold = stack.find((held) => held.loan === null && held.record === this.#record);
331
+ if (hold && !holdsFocus(element)) this.#release(element, stack, hold);
332
+ }
333
+ reclaimWithin(root) {
334
+ for (const element of queryOpenDescendants(root, `[${this.#record}]`)) {
335
+ this.reclaim(element);
336
+ }
337
+ }
338
+ #stack(element) {
339
+ const stacks = _TabindexLoan.#registry.stacks;
340
+ const stack = stacks.get(element) ?? this.#seed(element);
341
+ stacks.set(element, stack);
342
+ return stack;
343
+ }
344
+ #seed(element) {
345
+ const current = element.getAttribute("tabindex");
346
+ const holds = [];
347
+ for (const record of _TabindexLoan.#registry.names) {
348
+ const value = element.getAttribute(record);
349
+ if (value !== null) holds.push({ loan: null, record, value, linked: true });
350
+ }
351
+ holds.sort((one, other) => Number(one.value === current) - Number(other.value === current));
352
+ for (const [index, hold] of holds.entries()) hold.linked = index > 0;
353
+ return holds;
354
+ }
355
+ #release(element, stack, hold, preserveFocus = false) {
356
+ const current = element.getAttribute("tabindex");
357
+ const index = stack.indexOf(hold);
358
+ const owns = current === hold.value && !stack.slice(index + 1).some((above2) => above2.value === current);
359
+ if (owns && preserveFocus && holdsFocus(element)) return false;
360
+ stack.splice(index, 1);
361
+ const above = stack[index];
362
+ if (above) above.linked &&= hold.linked;
363
+ this.#mark(element, stack);
364
+ if (!owns) return true;
365
+ const below = hold.linked ? stack[index - 1] : void 0;
366
+ if (!below) element.removeAttribute("tabindex");
367
+ else if (below.value !== current) element.setAttribute("tabindex", below.value);
368
+ return true;
369
+ }
370
+ #mark(element, stack) {
371
+ const records = /* @__PURE__ */ new Map([[this.#record, null]]);
372
+ for (const hold of stack) records.set(hold.record, hold.value);
373
+ for (const [name, recorded] of records) {
374
+ setAttributeIfChanged(element, name, recorded);
188
375
  }
189
- this.#lent.clear();
190
- this.#beforeCache.deactivate();
191
376
  }
192
377
  };
193
378
 
194
- // src/controllers/conditional_fields_controller.ts
195
379
  var DISABLED_MARKER = "data-conditional-disabled";
380
+ var CONTROLS = "input, textarea, select, button";
196
381
  var OBSERVED_ATTRIBUTES = [
197
382
  "hidden",
198
383
  "aria-hidden",
@@ -215,23 +400,17 @@ var ConditionalFieldsController = class extends Controller {
215
400
  };
216
401
  static actions = ["evaluate"];
217
402
  static events = ["change", "reconcile"];
218
- /** Logical state last committed for each current region; rebuilt on every connect. */
219
403
  #lastVisible = /* @__PURE__ */ new WeakMap();
220
- /** Controller writes awaiting an observer callback, separated from authored morphs. */
221
- #internalWrites = /* @__PURE__ */ new WeakMap();
222
- #observing = false;
223
- /** Coalesces one target/morph/mutation batch into one full DOM reconciliation. */
224
- #reconcile = new MicrotaskCoalescer(() => this.#reconcileDom());
404
+ #departed = /* @__PURE__ */ new Set();
405
+ #concealed = /* @__PURE__ */ new WeakSet();
406
+ #reconcile = new MorphRenderWatcher(() => this.#reconcileDom());
225
407
  #listeners = new ListenerSet();
226
408
  #formReset = new FormResetWatcher(
227
409
  (form) => this.#hasTriggerOwnedBy(form),
228
410
  () => this.#reconcile.schedule()
229
411
  );
230
- /** Provides the last-resort focus landmark without claiming an authored tabindex. */
231
- #rootTabindex = new TabindexLoan();
232
- /** Watches retained targets and controls whose declarative or reflected state changed. */
233
- #observer = new MutationObserver((records) => this.#onMutations(records));
234
- /** Evaluates only events whose source is one of this instance's live trigger targets. */
412
+ #rootTabindex = new TabindexLoan("-1", this.identifier);
413
+ #observer = new AuthoredMutationWatcher((records) => this.#onMutations(records));
235
414
  #onTriggerInput = (event) => {
236
415
  const target = event.target;
237
416
  const triggers = this.triggerTargets;
@@ -239,75 +418,57 @@ var ConditionalFieldsController = class extends Controller {
239
418
  this.#commitChange(triggers);
240
419
  }
241
420
  };
242
- /** Reconciles property-only retained-element changes after Turbo morphs. */
243
- #onMorph = () => {
244
- this.#reconcile.schedule();
245
- };
246
- /** Reflects initial live state and opens every retained-DOM reconciliation path. */
247
421
  connect() {
422
+ this.#rootTabindex.reclaim(this.element);
248
423
  this.#lastVisible = /* @__PURE__ */ new WeakMap();
249
- this.#internalWrites = /* @__PURE__ */ new WeakMap();
250
- this.#reconcile.activate();
251
424
  this.#settle();
425
+ this.#reconcile.observe(this.element);
252
426
  this.#observer.observe(this.element, {
253
- attributes: true,
254
- attributeFilter: OBSERVED_ATTRIBUTES,
427
+ attributes: OBSERVED_ATTRIBUTES,
255
428
  childList: true,
256
429
  subtree: true
257
430
  });
258
- this.#observing = true;
259
431
  this.#listeners.add(this.element, "change", this.#onTriggerInput);
260
432
  this.#listeners.add(this.element, "input", this.#onTriggerInput);
261
- this.#listeners.add(this.element, "turbo:morph-element", this.#onMorph);
262
433
  this.#formReset.observe();
263
434
  }
264
- /** Releases all external resources and returns the temporary focus landmark loan. */
265
435
  disconnect() {
266
- this.#reconcile.cancel();
267
- this.#observing = false;
436
+ this.#reconcile.disconnect();
268
437
  this.#observer.disconnect();
269
438
  this.#listeners.dispose();
270
439
  this.#formReset.disconnect();
271
440
  this.#rootTabindex.returnAll();
272
441
  }
273
- /** Reconciles after a trigger target is inserted or restored. */
274
442
  triggerTargetConnected() {
275
443
  this.#reconcile.schedule();
276
444
  }
277
- /** Reconciles after a trigger target is removed or replaced. */
278
445
  triggerTargetDisconnected() {
279
446
  this.#reconcile.schedule();
280
447
  }
281
- /** Initializes a region target inserted or restored at runtime. */
282
448
  regionTargetConnected() {
283
449
  this.#reconcile.schedule();
284
450
  }
285
- /** Reconciles the remaining region set after a target leaves. */
286
- regionTargetDisconnected() {
451
+ regionTargetDisconnected(region) {
452
+ this.#departed.add(region);
287
453
  this.#reconcile.schedule();
288
454
  }
289
- /** Reconciles when application code or a morph changes the match policy. */
290
455
  matchValueChanged() {
291
456
  this.#reconcile.schedule();
292
457
  }
293
- /** Reconciles control ownership when hidden controls become enabled or excluded. */
294
458
  disableHiddenValueChanged() {
295
459
  this.#reconcile.schedule();
296
460
  }
297
- /** Re-evaluates every region and repairs all reflected DOM state. */
298
461
  evaluate() {
299
462
  this.#commitChange();
300
463
  }
301
- /**
302
- * Computes one settled plan, shows destinations before hiding sources, and then
303
- * returns logical transitions in DOM order after every region is internally coherent.
304
- *
305
- * @stimeoRenderRoot
306
- */
307
464
  #settle(triggers = this.triggerTargets) {
308
465
  const regions = this.regionTargets;
309
466
  const plan = /* @__PURE__ */ new Map();
310
467
  for (const region of regions) plan.set(region, this.#isVisible(region, triggers));
468
+ for (const departed of this.#departed) {
469
+ if (!plan.has(departed)) this.#release(departed, plan);
470
+ }
471
+ this.#departed.clear();
311
472
  const changed = /* @__PURE__ */ new Set();
312
473
  const applicationOrder = [
313
474
  ...regions.filter((region) => plan.get(region) === true),
@@ -321,19 +482,16 @@ var ConditionalFieldsController = class extends Controller {
321
482
  }
322
483
  return regions.filter((region) => changed.has(region)).map((region) => ({ region, visible: plan.get(region) === true }));
323
484
  }
324
- /** Reports logical transitions caused by user input or the public action. */
325
485
  #commitChange(triggers = this.triggerTargets) {
326
486
  for (const detail of this.#settle(triggers)) {
327
487
  this.dispatch("change", { detail });
328
488
  }
329
489
  }
330
- /** Reports logical transitions derived from DOM, lifecycle, reset, or Value state. */
331
490
  #reconcileDom() {
332
491
  for (const detail of this.#settle()) {
333
492
  this.dispatch("reconcile", { detail });
334
493
  }
335
494
  }
336
- /** Applies one planned state while keeping event history separate from DOM repair. */
337
495
  #applyRegion(region, visible, plan) {
338
496
  const previous = this.#lastVisible.get(region) ?? !region.hidden;
339
497
  const changed = visible !== previous;
@@ -343,17 +501,16 @@ var ConditionalFieldsController = class extends Controller {
343
501
  this.#syncRegionControls(region, visible);
344
502
  return changed;
345
503
  }
346
- /** Reflects visibility idempotently, recording writes so the observer ignores its own work. */
347
504
  #syncRegionState(region, visible) {
505
+ if (!visible && this.#predicateFor(region) !== null) this.#concealed.add(region);
506
+ else this.#concealed.delete(region);
348
507
  this.#writeAttribute(region, "hidden", visible ? null : "");
349
508
  this.#writeAttribute(region, "aria-hidden", visible ? null : "true");
350
509
  this.#writeAttribute(region, "data-visible", visible ? "true" : null);
351
510
  }
352
- /** Enables/disables descendant controls, touching only state carrying our marker. */
353
511
  #syncRegionControls(region, visible) {
354
512
  const shouldDisable = !visible && this.disableHiddenValue;
355
- const controls = region.querySelectorAll("input, textarea, select, button");
356
- for (const control of controls) {
513
+ for (const control of region.querySelectorAll(CONTROLS)) {
357
514
  const marked = control.hasAttribute(DISABLED_MARKER);
358
515
  if (shouldDisable) {
359
516
  if (!control.disabled) {
@@ -363,18 +520,30 @@ var ConditionalFieldsController = class extends Controller {
363
520
  this.#writeAttribute(control, DISABLED_MARKER, "true");
364
521
  }
365
522
  } else if (marked) {
366
- this.#writeAttribute(control, "disabled", null);
367
- this.#writeAttribute(control, DISABLED_MARKER, null);
523
+ this.#enable(control);
524
+ }
525
+ }
526
+ }
527
+ #enable(control) {
528
+ this.#writeAttribute(control, "disabled", null);
529
+ this.#writeAttribute(control, DISABLED_MARKER, null);
530
+ }
531
+ #release(element, plan) {
532
+ this.#lastVisible.delete(element);
533
+ if (this.#concealed.delete(element)) this.#writeAttribute(element, "hidden", null);
534
+ this.#writeAttribute(element, "aria-hidden", null);
535
+ this.#writeAttribute(element, "data-visible", null);
536
+ for (const control of element.querySelectorAll(CONTROLS)) {
537
+ if (control.hasAttribute(DISABLED_MARKER) && this.#survivesPlan(control, plan)) {
538
+ this.#enable(control);
368
539
  }
369
540
  }
370
541
  }
371
- /** Whether a region's declared condition holds across `triggers` per `match`. */
372
542
  #isVisible(region, triggers) {
373
543
  const predicate = this.#predicateFor(region);
374
544
  if (predicate === null) return !region.hidden;
375
545
  return triggers.length > 0 && (this.matchValue === "all" ? triggers.every(predicate) : triggers.some(predicate));
376
546
  }
377
- /** Builds the deterministic per-trigger predicate from the region's condition. */
378
547
  #predicateFor(region) {
379
548
  if (region.hasAttribute("data-when-checked")) {
380
549
  return (trigger) => this.#isChecked(trigger);
@@ -391,19 +560,16 @@ var ConditionalFieldsController = class extends Controller {
391
560
  #isChecked(trigger) {
392
561
  return trigger instanceof HTMLInputElement && trigger.checked;
393
562
  }
394
- /** A trigger has a value when a radio/checkbox is selected, or its control value matches. */
395
563
  #matchesValue(trigger, wanted) {
396
564
  if (trigger instanceof HTMLInputElement && (trigger.type === "checkbox" || trigger.type === "radio")) {
397
565
  return trigger.checked && trigger.value === wanted;
398
566
  }
399
567
  return trigger.value === wanted;
400
568
  }
401
- /** Moves focus to the first safe trigger, or to the controller landmark as a fallback. */
402
569
  #retreatFocus(region, plan) {
403
570
  const active = document.activeElement;
404
571
  if (active && region.contains(active)) this.#moveFocus(plan);
405
572
  }
406
- /** Moves focus after the caller establishes that the active node is being hidden. */
407
573
  #moveFocus(plan) {
408
574
  const destination = this.triggerTargets.find(
409
575
  (trigger) => canTakeFocus(trigger) && this.#survivesPlan(trigger, plan)
@@ -416,65 +582,28 @@ var ConditionalFieldsController = class extends Controller {
416
582
  this.#rootTabindex.lend(this.element);
417
583
  this.element.focus();
418
584
  }
419
- /** Whether a focus candidate sits outside every region this pass will hide. */
420
585
  #survivesPlan(candidate, plan) {
421
586
  return [...plan].every(([region, visible]) => visible || !region.contains(candidate));
422
587
  }
423
- /** Records one idempotent attribute write before MutationObserver sees it. */
424
588
  #writeAttribute(element, name, value) {
425
- if (element.getAttribute(name) !== value) {
426
- if (this.#observing) {
427
- let writes = this.#internalWrites.get(element);
428
- if (!writes) {
429
- writes = /* @__PURE__ */ new Map();
430
- this.#internalWrites.set(element, writes);
431
- }
432
- writes.set(name, value);
433
- }
434
- if (value === null) element.removeAttribute(name);
435
- else element.setAttribute(name, value);
436
- }
589
+ setAttributeIfChanged(element, name, value, () => this.#observer.claim(element, name, value));
437
590
  }
438
- /** Separates authored records from controller writes and queues one relevant repair. */
439
591
  #onMutations(records) {
440
592
  const triggers = this.triggerTargets;
441
593
  const regions = this.regionTargets;
442
- const touchedWrites = /* @__PURE__ */ new Map();
443
- let needsReconcile = false;
444
- for (const record of records) {
445
- if (record.type === "attributes" && record.target instanceof Element) {
446
- const name = record.attributeName;
447
- const writes = this.#internalWrites.get(record.target);
448
- if (name && writes?.has(name)) {
449
- let names = touchedWrites.get(record.target);
450
- if (!names) {
451
- names = /* @__PURE__ */ new Set();
452
- touchedWrites.set(record.target, names);
453
- }
454
- names.add(name);
455
- if (record.target.getAttribute(name) === writes.get(name)) continue;
456
- }
457
- }
458
- if (record.target instanceof Element && this.#elementAffectsState(record.target, triggers, regions)) {
459
- needsReconcile = true;
460
- }
461
- }
462
- for (const [element, names] of touchedWrites) {
463
- const writes = this.#internalWrites.get(element);
464
- for (const name of names) writes?.delete(name);
594
+ if (records.some(
595
+ (record) => record.target instanceof Element && this.#elementAffectsState(record.target, triggers, regions)
596
+ )) {
597
+ this.#reconcile.schedule();
465
598
  }
466
- if (needsReconcile) this.#reconcile.schedule();
467
599
  }
468
- /** Whether an authored mutation target belongs to a trigger, region, or managed control. */
469
600
  #elementAffectsState(target, triggers, regions) {
470
601
  return ownerIndex(triggers, target) !== -1 || ownerIndex(regions, target) !== -1;
471
602
  }
472
- /** Whether a form owns at least one current trigger, including `form=` associations. */
473
603
  #hasTriggerOwnedBy(form) {
474
604
  return this.triggerTargets.some((trigger) => trigger.form === form);
475
605
  }
476
606
  };
477
607
 
478
608
  export { ConditionalFieldsController };
479
- //# sourceMappingURL=conditional_fields_controller.js.map
480
609
  //# sourceMappingURL=conditional_fields_controller.js.map