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 +1 @@
1
- {"version":3,"sources":["../../src/utils/announce.ts","../../src/utils/aria_ids.ts","../../src/utils/attribute_lease.ts","../../src/utils/before_cache_reset.ts","../../src/utils/event_owner.ts","../../src/utils/microtask_coalescer.ts","../../src/controllers/form_field_controller.ts"],"names":[],"mappings":";;;;;AAoBO,SAAS,QAAA,CAAS,OAAA,EAAiB,OAAA,GAAmC,EAAC,EAAS;AACrF,EAAA,MAAM,IAAA,GAAO,QAAQ,IAAA,EAAK;AAC1B,EAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;AACvB,EAAA,MAAA,CAAO,aAAA;AAAA,IACL,IAAI,YAAY,4BAAA,EAA8B;AAAA,MAC5C,QAAQ,EAAE,OAAA,EAAS,MAAM,SAAA,EAAW,OAAA,CAAQ,cAAc,IAAA;AAAK,KAChE;AAAA,GACH;AACF;;;ACVA,IAAI,OAAA,GAAU,CAAA;AAeP,SAAS,QAAA,CAAS,SAAS,QAAA,EAAkB;AAClD,EAAA,IAAI,SAAA;AACJ,EAAA,GAAG;AACD,IAAA,OAAA,IAAW,CAAA;AACX,IAAA,SAAA,GAAY,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,OAAO,CAAA,CAAA;AAAA,EAClC,SAAS,OAAO,QAAA,KAAa,eAAe,QAAA,CAAS,cAAA,CAAe,SAAS,CAAA,KAAM,IAAA;AACnF,EAAA,OAAO,SAAA;AACT;AAYO,SAAS,QAAA,CAAS,OAAA,EAAkB,MAAA,GAAS,QAAA,EAAkB;AACpE,EAAA,IAAI,OAAA,CAAQ,EAAA,EAAI,OAAO,OAAA,CAAQ,EAAA;AAC/B,EAAA,MAAM,EAAA,GAAK,SAAS,MAAM,CAAA;AAC1B,EAAA,OAAA,CAAQ,EAAA,GAAK,EAAA;AACb,EAAA,OAAO,EAAA;AACT;;;ACjCO,IAAM,iBAAN,MAAkD;AAAA,EAC9C,UAAA;AAAA,EACA,QAAA,uBAAe,GAAA,EAA6B;AAAA;AAAA,EAGrD,YAAY,SAAA,EAAmB;AAC7B,IAAA,IAAA,CAAK,UAAA,GAAa,SAAA;AAAA,EACpB;AAAA;AAAA,EAGA,KAAA,CAAM,SAAY,KAAA,EAA4B;AAC5C,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,OAAO,CAAA;AAC1C,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,QAAA,CAAS,OAAA,GAAU,KAAA;AAAA,IACrB,CAAA,MAAO;AACL,MAAA,IAAA,CAAK,QAAA,CAAS,IAAI,OAAA,EAAS;AAAA,QACzB,QAAA,EAAU,OAAA,CAAQ,YAAA,CAAa,IAAA,CAAK,UAAU,CAAA;AAAA,QAC9C,OAAA,EAAS;AAAA,OACV,CAAA;AAAA,IACH;AAEA,IAAA,IAAA,CAAK,QAAA,CAAS,SAAS,KAAK,CAAA;AAAA,EAC9B;AAAA;AAAA,EAGA,OAAO,OAAA,EAAkB;AACvB,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,QAAA,CAAS,GAAA,CAAI,OAAO,CAAA;AACxC,IAAA,IAAI,CAAC,MAAA,EAAQ;AACb,IAAA,IAAA,CAAK,QAAA,CAAS,OAAO,OAAO,CAAA;AAC5B,IAAA,MAAM,aAAa,OAAA,CAAQ,YAAA,CAAa,IAAA,CAAK,UAAU,MAAM,MAAA,CAAO,OAAA;AACpE,IAAA,IAAI,UAAA,EAAY,IAAA,CAAK,QAAA,CAAS,OAAA,EAAS,OAAO,QAAQ,CAAA;AAAA,EACxD;AAAA;AAAA,EAGA,QAAA,CAAS,SAAY,KAAA,EAA4B;AAC/C,IAAA,IAAI,OAAA,CAAQ,YAAA,CAAa,IAAA,CAAK,UAAU,MAAM,KAAA,EAAO;AACrD,IAAA,IAAI,KAAA,KAAU,IAAA,EAAM,OAAA,CAAQ,eAAA,CAAgB,KAAK,UAAU,CAAA;AAAA,SACtD,OAAA,CAAQ,YAAA,CAAa,IAAA,CAAK,UAAA,EAAY,KAAK,CAAA;AAAA,EAClD;AAAA;AAAA,EAGA,SAAA,GAAkB;AAChB,IAAA,KAAA,MAAW,OAAA,IAAW,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,QAAA,CAAS,MAAM,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,OAAO,CAAA;AAAA,EAC7E;AACF,CAAA;;;ACzBO,IAAM,gBAAA,GAAN,MAAM,iBAAA,CAAiB;AAAA;AAAA,EAE5B,OAAgB,YAAA,mBAAe,IAAI,GAAA,EAAsB;AAAA;AAAA,EAGzD,OAAgB,iBAAiB,MAAY;AAC3C,IAAA,KAAA,MAAW,UAAA,IAAc,iBAAA,CAAiB,YAAA,EAAc,UAAA,CAAW,OAAA,EAAQ;AAAA,EAC7E,CAAA;AAAA,EAES,OAAA;AAAA;AAAA,EAGT,YAAY,MAAA,EAAoB;AAC9B,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AAAA,EACjB;AAAA;AAAA,EAGA,QAAA,GAAiB;AACf,IAAA,MAAM,KAAA,GAAQ,iBAAA,CAAiB,YAAA,CAAa,IAAA,KAAS,CAAA;AACrD,IAAA,iBAAA,CAAiB,YAAA,CAAa,IAAI,IAAI,CAAA;AACtC,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,QAAA,CAAS,gBAAA,CAAiB,oBAAA,EAAsB,iBAAA,CAAiB,cAAc,CAAA;AAAA,IACjF;AAAA,EACF;AAAA;AAAA,EAGA,UAAA,GAAmB;AACjB,IAAA,iBAAA,CAAiB,YAAA,CAAa,OAAO,IAAI,CAAA;AACzC,IAAA,IAAI,iBAAA,CAAiB,YAAA,CAAa,IAAA,GAAO,CAAA,EAAG;AAC5C,IAAA,QAAA,CAAS,mBAAA,CAAoB,oBAAA,EAAsB,iBAAA,CAAiB,cAAc,CAAA;AAAA,EACpF;AACF,CAAA;;;AC1CO,SAAS,UAAA,CACd,YACA,IAAA,EACQ;AACR,EAAA,IAAI,EAAE,IAAA,YAAgB,IAAA,CAAA,EAAO,OAAO,EAAA;AACpC,EAAA,OAAO,WAAW,SAAA,CAAU,CAAC,cAAc,SAAA,CAAU,QAAA,CAAS,IAAI,CAAC,CAAA;AACrE;;;ACeO,IAAM,qBAAN,MAAyB;AAAA,EACrB,IAAA;AAAA,EACT,OAAA,GAAU,KAAA;AAAA,EACV,OAAA,GAAU,KAAA;AAAA,EACV,WAAA,GAAc,CAAA;AAAA;AAAA,EAGd,YAAY,GAAA,EAAiB;AAC3B,IAAA,IAAA,CAAK,IAAA,GAAO,GAAA;AAAA,EACd;AAAA;AAAA,EAGA,QAAA,GAAiB;AACf,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AAAA,EACjB;AAAA;AAAA,EAGA,MAAA,GAAe;AACb,IAAA,IAAA,CAAK,OAAA,GAAU,KAAA;AACf,IAAA,IAAA,CAAK,OAAA,GAAU,KAAA;AACf,IAAA,IAAA,CAAK,WAAA,IAAe,CAAA;AAAA,EACtB;AAAA;AAAA,EAGA,QAAA,GAAiB;AACf,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,IAAW,IAAA,CAAK,OAAA,EAAS;AACnC,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,IAAA,MAAM,aAAa,IAAA,CAAK,WAAA;AACxB,IAAA,cAAA,CAAe,MAAM;AAEnB,MAAA,IAAI,UAAA,KAAe,KAAK,WAAA,IAAe,CAAC,KAAK,OAAA,IAAW,CAAC,KAAK,OAAA,EAAS;AACvE,MAAA,IAAA,CAAK,OAAA,GAAU,KAAA;AACf,MAAA,IAAA,CAAK,IAAA,EAAK;AAAA,IACZ,CAAC,CAAA;AAAA,EACH;AACF,CAAA;;;ACxDA,IAAM,mBAAA,GAAsB,CAAC,QAAA,EAAU,IAAI,CAAA;AAwCpC,IAAM,mBAAA,GAAN,cAAkC,UAAA,CAAwB;AAAA,EAC/D,OAAgB,OAAA,GAAU,CAAC,SAAA,EAAW,eAAe,OAAO,CAAA;AAAA,EAC5D,OAAgB,MAAA,GAAS;AAAA,IACvB,YAAA,EAAc,EAAE,IAAA,EAAM,OAAA,EAAS,SAAS,KAAA;AAAM,GAChD;AAAA,EACA,OAAO,OAAA,GAAU,CAAC,YAAA,EAAc,UAAU,CAAA;AAAA,EAC1C,OAAO,MAAA,GAAS,CAAC,UAAU,CAAA;AAAA;AAAA,EAW3B,IAAI,iBAAA,GAA4B;AAC9B,IAAA,OAAO,CAAA,KAAA,EAAQ,KAAK,UAAU,CAAA,QAAA,CAAA;AAAA,EAChC;AAAA;AAAA,EAGS,aAAa,IAAI,kBAAA,CAAmB,MAAM,IAAA,CAAK,eAAe,CAAA;AAAA;AAAA,EAE9D,eAAe,IAAI,gBAAA,CAAiB,MAAM,IAAA,CAAK,iBAAiB,CAAA;AAAA,EAChE,gBAAA,GAAmB,IAAI,cAAA,CAA4B,kBAAkB,CAAA;AAAA,EACrE,iBAAA,GAAoB,IAAI,cAAA,CAA4B,mBAAmB,CAAA;AAAA,EACvE,YAAA,GAAe,IAAI,cAAA,CAA4B,cAAc,CAAA;AAAA;AAAA,EAE7D,SAAA,GAAY,IAAI,gBAAA,CAAiB,CAAC,OAAA,KAAY;AACrD,IAAA,IAAI,OAAA,CAAQ,KAAK,CAAC,MAAA,KAAW,KAAK,mBAAA,CAAoB,MAAM,CAAC,CAAA,EAAG;AAC9D,MAAA,IAAA,CAAK,WAAW,QAAA,EAAS;AAAA,IAC3B;AAAA,EACF,CAAC,CAAA;AAAA,EAED,cAAA,GAAqC,IAAA;AAAA,EACrC,mBAA6B,EAAC;AAAA,EAC9B,gBAAA,GAAmB,KAAA;AAAA,EACnB,YAAA,GAAe,KAAA;AAAA;AAAA,EAGN,OAAA,GAAgB;AACvB,IAAA,IAAA,CAAK,WAAW,QAAA,EAAS;AACzB,IAAA,IAAA,CAAK,qBAAA,EAAsB;AAC3B,IAAA,IAAA,CAAK,aAAa,QAAA,EAAS;AAK3B,IAAA,IAAI,CAAC,KAAK,YAAA,EAAc;AACtB,MAAA,IAAA,CAAK,gBAAA,GACH,IAAA,CAAK,OAAA,CAAQ,YAAA,CAAa,IAAA,CAAK,iBAAiB,CAAA,IAAK,IAAA,CAAK,YAAA,EAAa,CAAE,MAAA,KAAW,CAAA;AACtF,MAAA,IAAA,CAAK,YAAA,GAAe,IAAA;AAAA,IACtB;AAEA,IAAA,IAAA,CAAK,aAAA,EAAc;AACnB,IAAA,IAAA,CAAK,SAAA,CAAU,OAAA,CAAQ,IAAA,CAAK,OAAA,EAAS;AAAA,MACnC,UAAA,EAAY,IAAA;AAAA,MACZ,eAAA,EAAiB,mBAAA;AAAA,MACjB,aAAA,EAAe,IAAA;AAAA,MACf,SAAA,EAAW,IAAA;AAAA,MACX,OAAA,EAAS;AAAA,KACV,CAAA;AAAA,EACH;AAAA;AAAA,EAGS,UAAA,GAAmB;AAC1B,IAAA,IAAA,CAAK,WAAW,MAAA,EAAO;AACvB,IAAA,IAAA,CAAK,UAAU,UAAA,EAAW;AAC1B,IAAA,IAAA,CAAK,aAAa,UAAA,EAAW;AAC7B,IAAA,IAAA,CAAK,cAAA,IAAkB,IAAA,CAAK,eAAA,CAAgB,IAAA,CAAK,cAAc,CAAA;AAAA,EACjE;AAAA;AAAA,EAGA,sBAAA,GAA+B;AAC7B,IAAA,IAAA,CAAK,WAAW,QAAA,EAAS;AAAA,EAC3B;AAAA;AAAA,EAGA,yBAAA,GAAkC;AAChC,IAAA,IAAA,CAAK,WAAW,QAAA,EAAS;AAAA,EAC3B;AAAA;AAAA,EAGA,0BAAA,GAAmC;AACjC,IAAA,IAAA,CAAK,WAAW,QAAA,EAAS;AAAA,EAC3B;AAAA;AAAA,EAGA,6BAAA,GAAsC;AACpC,IAAA,IAAA,CAAK,WAAW,QAAA,EAAS;AAAA,EAC3B;AAAA;AAAA,EAGA,oBAAA,GAA6B;AAC3B,IAAA,IAAA,CAAK,WAAW,QAAA,EAAS;AAAA,EAC3B;AAAA;AAAA,EAGA,uBAAA,GAAgC;AAC9B,IAAA,IAAA,CAAK,WAAW,QAAA,EAAS;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcA,QAAA,CAAS,GAAA,EAA4B,OAAA,GAAoC,EAAC,EAAS;AACjF,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,eAAA,CAAgB,GAAG,CAAA;AACxC,IAAA,IAAI,OAAA,KAAY,IAAA,IAAQ,IAAA,CAAK,cAAA,EAAgB;AAC3C,MAAA,IAAA,CAAK,aAAa,CAAC,CAAA,EAAG,gBAAgB,QAAA,CAAS,cAAA,CAAe,OAAO,CAAC,CAAA;AAAA,IACxE;AACA,IAAA,KAAA,MAAW,KAAA,IAAS,KAAK,YAAA,EAAc;AACrC,MAAA,KAAA,CAAM,MAAA,GAAA,CAAU,KAAA,CAAM,WAAA,IAAe,EAAA,EAAI,MAAK,KAAM,EAAA;AAAA,IACtD;AAIA,IAAA,IAAA,CAAK,gBAAA,GAAmB,IAAA;AACxB,IAAA,IAAA,CAAK,aAAA,EAAc;AACnB,IAAA,MAAM,YAAA,GAAe,KAAK,aAAA,EAAc;AACxC,IAAA,MAAM,MAAA,GAAkC,EAAE,KAAA,EAAO,KAAA,EAAO,SAAS,YAAA,EAAa;AAC9E,IAAA,IAAA,CAAK,QAAA,CAAS,UAAA,EAAY,EAAE,MAAA,EAAQ,CAAA;AACpC,IAAA,QAAA,CAAS,YAAA,EAAc,EAAE,SAAA,EAAW,IAAA,EAAM,CAAA;AAE1C,IAAA,IAAI,QAAQ,KAAA,IAAS,IAAA,CAAK,iBAAA,EAAmB,IAAA,CAAK,gBAAgB,KAAA,EAAM;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,UAAA,GAAmB;AACjB,IAAA,KAAA,MAAW,KAAA,IAAS,KAAK,YAAA,EAAc;AACrC,MAAA,KAAA,CAAM,eAAA,EAAgB;AACtB,MAAA,KAAA,CAAM,MAAA,GAAS,IAAA;AAAA,IACjB;AACA,IAAA,IAAA,CAAK,gBAAA,GAAmB,KAAA;AACxB,IAAA,IAAA,CAAK,aAAA,EAAc;AACnB,IAAA,MAAM,MAAA,GAAkC,EAAE,KAAA,EAAO,IAAA,EAAM,SAAS,EAAA,EAAG;AACnE,IAAA,IAAA,CAAK,QAAA,CAAS,UAAA,EAAY,EAAE,MAAA,EAAQ,CAAA;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAA,GAAsB;AACpB,IAAA,IAAA,CAAK,qBAAA,EAAsB;AAC3B,IAAA,IAAA,CAAK,oBAAA,EAAqB;AAE1B,IAAA,MAAM,KAAA,GAAQ,KAAK,YAAA,EAAa;AAChC,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,gBAAA,IAAoB,KAAA,CAAM,MAAA,GAAS,CAAA;AACxD,IAAA,IAAA,CAAK,OAAA,CAAQ,eAAA,CAAgB,IAAA,CAAK,iBAAA,EAAmB,OAAO,CAAA;AAE5D,IAAA,MAAM,UAAU,IAAA,CAAK,cAAA;AACrB,IAAA,IAAI,CAAC,OAAA,EAAS;AAEd,IAAA,IAAA,CAAK,YAAA,CAAa,KAAA,CAAM,OAAA,EAAS,OAAA,GAAU,SAAS,OAAO,CAAA;AAE3D,IAAA,MAAM,cAAA,GAAiB,KAAA,CAAM,CAAC,CAAA,EAAG,EAAA,IAAM,IAAA;AACvC,IAAA,IAAA,CAAK,iBAAA,CAAkB,KAAA,CAAM,OAAA,EAAS,cAAc,CAAA;AAEpD,IAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,gBAAA,CAAiB,CAAC,GAAG,KAAK,kBAAA,EAAoB,GAAG,KAAK,CAAC,CAAA,CAAE,GAAA;AAAA,MACnF,CAAC,YAAY,OAAA,CAAQ;AAAA,KACvB;AACA,IAAA,MAAM,WAAA,GAAc,KAAK,aAAA,CAAc,CAAC,GAAG,IAAA,CAAK,gBAAA,EAAkB,GAAG,cAAc,CAAC,CAAA;AACpF,IAAA,IAAA,CAAK,gBAAA,CAAiB,KAAA,CAAM,OAAA,EAAS,WAAA,CAAY,MAAA,GAAS,IAAI,WAAA,CAAY,IAAA,CAAK,GAAG,CAAA,GAAI,IAAI,CAAA;AAAA,EAC5F;AAAA;AAAA,EAGA,qBAAA,GAA8B;AAC5B,IAAA,KAAA,MAAW,WAAA,IAAe,KAAK,kBAAA,EAAoB;AACjD,MAAA,QAAA,CAAS,aAAa,yBAAyB,CAAA;AAAA,IACjD;AACA,IAAA,KAAA,MAAW,KAAA,IAAS,KAAK,YAAA,EAAc;AACrC,MAAA,QAAA,CAAS,OAAO,0BAA0B,CAAA;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA,EAGA,oBAAA,GAA6B;AAC3B,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,gBAAA,GAAmB,IAAA,CAAK,aAAA,GAAgB,IAAA;AAC1D,IAAA,IAAI,IAAA,KAAS,KAAK,cAAA,EAAgB;AAClC,IAAA,IAAA,CAAK,cAAA,IAAkB,IAAA,CAAK,eAAA,CAAgB,IAAA,CAAK,cAAc,CAAA;AAC/D,IAAA,IAAA,CAAK,cAAA,GAAiB,IAAA;AACtB,IAAA,IAAA,CAAK,mBAAmB,IAAA,GAAO,IAAA,CAAK,0BAAA,CAA2B,IAAI,IAAI,EAAC;AAAA,EAC1E;AAAA;AAAA,EAGA,gBAAgB,OAAA,EAA4B;AAC1C,IAAA,IAAA,CAAK,gBAAA,CAAiB,OAAO,OAAO,CAAA;AACpC,IAAA,IAAA,CAAK,iBAAA,CAAkB,OAAO,OAAO,CAAA;AACrC,IAAA,IAAA,CAAK,YAAA,CAAa,OAAO,OAAO,CAAA;AAChC,IAAA,IAAI,OAAA,KAAY,KAAK,cAAA,EAAgB;AACnC,MAAA,IAAA,CAAK,cAAA,GAAiB,IAAA;AACtB,MAAA,IAAA,CAAK,mBAAmB,EAAC;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA,EAGA,YAAA,GAA8B;AAC5B,IAAA,OAAO,IAAA,CAAK,gBAAA;AAAA,MACV,IAAA,CAAK,YAAA,CAAa,MAAA,CAAO,CAAC,KAAA,KAAU,CAAC,KAAA,CAAM,MAAA,IAAA,CAAW,KAAA,CAAM,WAAA,IAAe,EAAA,EAAI,IAAA,OAAW,EAAE;AAAA,KAC9F;AAAA,EACF;AAAA;AAAA,EAGA,aAAA,GAAwB;AACtB,IAAA,OAAA,CAAQ,KAAK,YAAA,EAAa,CAAE,CAAC,CAAA,EAAG,WAAA,IAAe,IAAI,IAAA,EAAK;AAAA,EAC1D;AAAA;AAAA,EAGA,gBAAgB,GAAA,EAA2C;AACzD,IAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,GAAA;AACpC,IAAA,MAAM,OAAA,GAAU,KAAK,MAAA,EAAQ,OAAA;AAC7B,IAAA,OAAO,OAAO,OAAA,KAAY,QAAA,GAAW,OAAA,GAAU,IAAA;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,2BAA2B,OAAA,EAAgC;AACzD,IAAA,MAAM,KAAA,uBAAY,GAAA,CAAI;AAAA,MACpB,GAAG,IAAA,CAAK,kBAAA,CAAmB,IAAI,CAAC,WAAA,KAAgB,YAAY,EAAE,CAAA;AAAA,MAC9D,GAAG,IAAA,CAAK,YAAA,CAAa,IAAI,CAAC,KAAA,KAAU,MAAM,EAAE;AAAA,KAC7C,CAAA;AACD,IAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,YAAA,CAAa,kBAAkB,CAAA,IAAK,EAAA;AAC7D,IAAA,OAAO,IAAA,CAAK,aAAA;AAAA,MACV,QAAA,CAAS,KAAA,CAAM,KAAK,CAAA,CAAE,OAAO,CAAC,KAAA,KAAU,KAAA,CAAM,MAAA,GAAS,CAAA,IAAK,CAAC,KAAA,CAAM,GAAA,CAAI,KAAK,CAAC;AAAA,KAC/E;AAAA,EACF;AAAA;AAAA,EAGA,cAAc,MAAA,EAA4B;AACxC,IAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,IAAA,OAAO,MAAA,CAAO,MAAA,CAAO,CAAC,KAAA,KAAU;AAC9B,MAAA,IAAI,MAAM,MAAA,KAAW,CAAA,IAAK,KAAK,GAAA,CAAI,KAAK,GAAG,OAAO,KAAA;AAClD,MAAA,IAAA,CAAK,IAAI,KAAK,CAAA;AACd,MAAA,OAAO,IAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,iBAAiB,QAAA,EAAwC;AACvD,IAAA,MAAM,UAAA,GAAa,IAAI,GAAA,CAAI,QAAQ,CAAA;AACnC,IAAA,OAAO,CAAC,KAAK,OAAA,EAAS,GAAG,KAAK,OAAA,CAAQ,gBAAA,CAA8B,GAAG,CAAC,CAAA,CAAE,MAAA;AAAA,MAAO,CAAC,OAAA,KAChF,UAAA,CAAW,GAAA,CAAI,OAAO;AAAA,KACxB;AAAA,EACF;AAAA;AAAA,EAGA,oBAAoB,MAAA,EAAiC;AACnD,IAAA,MAAM,SAAS,MAAA,CAAO,MAAA;AACtB,IAAA,IAAI,MAAA,CAAO,SAAS,YAAA,EAAc;AAChC,MAAA,IAAI,OAAO,aAAA,KAAkB,QAAA;AAC3B,QAAA,OAAO,IAAA,CAAK,YAAA,CAAa,QAAA,CAAS,MAAqB,CAAA;AACzD,MAAA,OACE,MAAA,CAAO,aAAA,KAAkB,IAAA,IACzB,CAAC,GAAG,IAAA,CAAK,kBAAA,EAAoB,GAAG,IAAA,CAAK,YAAY,CAAA,CAAE,QAAA,CAAS,MAAqB,CAAA;AAAA,IAErF;AAEA,IAAA,OAAO,UAAA,CAAW,IAAA,CAAK,YAAA,EAAc,MAAM,CAAA,KAAM,EAAA;AAAA,EACnD;AAAA;AAAA,EAEA,eAAA,GAAwB;AACtB,IAAA,IAAA,CAAK,iBAAiB,SAAA,EAAU;AAChC,IAAA,IAAA,CAAK,kBAAkB,SAAA,EAAU;AACjC,IAAA,IAAA,CAAK,aAAa,SAAA,EAAU;AAAA,EAC9B;AACF","file":"form_field_controller.js","sourcesContent":["/**\n * Sends one message to the page's shared `stimeo--announcer`.\n *\n * A component that has to reach assistive tech does not carry a live region of its\n * own: a region only announces what changes *after* assistive tech already knows\n * about it, which a region that appears (or is un-hidden) with its message cannot\n * satisfy. The one region that can is the announcer sitting in the page from the\n * start, so state changes are handed to it as an event and it does the reading.\n *\n * The event goes to `window` because the announcer is usually a sibling high in the\n * document rather than an ancestor of the component dispatching it.\n *\n * Wording comes from the consumer — the library ships no English strings — so an\n * empty message is silently dropped and nothing is announced.\n *\n * @example\n * ```ts\n * announce(this.announceTextValue, { assertive: false });\n * ```\n */\nexport function announce(message: string, options: { assertive?: boolean } = {}): void {\n const text = message.trim();\n if (text.length === 0) return;\n window.dispatchEvent(\n new CustomEvent(\"stimeo--announcer:announce\", {\n detail: { message: text, assertive: options.assertive === true },\n }),\n );\n}\n\n/**\n * Fills `{name}` placeholders in an announcement template from `values`.\n *\n * The same substitution the value-text templates use, so a consumer writes\n * `\"{percent}% complete\"` in one attribute and gets the same rules everywhere. A\n * placeholder with no matching entry is left as authored rather than blanked, which\n * keeps a typo visible instead of silently swallowing the word.\n */\nexport function fillTemplate(template: string, values: Record<string, string | number>): string {\n return template.replace(/\\{([a-zA-Z][a-zA-Z0-9]*)\\}/g, (match, name: string) => {\n const replacement = values[name];\n return replacement === undefined ? match : String(replacement);\n });\n}\n","/**\n * Minimal id primitives for wiring ARIA relationships.\n *\n * Accessible relationships such as `aria-describedby`, `aria-errormessage`,\n * `aria-labelledby`, and `aria-activedescendant` reference their targets by DOM\n * `id`. When a controller must establish such a relationship but the consumer's\n * markup left the target without an `id`, it needs to mint one that is stable for\n * the page's lifetime and guaranteed not to collide with another generated id.\n *\n * These helpers own *only* id generation/assignment. The linking policy (which\n * attribute, what order, when to add or remove it) stays in each controller —\n * this deliberately avoids a premature generic \"ARIA linker\" abstraction.\n */\n\n/**\n * Monotonic counter backing {@link uniqueId}. Module-scoped so every generated\n * id is unique across all controller instances sharing this module in a document.\n */\nlet counter = 0;\n\n/**\n * Returns a unique, DOM-id-safe string of the form `` `${prefix}-${n}` `` where\n * `n` increases on each call.\n *\n * The counter alone guarantees uniqueness against other *generated* ids, but a\n * consumer-authored element could already own `` `${prefix}-${n}` ``. When a\n * `document` is available the candidate is therefore advanced until no element\n * with that id exists, so a generated id never collides with author markup\n * either — the minimal \"id registry\" guarantee these helpers exist to provide.\n *\n * @param prefix - Leading segment of the id (e.g. a controller's identifier).\n * Defaults to `\"stimeo\"`.\n */\nexport function uniqueId(prefix = \"stimeo\"): string {\n let candidate: string;\n do {\n counter += 1;\n candidate = `${prefix}-${counter}`;\n } while (typeof document !== \"undefined\" && document.getElementById(candidate) !== null);\n return candidate;\n}\n\n/**\n * Returns `element`'s existing `id`, or assigns it a freshly generated\n * {@link uniqueId} (with the given `prefix`) and returns that. Idempotent: an\n * element that already has an id keeps it, so consumer-authored ids are never\n * overwritten.\n *\n * @param element - The element to read or stamp an `id` onto.\n * @param prefix - Prefix forwarded to {@link uniqueId} when one must be generated.\n * @returns The element's id (existing or newly assigned).\n */\nexport function ensureId(element: Element, prefix = \"stimeo\"): string {\n if (element.id) return element.id;\n const id = uniqueId(prefix);\n element.id = id;\n return id;\n}\n","/** One temporarily controlled attribute value and the authored value it displaced. */\ninterface AttributeLeaseRecord {\n readonly original: string | null;\n written: string | null;\n}\n\n/**\n * Temporarily controls one attribute across a changing set of elements.\n *\n * The first write remembers the authored value, including the distinction between\n * an absent attribute and an authored empty string. Returning a lease restores that\n * value only while the attribute still matches the controller's last write. If a\n * consumer changed it in the meantime, the consumer owns the new value and teardown\n * leaves it alone.\n *\n * A `null` write deliberately removes the attribute while retaining the lease. This\n * is useful for derived ARIA whose valid absence is itself controller state, such as\n * an unbounded `aria-valuemin` or a blank spinbutton's `aria-valuenow`.\n *\n * The lease has no lifecycle of its own, so it never subscribes to document events.\n * A consumer that must not let a derived value become the authored baseline of a\n * cached page returns its leases from its own `turbo:before-cache` rewind, where the\n * matching `disconnect()` also releases the subscription.\n */\nexport class AttributeLease<T extends Element = Element> {\n readonly #attribute: string;\n readonly #records = new Map<T, AttributeLeaseRecord>();\n\n /** @param attribute - The attribute whose temporary values this lease owns. */\n constructor(attribute: string) {\n this.#attribute = attribute;\n }\n\n /** Writes or removes the leased attribute while preserving its authored value. */\n write(element: T, value: string | null): void {\n const existing = this.#records.get(element);\n if (existing) {\n existing.written = value;\n } else {\n this.#records.set(element, {\n original: element.getAttribute(this.#attribute),\n written: value,\n });\n }\n\n this.#reflect(element, value);\n }\n\n /** Returns one lease without overwriting a value subsequently authored by a consumer. */\n return(element: T): void {\n const record = this.#records.get(element);\n if (!record) return;\n this.#records.delete(element);\n const stillOwned = element.getAttribute(this.#attribute) === record.written;\n if (stillOwned) this.#reflect(element, record.original);\n }\n\n /** Reflects only a real value transition, avoiding self-triggered mutation work. */\n #reflect(element: T, value: string | null): void {\n if (element.getAttribute(this.#attribute) === value) return;\n if (value === null) element.removeAttribute(this.#attribute);\n else element.setAttribute(this.#attribute, value);\n }\n\n /** Returns every outstanding lease using the same ownership check as {@link return}. */\n returnAll(): void {\n for (const element of Array.from(this.#records.keys())) this.return(element);\n }\n}\n","/**\n * Runs a controller's \"return to the initial state\" pass just before Turbo\n * caches the page.\n *\n * **`disconnect()` cannot do this job, for two independent reasons.** Turbo\n * queues the clone from this event rather than taking it here, and the body swap\n * that runs the controller's `disconnect()` is queued separately — so which of\n * the two lands first is not something a controller can rely on, and a rewind\n * written in `disconnect()` may reach only the DOM being thrown away. In the\n * other direction, `disconnect()` also fires on an in-page move (Stimulus tears\n * down and reconnects the same element), where rewinding would wipe a\n * legitimately in-progress interaction — a spinner mid-load would vanish. One\n * timing is unreliable, the other is too eager; `turbo:before-cache` is the only\n * point that is exactly \"the page is about to be frozen\".\n *\n * Scope is the subscription only: registering on `activate()`, unregistering on\n * `deactivate()`, and one shared document listener no matter how many instances\n * are live. *What* to return to its initial state — which `data-state`, which\n * `hidden`, which `aria-busy` — stays in the controller, because no two\n * consumers answer it the same way.\n *\n * **Rewind state, not appearance.** The pass writes attributes the controller\n * itself owns; the visual result of those attributes is the consumer's CSS, and\n * a library that reached for style or class names would be guessing at markup\n * it does not own.\n *\n * Both entry points are idempotent, so the lifecycle hooks can call them\n * unconditionally: a second `activate()` does not double-subscribe and does not\n * make the callback run twice, and `deactivate()` on an instance that never\n * subscribed is a no-op.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #beforeCache = new BeforeCacheReset(() => this.#rewind());\n *\n * connect() { this.#beforeCache.activate(); }\n * disconnect() { this.#beforeCache.deactivate(); }\n * ```\n */\nexport class BeforeCacheReset {\n /** Every subscribed instance, iterated by the one shared document listener. */\n static readonly #subscribers = new Set<BeforeCacheReset>();\n\n /** The shared listener; installed while at least one instance is subscribed. */\n static readonly #onBeforeCache = (): void => {\n for (const subscriber of BeforeCacheReset.#subscribers) subscriber.#rewind();\n };\n\n readonly #rewind: () => void;\n\n /** @param rewind - the pass that returns this controller's state to its initial form. */\n constructor(rewind: () => void) {\n this.#rewind = rewind;\n }\n\n /** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */\n activate(): void {\n const first = BeforeCacheReset.#subscribers.size === 0;\n BeforeCacheReset.#subscribers.add(this);\n if (first) {\n document.addEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n }\n\n /** Unsubscribes; call from `disconnect()`. Safe when never subscribed. */\n deactivate(): void {\n BeforeCacheReset.#subscribers.delete(this);\n if (BeforeCacheReset.#subscribers.size > 0) return;\n document.removeEventListener(\"turbo:before-cache\", BeforeCacheReset.#onBeforeCache);\n }\n}\n","/**\n * Resolves which of a controller's elements owns a node.\n *\n * A delegated listener hears events from a whole subtree, so the handler's first\n * job is almost always the same question: which item, handle, or control does\n * this `event.target` belong to? The same question comes up for a\n * `MutationRecord.target`, for `document.activeElement`, and for a\n * `relatedTarget` on the way out of a hover region.\n *\n * The answer is `Node.contains()`, which is **inclusive** — an element contains\n * itself — so testing the candidate for identity as well would be redundant.\n *\n * **The guard is what makes this safe to call with a raw event target.**\n * `event.target` is typed `EventTarget | null`, and `contains()` takes a `Node?`:\n * browsers throw `TypeError` for anything else, and `window` — the everyday\n * `EventTarget` that is not a `Node` — is what an event dispatched at it carries.\n * Narrowing here means a caller never has to cast, and the rule cannot drift\n * between the places that ask the question.\n *\n * Scope stays with the caller. These helpers say *which candidate owns the node*,\n * not *whether the node belongs to this controller at all* — a component with\n * nested instances of itself decides that first (by comparing the closest\n * annotated ancestor) and passes the candidates it owns.\n */\n\n/**\n * Index in `candidates` of the first one that is, or contains, `node`.\n *\n * `-1` when none does, when `node` is absent, and when it is an `EventTarget`\n * that is not a `Node`. Candidates are tested in array order, so a nested pair\n * resolves to whichever the caller listed first.\n */\nexport function ownerIndex<T extends Element>(\n candidates: readonly T[],\n node: EventTarget | null | undefined,\n): number {\n if (!(node instanceof Node)) return -1;\n return candidates.findIndex((candidate) => candidate.contains(node));\n}\n\n/**\n * The first candidate that is, or contains, `node`; `null` when none does.\n *\n * A miss indexes the array at `-1`, which reads as `undefined` and lands on the\n * same `null` the absent cases produce.\n */\nexport function ownerOf<T extends Element>(\n candidates: readonly T[],\n node: EventTarget | null | undefined,\n): T | null {\n return candidates[ownerIndex(candidates, node)] ?? null;\n}\n","/**\n * Collapses many Stimulus lifecycle callbacks from one DOM mutation into a\n * single pass.\n *\n * Stimulus fires `<name>TargetConnected` / `Disconnected` once per element and\n * `<name>ValueChanged` once per changed attribute. Replacing a list of N options\n * or morphing several render Values therefore delivers N callbacks — but the\n * useful unit of work is \"reconcile against the resulting declarative input\",\n * once, after the batch has settled. Every controller with reconcilable targets\n * or render Values needs the same shape: a `queued` flag plus `queueMicrotask`.\n *\n * **A microtask is the right horizon, and the reason is specific.** Stimulus\n * drives these callbacks from a `MutationObserver`, whose own callback already\n * runs as a microtask with the whole batch in hand; scheduling one more lands\n * after the last sibling callback of that batch and still before paint or any\n * event handler. A timer would be later than it needs to be, and reconciling\n * synchronously would run once per element against a half-applied DOM.\n *\n * **The two guards are not the same guard.** Scheduling is refused before the\n * controller connects, and running is refused after it disconnects:\n *\n * - **Before `connect()`** — Stimulus delivers initial target and Value callbacks\n * ahead of `connect()`. Reconciling there would compute output against a\n * controller whose own state has not been initialised, and `connect()` is\n * about to do a full pass anyway.\n * - **After `disconnect()`** — Stimulus fires a callback for **every** target\n * during teardown, and a microtask queued just before it would otherwise run\n * against a detached tree. {@link MicrotaskCoalescer.cancel} exists for the\n * teardown path to drop the pending pass outright.\n *\n * Both guards are part of one contract here rather than something each consumer\n * has to remember separately.\n *\n * Scope is the scheduling only. *What* to reconcile — keep the surviving active\n * option, fall back to the next / previous / first visible one, rebuild derived\n * chips or hidden fields — stays in the controller, because no two consumers\n * answer it the same way.\n *\n * This file's own doc block is dropped from `dist`, but every member comment is\n * inlined into each consumer entry (`tsup` builds with `splitting: false`), so\n * rationale belongs here and only the contract belongs on the members.\n *\n * @example\n * ```ts\n * readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileOptions());\n *\n * connect() { this.#reconcile.activate(); }\n * disconnect() { this.#reconcile.cancel(); }\n *\n * optionTargetConnected() { this.#reconcile.schedule(); }\n * optionTargetDisconnected() { this.#reconcile.schedule(); }\n * ```\n */\nexport class MicrotaskCoalescer {\n readonly #run: () => void;\n #queued = false;\n #active = false;\n #generation = 0;\n\n /** @param run - the single reconciliation pass, invoked at most once per batch. */\n constructor(run: () => void) {\n this.#run = run;\n }\n\n /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */\n activate(): void {\n this.#active = true;\n }\n\n /** Closes the window and drops any pending pass; call from `disconnect()`. */\n cancel(): void {\n this.#active = false;\n this.#queued = false;\n this.#generation += 1;\n }\n\n /** Requests one pass after the batch settles. Idempotent; inert outside the window. */\n schedule(): void {\n if (!this.#active || this.#queued) return;\n this.#queued = true;\n const generation = this.#generation;\n queueMicrotask(() => {\n // A cancelled callback must not consume a pass queued after reconnect.\n if (generation !== this.#generation || !this.#queued || !this.#active) return;\n this.#queued = false;\n this.#run();\n });\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { announce } from \"../utils/announce\";\nimport { ensureId } from \"../utils/aria_ids\";\nimport { AttributeLease } from \"../utils/attribute_lease\";\nimport { BeforeCacheReset } from \"../utils/before_cache_reset\";\nimport { ownerIndex } from \"../utils/event_owner\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\n\n/** Stimulus action params understood by {@link FormFieldController.setError}. */\ninterface SetErrorParams {\n /** The error message to display. */\n message?: string;\n}\n\n/** An action event carrying Stimulus `data-*-param` values. */\ntype ActionEvent = Event & { params?: SetErrorParams };\n\n/** Programmatic behavior switches for {@link FormFieldController.setError}. */\nexport interface FormFieldSetErrorOptions {\n /** Override the `focusOnError` Value for this call. */\n focus?: boolean;\n}\n\n/** Detail dispatched with `stimeo--form-field:validate`. */\nexport interface FormFieldValidateDetail {\n /** Whether the explicit validation action left the field valid. */\n valid: boolean;\n /** The first visible error message, or an empty string when valid/unavailable. */\n message: string;\n}\n\n/** Attributes on retained association targets that can change the ARIA graph. */\nconst OBSERVED_ATTRIBUTES = [\"hidden\", \"id\"];\n\n/**\n * Headless, accessible form-field association behavior.\n *\n * Markup contract (identifier: `stimeo--form-field`):\n * <div data-controller=\"stimeo--form-field\">\n * <label for=\"email\">Email</label>\n * <input id=\"email\" type=\"email\" aria-invalid=\"false\"\n * data-stimeo--form-field-target=\"control\" />\n * <p data-stimeo--form-field-target=\"description\">We'll send a confirmation.</p>\n * <p hidden data-stimeo--form-field-target=\"error\"></p>\n * </div>\n *\n * Not an APG widget pattern — this is the wiring substrate behind form controls:\n * it supports **Name, Role, Value** (WCAG 4.1.2) and **error identification**\n * (3.3.1 / 4.1.3) by composing the control's `aria-describedby`, toggling\n * `aria-invalid`, and pointing `aria-errormessage` at the visual error.\n *\n * `validate` dispatches `{ valid: boolean, message: string }`.\n *\n * @remarks\n * Behavior only — it sets semantic attributes and the `hidden` state of the\n * visual error; it never validates input (the consumer / server decides) and\n * never styles. Runtime errors are handed to a separately seated\n * `stimeo--announcer`, because showing a live region together with its first\n * message is not a reliable announcement primitive.\n *\n * Behavior provided:\n * - Assigns ids to description/error targets and composes the control's\n * `aria-describedby` from them in DOM order (preserving the control's authored\n * tokens and removing duplicates).\n * - Reflects server-rendered errors: an error target that is already visible and\n * non-empty at connect puts the field into the invalid state (progressive\n * enhancement).\n * - Reconciles added, removed, replaced, and retained/morphed targets without\n * emitting validation events or announcements.\n * - {@link setError} / {@link clearError} drive the invalid state at runtime and\n * dispatch `stimeo--form-field:validate`.\n */\nexport class FormFieldController extends Controller<HTMLElement> {\n static override targets = [\"control\", \"description\", \"error\"];\n static override values = {\n focusOnError: { type: Boolean, default: false },\n };\n static actions = [\"clearError\", \"setError\"] as const;\n static events = [\"validate\"] as const;\n\n declare readonly controlTarget: HTMLElement;\n declare readonly hasControlTarget: boolean;\n declare readonly descriptionTargets: HTMLElement[];\n declare readonly errorTargets: HTMLElement[];\n declare readonly hasErrorTarget: boolean;\n /** Whether an explicit {@link setError} call moves focus to the current control. */\n declare focusOnErrorValue: boolean;\n\n /** Root attribute (CSS hook) reflecting the invalid state, in this controller's namespace. */\n get #invalidAttribute(): string {\n return `data-${this.identifier}-invalid`;\n }\n\n /** Collapses one target/morph batch into one silent ARIA reconciliation. */\n readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileDom());\n /** Returns borrowed control ARIA before Turbo snapshots the page. */\n readonly #beforeCache = new BeforeCacheReset(() => this.#rewindForCache());\n readonly #ariaDescribedBy = new AttributeLease<HTMLElement>(\"aria-describedby\");\n readonly #ariaErrorMessage = new AttributeLease<HTMLElement>(\"aria-errormessage\");\n readonly #ariaInvalid = new AttributeLease<HTMLElement>(\"aria-invalid\");\n /** Watches retained target ids, error visibility, and error content. */\n readonly #observer = new MutationObserver((records) => {\n if (records.some((record) => this.#isRelevantMutation(record))) {\n this.#reconcile.schedule();\n }\n });\n\n #activeControl: HTMLElement | null = null;\n #baseDescribedBy: string[] = [];\n #explicitInvalid = false;\n #initialized = false;\n\n /** Wires the initial graph and starts retained-target reconciliation. */\n override connect(): void {\n this.#reconcile.activate();\n this.#ensureAssociationIds();\n this.#beforeCache.activate();\n\n // A restored DOM can contain the invalid hook with no surviving visual\n // message. Treat that one shape as the persisted explicit setError state;\n // visible server errors remain derived and can clear when their DOM clears.\n if (!this.#initialized) {\n this.#explicitInvalid =\n this.element.hasAttribute(this.#invalidAttribute) && this.#shownErrors().length === 0;\n this.#initialized = true;\n }\n\n this.#reconcileDom();\n this.#observer.observe(this.element, {\n attributes: true,\n attributeFilter: OBSERVED_ATTRIBUTES,\n characterData: true,\n childList: true,\n subtree: true,\n });\n }\n\n /** Releases observers, queued work, and ARIA borrowed on the current control. */\n override disconnect(): void {\n this.#reconcile.cancel();\n this.#observer.disconnect();\n this.#beforeCache.deactivate();\n this.#activeControl && this.#releaseControl(this.#activeControl);\n }\n\n /** Reconciles a control inserted or replaced at runtime. */\n controlTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Schedules restoration of authored ARIA when a control leaves this field. */\n controlTargetDisconnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Reconciles a description inserted or replaced at runtime. */\n descriptionTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Removes a departed description from the control's association graph. */\n descriptionTargetDisconnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Reconciles an error region inserted or replaced at runtime. */\n errorTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Removes a departed error from invalid state and the association graph. */\n errorTargetDisconnected(): void {\n this.#reconcile.schedule();\n }\n\n /**\n * Marks the field invalid and shows the error message. Bound via `data-action`\n * (`#setError`) or callable directly.\n *\n * A non-empty shown message is announced exactly once through the shared\n * assertive announcer. Initial/server reconciliation is deliberately silent.\n *\n * @param arg - Either the message string, or the action event whose\n * `data-stimeo--form-field-message-param` supplies it. When no message is\n * resolvable, any already-populated error targets are simply (re)shown.\n * @param options - Programmatic overrides. Stimulus actions use the Values.\n */\n setError(arg?: string | ActionEvent, options: FormFieldSetErrorOptions = {}): void {\n const message = this.#resolveMessage(arg);\n if (message !== null && this.hasErrorTarget) {\n this.errorTargets[0]?.replaceChildren(document.createTextNode(message));\n }\n for (const error of this.errorTargets) {\n error.hidden = (error.textContent ?? \"\").trim() === \"\";\n }\n\n // setError is an explicit invalid request: it remains invalid even if an\n // error target is absent or replaced before clearError is called.\n this.#explicitInvalid = true;\n this.#reconcileDom();\n const shownMessage = this.#shownMessage();\n const detail: FormFieldValidateDetail = { valid: false, message: shownMessage };\n this.dispatch(\"validate\", { detail });\n announce(shownMessage, { assertive: true });\n\n if (options.focus ?? this.focusOnErrorValue) this.#activeControl?.focus();\n }\n\n /**\n * Clears the error: empties and hides every error target and marks the field\n * valid. Bound via `data-action` (`#clearError`) or callable directly.\n *\n * Clearing is silent: the visual/ARIA state and validation event are sufficient,\n * while success wording remains an explicit consumer announcement.\n */\n clearError(): void {\n for (const error of this.errorTargets) {\n error.replaceChildren();\n error.hidden = true;\n }\n this.#explicitInvalid = false;\n this.#reconcileDom();\n const detail: FormFieldValidateDetail = { valid: true, message: \"\" };\n this.dispatch(\"validate\", { detail });\n }\n\n /**\n * Rebuilds ids and derived ARIA from the settled target graph without reporting\n * a user validation action.\n */\n #reconcileDom(): void {\n this.#ensureAssociationIds();\n this.#adoptCurrentControl();\n\n const shown = this.#shownErrors();\n const invalid = this.#explicitInvalid || shown.length > 0;\n this.element.toggleAttribute(this.#invalidAttribute, invalid);\n\n const control = this.#activeControl;\n if (!control) return;\n\n this.#ariaInvalid.write(control, invalid ? \"true\" : \"false\");\n\n const primaryErrorId = shown[0]?.id ?? null;\n this.#ariaErrorMessage.write(control, primaryErrorId);\n\n const associationIds = this.#orderedElements([...this.descriptionTargets, ...shown]).map(\n (element) => element.id,\n );\n const describedBy = this.#uniqueTokens([...this.#baseDescribedBy, ...associationIds]);\n this.#ariaDescribedBy.write(control, describedBy.length > 0 ? describedBy.join(\" \") : null);\n }\n\n /** Assigns stable ids before either capture or reflection uses them. */\n #ensureAssociationIds(): void {\n for (const description of this.descriptionTargets) {\n ensureId(description, \"stimeo--form-field-desc\");\n }\n for (const error of this.errorTargets) {\n ensureId(error, \"stimeo--form-field-error\");\n }\n }\n\n /** Switches ARIA ownership when the singular current control target changes. */\n #adoptCurrentControl(): void {\n const next = this.hasControlTarget ? this.controlTarget : null;\n if (next === this.#activeControl) return;\n this.#activeControl && this.#releaseControl(this.#activeControl);\n this.#activeControl = next;\n this.#baseDescribedBy = next ? this.#externalDescribedByTokens(next) : [];\n }\n\n /** Restores one departed control without overwriting later consumer edits. */\n #releaseControl(control: HTMLElement): void {\n this.#ariaDescribedBy.return(control);\n this.#ariaErrorMessage.return(control);\n this.#ariaInvalid.return(control);\n if (control === this.#activeControl) {\n this.#activeControl = null;\n this.#baseDescribedBy = [];\n }\n }\n\n /** Error targets currently visible and non-empty, in document order. */\n #shownErrors(): HTMLElement[] {\n return this.#orderedElements(\n this.errorTargets.filter((error) => !error.hidden && (error.textContent ?? \"\").trim() !== \"\"),\n );\n }\n\n /** Text of the first shown error, for validation detail and announcement. */\n #shownMessage(): string {\n return (this.#shownErrors()[0]?.textContent ?? \"\").trim();\n }\n\n /** Resolves a message from a string argument or an action event's params. */\n #resolveMessage(arg?: string | ActionEvent): string | null {\n if (typeof arg === \"string\") return arg;\n const message = arg?.params?.message;\n return typeof message === \"string\" ? message : null;\n }\n\n /**\n * Tokens authored on a newly adopted control, excluding ids this controller\n * owns through its current description/error targets.\n */\n #externalDescribedByTokens(control: HTMLElement): string[] {\n const owned = new Set([\n ...this.descriptionTargets.map((description) => description.id),\n ...this.errorTargets.map((error) => error.id),\n ]);\n const existing = control.getAttribute(\"aria-describedby\") ?? \"\";\n return this.#uniqueTokens(\n existing.split(/\\s+/).filter((token) => token.length > 0 && !owned.has(token)),\n );\n }\n\n /** Deduplicates ARIA tokens without disturbing their first occurrence. */\n #uniqueTokens(tokens: string[]): string[] {\n const seen = new Set<string>();\n return tokens.filter((token) => {\n if (token.length === 0 || seen.has(token)) return false;\n seen.add(token);\n return true;\n });\n }\n\n /** Returns unique current targets in DOM order before serializing IDREF lists. */\n #orderedElements(elements: HTMLElement[]): HTMLElement[] {\n const candidates = new Set(elements);\n return [this.element, ...this.element.querySelectorAll<HTMLElement>(\"*\")].filter((element) =>\n candidates.has(element),\n );\n }\n\n /** Whether one retained-node mutation can alter this controller's derived state. */\n #isRelevantMutation(record: MutationRecord): boolean {\n const target = record.target;\n if (record.type === \"attributes\") {\n if (record.attributeName === \"hidden\")\n return this.errorTargets.includes(target as HTMLElement);\n return (\n record.attributeName === \"id\" &&\n [...this.descriptionTargets, ...this.errorTargets].includes(target as HTMLElement)\n );\n }\n\n return ownerIndex(this.errorTargets, target) !== -1;\n }\n /** Returns borrowed control ARIA before Turbo snapshots the page. */\n #rewindForCache(): void {\n this.#ariaDescribedBy.returnAll();\n this.#ariaErrorMessage.returnAll();\n this.#ariaInvalid.returnAll();\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/utils/announce.ts","../../src/utils/shared_registry.ts","../../src/utils/aria_ids.ts","../../src/utils/attribute_write.ts","../../src/utils/attribute_lease.ts","../../src/utils/event_owner.ts","../../src/utils/microtask_coalescer.ts","../../src/controllers/form_field_controller.ts"],"names":["registry"],"mappings":"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","file":"form_field_controller.js","sourcesContent":["export { fillTemplate } from \"./template\";\n\n/**\n * Sends one message to the page's shared `stimeo--announcer`.\n *\n * A message that has to reach assistive tech is not put into a live region created\n * or un-hidden along with it: a region only announces what changes *after* assistive\n * tech already knows about it, which such a region cannot satisfy. The announcer has\n * to be in the page before any message is handed to it — one sent while no announcer\n * is listening is not read — so state changes reach it as an event and it does the\n * reading.\n *\n * The event goes to `window` because the announcer is usually a sibling high in the\n * document rather than an ancestor of the component dispatching it.\n *\n * Wording comes from the consumer — this helper adds no text of its own — so an\n * empty message is silently dropped and nothing is announced.\n *\n * @example\n * ```ts\n * announce(this.announceTextValue, { assertive: false });\n * ```\n */\nexport function announce(message: string, options: { assertive?: boolean } = {}): void {\n const text = message.trim();\n if (text.length === 0) return;\n window.dispatchEvent(\n new CustomEvent(\"stimeo--announcer:announce\", {\n detail: { message: text, assertive: options.assertive === true },\n }),\n );\n}\n","/**\n * One registry per page for every copy of the library.\n *\n * Each `stimeo-ui/controllers/*` file, and each opt-in entry, is built on its own and carries\n * its own copy of every utility it uses, so a page that imports controllers one by one, or one\n * of them next to the barrel, evaluates a utility several times. A registry that coordinates\n * instances of different controllers — the stacks of leased values, the loans of a\n * `tabindex`, the Escape layers, the focus traps — must not be split by that: a dialog inside\n * a drawer, or a character counter and a form field on one input, coordinate whichever files\n * they came from. So such a registry lives once on `globalThis`, under a `Symbol.for` key the\n * copies agree on, and the first copy to ask for it creates it.\n *\n * The key names the registry and the version of its shape\n * (`stimeo-ui.<utility>.registry.v<n>`). Copies whose registries have the same shape share\n * one; a release that changes the shape changes the version, so a copy of another release\n * keeps a registry of its own instead of reading entries it does not understand — the two\n * then coordinate within each release only. An entry another copy put in a registry is read\n * through its fields alone, never through `#private` members, which belong to the class of\n * the copy that created it.\n */\n\n/**\n * The registry stored under `key`, created by `create` on first use.\n *\n * @param key - `stimeo-ui.<utility>.registry.v<n>`: the version is that of the shape `create`\n * returns.\n * @param create - Builds the empty registry.\n */\nexport function sharedRegistry<T extends object>(key: string, create: () => T): T {\n const symbol = Symbol.for(key);\n const scope = globalThis as unknown as Record<symbol, T | undefined>;\n const existing = scope[symbol];\n if (existing !== undefined) return existing;\n const registry = create();\n Object.defineProperty(globalThis, symbol, { value: registry });\n return registry;\n}\n","import { sharedRegistry } from \"./shared_registry\";\n\n/**\n * Minimal id primitives for wiring ARIA relationships.\n *\n * Accessible relationships such as `aria-describedby`, `aria-errormessage`,\n * `aria-labelledby`, and `aria-activedescendant` reference their targets by DOM\n * `id`. When a controller must establish such a relationship but the consumer's\n * markup left the target without an `id`, it needs to mint one that is stable for\n * the page's lifetime and guaranteed not to collide with another generated id.\n *\n * These helpers own *only* id generation/assignment. The linking policy (which\n * attribute, what order, when to add or remove it) stays in each controller —\n * this deliberately avoids a premature generic \"ARIA linker\" abstraction.\n */\n\n/**\n * Monotonic counter backing {@link uniqueId}, shared by every entry copy so generated\n * ids are distinct even before their elements enter the document.\n */\nconst ids = sharedRegistry(\"stimeo-ui.aria-ids.registry.v1\", () => ({ counter: 0 }));\n\n/**\n * Returns a unique, DOM-id-safe string of the form `` `${prefix}-${n}` `` where\n * `n` increases on each call.\n *\n * The counter alone guarantees uniqueness against other *generated* ids, but a\n * consumer-authored element could already own `` `${prefix}-${n}` ``. When a\n * `document` is available the candidate is therefore advanced until no element\n * with that id exists, so a generated id never collides with author markup\n * either — the minimal \"id registry\" guarantee these helpers exist to provide.\n *\n * @param prefix - Leading segment of the id (e.g. a controller's identifier).\n * Defaults to `\"stimeo\"`.\n */\nexport function uniqueId(prefix = \"stimeo\"): string {\n let candidate: string;\n do {\n ids.counter += 1;\n candidate = `${prefix}-${ids.counter}`;\n } while (typeof document !== \"undefined\" && document.getElementById(candidate) !== null);\n return candidate;\n}\n\n/**\n * Returns `element`'s existing `id`, or assigns it a freshly generated\n * {@link uniqueId} (with the given `prefix`) and returns that. Idempotent: an\n * element that already has an id keeps it, so consumer-authored ids are never\n * overwritten.\n *\n * @param element - The element to read or stamp an `id` onto.\n * @param prefix - Prefix forwarded to {@link uniqueId} when one must be generated.\n * @returns The element's id (existing or newly assigned).\n */\nexport function ensureId(element: Element, prefix = \"stimeo\"): string {\n if (element.id) return element.id;\n const id = uniqueId(prefix);\n element.id = id;\n return id;\n}\n","/**\n * Reflects a serialized attribute value only when the current value differs.\n *\n * A same-value `setAttribute` still queues a mutation record for every observer, so an\n * unchanged value writes nothing.\n *\n * @param element - The element whose attribute is reflected.\n * @param name - The attribute name, using the non-namespaced DOM API.\n * @param value - The serialized value, or null to remove the attribute.\n * @param beforeWrite - Called only for a change, before the DOM mutation, so the\n * caller can record ownership or identify its own observer records.\n * @returns Whether an attribute was written or removed.\n */\nexport function setAttributeIfChanged(\n element: Element,\n name: string,\n value: string | null,\n beforeWrite?: () => void,\n): boolean {\n if (element.getAttribute(name) === value) return false;\n beforeWrite?.();\n if (value === null) element.removeAttribute(name);\n else element.setAttribute(name, value);\n return true;\n}\n","import { setAttributeIfChanged } from \"./attribute_write\";\nimport { sharedRegistry } from \"./shared_registry\";\n\n/** What a lease's record says: the author's value, its last write, the leases beneath. */\ninterface AttributeLeaseRecord {\n readonly original: string | null;\n readonly written: string | null;\n /** Whether it hands back what the lease right beneath it wrote last. */\n readonly linked: boolean;\n /** The records of the other owners' leases beneath it, nearest first. */\n readonly beneath: readonly string[];\n}\n\n/** One lease's hold on one element's attribute, in the stack every lease of it shares. */\ninterface AttributeHold {\n /** The lease holding it; `null` for a hold read from a copy's record until its lease takes it. */\n lease: object | null;\n readonly record: string;\n written: string | null;\n /** What it hands back with nothing beneath it: the author's value. */\n readonly original: string | null;\n /** Whether it hands back what the hold beneath it wrote last instead. */\n linked: boolean;\n}\n\n/** The holds on each element by attribute, and every lease's record name by attribute. */\ninterface AttributeLeaseRegistry {\n readonly stacks: WeakMap<Element, Map<string, AttributeHold[]>>;\n readonly names: Map<string, Set<string>>;\n}\n\n/** Holds and record names coordinate across separately built package entries. */\nconst registry = sharedRegistry(\n \"stimeo-ui.attribute-lease.registry.v1\",\n (): AttributeLeaseRegistry => ({ stacks: new WeakMap(), names: new Map() }),\n);\n\n/** Whether a parsed record entry is an attribute value: a string, or `null` for absence. */\nfunction isAttributeValue(value: unknown): value is string | null {\n return value === null || typeof value === \"string\";\n}\n\n/**\n * Reads the record a lease left on `element`: the author's value, the value the lease wrote\n * last, whether it hands back the value beneath it (`false` before the names when it does not)\n * and the records beneath it. `undefined` when the record is missing or holds anything else.\n */\nfunction readLeaseRecord(element: Element, record: string): AttributeLeaseRecord | undefined {\n try {\n const parsed: unknown = JSON.parse(element.getAttribute(record) ?? \"null\");\n if (!Array.isArray(parsed)) return undefined;\n const [original, written, ...rest] = parsed as unknown[];\n const linked = rest[0] !== false;\n const beneath = linked ? rest : rest.slice(1);\n if (!beneath.every((under): under is string => typeof under === \"string\")) return undefined;\n return isAttributeValue(original) && isAttributeValue(written)\n ? { original, written, linked, beneath }\n : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** The element's stack, seeded from complete ownership records once. */\nfunction attributeStack(element: Element, attribute: string): AttributeHold[] {\n const byAttribute = registry.stacks.get(element) ?? new Map<string, AttributeHold[]>();\n registry.stacks.set(element, byAttribute);\n const known = byAttribute.get(attribute);\n if (known) return known;\n const found: (AttributeLeaseRecord & { readonly record: string })[] = [];\n for (const record of registry.names.get(attribute) ?? []) {\n const read = readLeaseRecord(element, record);\n if (read) found.push({ ...read, record });\n }\n const depth = ({ beneath }: (typeof found)[number]) =>\n beneath.filter((name) => found.some((other) => other.record === name)).length;\n const stack = found\n .sort((one, other) => depth(one) - depth(other))\n .map(({ record, written, original, linked }, index) => ({\n lease: null,\n record,\n written,\n original,\n linked: linked && index > 0,\n }));\n byAttribute.set(attribute, stack);\n return stack;\n}\n\n/** The lease's live hold or the unclaimed hold described by its owner's record. */\nfunction findHold(\n stack: readonly AttributeHold[],\n lease: object,\n record: string,\n): AttributeHold | undefined {\n return (\n stack.find((held) => held.lease === lease) ??\n stack.find((held) => held.lease === null && held.record === record)\n );\n}\n\n/**\n * Inspects a derived writer's continuation without acquiring or returning a hold.\n * A covered hold may update beneath its cover. Without a hold, the expected authored\n * value is compared with the original beneath any temporary cover. The original\n * distinguishes an absent attribute from an empty one.\n */\nexport function readAttributeLease(\n element: Element,\n attribute: string,\n owner: string,\n lease: object,\n expected: string | null,\n): { readonly allowed: boolean; readonly original: string | null } {\n const stack = attributeStack(element, attribute);\n const hold = findHold(stack, lease, `data-${owner}-${attribute}-lease`);\n const current = element.getAttribute(attribute);\n const covering = [...stack].reverse().find((other) => other.written === current);\n const original = (hold ?? covering)?.original;\n const authored = original === undefined ? current : original;\n return {\n original: authored,\n allowed: hold\n ? current === hold.written ||\n stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current)\n : authored === expected,\n };\n}\n\n/**\n * The value `element`'s author wrote for `attribute`, as the record a lease of any owner leaves\n * on the element carries it; `undefined` while no lease leaves one, as when nothing has moved\n * the attribute off the author's value. A field a reveal turned from `password` into `text`\n * still reads `\"password\"` here.\n */\nexport function leasedAuthorValue(element: Element, attribute: string): string | null | undefined {\n const suffix = `-${attribute}-lease`;\n for (const name of element.getAttributeNames()) {\n if (!name.startsWith(\"data-\") || !name.endsWith(suffix)) continue;\n const record = readLeaseRecord(element, name);\n if (record) return record.original;\n }\n return undefined;\n}\n\n/**\n * Temporarily controls one attribute across a changing set of elements.\n *\n * The first write remembers the authored value, including the distinction between\n * an absent attribute and an authored empty string. Returning a lease restores that\n * value only while the attribute still matches the controller's last write. If a\n * consumer changed it in the meantime, the consumer owns the new value and teardown\n * leaves it alone.\n *\n * A `null` write deliberately removes the attribute while retaining the lease. This\n * is useful for derived ARIA whose valid absence is itself controller state, such as\n * an unbounded `aria-valuemin` or a blank spinbutton's `aria-valuenow`.\n *\n * **Every lease of an attribute shares one stack of holds per element**, whatever its owner\n * and whichever file of the package constructed it (the stacks are one per page): the holds\n * sit in the order their leases first wrote the element, each with the value it wrote last.\n * The element's value is the highest hold's that carries it, and the page's when none does.\n * A write reaches the element unless a hold above the writer carries the element's value: the\n * top hold always shows its writes, a hold beneath it shows nothing while a hold above keeps\n * its value on the element, and once the page has put a value there that no hold carries, the\n * next write of any hold replaces it. A return gives a value back only from the hold the\n * element's value is: the value the hold beneath it wrote last, or the author's once nothing\n * is beneath it; any other return only leaves the stack, and the page's value stays. Holds\n * that wrote the same value are told apart by the stack, never by the value: the higher one\n * keeps it. A first write over a top hold whose value the page has replaced takes the\n * element's value as the author's. Two instances of one controller on one element — an\n * element outside their scope — stack the same way.\n *\n * A **base lease** (`{ base: true }`) holds the element's own state rather than a value over\n * it — a form field's ARIA on its control is one — so its first write goes to the bottom of\n * the stack, beneath the leases of other owners already there: a temporary value another\n * owner leased stays shown and returns to the base lease's latest value.\n *\n * **The stack travels with the element.** While a hold shows a value other than the author's,\n * lies on another hold or is covered by one, the element carries its owner's record\n * `data-<owner>-<attribute>-lease`: JSON of the author's value and the value the hold wrote\n * last (each a string, or `null` for an absent attribute), `false` where the hold hands back\n * the author's value rather than the latest value of the hold beneath it, and the records of\n * every hold beneath it, nearest first. Returning the last lease of an owner removes its\n * record. A copy of the element — a page Turbo restores from its cache is one — therefore\n * carries the stack, and the first lease to touch the copy reads it back under the record\n * names of the leases constructed so far, which include every lease that wrote a record the\n * cache holds, and orders the holds by the records each one lists beneath it. Each lease takes\n * the hold its owner's record describes over in place. Complete records for distinct owners\n * preserve their order across a copy. The records describe holds by owner, not by instance:\n * one owner holding the element more than once leaves only its topmost hold's record, which\n * the first of its leases to write or return on the copy takes. Lower holds of that owner and\n * their positions are absent; mutually listed owners cannot express their full live order.\n * A hold that showed the author's value alone carries no record and is taken by its first\n * write on the copy. Missing or unreadable records also leave their holds unknown, so copying\n * the DOM does not promise identical decisions for every live stack. Without a record it can\n * read, a new stack takes the current value as the author's. A Turbo morph removes records\n * absent from the server HTML; existing holds remain in memory until their leases return.\n *\n * The lease has no lifecycle of its own, so it never subscribes to document events,\n * and nothing rewinds a live page before Turbo caches it: `turbo:before-cache` also\n * fires on pages that stay.\n */\nexport class AttributeLease<T extends Element = Element> {\n readonly #attribute: string;\n readonly #record: string;\n readonly #base: boolean;\n readonly #preserveAuthor: boolean;\n readonly #held = new Set<T>();\n\n /**\n * @param attribute - The attribute whose temporary values this lease owns.\n * @param owner - Names the record on the element; the controller's identifier.\n * @param options - `base`: written beneath the other owners' leases;\n * `preserveAuthor`: a new base hold keeps a current value that no hold carries as authored.\n */\n constructor(\n attribute: string,\n owner: string,\n options: { readonly base?: boolean; readonly preserveAuthor?: boolean } = {},\n ) {\n this.#attribute = attribute;\n this.#record = `data-${owner}-${attribute}-lease`;\n this.#base = options.base === true;\n this.#preserveAuthor = options.preserveAuthor === true;\n const names = registry.names;\n names.set(attribute, (names.get(attribute) ?? new Set<string>()).add(this.#record));\n }\n\n /** Writes or removes the leased attribute while preserving its authored value. */\n write(element: T, value: string | null): void {\n const stack = attributeStack(element, this.#attribute);\n const hold = this.#take(stack) ?? this.#acquire(element, stack);\n this.#held.add(element);\n const shows = !this.#covered(element, stack, hold);\n hold.written = value;\n this.#mark(element, stack);\n if (shows) this.#reflect(element, value);\n }\n\n /**\n * Returns one lease, also on a restored copy, to the value the hold beneath it wrote last or\n * the author's, without overwriting a value a consumer wrote since. Says whether there was a\n * lease to return: a hold this lease has, or the hold a copy's record describes while no live\n * lease of the owner has taken it — a copy of a page an earlier connection wrote carries one.\n */\n return(element: T): boolean {\n const held = this.#held.delete(element);\n const known = registry.stacks.get(element)?.has(this.#attribute);\n const stack =\n held || known || element.hasAttribute(this.#record)\n ? attributeStack(element, this.#attribute)\n : [];\n const hold = this.#take(stack);\n if (!hold) return false;\n const carries = element.getAttribute(this.#attribute) === hold.written;\n const owns = carries && !this.#covered(element, stack, hold);\n const index = stack.indexOf(hold);\n stack.splice(index, 1);\n const above = stack[index];\n if (above) above.linked &&= hold.linked;\n this.#mark(element, stack);\n if (!owns) return true;\n const below = hold.linked ? stack[index - 1] : undefined;\n this.#reflect(element, below ? below.written : hold.original);\n return true;\n }\n\n /** Returns every lease it holds, with the same ownership check as {@link return}. */\n returnAll(): void {\n for (const element of Array.from(this.#held)) this.return(element);\n }\n\n /** Its hold in `stack`, taking over one read from its record. */\n #take(stack: AttributeHold[]): AttributeHold | undefined {\n const hold = findHold(stack, this, this.#record);\n if (hold) hold.lease = this;\n return hold;\n }\n\n /** A new hold: on top, over the top hold while the element shows it; a base one at the bottom. */\n #acquire(element: T, stack: AttributeHold[]): AttributeHold {\n const current = element.getAttribute(this.#attribute);\n const top = stack.at(-1);\n const bottom = stack[0];\n const over = top?.written === current ? top : undefined;\n const from = this.#base\n ? this.#preserveAuthor && !stack.some((held) => held.written === current)\n ? undefined\n : bottom\n : over;\n const hold: AttributeHold = {\n lease: this,\n record: this.#record,\n written: current,\n original: from ? from.original : current,\n linked: !this.#base && over !== undefined,\n };\n if (this.#base && bottom) {\n bottom.linked = true;\n stack.unshift(hold);\n } else stack.push(hold);\n return hold;\n }\n\n /** Whether a hold above `hold` carries the element's value, which is then that hold's. */\n #covered(element: T, stack: readonly AttributeHold[], hold: AttributeHold): boolean {\n const current = element.getAttribute(this.#attribute);\n return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current);\n }\n\n /** Leaves each owner's record of its topmost hold, or none where nothing needs one. */\n #mark(element: T, stack: readonly AttributeHold[]): void {\n const records = new Map<string, string | null>([[this.#record, null]]);\n stack.forEach((hold, index) => {\n const names = stack.slice(0, index).map((under) => under.record);\n const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);\n const marker = hold.linked || beneath.length === 0 ? [] : [false];\n records.set(\n hold.record,\n hold.written === hold.original && beneath.length === 0 && index === stack.length - 1\n ? null\n : JSON.stringify([hold.original, hold.written, ...marker, ...beneath]),\n );\n });\n for (const [name, recorded] of records) {\n setAttributeIfChanged(element, name, recorded);\n }\n }\n\n /** Reflects only a real value transition, avoiding self-triggered mutation work. */\n #reflect(element: T, value: string | null): void {\n setAttributeIfChanged(element, this.#attribute, value);\n }\n}\n","/**\n * Resolves which of a controller's elements owns a node.\n *\n * A delegated listener hears events from a whole subtree, so the handler's first\n * job is almost always the same question: which item, handle, or control does\n * this `event.target` belong to? The same question comes up for a\n * `MutationRecord.target`, for `document.activeElement`, and for a\n * `relatedTarget` on the way out of a hover region.\n *\n * The answer is `Node.contains()`, which is **inclusive** — an element contains\n * itself — so testing the candidate for identity as well would be redundant.\n *\n * **The guard is what makes this safe to call with a raw event target.**\n * `event.target` is typed `EventTarget | null`, and `contains()` takes a `Node?`:\n * browsers throw `TypeError` for anything else, and `window` — the everyday\n * `EventTarget` that is not a `Node` — is what an event dispatched at it carries.\n * Narrowing here means a caller never has to cast, and the rule cannot drift\n * between the places that ask the question.\n *\n * Scope stays with the caller. These helpers say *which candidate owns the node*,\n * not *whether the node belongs to this controller at all* — a component with\n * nested instances of itself decides that first (by comparing the closest\n * annotated ancestor) and passes the candidates it owns.\n *\n * Candidates can nest, and then more than one holds the node: {@link ownerIndex}\n * and {@link ownerOf} answer the first one listed, {@link ownersOf} all of them.\n */\n\n/**\n * Index in `candidates` of the first one that is, or contains, `node`.\n *\n * `-1` when none does, when `node` is absent, and when it is an `EventTarget`\n * that is not a `Node`. Candidates are tested in array order, so a nested pair\n * resolves to whichever the caller listed first.\n */\nexport function ownerIndex<T extends Element>(\n candidates: readonly T[],\n node: EventTarget | null | undefined,\n): number {\n if (!(node instanceof Node)) return -1;\n return candidates.findIndex((candidate) => candidate.contains(node));\n}\n\n/**\n * The first candidate that is, or contains, `node`; `null` when none does.\n *\n * A miss indexes the array at `-1`, which reads as `undefined` and lands on the\n * same `null` the absent cases produce.\n */\nexport function ownerOf<T extends Element>(\n candidates: readonly T[],\n node: EventTarget | null | undefined,\n): T | null {\n return candidates[ownerIndex(candidates, node)] ?? null;\n}\n\n/**\n * Every candidate that is, or contains, `node`, in array order.\n *\n * Empty when none does, when `node` is absent, and when it is an `EventTarget`\n * that is not a `Node`. A caller asking whether any owner of a node refuses\n * something reads the whole list, since an owner nested in another one holds the\n * node too.\n */\nexport function ownersOf<T extends Element>(\n candidates: readonly T[],\n node: EventTarget | null | undefined,\n): T[] {\n if (!(node instanceof Node)) return [];\n return candidates.filter((candidate) => candidate.contains(node));\n}\n","/**\n * Collapses many Stimulus lifecycle callbacks from one DOM mutation into a\n * single pass.\n *\n * Stimulus fires `<name>TargetConnected` / `Disconnected` once per element and\n * `<name>ValueChanged` once per changed attribute. Replacing a list of N options\n * or morphing several render Values therefore delivers N callbacks — but the\n * useful unit of work is \"reconcile against the resulting declarative input\",\n * once, after the batch has settled. Every controller with reconcilable targets\n * or render Values needs the same shape: a `queued` flag plus `queueMicrotask`.\n *\n * **A microtask is the right horizon, and the reason is specific.** Stimulus\n * drives these callbacks from a `MutationObserver`, whose own callback already\n * runs as a microtask with the whole batch in hand; scheduling one more lands\n * after the last sibling callback of that batch and still before paint or any\n * event handler. A timer would be later than it needs to be, and reconciling\n * synchronously would run once per element against a half-applied DOM.\n *\n * **The two guards are not the same guard.** Scheduling is refused before the\n * controller connects, and running is refused after it disconnects:\n *\n * - **Before `connect()`** — Stimulus delivers initial target and Value callbacks\n * ahead of `connect()`. Reconciling there would compute output against a\n * controller whose own state has not been initialised, and `connect()` is\n * about to do a full pass anyway.\n * - **After `disconnect()`** — Stimulus fires a callback for **every** target\n * during teardown, and a microtask queued just before it would otherwise run\n * against a detached tree. {@link MicrotaskCoalescer.cancel} exists for the\n * teardown path to drop the pending pass outright.\n *\n * Both guards are part of one contract here rather than something each consumer\n * has to remember separately.\n *\n * Scope is the scheduling only. *What* to reconcile — keep the surviving active\n * option, fall back to the next / previous / first visible one, rebuild derived\n * chips or hidden fields — stays in the controller, because no two consumers\n * answer it the same way.\n *\n * @example\n * ```ts\n * readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileOptions());\n *\n * connect() { this.#reconcile.activate(); }\n * disconnect() { this.#reconcile.cancel(); }\n *\n * optionTargetConnected() { this.#reconcile.schedule(); }\n * optionTargetDisconnected() { this.#reconcile.schedule(); }\n * ```\n */\nexport class MicrotaskCoalescer {\n readonly #run: () => void;\n #queued = false;\n #active = false;\n #generation = 0;\n\n /** @param run - the single reconciliation pass, invoked at most once per batch. */\n constructor(run: () => void) {\n this.#run = run;\n }\n\n /** Opens the window in which {@link schedule} is honoured; call from `connect()`. */\n activate(): void {\n this.#active = true;\n }\n\n /** Closes the window and drops any pending pass; call from `disconnect()`. */\n cancel(): void {\n this.#active = false;\n this.#queued = false;\n this.#generation += 1;\n }\n\n /** Whether a requested pass has yet to run. */\n get pending(): boolean {\n return this.#queued;\n }\n\n /** Requests one pass after the batch settles. Idempotent; inert outside the window. */\n schedule(): void {\n if (!this.#active || this.#queued) return;\n this.#queued = true;\n const generation = this.#generation;\n queueMicrotask(() => {\n // A cancelled callback must not consume a pass queued after reconnect.\n if (generation !== this.#generation || !this.#queued || !this.#active) return;\n this.#queued = false;\n this.#run();\n });\n }\n}\n","import { Controller } from \"@hotwired/stimulus\";\nimport { announce } from \"../utils/announce\";\nimport { ensureId } from \"../utils/aria_ids\";\nimport { AttributeLease } from \"../utils/attribute_lease\";\nimport { ownerIndex } from \"../utils/event_owner\";\nimport { MicrotaskCoalescer } from \"../utils/microtask_coalescer\";\n\n/** Stimulus action params understood by {@link FormFieldController.setError}. */\ninterface SetErrorParams {\n /** The error message to display. */\n message?: string;\n}\n\n/** An action event carrying Stimulus `data-*-param` values. */\ntype ActionEvent = Event & { params?: SetErrorParams };\n\n/** Programmatic behavior switches for {@link FormFieldController.setError}. */\nexport interface FormFieldSetErrorOptions {\n /** Override the `focusOnError` Value for this call. */\n focus?: boolean;\n}\n\n/** Detail dispatched with `stimeo--form-field:validate`. */\nexport interface FormFieldValidateDetail {\n /** Whether the explicit validation action left the field valid. */\n valid: boolean;\n /** The first visible error message, or an empty string when valid/unavailable. */\n message: string;\n}\n\n/** Attributes on retained association targets that can change the ARIA graph. */\nconst OBSERVED_ATTRIBUTES = [\"hidden\", \"id\"];\n\n/**\n * Headless, accessible form-field association behavior.\n *\n * Markup contract (identifier: `stimeo--form-field`):\n * <div data-controller=\"stimeo--form-field\">\n * <label for=\"email\">Email</label>\n * <input id=\"email\" type=\"email\" aria-invalid=\"false\"\n * data-stimeo--form-field-target=\"control\" />\n * <p data-stimeo--form-field-target=\"description\">We'll send a confirmation.</p>\n * <p hidden data-stimeo--form-field-target=\"error\"></p>\n * </div>\n *\n * Not an APG widget pattern — this is the wiring substrate behind form controls:\n * it supports **Name, Role, Value** (WCAG 4.1.2) and **error identification**\n * (3.3.1 / 4.1.3) by composing the control's `aria-describedby`, toggling\n * `aria-invalid`, and pointing `aria-errormessage` at the visual error.\n *\n * `validate` dispatches `{ valid: boolean, message: string }`.\n *\n * @remarks\n * Behavior only — it sets semantic attributes and the `hidden` state of the\n * visual error; it never validates input (the consumer / server decides) and\n * never styles. Runtime errors are handed to a separately seated\n * `stimeo--announcer`, because showing a live region together with its first\n * message is not a reliable announcement primitive.\n *\n * Behavior provided:\n * - Assigns ids to description/error targets and composes the control's\n * `aria-describedby` from them in DOM order (preserving the control's authored\n * tokens and removing duplicates).\n * - Reflects server-rendered errors: an error target that is already visible and\n * non-empty at connect puts the field into the invalid state (progressive\n * enhancement).\n * - Reconciles added, removed, replaced, and retained/morphed targets without\n * emitting validation events or announcements.\n * - {@link setError} / {@link clearError} drive the invalid state at runtime and\n * dispatch `stimeo--form-field:validate`.\n */\nexport class FormFieldController extends Controller<HTMLElement> {\n static override targets = [\"control\", \"description\", \"error\"];\n static override values = {\n focusOnError: { type: Boolean, default: false },\n };\n static actions = [\"clearError\", \"setError\"] as const;\n static events = [\"validate\"] as const;\n\n declare readonly controlTarget: HTMLElement;\n declare readonly hasControlTarget: boolean;\n declare readonly descriptionTargets: HTMLElement[];\n declare readonly errorTargets: HTMLElement[];\n declare readonly hasErrorTarget: boolean;\n /** Whether an explicit {@link setError} call moves focus to the current control. */\n declare focusOnErrorValue: boolean;\n\n /** Root attribute (CSS hook) reflecting the invalid state, in this controller's namespace. */\n get #invalidAttribute(): string {\n return `data-${this.identifier}-invalid`;\n }\n\n /** Collapses one target/morph batch into one silent ARIA reconciliation. */\n readonly #reconcile = new MicrotaskCoalescer(() => this.#reconcileDom());\n /**\n * The control's ARIA is the field's own state, so each lease is a base lease: a value another\n * owner leases on the control (a character counter's `aria-invalid`) stays on top of it.\n */\n readonly #ariaDescribedBy = new AttributeLease<HTMLElement>(\"aria-describedby\", this.identifier, {\n base: true,\n });\n readonly #ariaErrorMessage = new AttributeLease<HTMLElement>(\n \"aria-errormessage\",\n this.identifier,\n { base: true },\n );\n readonly #ariaInvalid = new AttributeLease<HTMLElement>(\"aria-invalid\", this.identifier, {\n base: true,\n });\n /** Watches retained target ids, error visibility, and error content. */\n readonly #observer = new MutationObserver((records) => {\n if (records.some((record) => this.#isRelevantMutation(record))) {\n this.#reconcile.schedule();\n }\n });\n\n #activeControl: HTMLElement | null = null;\n #baseDescribedBy: string[] = [];\n #explicitInvalid = false;\n #initialized = false;\n\n /** Wires the initial graph and starts retained-target reconciliation. */\n override connect(): void {\n this.#reconcile.activate();\n\n // A restored DOM can contain the invalid hook with no surviving visual\n // message. Treat that one shape as the persisted explicit setError state;\n // visible server errors remain derived and can clear when their DOM clears.\n if (!this.#initialized) {\n this.#explicitInvalid =\n this.element.hasAttribute(this.#invalidAttribute) && this.#shownErrors().length === 0;\n this.#initialized = true;\n }\n\n this.#reconcileDom();\n this.#observer.observe(this.element, {\n attributes: true,\n attributeFilter: OBSERVED_ATTRIBUTES,\n characterData: true,\n childList: true,\n subtree: true,\n });\n }\n\n /** Releases observers, queued work, and ARIA borrowed on the current control. */\n override disconnect(): void {\n this.#reconcile.cancel();\n this.#observer.disconnect();\n this.#activeControl && this.#releaseControl(this.#activeControl);\n }\n\n /** Reconciles a control inserted or replaced at runtime. */\n controlTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Schedules restoration of authored ARIA when a control leaves this field. */\n controlTargetDisconnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Reconciles a description inserted or replaced at runtime. */\n descriptionTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Removes a departed description from the control's association graph. */\n descriptionTargetDisconnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Reconciles an error region inserted or replaced at runtime. */\n errorTargetConnected(): void {\n this.#reconcile.schedule();\n }\n\n /** Removes a departed error from invalid state and the association graph. */\n errorTargetDisconnected(): void {\n this.#reconcile.schedule();\n }\n\n /**\n * Marks the field invalid and shows the error message. Bound via `data-action`\n * (`#setError`) or callable directly.\n *\n * A non-empty shown message is announced exactly once through the shared\n * assertive announcer. Initial/server reconciliation is deliberately silent.\n *\n * @param arg - Either the message string, or the action event whose\n * `data-stimeo--form-field-message-param` supplies it. When no message is\n * resolvable, any already-populated error targets are simply (re)shown.\n * @param options - Programmatic overrides. Stimulus actions use the Values.\n */\n setError(arg?: string | ActionEvent, options: FormFieldSetErrorOptions = {}): void {\n const message = this.#resolveMessage(arg);\n if (message !== null && this.hasErrorTarget) {\n this.errorTargets[0]?.replaceChildren(document.createTextNode(message));\n }\n for (const error of this.errorTargets) {\n error.hidden = (error.textContent ?? \"\").trim() === \"\";\n }\n\n // setError is an explicit invalid request: it remains invalid even if an\n // error target is absent or replaced before clearError is called.\n this.#explicitInvalid = true;\n this.#reconcileDom();\n const shownMessage = this.#shownMessage();\n const detail: FormFieldValidateDetail = { valid: false, message: shownMessage };\n this.dispatch(\"validate\", { detail });\n announce(shownMessage, { assertive: true });\n\n if (options.focus ?? this.focusOnErrorValue) this.#activeControl?.focus();\n }\n\n /**\n * Clears the error: empties and hides every error target and marks the field\n * valid. Bound via `data-action` (`#clearError`) or callable directly.\n *\n * Clearing is silent: the visual/ARIA state and validation event are sufficient,\n * while success wording remains an explicit consumer announcement.\n */\n clearError(): void {\n for (const error of this.errorTargets) {\n error.replaceChildren();\n error.hidden = true;\n }\n this.#explicitInvalid = false;\n this.#reconcileDom();\n const detail: FormFieldValidateDetail = { valid: true, message: \"\" };\n this.dispatch(\"validate\", { detail });\n }\n\n /**\n * Rebuilds ids and derived ARIA from the settled target graph without reporting\n * a user validation action.\n */\n #reconcileDom(): void {\n this.#ensureAssociationIds();\n this.#adoptCurrentControl();\n\n const shown = this.#shownErrors();\n const invalid = this.#explicitInvalid || shown.length > 0;\n this.element.toggleAttribute(this.#invalidAttribute, invalid);\n\n const control = this.#activeControl;\n if (!control) return;\n\n this.#ariaInvalid.write(control, invalid ? \"true\" : \"false\");\n\n const primaryErrorId = shown[0]?.id ?? null;\n this.#ariaErrorMessage.write(control, primaryErrorId);\n\n const associationIds = this.#orderedElements([...this.descriptionTargets, ...shown]).map(\n (element) => element.id,\n );\n const describedBy = this.#uniqueTokens([...this.#baseDescribedBy, ...associationIds]);\n this.#ariaDescribedBy.write(control, describedBy.length > 0 ? describedBy.join(\" \") : null);\n }\n\n /** Assigns stable ids before either capture or reflection uses them. */\n #ensureAssociationIds(): void {\n for (const description of this.descriptionTargets) {\n ensureId(description, \"stimeo--form-field-desc\");\n }\n for (const error of this.errorTargets) {\n ensureId(error, \"stimeo--form-field-error\");\n }\n }\n\n /** Switches ARIA ownership when the singular current control target changes. */\n #adoptCurrentControl(): void {\n const next = this.hasControlTarget ? this.controlTarget : null;\n if (next === this.#activeControl) return;\n this.#activeControl && this.#releaseControl(this.#activeControl);\n this.#activeControl = next;\n this.#baseDescribedBy = next ? this.#externalDescribedByTokens(next) : [];\n }\n\n /** Restores one departed control without overwriting later consumer edits. */\n #releaseControl(control: HTMLElement): void {\n this.#ariaDescribedBy.return(control);\n this.#ariaErrorMessage.return(control);\n this.#ariaInvalid.return(control);\n if (control === this.#activeControl) {\n this.#activeControl = null;\n this.#baseDescribedBy = [];\n }\n }\n\n /** Error targets currently visible and non-empty, in document order. */\n #shownErrors(): HTMLElement[] {\n return this.#orderedElements(\n this.errorTargets.filter((error) => !error.hidden && (error.textContent ?? \"\").trim() !== \"\"),\n );\n }\n\n /** Text of the first shown error, for validation detail and announcement. */\n #shownMessage(): string {\n return (this.#shownErrors()[0]?.textContent ?? \"\").trim();\n }\n\n /** Resolves a message from a string argument or an action event's params. */\n #resolveMessage(arg?: string | ActionEvent): string | null {\n if (typeof arg === \"string\") return arg;\n const message = arg?.params?.message;\n return typeof message === \"string\" ? message : null;\n }\n\n /**\n * Tokens authored on a newly adopted control, excluding ids this controller\n * owns through its current description/error targets.\n */\n #externalDescribedByTokens(control: HTMLElement): string[] {\n const owned = new Set([\n ...this.descriptionTargets.map((description) => description.id),\n ...this.errorTargets.map((error) => error.id),\n ]);\n const existing = control.getAttribute(\"aria-describedby\") ?? \"\";\n return this.#uniqueTokens(\n existing.split(/\\s+/).filter((token) => token.length > 0 && !owned.has(token)),\n );\n }\n\n /** Deduplicates ARIA tokens without disturbing their first occurrence. */\n #uniqueTokens(tokens: string[]): string[] {\n const seen = new Set<string>();\n return tokens.filter((token) => {\n if (token.length === 0 || seen.has(token)) return false;\n seen.add(token);\n return true;\n });\n }\n\n /** Returns unique current targets in DOM order before serializing IDREF lists. */\n #orderedElements(elements: HTMLElement[]): HTMLElement[] {\n const candidates = new Set(elements);\n return [this.element, ...this.element.querySelectorAll<HTMLElement>(\"*\")].filter((element) =>\n candidates.has(element),\n );\n }\n\n /** Whether one retained-node mutation can alter this controller's derived state. */\n #isRelevantMutation(record: MutationRecord): boolean {\n const target = record.target;\n if (record.type === \"attributes\") {\n if (record.attributeName === \"hidden\")\n return this.errorTargets.includes(target as HTMLElement);\n return (\n record.attributeName === \"id\" &&\n [...this.descriptionTargets, ...this.errorTargets].includes(target as HTMLElement)\n );\n }\n\n return ownerIndex(this.errorTargets, target) !== -1;\n }\n}\n"]}
@@ -31,7 +31,7 @@ import { FormFieldController } from './form_field_controller.js';
31
31
  * constraints: `required`, `type`, `pattern`, `min`/`max`, …) or in the consumer's
32
32
  * own `setCustomValidity()` calls, which `checkValidity()` surfaces transparently.
33
33
  * It sets the form's `novalidate` so it can replace the browser's default error
34
- * bubbles with accessible in-page visual errors plus the shared Announcer, and
34
+ * bubbles with accessible in-page visual errors plus the shared `stimeo--announcer`, and
35
35
  * restores the attribute on disconnect.
36
36
  *
37
37
  * Two declarative escape hatches let a field **exceed** native validation with no
@@ -40,8 +40,8 @@ import { FormFieldController } from './form_field_controller.js';
40
40
  * (`value-missing`, `too-short`, `too-long`, `pattern-mismatch`, `type-mismatch`,
41
41
  * `range-overflow`, `range-underflow`, `step-mismatch`, `bad-input`), or a generic
42
42
  * `data-stimeo--form-validation-message` fallback, override the shown text per failing
43
- * `ValidityState` flag — controlled, localizable wording that also fixes headless
44
- * browsers returning an empty native `validationMessage`. Falls back to native.
43
+ * `ValidityState` flag — controlled, localizable wording that also covers an engine
44
+ * whose native `validationMessage` is empty or generic. Falls back to native.
45
45
  * - **`data-stimeo--form-validation-disallow="whitespace"`** — a built-in custom rule
46
46
  * rejecting a value that is blank after trimming (which slips past `required` /
47
47
  * `minlength`), wired through `setCustomValidity` so it blocks submit like any
@@ -1,15 +1,11 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/form_validation_controller.ts
4
-
5
- // src/utils/default_attribute.ts
6
3
  function setDefaultAttribute(element, name, value) {
7
4
  if (element.hasAttribute(name)) return false;
8
5
  element.setAttribute(name, value);
9
6
  return true;
10
7
  }
11
8
 
12
- // src/utils/focus_candidate.ts
13
9
  function inheritsFieldsetDisabled(control) {
14
10
  let fieldset = control.closest("fieldset[disabled]");
15
11
  while (fieldset) {
@@ -19,8 +15,19 @@ function inheritsFieldsetDisabled(control) {
19
15
  }
20
16
  return false;
21
17
  }
18
+ function unslotted(element) {
19
+ return element.assignedSlot === null && element.parentElement?.shadowRoot != null;
20
+ }
21
+ function flatTreeParent(element) {
22
+ if (unslotted(element)) return null;
23
+ const parent = element.assignedSlot ?? element.parentNode;
24
+ if (parent instanceof ShadowRoot) return parent.host;
25
+ return parent instanceof Element ? parent : null;
26
+ }
22
27
  function canTakeFocus(element) {
23
- if (element.closest("[hidden], [inert]")) return false;
28
+ for (let node = element; node; node = flatTreeParent(node)) {
29
+ if (unslotted(node) || node.matches("[hidden], [inert]")) return false;
30
+ }
24
31
  if (element instanceof HTMLInputElement && element.type === "hidden") return false;
25
32
  if (!("disabled" in element)) return true;
26
33
  if (element.disabled) return false;
@@ -84,7 +91,17 @@ function firstTabStop(root) {
84
91
  return null;
85
92
  }
86
93
 
87
- // src/controllers/form_validation_controller.ts
94
+ var ListenerSet = class {
95
+ #abort = new AbortController();
96
+ add(target, type, handler, options) {
97
+ target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
98
+ }
99
+ dispose() {
100
+ this.#abort.abort();
101
+ this.#abort = new AbortController();
102
+ }
103
+ };
104
+
88
105
  var CONSTRAINT_MESSAGE_KEYS = [
89
106
  ["valueMissing", "value-missing"],
90
107
  ["typeMismatch", "type-mismatch"],
@@ -101,11 +118,9 @@ var DISALLOW_PART = "disallow";
101
118
  var DISALLOW_WHITESPACE_DEFAULT = "Please enter a value that is not only whitespace.";
102
119
  var FORM_FIELD_INVALID_ATTR = "data-stimeo--form-field-invalid";
103
120
  var FormValidationController = class _FormValidationController extends Controller {
104
- /** The generic message override, in the namespace this controller is registered under. */
105
121
  get #messageAttribute() {
106
122
  return `data-${this.identifier}-${MESSAGE_PART}`;
107
123
  }
108
- /** Marks the `novalidate` this controller applied, so an authored one is left alone. */
109
124
  get #novalidateMarker() {
110
125
  return `data-${this.identifier}-${_FormValidationController.#NOVALIDATE_PART}`;
111
126
  }
@@ -118,23 +133,12 @@ var FormValidationController = class _FormValidationController extends Controlle
118
133
  };
119
134
  static actions = ["validate"];
120
135
  static events = ["valid", "invalid"];
121
- /** Suffix of the marker recording that we added `novalidate`, so we only remove our own. */
122
136
  static #NOVALIDATE_PART = "novalidate";
123
- /** Object-backed groups already interacted with — the input revalidation gate. */
124
137
  #touchedGroups = /* @__PURE__ */ new WeakSet();
125
- /** String-backed fallback radio groups already interacted with. */
126
138
  #touchedRadioGroups = /* @__PURE__ */ new Set();
127
- /**
128
- * Last message this controller wrote through `setCustomValidity`, kept as a
129
- * two-layer ownership ledger: a value is cleared only while the live message
130
- * still equals the recorded write. Iterable so disconnect can release every
131
- * surviving loan without touching a consumer's later custom error.
132
- */
133
139
  #ownedCustomErrors = /* @__PURE__ */ new Map();
134
- /** Last invalid message routed to each field, suppressing duplicate reports. */
135
140
  #reportedErrors = /* @__PURE__ */ new WeakMap();
136
- /** Exact document that owns the delegated listeners for this connection. */
137
- #listenerDocument = null;
141
+ #listeners = new ListenerSet();
138
142
  #onSubmit = (event) => {
139
143
  if (event.target !== this.element) return;
140
144
  const invalid = this.#validateAll();
@@ -172,50 +176,30 @@ var FormValidationController = class _FormValidationController extends Controlle
172
176
  this.#markTouched(group.key);
173
177
  this.#applyGroup(group);
174
178
  };
175
- /** Suppresses native bubbles and binds the submit / blur / input listeners. */
176
179
  connect() {
177
180
  if (setDefaultAttribute(this.element, "novalidate", "")) {
178
181
  this.element.setAttribute(this.#novalidateMarker, "");
179
182
  }
180
- this.#listenerDocument = this.element.ownerDocument;
181
- this.#listenerDocument.addEventListener("submit", this.#onSubmit, true);
182
- this.#listenerDocument.addEventListener("focusout", this.#onFocusOut);
183
- this.#listenerDocument.addEventListener("input", this.#onInput);
184
- this.#listenerDocument.addEventListener("change", this.#onChange);
183
+ const { ownerDocument } = this.element;
184
+ this.#listeners.add(ownerDocument, "submit", this.#onSubmit, { capture: true });
185
+ this.#listeners.add(ownerDocument, "focusout", this.#onFocusOut);
186
+ this.#listeners.add(ownerDocument, "input", this.#onInput);
187
+ this.#listeners.add(ownerDocument, "change", this.#onChange);
185
188
  }
186
- /** Tears down listeners and restores `novalidate` if we added it. */
187
189
  disconnect() {
188
- this.#listenerDocument?.removeEventListener("submit", this.#onSubmit, true);
189
- this.#listenerDocument?.removeEventListener("focusout", this.#onFocusOut);
190
- this.#listenerDocument?.removeEventListener("input", this.#onInput);
191
- this.#listenerDocument?.removeEventListener("change", this.#onChange);
192
- this.#listenerDocument = null;
190
+ this.#listeners.dispose();
193
191
  for (const [control, message] of this.#ownedCustomErrors) {
194
192
  if (control.validationMessage === message) control.setCustomValidity("");
195
193
  }
196
194
  this.#ownedCustomErrors.clear();
197
- this.#touchedRadioGroups.clear();
198
195
  if (this.element.hasAttribute(this.#novalidateMarker)) {
199
196
  this.element.removeAttribute("novalidate");
200
197
  this.element.removeAttribute(this.#novalidateMarker);
201
198
  }
202
199
  }
203
- /**
204
- * Validates every control now, rendering or clearing each field's message, and
205
- * returns whether the whole form is valid. Marks every field/group touched so
206
- * a later input from any sibling re-validates it. Bound via `data-action`
207
- * (`#validate`) or callable directly (e.g. before a programmatic submit).
208
- */
209
200
  validate() {
210
201
  return this.#validateAll().length === 0;
211
202
  }
212
- /**
213
- * Validates every control and returns one invalid control per field. Controls
214
- * are grouped by field first (see {@link #keyFor}) so a field with several
215
- * controls — a radio group, or a mirror plus its visible control — reflects
216
- * *all* of them: a valid sibling must never clear an invalid one's message.
217
- * Each group's first invalid control supplies the message and the focus target.
218
- */
219
203
  #validateAll() {
220
204
  const invalid = [];
221
205
  for (const group of this.#snapshot().groups.values()) {
@@ -225,7 +209,6 @@ var FormValidationController = class _FormValidationController extends Controlle
225
209
  }
226
210
  return invalid;
227
211
  }
228
- /** Builds the current field table in one pass over form controls and DOM depth. */
229
212
  #snapshot() {
230
213
  const fields = this.#fieldOutlets();
231
214
  const groups = /* @__PURE__ */ new Map();
@@ -243,7 +226,6 @@ var FormValidationController = class _FormValidationController extends Controlle
243
226
  }
244
227
  return { groups, groupByControl };
245
228
  }
246
- /** Records that a whole field/group, rather than one sibling control, was visited. */
247
229
  #markTouched(key) {
248
230
  if (typeof key === "string") {
249
231
  this.#touchedRadioGroups.add(key);
@@ -254,13 +236,6 @@ var FormValidationController = class _FormValidationController extends Controlle
254
236
  #isTouched(key) {
255
237
  return typeof key === "string" ? this.#touchedRadioGroups.has(key) : this.#touchedGroups.has(key);
256
238
  }
257
- /**
258
- * Runs native constraint validation across a field's controls and routes the
259
- * result to its `stimeo--form-field` outlet: the first invalid control's
260
- * `validationMessage` is shown, an all-valid field is cleared. Returns the
261
- * first invalid control (for the invalid list / focus), or `null` when valid.
262
- * Routing goes through the outlet, so the ARIA wiring is never duplicated here.
263
- */
264
239
  #applyGroup(group) {
265
240
  for (const control of group.controls) this.#syncCustomValidity(control);
266
241
  const firstInvalid = group.controls.find((control) => !control.checkValidity()) ?? null;
@@ -277,14 +252,6 @@ var FormValidationController = class _FormValidationController extends Controlle
277
252
  }
278
253
  return firstInvalid;
279
254
  }
280
- /**
281
- * Resolves the message to show for an invalid control: a per-constraint
282
- * override (`data-stimeo--form-validation-message-<constraint>`) for the first failing
283
- * `ValidityState` flag, then a generic `data-stimeo--form-validation-message`
284
- * override, then the browser's native `validationMessage`. Authoring an override
285
- * gives controlled, localizable, theme-able wording with **no consumer JS** —
286
- * and sidesteps headless browsers that return an empty native message.
287
- */
288
255
  #messageFor(control) {
289
256
  if (control.validity.customError) return control.validationMessage;
290
257
  for (const [flag, key] of CONSTRAINT_MESSAGE_KEYS) {
@@ -294,17 +261,6 @@ var FormValidationController = class _FormValidationController extends Controlle
294
261
  }
295
262
  return control.validationMessage || this.#authoredMessage(control, this.#messageAttribute) || "";
296
263
  }
297
- /**
298
- * Applies (or clears) a declarative custom constraint via `setCustomValidity`,
299
- * for controls that opt in with `data-stimeo--form-validation-disallow`. The supported
300
- * rule is `"whitespace"` — a value that is non-empty but blank
301
- * after trimming (which slips past `required` / `minlength`); its message follows
302
- * the whitespace-specific → generic → default chain.
303
- *
304
- * Don't-clobber-authored-state: an unknown/absent rule is never written, an
305
- * existing consumer custom error wins, and a controller error is only cleared
306
- * while the live message still equals the recorded controller write.
307
- */
308
264
  #syncCustomValidity(control) {
309
265
  const recorded = this.#ownedCustomErrors.get(control);
310
266
  const ownsCurrent = recorded !== void 0 && control.validationMessage === recorded;
@@ -319,16 +275,10 @@ var FormValidationController = class _FormValidationController extends Controlle
319
275
  if (!ownsCurrent || recorded !== message) control.setCustomValidity(message);
320
276
  this.#ownedCustomErrors.set(control, message);
321
277
  }
322
- /** Returns a non-blank authored message, otherwise falls through to a fallback. */
323
278
  #authoredMessage(control, attribute) {
324
279
  const message = control.getAttribute(attribute);
325
280
  return message && message.trim().length > 0 ? message : null;
326
281
  }
327
- /**
328
- * A grouping key that collects controls belonging to the same field: the owning
329
- * `stimeo--form-field` when present, else a radio group's shared `name`, else
330
- * the control itself (always distinct).
331
- */
332
282
  #keyFor(control, field) {
333
283
  if (field) return field;
334
284
  if (control instanceof HTMLInputElement && control.type === "radio" && control.name) {
@@ -336,15 +286,6 @@ var FormValidationController = class _FormValidationController extends Controlle
336
286
  }
337
287
  return control;
338
288
  }
339
- /**
340
- * Where focus should land for an invalid control. A visible control is focused
341
- * directly — the case for native fields and radios. A validatable mirror
342
- * (the `hidden` attribute) cannot receive focus, so focus is delegated to the
343
- * visible widget: the owning field's `control` target when it is itself
344
- * focusable, else its first focusable descendant (e.g. a roving-tabindex
345
- * member). Resolved structurally — never by probing `focus()` — so behavior
346
- * is deterministic and CSS-independent.
347
- */
348
289
  #focusTargetFor(control) {
349
290
  if (canTakeFocus(control)) return control;
350
291
  const field = this.#fieldFor(control, this.#fieldOutlets());
@@ -353,7 +294,6 @@ var FormValidationController = class _FormValidationController extends Controlle
353
294
  if (isTabStop(root)) return root;
354
295
  return firstTabStop(root);
355
296
  }
356
- /** Pairs each live outlet element with its controller once per operation. */
357
297
  #fieldOutlets() {
358
298
  const fields = /* @__PURE__ */ new Map();
359
299
  const elements = this.stimeoFormFieldOutletElements;
@@ -365,7 +305,6 @@ var FormValidationController = class _FormValidationController extends Controlle
365
305
  }
366
306
  return fields;
367
307
  }
368
- /** The nearest configured field ancestor of `control`, if any. */
369
308
  #fieldFor(control, fields) {
370
309
  let ancestor = control;
371
310
  while (ancestor) {
@@ -375,7 +314,6 @@ var FormValidationController = class _FormValidationController extends Controlle
375
314
  }
376
315
  return void 0;
377
316
  }
378
- /** This form's native controls that participate in constraint validation. */
379
317
  get #controls() {
380
318
  const controls = [];
381
319
  for (const element of Array.from(this.element.elements)) {
@@ -383,18 +321,14 @@ var FormValidationController = class _FormValidationController extends Controlle
383
321
  }
384
322
  return controls;
385
323
  }
386
- /** Narrows an event target to a validatable control. */
387
324
  #controlFrom(target) {
388
325
  return target instanceof Element && this.#isValidatable(target) && target.form === this.element ? target : null;
389
326
  }
390
327
  #isValidatable(element) {
391
- return (element instanceof HTMLInputElement || element instanceof HTMLSelectElement || element instanceof HTMLTextAreaElement) && // `willValidate` already excludes disabled, read-only, input[type=hidden],
392
- // and button-type controls. The `hidden` attribute intentionally does not
393
- // bar a text mirror from constraint validation.
328
+ return (element instanceof HTMLInputElement || element instanceof HTMLSelectElement || element instanceof HTMLTextAreaElement) &&
394
329
  element.willValidate;
395
330
  }
396
331
  };
397
332
 
398
333
  export { FormValidationController };
399
- //# sourceMappingURL=form_validation_controller.js.map
400
334
  //# sourceMappingURL=form_validation_controller.js.map