stimeo-ui 0.15.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (332) hide show
  1. package/CHANGELOG.md +209 -0
  2. package/README.md +128 -1
  3. package/dist/cable/index.d.ts +79 -23
  4. package/dist/cable/index.js +392 -417
  5. package/dist/cable/index.js.map +1 -1
  6. package/dist/controllers/accordion_controller.d.ts +34 -5
  7. package/dist/controllers/accordion_controller.js +228 -28
  8. package/dist/controllers/accordion_controller.js.map +1 -1
  9. package/dist/controllers/alert_dialog_controller.d.ts +20 -9
  10. package/dist/controllers/alert_dialog_controller.js +862 -221
  11. package/dist/controllers/alert_dialog_controller.js.map +1 -1
  12. package/dist/controllers/announcer_controller.d.ts +38 -7
  13. package/dist/controllers/announcer_controller.js +135 -191
  14. package/dist/controllers/announcer_controller.js.map +1 -1
  15. package/dist/controllers/aspect_ratio_controller.js +0 -10
  16. package/dist/controllers/aspect_ratio_controller.js.map +1 -1
  17. package/dist/controllers/auto_submit_controller.d.ts +30 -6
  18. package/dist/controllers/auto_submit_controller.js +295 -110
  19. package/dist/controllers/auto_submit_controller.js.map +1 -1
  20. package/dist/controllers/avatar_controller.js +172 -106
  21. package/dist/controllers/avatar_controller.js.map +1 -1
  22. package/dist/controllers/breadcrumb_controller.d.ts +10 -7
  23. package/dist/controllers/breadcrumb_controller.js +0 -129
  24. package/dist/controllers/breadcrumb_controller.js.map +1 -1
  25. package/dist/controllers/bulk_select_controller.d.ts +22 -4
  26. package/dist/controllers/bulk_select_controller.js +264 -53
  27. package/dist/controllers/bulk_select_controller.js.map +1 -1
  28. package/dist/controllers/calendar_controller.d.ts +109 -28
  29. package/dist/controllers/calendar_controller.js +346 -180
  30. package/dist/controllers/calendar_controller.js.map +1 -1
  31. package/dist/controllers/carousel_controller.d.ts +99 -27
  32. package/dist/controllers/carousel_controller.js +587 -300
  33. package/dist/controllers/carousel_controller.js.map +1 -1
  34. package/dist/controllers/character_counter_controller.d.ts +18 -2
  35. package/dist/controllers/character_counter_controller.js +271 -143
  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 +77 -75
  39. package/dist/controllers/checkbox_controller.js.map +1 -1
  40. package/dist/controllers/clipboard_controller.d.ts +44 -7
  41. package/dist/controllers/clipboard_controller.js +187 -108
  42. package/dist/controllers/clipboard_controller.js.map +1 -1
  43. package/dist/controllers/collapsible_controller.d.ts +41 -5
  44. package/dist/controllers/collapsible_controller.js +374 -108
  45. package/dist/controllers/collapsible_controller.js.map +1 -1
  46. package/dist/controllers/color_picker_controller.d.ts +47 -14
  47. package/dist/controllers/color_picker_controller.js +183 -127
  48. package/dist/controllers/color_picker_controller.js.map +1 -1
  49. package/dist/controllers/combobox_controller.d.ts +33 -6
  50. package/dist/controllers/combobox_controller.js +426 -109
  51. package/dist/controllers/combobox_controller.js.map +1 -1
  52. package/dist/controllers/command_palette_controller.d.ts +45 -14
  53. package/dist/controllers/command_palette_controller.js +994 -350
  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 +212 -125
  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 +939 -245
  60. package/dist/controllers/confirm_controller.js.map +1 -1
  61. package/dist/controllers/context_menu_controller.d.ts +36 -3
  62. package/dist/controllers/context_menu_controller.js +275 -127
  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 +75 -2
  68. package/dist/controllers/countdown_controller.js +235 -97
  69. package/dist/controllers/countdown_controller.js.map +1 -1
  70. package/dist/controllers/currency_input_controller.d.ts +93 -15
  71. package/dist/controllers/currency_input_controller.js +241 -118
  72. package/dist/controllers/currency_input_controller.js.map +1 -1
  73. package/dist/controllers/data_grid_controller.d.ts +78 -22
  74. package/dist/controllers/data_grid_controller.js +229 -135
  75. package/dist/controllers/data_grid_controller.js.map +1 -1
  76. package/dist/controllers/date_range_picker_controller.d.ts +64 -11
  77. package/dist/controllers/date_range_picker_controller.js +359 -165
  78. package/dist/controllers/date_range_picker_controller.js.map +1 -1
  79. package/dist/controllers/dialog_controller.d.ts +22 -3
  80. package/dist/controllers/dialog_controller.js +887 -225
  81. package/dist/controllers/dialog_controller.js.map +1 -1
  82. package/dist/controllers/direct_upload_controller.d.ts +24 -7
  83. package/dist/controllers/direct_upload_controller.js +80 -142
  84. package/dist/controllers/direct_upload_controller.js.map +1 -1
  85. package/dist/controllers/dirty_form_controller.d.ts +2 -2
  86. package/dist/controllers/dirty_form_controller.js +26 -47
  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 +175 -20
  90. package/dist/controllers/dismissible_controller.js.map +1 -1
  91. package/dist/controllers/drawer_controller.d.ts +52 -16
  92. package/dist/controllers/drawer_controller.js +963 -336
  93. package/dist/controllers/drawer_controller.js.map +1 -1
  94. package/dist/controllers/dropdown_controller.d.ts +39 -3
  95. package/dist/controllers/dropdown_controller.js +342 -85
  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 +182 -58
  99. package/dist/controllers/editable_controller.js.map +1 -1
  100. package/dist/controllers/empty_state_controller.js +67 -53
  101. package/dist/controllers/empty_state_controller.js.map +1 -1
  102. package/dist/controllers/file_dropzone_controller.d.ts +60 -18
  103. package/dist/controllers/file_dropzone_controller.js +426 -229
  104. package/dist/controllers/file_dropzone_controller.js.map +1 -1
  105. package/dist/controllers/filter_controller.d.ts +10 -4
  106. package/dist/controllers/filter_controller.js +78 -36
  107. package/dist/controllers/filter_controller.js.map +1 -1
  108. package/dist/controllers/flash_controller.d.ts +57 -14
  109. package/dist/controllers/flash_controller.js +328 -211
  110. package/dist/controllers/flash_controller.js.map +1 -1
  111. package/dist/controllers/focus_controller.d.ts +12 -3
  112. package/dist/controllers/focus_controller.js +654 -239
  113. package/dist/controllers/focus_controller.js.map +1 -1
  114. package/dist/controllers/form_field_controller.js +153 -136
  115. package/dist/controllers/form_field_controller.js.map +1 -1
  116. package/dist/controllers/form_validation_controller.js +29 -96
  117. package/dist/controllers/form_validation_controller.js.map +1 -1
  118. package/dist/controllers/frame_loading_controller.d.ts +41 -9
  119. package/dist/controllers/frame_loading_controller.js +263 -198
  120. package/dist/controllers/frame_loading_controller.js.map +1 -1
  121. package/dist/controllers/highlight_controller.d.ts +22 -2
  122. package/dist/controllers/highlight_controller.js +119 -70
  123. package/dist/controllers/highlight_controller.js.map +1 -1
  124. package/dist/controllers/hover_card_controller.d.ts +65 -4
  125. package/dist/controllers/hover_card_controller.js +335 -118
  126. package/dist/controllers/hover_card_controller.js.map +1 -1
  127. package/dist/controllers/idle_controller.d.ts +58 -4
  128. package/dist/controllers/idle_controller.js +316 -65
  129. package/dist/controllers/idle_controller.js.map +1 -1
  130. package/dist/controllers/input_mask_controller.d.ts +5 -2
  131. package/dist/controllers/input_mask_controller.js +116 -61
  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 +147 -103
  135. package/dist/controllers/intersection_controller.js.map +1 -1
  136. package/dist/controllers/lazy_frame_controller.d.ts +16 -0
  137. package/dist/controllers/lazy_frame_controller.js +9 -56
  138. package/dist/controllers/lazy_frame_controller.js.map +1 -1
  139. package/dist/controllers/listbox_controller.d.ts +84 -10
  140. package/dist/controllers/listbox_controller.js +413 -153
  141. package/dist/controllers/listbox_controller.js.map +1 -1
  142. package/dist/controllers/local_time_controller.d.ts +1 -1
  143. package/dist/controllers/local_time_controller.js +54 -64
  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 +70 -95
  147. package/dist/controllers/masonry_controller.js.map +1 -1
  148. package/dist/controllers/menu_controller.d.ts +40 -9
  149. package/dist/controllers/menu_controller.js +254 -167
  150. package/dist/controllers/menu_controller.js.map +1 -1
  151. package/dist/controllers/menubar_controller.d.ts +15 -4
  152. package/dist/controllers/menubar_controller.js +206 -331
  153. package/dist/controllers/menubar_controller.js.map +1 -1
  154. package/dist/controllers/meter_controller.d.ts +20 -0
  155. package/dist/controllers/meter_controller.js +159 -71
  156. package/dist/controllers/meter_controller.js.map +1 -1
  157. package/dist/controllers/multi_select_controller.d.ts +50 -7
  158. package/dist/controllers/multi_select_controller.js +797 -388
  159. package/dist/controllers/multi_select_controller.js.map +1 -1
  160. package/dist/controllers/navigation_menu_controller.d.ts +19 -1
  161. package/dist/controllers/navigation_menu_controller.js +156 -231
  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 +373 -174
  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 +241 -45
  168. package/dist/controllers/network_status_controller.js.map +1 -1
  169. package/dist/controllers/number_input_controller.d.ts +62 -10
  170. package/dist/controllers/number_input_controller.js +387 -227
  171. package/dist/controllers/number_input_controller.js.map +1 -1
  172. package/dist/controllers/optimistic_controller.js +28 -75
  173. package/dist/controllers/optimistic_controller.js.map +1 -1
  174. package/dist/controllers/otp_controller.d.ts +38 -7
  175. package/dist/controllers/otp_controller.js +344 -196
  176. package/dist/controllers/otp_controller.js.map +1 -1
  177. package/dist/controllers/overflow_indicator_controller.d.ts +13 -12
  178. package/dist/controllers/overflow_indicator_controller.js +167 -93
  179. package/dist/controllers/overflow_indicator_controller.js.map +1 -1
  180. package/dist/controllers/overflow_menu_controller.d.ts +66 -9
  181. package/dist/controllers/overflow_menu_controller.js +408 -277
  182. package/dist/controllers/overflow_menu_controller.js.map +1 -1
  183. package/dist/controllers/pagination_controller.d.ts +52 -15
  184. package/dist/controllers/pagination_controller.js +342 -120
  185. package/dist/controllers/pagination_controller.js.map +1 -1
  186. package/dist/controllers/password_reveal_controller.d.ts +60 -9
  187. package/dist/controllers/password_reveal_controller.js +424 -99
  188. package/dist/controllers/password_reveal_controller.js.map +1 -1
  189. package/dist/controllers/password_strength_controller.d.ts +14 -5
  190. package/dist/controllers/password_strength_controller.js +99 -153
  191. package/dist/controllers/password_strength_controller.js.map +1 -1
  192. package/dist/controllers/persist_controller.d.ts +11 -4
  193. package/dist/controllers/persist_controller.js +252 -96
  194. package/dist/controllers/persist_controller.js.map +1 -1
  195. package/dist/controllers/pointer_drag_controller.d.ts +19 -7
  196. package/dist/controllers/pointer_drag_controller.js +263 -164
  197. package/dist/controllers/pointer_drag_controller.js.map +1 -1
  198. package/dist/controllers/popover_controller.d.ts +46 -4
  199. package/dist/controllers/popover_controller.js +267 -94
  200. package/dist/controllers/popover_controller.js.map +1 -1
  201. package/dist/controllers/portal_controller.d.ts +44 -4
  202. package/dist/controllers/portal_controller.js +209 -72
  203. package/dist/controllers/portal_controller.js.map +1 -1
  204. package/dist/controllers/preview_guard_controller.d.ts +10 -4
  205. package/dist/controllers/preview_guard_controller.js +243 -112
  206. package/dist/controllers/preview_guard_controller.js.map +1 -1
  207. package/dist/controllers/progress_controller.d.ts +11 -0
  208. package/dist/controllers/progress_controller.js +132 -59
  209. package/dist/controllers/progress_controller.js.map +1 -1
  210. package/dist/controllers/radio_group_controller.d.ts +19 -8
  211. package/dist/controllers/radio_group_controller.js +138 -133
  212. package/dist/controllers/radio_group_controller.js.map +1 -1
  213. package/dist/controllers/range_slider_controller.d.ts +92 -4
  214. package/dist/controllers/range_slider_controller.js +245 -112
  215. package/dist/controllers/range_slider_controller.js.map +1 -1
  216. package/dist/controllers/rating_controller.d.ts +33 -6
  217. package/dist/controllers/rating_controller.js +429 -194
  218. package/dist/controllers/rating_controller.js.map +1 -1
  219. package/dist/controllers/read_more_controller.d.ts +26 -2
  220. package/dist/controllers/read_more_controller.js +185 -47
  221. package/dist/controllers/read_more_controller.js.map +1 -1
  222. package/dist/controllers/reading_progress_controller.d.ts +1 -1
  223. package/dist/controllers/reading_progress_controller.js +147 -135
  224. package/dist/controllers/reading_progress_controller.js.map +1 -1
  225. package/dist/controllers/relative_time_controller.d.ts +18 -4
  226. package/dist/controllers/relative_time_controller.js +145 -110
  227. package/dist/controllers/relative_time_controller.js.map +1 -1
  228. package/dist/controllers/reset_on_restore_controller.d.ts +85 -0
  229. package/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +97 -38
  230. package/dist/controllers/reset_on_restore_controller.js.map +1 -0
  231. package/dist/controllers/resizable_controller.d.ts +44 -4
  232. package/dist/controllers/resizable_controller.js +294 -118
  233. package/dist/controllers/resizable_controller.js.map +1 -1
  234. package/dist/controllers/roving_controller.js +39 -84
  235. package/dist/controllers/roving_controller.js.map +1 -1
  236. package/dist/controllers/scroll_area_controller.d.ts +7 -3
  237. package/dist/controllers/scroll_area_controller.js +428 -221
  238. package/dist/controllers/scroll_area_controller.js.map +1 -1
  239. package/dist/controllers/scroll_restore_controller.js +0 -53
  240. package/dist/controllers/scroll_restore_controller.js.map +1 -1
  241. package/dist/controllers/scroll_visibility_controller.d.ts +28 -12
  242. package/dist/controllers/scroll_visibility_controller.js +395 -146
  243. package/dist/controllers/scroll_visibility_controller.js.map +1 -1
  244. package/dist/controllers/scrollspy_controller.d.ts +9 -3
  245. package/dist/controllers/scrollspy_controller.js +181 -236
  246. package/dist/controllers/scrollspy_controller.js.map +1 -1
  247. package/dist/controllers/separator_controller.d.ts +59 -17
  248. package/dist/controllers/separator_controller.js +288 -132
  249. package/dist/controllers/separator_controller.js.map +1 -1
  250. package/dist/controllers/sidebar_controller.d.ts +81 -7
  251. package/dist/controllers/sidebar_controller.js +1071 -375
  252. package/dist/controllers/sidebar_controller.js.map +1 -1
  253. package/dist/controllers/skeleton_controller.d.ts +23 -0
  254. package/dist/controllers/skeleton_controller.js +248 -92
  255. package/dist/controllers/skeleton_controller.js.map +1 -1
  256. package/dist/controllers/slider_controller.d.ts +72 -8
  257. package/dist/controllers/slider_controller.js +211 -96
  258. package/dist/controllers/slider_controller.js.map +1 -1
  259. package/dist/controllers/smart_sticky_header_controller.d.ts +21 -3
  260. package/dist/controllers/smart_sticky_header_controller.js +163 -54
  261. package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
  262. package/dist/controllers/sortable_controller.js +13 -110
  263. package/dist/controllers/sortable_controller.js.map +1 -1
  264. package/dist/controllers/spinner_controller.d.ts +39 -4
  265. package/dist/controllers/spinner_controller.js +277 -161
  266. package/dist/controllers/spinner_controller.js.map +1 -1
  267. package/dist/controllers/step_indicator_controller.d.ts +24 -17
  268. package/dist/controllers/step_indicator_controller.js +107 -53
  269. package/dist/controllers/step_indicator_controller.js.map +1 -1
  270. package/dist/controllers/stepper_controller.d.ts +43 -9
  271. package/dist/controllers/stepper_controller.js +171 -48
  272. package/dist/controllers/stepper_controller.js.map +1 -1
  273. package/dist/controllers/stick_to_bottom_controller.d.ts +25 -0
  274. package/dist/controllers/stick_to_bottom_controller.js +310 -116
  275. package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
  276. package/dist/controllers/sticky_observer_controller.d.ts +11 -0
  277. package/dist/controllers/sticky_observer_controller.js +214 -49
  278. package/dist/controllers/sticky_observer_controller.js.map +1 -1
  279. package/dist/controllers/submit_once_controller.d.ts +22 -6
  280. package/dist/controllers/submit_once_controller.js +294 -192
  281. package/dist/controllers/submit_once_controller.js.map +1 -1
  282. package/dist/controllers/switch_controller.d.ts +40 -7
  283. package/dist/controllers/switch_controller.js +107 -43
  284. package/dist/controllers/switch_controller.js.map +1 -1
  285. package/dist/controllers/tabs_controller.d.ts +13 -1
  286. package/dist/controllers/tabs_controller.js +50 -25
  287. package/dist/controllers/tabs_controller.js.map +1 -1
  288. package/dist/controllers/tags_input_controller.d.ts +27 -3
  289. package/dist/controllers/tags_input_controller.js +290 -149
  290. package/dist/controllers/tags_input_controller.js.map +1 -1
  291. package/dist/controllers/textarea_autosize_controller.d.ts +10 -0
  292. package/dist/controllers/textarea_autosize_controller.js +71 -58
  293. package/dist/controllers/textarea_autosize_controller.js.map +1 -1
  294. package/dist/controllers/theme_controller.d.ts +37 -8
  295. package/dist/controllers/theme_controller.js +148 -80
  296. package/dist/controllers/theme_controller.js.map +1 -1
  297. package/dist/controllers/time_picker_controller.d.ts +18 -1
  298. package/dist/controllers/time_picker_controller.js +162 -81
  299. package/dist/controllers/time_picker_controller.js.map +1 -1
  300. package/dist/controllers/toast_controller.d.ts +85 -23
  301. package/dist/controllers/toast_controller.js +365 -193
  302. package/dist/controllers/toast_controller.js.map +1 -1
  303. package/dist/controllers/toggle_group_controller.d.ts +60 -9
  304. package/dist/controllers/toggle_group_controller.js +194 -99
  305. package/dist/controllers/toggle_group_controller.js.map +1 -1
  306. package/dist/controllers/toolbar_controller.js +92 -90
  307. package/dist/controllers/toolbar_controller.js.map +1 -1
  308. package/dist/controllers/tooltip_controller.d.ts +52 -2
  309. package/dist/controllers/tooltip_controller.js +185 -125
  310. package/dist/controllers/tooltip_controller.js.map +1 -1
  311. package/dist/controllers/transition_controller.d.ts +22 -4
  312. package/dist/controllers/transition_controller.js +123 -115
  313. package/dist/controllers/transition_controller.js.map +1 -1
  314. package/dist/controllers/tree_view_controller.d.ts +59 -18
  315. package/dist/controllers/tree_view_controller.js +248 -290
  316. package/dist/controllers/tree_view_controller.js.map +1 -1
  317. package/dist/index.d.ts +33 -3
  318. package/dist/index.js +8649 -8572
  319. package/dist/index.js.map +1 -1
  320. package/dist/inspector/cli.d.ts +95 -9
  321. package/dist/inspector/cli.js +343 -77
  322. package/dist/inspector/cli.js.map +1 -1
  323. package/dist/inspector/cli_bin.js +390 -96
  324. package/dist/inspector/cli_bin.js.map +1 -1
  325. package/dist/inspector/examples.json +45 -45
  326. package/dist/inspector/manifest.json +1308 -155
  327. package/dist/positioning/index.d.ts +8 -0
  328. package/dist/positioning/index.js +148 -45
  329. package/dist/positioning/index.js.map +1 -1
  330. package/package.json +7 -7
  331. package/dist/controllers/reset_before_cache_controller.d.ts +0 -76
  332. package/dist/controllers/reset_before_cache_controller.js.map +0 -1
@@ -1,8 +1,152 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/popover_controller.ts
3
+ function sharedRegistry(key, create) {
4
+ const symbol = Symbol.for(key);
5
+ const scope = globalThis;
6
+ const existing = scope[symbol];
7
+ if (existing !== void 0) return existing;
8
+ const registry = create();
9
+ Object.defineProperty(globalThis, symbol, { value: registry });
10
+ return registry;
11
+ }
12
+
13
+ function isAttributeValue(value) {
14
+ return value === null || typeof value === "string";
15
+ }
16
+ function readLeaseRecord(element, record) {
17
+ try {
18
+ const parsed = JSON.parse(element.getAttribute(record) ?? "null");
19
+ if (!Array.isArray(parsed)) return void 0;
20
+ const [original, written, ...rest] = parsed;
21
+ const linked = rest[0] !== false;
22
+ const beneath = linked ? rest : rest.slice(1);
23
+ if (!beneath.every((under) => typeof under === "string")) return void 0;
24
+ return isAttributeValue(original) && isAttributeValue(written) ? { original, written, linked, beneath } : void 0;
25
+ } catch {
26
+ return void 0;
27
+ }
28
+ }
29
+ var AttributeLease = class _AttributeLease {
30
+ static #registry = sharedRegistry(
31
+ "stimeo-ui.attribute-lease.registry.v1",
32
+ () => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
33
+ );
34
+ #attribute;
35
+ #record;
36
+ #base;
37
+ #held = /* @__PURE__ */ new Set();
38
+ constructor(attribute, owner, options = {}) {
39
+ this.#attribute = attribute;
40
+ this.#record = `data-${owner}-${attribute}-lease`;
41
+ this.#base = options.base === true;
42
+ const names = _AttributeLease.#registry.names;
43
+ names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
44
+ }
45
+ write(element, value) {
46
+ const stack = this.#stack(element);
47
+ const hold = this.#take(stack) ?? this.#acquire(element, stack);
48
+ this.#held.add(element);
49
+ const shows = !this.#covered(element, stack, hold);
50
+ hold.written = value;
51
+ this.#mark(element, stack);
52
+ if (shows) this.#reflect(element, value);
53
+ }
54
+ return(element) {
55
+ const held = this.#held.delete(element);
56
+ const known = _AttributeLease.#registry.stacks.get(element)?.has(this.#attribute);
57
+ const stack = held || known || element.hasAttribute(this.#record) ? this.#stack(element) : [];
58
+ const hold = this.#take(stack);
59
+ if (!hold) return false;
60
+ const carries = element.getAttribute(this.#attribute) === hold.written;
61
+ const owns = carries && !this.#covered(element, stack, hold);
62
+ const index = stack.indexOf(hold);
63
+ stack.splice(index, 1);
64
+ const above = stack[index];
65
+ if (above) above.linked &&= hold.linked;
66
+ this.#mark(element, stack);
67
+ if (!owns) return true;
68
+ const below = hold.linked ? stack[index - 1] : void 0;
69
+ this.#reflect(element, below ? below.written : hold.original);
70
+ return true;
71
+ }
72
+ returnAll() {
73
+ for (const element of Array.from(this.#held)) this.return(element);
74
+ }
75
+ #stack(element) {
76
+ const stacks = _AttributeLease.#registry.stacks;
77
+ const byAttribute = stacks.get(element) ?? /* @__PURE__ */ new Map();
78
+ stacks.set(element, byAttribute);
79
+ const stack = byAttribute.get(this.#attribute) ?? this.#seed(element);
80
+ byAttribute.set(this.#attribute, stack);
81
+ return stack;
82
+ }
83
+ #seed(element) {
84
+ const found = [];
85
+ for (const record of _AttributeLease.#registry.names.get(this.#attribute) ?? []) {
86
+ const read = readLeaseRecord(element, record);
87
+ if (read) found.push({ ...read, record });
88
+ }
89
+ const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
90
+ return found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
91
+ lease: null,
92
+ record,
93
+ written,
94
+ original,
95
+ linked: linked && index > 0
96
+ }));
97
+ }
98
+ #take(stack) {
99
+ const hold = stack.find((held) => held.lease === this) ?? stack.find((held) => held.lease === null && held.record === this.#record);
100
+ if (hold) hold.lease = this;
101
+ return hold;
102
+ }
103
+ #acquire(element, stack) {
104
+ const current = element.getAttribute(this.#attribute);
105
+ const top = stack.at(-1);
106
+ const bottom = stack[0];
107
+ const over = top?.written === current ? top : void 0;
108
+ const from = this.#base ? bottom : over;
109
+ const hold = {
110
+ lease: this,
111
+ record: this.#record,
112
+ written: current,
113
+ original: from ? from.original : current,
114
+ linked: !this.#base && over !== void 0
115
+ };
116
+ if (this.#base && bottom) {
117
+ bottom.linked = true;
118
+ stack.unshift(hold);
119
+ } else stack.push(hold);
120
+ return hold;
121
+ }
122
+ #covered(element, stack, hold) {
123
+ const current = element.getAttribute(this.#attribute);
124
+ return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current);
125
+ }
126
+ #mark(element, stack) {
127
+ const records = /* @__PURE__ */ new Map([[this.#record, null]]);
128
+ stack.forEach((hold, index) => {
129
+ const names = stack.slice(0, index).map((under) => under.record);
130
+ const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
131
+ const marker = hold.linked || beneath.length === 0 ? [] : [false];
132
+ records.set(
133
+ hold.record,
134
+ hold.written === hold.original && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([hold.original, hold.written, ...marker, ...beneath])
135
+ );
136
+ });
137
+ for (const [name, recorded] of records) {
138
+ if (element.getAttribute(name) === recorded) continue;
139
+ if (recorded === null) element.removeAttribute(name);
140
+ else element.setAttribute(name, recorded);
141
+ }
142
+ }
143
+ #reflect(element, value) {
144
+ if (element.getAttribute(this.#attribute) === value) return;
145
+ if (value === null) element.removeAttribute(this.#attribute);
146
+ else element.setAttribute(this.#attribute, value);
147
+ }
148
+ };
4
149
 
5
- // src/utils/escape_layer.ts
6
150
  function claimsWhileFocusWithin(element) {
7
151
  return () => {
8
152
  const active = element.ownerDocument.activeElement;
@@ -10,17 +154,11 @@ function claimsWhileFocusWithin(element) {
10
154
  };
11
155
  }
12
156
  var EscapeLayer = class _EscapeLayer {
13
- static #registries = /* @__PURE__ */ new WeakMap();
14
- #ownerDocument = null;
15
- /** Dismissal callback while active; `null` when inactive. */
16
- #onDismiss = null;
17
- /** Live predicate deciding whether the layer claims a press; `null` = always. */
18
- #claims = null;
19
- /**
20
- * Activates this layer at the top of its document's Escape stack, installing
21
- * the document's shared resolver listener if this is its first layer.
22
- * Re-activating an already-active layer moves it to the top.
23
- */
157
+ static #registries = sharedRegistry(
158
+ "stimeo-ui.escape-layer.registry.v1",
159
+ () => /* @__PURE__ */ new WeakMap()
160
+ );
161
+ #active = null;
24
162
  activate(ownerDocument = document, options) {
25
163
  this.deactivate();
26
164
  let registry = _EscapeLayer.#registries.get(ownerDocument);
@@ -29,44 +167,31 @@ var EscapeLayer = class _EscapeLayer {
29
167
  _EscapeLayer.#registries.set(ownerDocument, registry);
30
168
  ownerDocument.addEventListener("keydown", registry.onKeydown);
31
169
  }
32
- registry.stack.push(this);
33
- this.#ownerDocument = ownerDocument;
34
- this.#onDismiss = options.onDismiss;
35
- this.#claims = options.claims ?? null;
36
- }
37
- /**
38
- * Removes this layer from its document's Escape stack, uninstalling the
39
- * shared listener when the stack empties. Safe to call when inactive.
40
- */
170
+ const entry = { onDismiss: options.onDismiss, claims: options.claims ?? null };
171
+ registry.stack.push(entry);
172
+ this.#active = { document: ownerDocument, entry };
173
+ }
41
174
  deactivate() {
42
- const ownerDocument = this.#ownerDocument;
43
- if (!ownerDocument) return;
44
- const registry = _EscapeLayer.#registries.get(ownerDocument);
175
+ const active = this.#active;
176
+ if (!active) return;
177
+ const registry = _EscapeLayer.#registries.get(active.document);
45
178
  if (registry) {
46
- const index = registry.stack.lastIndexOf(this);
179
+ const index = registry.stack.lastIndexOf(active.entry);
47
180
  if (index >= 0) registry.stack.splice(index, 1);
48
181
  if (registry.stack.length === 0) {
49
- ownerDocument.removeEventListener("keydown", registry.onKeydown);
50
- _EscapeLayer.#registries.delete(ownerDocument);
182
+ active.document.removeEventListener("keydown", registry.onKeydown);
183
+ _EscapeLayer.#registries.delete(active.document);
51
184
  }
52
185
  }
53
- this.#ownerDocument = null;
54
- this.#onDismiss = null;
55
- this.#claims = null;
56
- }
57
- /**
58
- * Whether this active layer would own a press right now: it is the topmost
59
- * layer whose {@link EscapeLayerOptions.claims} passes. Exposed for tests
60
- * and diagnostics — production dismissal goes through the shared listener.
61
- */
186
+ this.#active = null;
187
+ }
62
188
  get ownsEscape() {
63
- const ownerDocument = this.#ownerDocument;
64
- if (!ownerDocument) return false;
65
- const registry = _EscapeLayer.#registries.get(ownerDocument);
189
+ const active = this.#active;
190
+ if (!active) return false;
191
+ const registry = _EscapeLayer.#registries.get(active.document);
66
192
  if (!registry) return false;
67
- return _EscapeLayer.#resolveOwner(registry.stack) === this;
193
+ return _EscapeLayer.#resolveOwner(registry.stack) === active.entry;
68
194
  }
69
- /** Builds a document's registry with its shared resolver listener. */
70
195
  static #createRegistry() {
71
196
  const registry = {
72
197
  stack: [],
@@ -75,24 +200,22 @@ var EscapeLayer = class _EscapeLayer {
75
200
  const owner = _EscapeLayer.#resolveOwner(registry.stack);
76
201
  if (!owner) return;
77
202
  event.preventDefault();
78
- owner.#onDismiss?.();
203
+ owner.onDismiss();
79
204
  }
80
205
  };
81
206
  return registry;
82
207
  }
83
- /** The topmost stack layer whose claims predicate passes, or `null`. */
84
208
  static #resolveOwner(stack) {
85
209
  for (let index = stack.length - 1; index >= 0; index--) {
86
210
  const layer = stack[index];
87
211
  if (!layer) continue;
88
- if (layer.#claims && !layer.#claims()) continue;
212
+ if (layer.claims && !layer.claims()) continue;
89
213
  return layer;
90
214
  }
91
215
  return null;
92
216
  }
93
217
  };
94
218
 
95
- // src/utils/focus_candidate.ts
96
219
  function inheritsFieldsetDisabled(control) {
97
220
  let fieldset = control.closest("fieldset[disabled]");
98
221
  while (fieldset) {
@@ -102,8 +225,19 @@ function inheritsFieldsetDisabled(control) {
102
225
  }
103
226
  return false;
104
227
  }
228
+ function unslotted(element) {
229
+ return element.assignedSlot === null && element.parentElement?.shadowRoot != null;
230
+ }
231
+ function flatTreeParent(element) {
232
+ if (unslotted(element)) return null;
233
+ const parent = element.assignedSlot ?? element.parentNode;
234
+ if (parent instanceof ShadowRoot) return parent.host;
235
+ return parent instanceof Element ? parent : null;
236
+ }
105
237
  function canTakeFocus(element) {
106
- if (element.closest("[hidden], [inert]")) return false;
238
+ for (let node = element; node; node = flatTreeParent(node)) {
239
+ if (unslotted(node) || node.matches("[hidden], [inert]")) return false;
240
+ }
107
241
  if (element instanceof HTMLInputElement && element.type === "hidden") return false;
108
242
  if (!("disabled" in element)) return true;
109
243
  if (element.disabled) return false;
@@ -167,7 +301,6 @@ function firstTabStop(root) {
167
301
  return null;
168
302
  }
169
303
 
170
- // src/utils/scroll_dismiss.ts
171
304
  function observeScrollDismiss(element, onScroll) {
172
305
  const targets = [...scrollParents(element), window];
173
306
  const handler = () => onScroll();
@@ -192,67 +325,114 @@ function isScrollable(element) {
192
325
  return /auto|scroll|overlay/.test(style.overflow + style.overflowX + style.overflowY);
193
326
  }
194
327
 
195
- // src/controllers/popover_controller.ts
328
+ var FOCUS_EVENTS = /* @__PURE__ */ new Set(["blur", "focus", "focusin", "focusout"]);
329
+ var POINTER_EVENTS = /* @__PURE__ */ new Set(["mouseenter", "mouseleave", "pointerenter", "pointerleave"]);
330
+ function stateReasonFor(event) {
331
+ if (!event) return "api";
332
+ if (FOCUS_EVENTS.has(event.type)) return "focus";
333
+ if (POINTER_EVENTS.has(event.type)) return "pointer";
334
+ return "user";
335
+ }
336
+
196
337
  var PopoverController = class extends Controller {
197
338
  static targets = ["trigger", "panel"];
198
339
  static values = {
199
340
  closeOnScroll: { type: Boolean, default: false }
200
341
  };
201
342
  static actions = ["close", "open", "toggle"];
202
- /** Cleanup for the dismiss-on-scroll listeners while open, or `null`. */
343
+ static events = ["close", "open"];
203
344
  #stopScrollDismiss = null;
204
- /** Escape-stack membership while open; the shared resolver dismisses via it. */
205
345
  #escapeLayer = new EscapeLayer();
206
- /** Starts closed and registers the standing dismissal listeners. */
346
+ #expanded = new AttributeLease("aria-expanded", this.identifier);
347
+ #shownPanel = null;
348
+ #connected = false;
349
+ #reporting = false;
207
350
  connect() {
208
- this.close();
351
+ this.#close("api");
209
352
  document.addEventListener("click", this.#onOutsideClick, true);
210
353
  this.element.addEventListener("focusout", this.#onFocusOut);
354
+ this.#connected = true;
355
+ this.#reporting = true;
211
356
  }
212
- /**
213
- * Removes every standing listener registered in {@link connect} plus any active
214
- * dismiss-on-scroll observers. `removeEventListener` is a no-op when it was
215
- * never added, so this is safe in the closed state too — no listener outlives
216
- * the element after a Turbo navigation.
217
- */
218
357
  disconnect() {
219
- this.#escapeLayer.deactivate();
358
+ this.#connected = false;
359
+ this.#reporting = false;
360
+ this.#release();
220
361
  document.removeEventListener("click", this.#onOutsideClick, true);
221
362
  this.element.removeEventListener("focusout", this.#onFocusOut);
222
- this.#stopScrollDismiss?.();
223
- this.#stopScrollDismiss = null;
224
363
  }
225
- /** Toggles the popover. Bound via `data-action` (click on the trigger). */
226
- toggle() {
364
+ closeOnScrollValueChanged() {
365
+ if (this.#shownPanel) this.#syncScrollDismiss();
366
+ }
367
+ panelTargetDisconnected(panel) {
368
+ if (panel !== this.#shownPanel) return;
369
+ if (this.panelTargets.includes(panel)) return;
370
+ this.#release();
371
+ panel.hidden = true;
372
+ this.#reflectClosed();
373
+ }
374
+ triggerTargetConnected() {
375
+ if (this.#connected) this.#reflectTrigger();
376
+ }
377
+ triggerTargetDisconnected(trigger) {
378
+ if (!this.triggerTargets.includes(trigger)) this.#expanded.return(trigger);
379
+ if (this.#connected) this.#reflectTrigger();
380
+ }
381
+ toggle(event) {
227
382
  if (this.#isOpen) {
228
- this.close();
383
+ this.close(event);
229
384
  } else {
230
- this.open();
385
+ this.open(event);
231
386
  }
232
387
  }
233
- /** Opens the panel, reflects state, and moves focus inside it. */
234
- open() {
388
+ open(event) {
389
+ this.#open(stateReasonFor(event));
390
+ }
391
+ close(event) {
392
+ this.#close(stateReasonFor(event));
393
+ }
394
+ #open(reason) {
235
395
  if (!this.hasPanelTarget || this.#isOpen) return;
236
- this.panelTarget.hidden = false;
237
- if (this.hasTriggerTarget) this.triggerTarget.setAttribute("aria-expanded", "true");
396
+ const panel = this.panelTarget;
397
+ panel.hidden = false;
398
+ if (this.hasTriggerTarget) this.#expanded.write(this.triggerTarget, "true");
399
+ this.#shownPanel = panel;
400
+ if (this.#reporting) this.dispatch("open", { detail: { reason }, cancelable: false });
401
+ if (this.#shownPanel !== panel || !this.#isOpen) return;
238
402
  this.#escapeLayer.activate(document, {
239
403
  onDismiss: () => this.#closeAndRestore(),
240
404
  claims: claimsWhileFocusWithin(this.element)
241
405
  });
242
- if (this.closeOnScrollValue && !this.#stopScrollDismiss) {
243
- this.#stopScrollDismiss = observeScrollDismiss(this.element, () => this.close());
244
- }
406
+ this.#syncScrollDismiss();
245
407
  this.#focusFirst();
246
408
  }
247
- /** Closes the panel and reflects the collapsed state. Bound via `data-action`. */
248
- close() {
409
+ #close(reason) {
410
+ const was = this.#isOpen;
411
+ this.#release();
412
+ this.#reflectClosed();
413
+ if (was && this.#reporting) this.dispatch("close", { detail: { reason }, cancelable: false });
414
+ }
415
+ #reflectClosed() {
416
+ if (this.hasPanelTarget) this.panelTarget.hidden = true;
417
+ if (this.hasTriggerTarget) this.#expanded.write(this.triggerTarget, "false");
418
+ }
419
+ #reflectTrigger() {
420
+ if (this.hasTriggerTarget) this.#expanded.write(this.triggerTarget, String(this.#isOpen));
421
+ }
422
+ #release() {
423
+ this.#shownPanel = null;
249
424
  this.#escapeLayer.deactivate();
250
425
  this.#stopScrollDismiss?.();
251
426
  this.#stopScrollDismiss = null;
252
- if (this.hasPanelTarget) this.panelTarget.hidden = true;
253
- if (this.hasTriggerTarget) this.triggerTarget.setAttribute("aria-expanded", "false");
254
427
  }
255
- /** Moves focus to the first focusable element in the panel, or the panel itself. */
428
+ #syncScrollDismiss() {
429
+ if (this.closeOnScrollValue) {
430
+ this.#stopScrollDismiss ??= observeScrollDismiss(this.element, () => this.#close("scroll"));
431
+ return;
432
+ }
433
+ this.#stopScrollDismiss?.();
434
+ this.#stopScrollDismiss = null;
435
+ }
256
436
  #focusFirst() {
257
437
  const first = firstTabStop(this.panelTarget);
258
438
  if (first) {
@@ -262,36 +442,29 @@ var PopoverController = class extends Controller {
262
442
  if (!this.panelTarget.hasAttribute("tabindex")) this.panelTarget.tabIndex = -1;
263
443
  this.panelTarget.focus();
264
444
  }
265
- /** Closes and restores focus to the trigger for explicit keyboard dismissal. */
266
445
  #closeAndRestore() {
267
- this.close();
446
+ this.#close("escape");
268
447
  if (this.hasTriggerTarget) this.triggerTarget.focus();
269
448
  }
270
- /** Closes without moving focus when a click lands outside the controller element. */
271
449
  #onOutsideClick = (event) => {
272
450
  const target = event.target;
273
- if (this.#isOpen && target instanceof Node && !this.element.contains(target)) this.close();
451
+ if (this.#closable && target instanceof Node && !this.element.contains(target)) {
452
+ this.#close("outside");
453
+ }
274
454
  };
275
- /**
276
- * Closes when focus leaves the controller for a known external destination
277
- * (e.g. forward Tab past the panel or reverse Tab past the trigger). Focus is
278
- * not restored — the natural destination is kept, which is the modeless
279
- * contract. A null/non-Node destination is indeterminate: browsers use it for
280
- * clicks on non-focusable content and window deactivation, so the later outside
281
- * click handler decides pointer dismissal instead.
282
- */
283
455
  #onFocusOut = (event) => {
284
- if (!this.#isOpen) return;
456
+ if (!this.#closable) return;
285
457
  const next = event.relatedTarget;
286
458
  if (!(next instanceof Node) || this.element.contains(next)) return;
287
- this.close();
459
+ this.#close("focus");
288
460
  };
289
- /** Whether the panel is currently visible. */
290
461
  get #isOpen() {
291
462
  return this.hasPanelTarget && !this.panelTarget.hidden;
292
463
  }
464
+ get #closable() {
465
+ return this.#isOpen || this.#shownPanel !== null;
466
+ }
293
467
  };
294
468
 
295
469
  export { PopoverController };
296
- //# sourceMappingURL=popover_controller.js.map
297
470
  //# sourceMappingURL=popover_controller.js.map