stimeo-ui 0.16.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (337) hide show
  1. package/CHANGELOG.md +136 -0
  2. package/README.md +27 -11
  3. package/dist/cable/index.d.ts +88 -31
  4. package/dist/cable/index.js +384 -449
  5. package/dist/cable/index.js.map +1 -1
  6. package/dist/coerce-JtZVNG5h.d.ts +20 -0
  7. package/dist/controllers/accordion_controller.d.ts +4 -2
  8. package/dist/controllers/accordion_controller.js +174 -55
  9. package/dist/controllers/accordion_controller.js.map +1 -1
  10. package/dist/controllers/alert_dialog_controller.d.ts +12 -2
  11. package/dist/controllers/alert_dialog_controller.js +903 -235
  12. package/dist/controllers/alert_dialog_controller.js.map +1 -1
  13. package/dist/controllers/announcer_controller.d.ts +37 -5
  14. package/dist/controllers/announcer_controller.js +238 -205
  15. package/dist/controllers/announcer_controller.js.map +1 -1
  16. package/dist/controllers/aspect_ratio_controller.js +0 -10
  17. package/dist/controllers/aspect_ratio_controller.js.map +1 -1
  18. package/dist/controllers/auto_submit_controller.d.ts +30 -6
  19. package/dist/controllers/auto_submit_controller.js +414 -145
  20. package/dist/controllers/auto_submit_controller.js.map +1 -1
  21. package/dist/controllers/avatar_controller.js +185 -107
  22. package/dist/controllers/avatar_controller.js.map +1 -1
  23. package/dist/controllers/breadcrumb_controller.js +0 -130
  24. package/dist/controllers/breadcrumb_controller.js.map +1 -1
  25. package/dist/controllers/bulk_select_controller.d.ts +21 -3
  26. package/dist/controllers/bulk_select_controller.js +282 -58
  27. package/dist/controllers/bulk_select_controller.js.map +1 -1
  28. package/dist/controllers/calendar_controller.d.ts +38 -16
  29. package/dist/controllers/calendar_controller.js +228 -260
  30. package/dist/controllers/calendar_controller.js.map +1 -1
  31. package/dist/controllers/carousel_controller.d.ts +43 -12
  32. package/dist/controllers/carousel_controller.js +536 -436
  33. package/dist/controllers/carousel_controller.js.map +1 -1
  34. package/dist/controllers/character_counter_controller.d.ts +44 -7
  35. package/dist/controllers/character_counter_controller.js +493 -207
  36. package/dist/controllers/character_counter_controller.js.map +1 -1
  37. package/dist/controllers/checkbox_controller.d.ts +7 -2
  38. package/dist/controllers/checkbox_controller.js +38 -74
  39. package/dist/controllers/checkbox_controller.js.map +1 -1
  40. package/dist/controllers/clipboard_controller.d.ts +16 -5
  41. package/dist/controllers/clipboard_controller.js +261 -149
  42. package/dist/controllers/clipboard_controller.js.map +1 -1
  43. package/dist/controllers/collapsible_controller.d.ts +17 -5
  44. package/dist/controllers/collapsible_controller.js +304 -120
  45. package/dist/controllers/collapsible_controller.js.map +1 -1
  46. package/dist/controllers/color_picker_controller.d.ts +18 -6
  47. package/dist/controllers/color_picker_controller.js +178 -146
  48. package/dist/controllers/color_picker_controller.js.map +1 -1
  49. package/dist/controllers/combobox_controller.d.ts +24 -6
  50. package/dist/controllers/combobox_controller.js +522 -156
  51. package/dist/controllers/combobox_controller.js.map +1 -1
  52. package/dist/controllers/command_palette_controller.d.ts +51 -20
  53. package/dist/controllers/command_palette_controller.js +1156 -395
  54. package/dist/controllers/command_palette_controller.js.map +1 -1
  55. package/dist/controllers/conditional_fields_controller.d.ts +15 -2
  56. package/dist/controllers/conditional_fields_controller.js +300 -171
  57. package/dist/controllers/conditional_fields_controller.js.map +1 -1
  58. package/dist/controllers/confirm_controller.d.ts +49 -12
  59. package/dist/controllers/confirm_controller.js +980 -262
  60. package/dist/controllers/confirm_controller.js.map +1 -1
  61. package/dist/controllers/context_menu_controller.d.ts +80 -18
  62. package/dist/controllers/context_menu_controller.js +346 -153
  63. package/dist/controllers/context_menu_controller.js.map +1 -1
  64. package/dist/controllers/count_up_controller.d.ts +13 -1
  65. package/dist/controllers/count_up_controller.js +73 -21
  66. package/dist/controllers/count_up_controller.js.map +1 -1
  67. package/dist/controllers/countdown_controller.d.ts +47 -3
  68. package/dist/controllers/countdown_controller.js +281 -158
  69. package/dist/controllers/countdown_controller.js.map +1 -1
  70. package/dist/controllers/currency_input_controller.d.ts +93 -10
  71. package/dist/controllers/currency_input_controller.js +575 -225
  72. package/dist/controllers/currency_input_controller.js.map +1 -1
  73. package/dist/controllers/data_grid_controller.d.ts +25 -12
  74. package/dist/controllers/data_grid_controller.js +248 -214
  75. package/dist/controllers/data_grid_controller.js.map +1 -1
  76. package/dist/controllers/date_range_picker_controller.d.ts +42 -14
  77. package/dist/controllers/date_range_picker_controller.js +338 -235
  78. package/dist/controllers/date_range_picker_controller.js.map +1 -1
  79. package/dist/controllers/dialog_controller.d.ts +17 -6
  80. package/dist/controllers/dialog_controller.js +899 -237
  81. package/dist/controllers/dialog_controller.js.map +1 -1
  82. package/dist/controllers/direct_upload_controller.d.ts +25 -8
  83. package/dist/controllers/direct_upload_controller.js +97 -167
  84. package/dist/controllers/direct_upload_controller.js.map +1 -1
  85. package/dist/controllers/dirty_form_controller.d.ts +6 -1
  86. package/dist/controllers/dirty_form_controller.js +72 -69
  87. package/dist/controllers/dirty_form_controller.js.map +1 -1
  88. package/dist/controllers/dismissible_controller.d.ts +19 -0
  89. package/dist/controllers/dismissible_controller.js +196 -24
  90. package/dist/controllers/dismissible_controller.js.map +1 -1
  91. package/dist/controllers/drawer_controller.d.ts +39 -11
  92. package/dist/controllers/drawer_controller.js +974 -355
  93. package/dist/controllers/drawer_controller.js.map +1 -1
  94. package/dist/controllers/dropdown_controller.d.ts +31 -1
  95. package/dist/controllers/dropdown_controller.js +339 -96
  96. package/dist/controllers/dropdown_controller.js.map +1 -1
  97. package/dist/controllers/editable_controller.d.ts +12 -1
  98. package/dist/controllers/editable_controller.js +315 -88
  99. package/dist/controllers/editable_controller.js.map +1 -1
  100. package/dist/controllers/empty_state_controller.js +79 -58
  101. package/dist/controllers/empty_state_controller.js.map +1 -1
  102. package/dist/controllers/file_dropzone_controller.d.ts +63 -18
  103. package/dist/controllers/file_dropzone_controller.js +322 -211
  104. package/dist/controllers/file_dropzone_controller.js.map +1 -1
  105. package/dist/controllers/filter_controller.js +77 -42
  106. package/dist/controllers/filter_controller.js.map +1 -1
  107. package/dist/controllers/flash_controller.d.ts +35 -12
  108. package/dist/controllers/flash_controller.js +238 -347
  109. package/dist/controllers/flash_controller.js.map +1 -1
  110. package/dist/controllers/focus_controller.d.ts +15 -6
  111. package/dist/controllers/focus_controller.js +679 -240
  112. package/dist/controllers/focus_controller.js.map +1 -1
  113. package/dist/controllers/form_field_controller.js +156 -132
  114. package/dist/controllers/form_field_controller.js.map +1 -1
  115. package/dist/controllers/form_validation_controller.d.ts +3 -3
  116. package/dist/controllers/form_validation_controller.js +31 -97
  117. package/dist/controllers/form_validation_controller.js.map +1 -1
  118. package/dist/controllers/frame_loading_controller.d.ts +47 -14
  119. package/dist/controllers/frame_loading_controller.js +275 -217
  120. package/dist/controllers/frame_loading_controller.js.map +1 -1
  121. package/dist/controllers/highlight_controller.d.ts +27 -6
  122. package/dist/controllers/highlight_controller.js +107 -75
  123. package/dist/controllers/highlight_controller.js.map +1 -1
  124. package/dist/controllers/hover_card_controller.d.ts +60 -4
  125. package/dist/controllers/hover_card_controller.js +327 -130
  126. package/dist/controllers/hover_card_controller.js.map +1 -1
  127. package/dist/controllers/idle_controller.d.ts +48 -6
  128. package/dist/controllers/idle_controller.js +271 -101
  129. package/dist/controllers/idle_controller.js.map +1 -1
  130. package/dist/controllers/input_mask_controller.d.ts +30 -13
  131. package/dist/controllers/input_mask_controller.js +483 -97
  132. package/dist/controllers/input_mask_controller.js.map +1 -1
  133. package/dist/controllers/intersection_controller.d.ts +32 -13
  134. package/dist/controllers/intersection_controller.js +150 -106
  135. package/dist/controllers/intersection_controller.js.map +1 -1
  136. package/dist/controllers/lazy_frame_controller.d.ts +19 -2
  137. package/dist/controllers/lazy_frame_controller.js +24 -68
  138. package/dist/controllers/lazy_frame_controller.js.map +1 -1
  139. package/dist/controllers/listbox_controller.d.ts +44 -9
  140. package/dist/controllers/listbox_controller.js +523 -240
  141. package/dist/controllers/listbox_controller.js.map +1 -1
  142. package/dist/controllers/local_time_controller.d.ts +9 -7
  143. package/dist/controllers/local_time_controller.js +102 -77
  144. package/dist/controllers/local_time_controller.js.map +1 -1
  145. package/dist/controllers/masonry_controller.d.ts +11 -3
  146. package/dist/controllers/masonry_controller.js +80 -96
  147. package/dist/controllers/masonry_controller.js.map +1 -1
  148. package/dist/controllers/menu_controller.d.ts +55 -11
  149. package/dist/controllers/menu_controller.js +302 -188
  150. package/dist/controllers/menu_controller.js.map +1 -1
  151. package/dist/controllers/menubar_controller.d.ts +51 -9
  152. package/dist/controllers/menubar_controller.js +232 -345
  153. package/dist/controllers/menubar_controller.js.map +1 -1
  154. package/dist/controllers/meter_controller.d.ts +33 -20
  155. package/dist/controllers/meter_controller.js +417 -87
  156. package/dist/controllers/meter_controller.js.map +1 -1
  157. package/dist/controllers/multi_select_controller.d.ts +48 -18
  158. package/dist/controllers/multi_select_controller.js +785 -393
  159. package/dist/controllers/multi_select_controller.js.map +1 -1
  160. package/dist/controllers/navigation_menu_controller.d.ts +27 -6
  161. package/dist/controllers/navigation_menu_controller.js +190 -250
  162. package/dist/controllers/navigation_menu_controller.js.map +1 -1
  163. package/dist/controllers/nested_form_controller.d.ts +10 -0
  164. package/dist/controllers/nested_form_controller.js +396 -192
  165. package/dist/controllers/nested_form_controller.js.map +1 -1
  166. package/dist/controllers/network_status_controller.d.ts +23 -0
  167. package/dist/controllers/network_status_controller.js +268 -62
  168. package/dist/controllers/network_status_controller.js.map +1 -1
  169. package/dist/controllers/number_input_controller.d.ts +50 -8
  170. package/dist/controllers/number_input_controller.js +610 -303
  171. package/dist/controllers/number_input_controller.js.map +1 -1
  172. package/dist/controllers/optimistic_controller.d.ts +8 -5
  173. package/dist/controllers/optimistic_controller.js +45 -87
  174. package/dist/controllers/optimistic_controller.js.map +1 -1
  175. package/dist/controllers/otp_controller.d.ts +55 -8
  176. package/dist/controllers/otp_controller.js +658 -255
  177. package/dist/controllers/otp_controller.js.map +1 -1
  178. package/dist/controllers/overflow_indicator_controller.d.ts +5 -0
  179. package/dist/controllers/overflow_indicator_controller.js +122 -113
  180. package/dist/controllers/overflow_indicator_controller.js.map +1 -1
  181. package/dist/controllers/overflow_menu_controller.d.ts +58 -20
  182. package/dist/controllers/overflow_menu_controller.js +470 -295
  183. package/dist/controllers/overflow_menu_controller.js.map +1 -1
  184. package/dist/controllers/pagination_controller.d.ts +37 -7
  185. package/dist/controllers/pagination_controller.js +332 -123
  186. package/dist/controllers/pagination_controller.js.map +1 -1
  187. package/dist/controllers/password_reveal_controller.d.ts +46 -8
  188. package/dist/controllers/password_reveal_controller.js +392 -121
  189. package/dist/controllers/password_reveal_controller.js.map +1 -1
  190. package/dist/controllers/password_strength_controller.d.ts +15 -6
  191. package/dist/controllers/password_strength_controller.js +111 -158
  192. package/dist/controllers/password_strength_controller.js.map +1 -1
  193. package/dist/controllers/persist_controller.d.ts +11 -4
  194. package/dist/controllers/persist_controller.js +165 -111
  195. package/dist/controllers/persist_controller.js.map +1 -1
  196. package/dist/controllers/pointer_drag_controller.d.ts +35 -12
  197. package/dist/controllers/pointer_drag_controller.js +434 -188
  198. package/dist/controllers/pointer_drag_controller.js.map +1 -1
  199. package/dist/controllers/popover_controller.d.ts +41 -5
  200. package/dist/controllers/popover_controller.js +269 -113
  201. package/dist/controllers/popover_controller.js.map +1 -1
  202. package/dist/controllers/portal_controller.d.ts +44 -4
  203. package/dist/controllers/portal_controller.js +215 -76
  204. package/dist/controllers/portal_controller.js.map +1 -1
  205. package/dist/controllers/preview_guard_controller.d.ts +10 -4
  206. package/dist/controllers/preview_guard_controller.js +243 -116
  207. package/dist/controllers/preview_guard_controller.js.map +1 -1
  208. package/dist/controllers/progress_controller.d.ts +20 -19
  209. package/dist/controllers/progress_controller.js +391 -78
  210. package/dist/controllers/progress_controller.js.map +1 -1
  211. package/dist/controllers/radio_group_controller.d.ts +21 -9
  212. package/dist/controllers/radio_group_controller.js +278 -211
  213. package/dist/controllers/radio_group_controller.js.map +1 -1
  214. package/dist/controllers/range_slider_controller.d.ts +47 -6
  215. package/dist/controllers/range_slider_controller.js +220 -113
  216. package/dist/controllers/range_slider_controller.js.map +1 -1
  217. package/dist/controllers/rating_controller.d.ts +20 -4
  218. package/dist/controllers/rating_controller.js +458 -211
  219. package/dist/controllers/rating_controller.js.map +1 -1
  220. package/dist/controllers/read_more_controller.d.ts +2 -0
  221. package/dist/controllers/read_more_controller.js +138 -63
  222. package/dist/controllers/read_more_controller.js.map +1 -1
  223. package/dist/controllers/reading_progress_controller.d.ts +1 -1
  224. package/dist/controllers/reading_progress_controller.js +166 -137
  225. package/dist/controllers/reading_progress_controller.js.map +1 -1
  226. package/dist/controllers/relative_time_controller.d.ts +20 -6
  227. package/dist/controllers/relative_time_controller.js +211 -112
  228. package/dist/controllers/relative_time_controller.js.map +1 -1
  229. package/dist/controllers/reset_on_restore_controller.d.ts +85 -0
  230. package/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +103 -38
  231. package/dist/controllers/reset_on_restore_controller.js.map +1 -0
  232. package/dist/controllers/resizable_controller.d.ts +31 -2
  233. package/dist/controllers/resizable_controller.js +299 -150
  234. package/dist/controllers/resizable_controller.js.map +1 -1
  235. package/dist/controllers/roving_controller.d.ts +3 -3
  236. package/dist/controllers/roving_controller.js +49 -88
  237. package/dist/controllers/roving_controller.js.map +1 -1
  238. package/dist/controllers/scroll_area_controller.d.ts +7 -3
  239. package/dist/controllers/scroll_area_controller.js +490 -246
  240. package/dist/controllers/scroll_area_controller.js.map +1 -1
  241. package/dist/controllers/scroll_restore_controller.d.ts +3 -3
  242. package/dist/controllers/scroll_restore_controller.js +14 -55
  243. package/dist/controllers/scroll_restore_controller.js.map +1 -1
  244. package/dist/controllers/scroll_visibility_controller.d.ts +28 -12
  245. package/dist/controllers/scroll_visibility_controller.js +432 -149
  246. package/dist/controllers/scroll_visibility_controller.js.map +1 -1
  247. package/dist/controllers/scrollspy_controller.d.ts +6 -1
  248. package/dist/controllers/scrollspy_controller.js +193 -248
  249. package/dist/controllers/scrollspy_controller.js.map +1 -1
  250. package/dist/controllers/separator_controller.d.ts +20 -5
  251. package/dist/controllers/separator_controller.js +285 -142
  252. package/dist/controllers/separator_controller.js.map +1 -1
  253. package/dist/controllers/sidebar_controller.d.ts +65 -8
  254. package/dist/controllers/sidebar_controller.js +1069 -404
  255. package/dist/controllers/sidebar_controller.js.map +1 -1
  256. package/dist/controllers/skeleton_controller.d.ts +23 -0
  257. package/dist/controllers/skeleton_controller.js +259 -101
  258. package/dist/controllers/skeleton_controller.js.map +1 -1
  259. package/dist/controllers/slider_controller.d.ts +29 -2
  260. package/dist/controllers/slider_controller.js +187 -86
  261. package/dist/controllers/slider_controller.js.map +1 -1
  262. package/dist/controllers/smart_sticky_header_controller.d.ts +22 -4
  263. package/dist/controllers/smart_sticky_header_controller.js +173 -66
  264. package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
  265. package/dist/controllers/sortable_controller.d.ts +4 -4
  266. package/dist/controllers/sortable_controller.js +26 -125
  267. package/dist/controllers/sortable_controller.js.map +1 -1
  268. package/dist/controllers/spinner_controller.d.ts +39 -4
  269. package/dist/controllers/spinner_controller.js +288 -173
  270. package/dist/controllers/spinner_controller.js.map +1 -1
  271. package/dist/controllers/step_indicator_controller.d.ts +9 -4
  272. package/dist/controllers/step_indicator_controller.js +105 -46
  273. package/dist/controllers/step_indicator_controller.js.map +1 -1
  274. package/dist/controllers/stepper_controller.d.ts +14 -6
  275. package/dist/controllers/stepper_controller.js +120 -73
  276. package/dist/controllers/stepper_controller.js.map +1 -1
  277. package/dist/controllers/stick_to_bottom_controller.d.ts +9 -1
  278. package/dist/controllers/stick_to_bottom_controller.js +275 -140
  279. package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
  280. package/dist/controllers/sticky_observer_controller.d.ts +11 -0
  281. package/dist/controllers/sticky_observer_controller.js +220 -49
  282. package/dist/controllers/sticky_observer_controller.js.map +1 -1
  283. package/dist/controllers/submit_once_controller.d.ts +24 -8
  284. package/dist/controllers/submit_once_controller.js +376 -227
  285. package/dist/controllers/submit_once_controller.js.map +1 -1
  286. package/dist/controllers/switch_controller.d.ts +18 -4
  287. package/dist/controllers/switch_controller.js +201 -84
  288. package/dist/controllers/switch_controller.js.map +1 -1
  289. package/dist/controllers/tabs_controller.d.ts +9 -6
  290. package/dist/controllers/tabs_controller.js +41 -30
  291. package/dist/controllers/tabs_controller.js.map +1 -1
  292. package/dist/controllers/tags_input_controller.d.ts +16 -3
  293. package/dist/controllers/tags_input_controller.js +293 -173
  294. package/dist/controllers/tags_input_controller.js.map +1 -1
  295. package/dist/controllers/textarea_autosize_controller.d.ts +11 -1
  296. package/dist/controllers/textarea_autosize_controller.js +108 -74
  297. package/dist/controllers/textarea_autosize_controller.js.map +1 -1
  298. package/dist/controllers/theme_controller.d.ts +24 -11
  299. package/dist/controllers/theme_controller.js +140 -116
  300. package/dist/controllers/theme_controller.js.map +1 -1
  301. package/dist/controllers/time_picker_controller.d.ts +55 -5
  302. package/dist/controllers/time_picker_controller.js +331 -127
  303. package/dist/controllers/time_picker_controller.js.map +1 -1
  304. package/dist/controllers/toast_controller.d.ts +40 -16
  305. package/dist/controllers/toast_controller.js +244 -324
  306. package/dist/controllers/toast_controller.js.map +1 -1
  307. package/dist/controllers/toggle_group_controller.d.ts +14 -6
  308. package/dist/controllers/toggle_group_controller.js +252 -191
  309. package/dist/controllers/toggle_group_controller.js.map +1 -1
  310. package/dist/controllers/toolbar_controller.d.ts +8 -6
  311. package/dist/controllers/toolbar_controller.js +219 -120
  312. package/dist/controllers/toolbar_controller.js.map +1 -1
  313. package/dist/controllers/tooltip_controller.d.ts +49 -4
  314. package/dist/controllers/tooltip_controller.js +158 -124
  315. package/dist/controllers/tooltip_controller.js.map +1 -1
  316. package/dist/controllers/transition_controller.d.ts +22 -4
  317. package/dist/controllers/transition_controller.js +123 -119
  318. package/dist/controllers/transition_controller.js.map +1 -1
  319. package/dist/controllers/tree_view_controller.d.ts +22 -12
  320. package/dist/controllers/tree_view_controller.js +283 -369
  321. package/dist/controllers/tree_view_controller.js.map +1 -1
  322. package/dist/index.d.ts +10 -5
  323. package/dist/index.js +8573 -10410
  324. package/dist/index.js.map +1 -1
  325. package/dist/inspector/cli.d.ts +38 -14
  326. package/dist/inspector/cli.js +108 -40
  327. package/dist/inspector/cli.js.map +1 -1
  328. package/dist/inspector/cli_bin.js +145 -64
  329. package/dist/inspector/cli_bin.js.map +1 -1
  330. package/dist/inspector/examples.json +20 -20
  331. package/dist/inspector/manifest.json +802 -101
  332. package/dist/positioning/index.d.ts +15 -7
  333. package/dist/positioning/index.js +154 -47
  334. package/dist/positioning/index.js.map +1 -1
  335. package/package.json +11 -10
  336. package/dist/controllers/reset_before_cache_controller.d.ts +0 -76
  337. package/dist/controllers/reset_before_cache_controller.js.map +0 -1
@@ -1,14 +1,207 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/context_menu_controller.ts
3
+ var FOCUS_EVENTS = /* @__PURE__ */ new Set(["blur", "focus", "focusin", "focusout"]);
4
+ var POINTER_EVENTS = /* @__PURE__ */ new Set(["mouseenter", "mouseleave", "pointerenter", "pointerleave"]);
5
+ function stateReasonFor(event) {
6
+ if (!event) return "api";
7
+ if (FOCUS_EVENTS.has(event.type)) return "focus";
8
+ if (POINTER_EVENTS.has(event.type)) return "pointer";
9
+ return "user";
10
+ }
11
+
12
+ function actionSource(source) {
13
+ if (source instanceof HTMLElement) {
14
+ return { event: null, host: source, origin: source, reason: "api" };
15
+ }
16
+ const event = source ?? null;
17
+ return {
18
+ event,
19
+ host: event?.currentTarget instanceof Element ? event.currentTarget : null,
20
+ origin: event?.target instanceof Element ? event.target : null,
21
+ reason: stateReasonFor(event)
22
+ };
23
+ }
24
+
25
+ function isAriaDisabled(element) {
26
+ for (let current = element; current; current = current.parentElement) {
27
+ if (current.getAttribute("aria-disabled") === "true") return true;
28
+ }
29
+ return false;
30
+ }
4
31
 
5
- // src/utils/arrow_step.ts
6
32
  function isReservedArrowChord(event, allow = []) {
7
33
  if (!event.key.startsWith("Arrow")) return false;
8
34
  return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
9
35
  }
36
+ function hasModifierChord(event) {
37
+ return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
38
+ }
39
+
40
+ function setAttributeIfChanged(element, name, value, beforeWrite) {
41
+ if (element.getAttribute(name) === value) return false;
42
+ if (value === null) element.removeAttribute(name);
43
+ else element.setAttribute(name, value);
44
+ return true;
45
+ }
46
+
47
+ function sharedRegistry(key, create) {
48
+ const symbol = Symbol.for(key);
49
+ const scope = globalThis;
50
+ const existing = scope[symbol];
51
+ if (existing !== void 0) return existing;
52
+ const registry2 = create();
53
+ Object.defineProperty(globalThis, symbol, { value: registry2 });
54
+ return registry2;
55
+ }
56
+
57
+ var registry = sharedRegistry(
58
+ "stimeo-ui.attribute-lease.registry.v1",
59
+ () => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
60
+ );
61
+ function isAttributeValue(value) {
62
+ return value === null || typeof value === "string";
63
+ }
64
+ function readLeaseRecord(element, record) {
65
+ try {
66
+ const parsed = JSON.parse(element.getAttribute(record) ?? "null");
67
+ if (!Array.isArray(parsed)) return void 0;
68
+ const [original, written, ...rest] = parsed;
69
+ const linked = rest[0] !== false;
70
+ const beneath = linked ? rest : rest.slice(1);
71
+ if (!beneath.every((under) => typeof under === "string")) return void 0;
72
+ return isAttributeValue(original) && isAttributeValue(written) ? { original, written, linked, beneath } : void 0;
73
+ } catch {
74
+ return void 0;
75
+ }
76
+ }
77
+ function attributeStack(element, attribute) {
78
+ const byAttribute = registry.stacks.get(element) ?? /* @__PURE__ */ new Map();
79
+ registry.stacks.set(element, byAttribute);
80
+ const known = byAttribute.get(attribute);
81
+ if (known) return known;
82
+ const found = [];
83
+ for (const record of registry.names.get(attribute) ?? []) {
84
+ const read = readLeaseRecord(element, record);
85
+ if (read) found.push({ ...read, record });
86
+ }
87
+ const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
88
+ const stack = found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
89
+ lease: null,
90
+ record,
91
+ written,
92
+ original,
93
+ linked: linked && index > 0
94
+ }));
95
+ byAttribute.set(attribute, stack);
96
+ return stack;
97
+ }
98
+ function findHold(stack, lease, record) {
99
+ return stack.find((held) => held.lease === lease) ?? stack.find((held) => held.lease === null && held.record === record);
100
+ }
101
+ var AttributeLease = class {
102
+ #attribute;
103
+ #record;
104
+ #base;
105
+ #preserveAuthor;
106
+ #held = /* @__PURE__ */ new Set();
107
+ constructor(attribute, owner, options = {}) {
108
+ this.#attribute = attribute;
109
+ this.#record = `data-${owner}-${attribute}-lease`;
110
+ this.#base = options.base === true;
111
+ this.#preserveAuthor = options.preserveAuthor === true;
112
+ const names = registry.names;
113
+ names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
114
+ }
115
+ write(element, value) {
116
+ const stack = attributeStack(element, this.#attribute);
117
+ const hold = this.#take(stack) ?? this.#acquire(element, stack);
118
+ this.#held.add(element);
119
+ const shows = !this.#covered(element, stack, hold);
120
+ hold.written = value;
121
+ this.#mark(element, stack);
122
+ if (shows) this.#reflect(element, value);
123
+ }
124
+ return(element) {
125
+ const held = this.#held.delete(element);
126
+ const known = registry.stacks.get(element)?.has(this.#attribute);
127
+ const stack = held || known || element.hasAttribute(this.#record) ? attributeStack(element, this.#attribute) : [];
128
+ const hold = this.#take(stack);
129
+ if (!hold) return false;
130
+ const carries = element.getAttribute(this.#attribute) === hold.written;
131
+ const owns = carries && !this.#covered(element, stack, hold);
132
+ const index = stack.indexOf(hold);
133
+ stack.splice(index, 1);
134
+ const above = stack[index];
135
+ if (above) above.linked &&= hold.linked;
136
+ this.#mark(element, stack);
137
+ if (!owns) return true;
138
+ const below = hold.linked ? stack[index - 1] : void 0;
139
+ this.#reflect(element, below ? below.written : hold.original);
140
+ return true;
141
+ }
142
+ returnAll() {
143
+ for (const element of Array.from(this.#held)) this.return(element);
144
+ }
145
+ #take(stack) {
146
+ const hold = findHold(stack, this, this.#record);
147
+ if (hold) hold.lease = this;
148
+ return hold;
149
+ }
150
+ #acquire(element, stack) {
151
+ const current = element.getAttribute(this.#attribute);
152
+ const top = stack.at(-1);
153
+ const bottom = stack[0];
154
+ const over = top?.written === current ? top : void 0;
155
+ const from = this.#base ? this.#preserveAuthor && !stack.some((held) => held.written === current) ? void 0 : bottom : over;
156
+ const hold = {
157
+ lease: this,
158
+ record: this.#record,
159
+ written: current,
160
+ original: from ? from.original : current,
161
+ linked: !this.#base && over !== void 0
162
+ };
163
+ if (this.#base && bottom) {
164
+ bottom.linked = true;
165
+ stack.unshift(hold);
166
+ } else stack.push(hold);
167
+ return hold;
168
+ }
169
+ #covered(element, stack, hold) {
170
+ const current = element.getAttribute(this.#attribute);
171
+ return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current);
172
+ }
173
+ #mark(element, stack) {
174
+ const records = /* @__PURE__ */ new Map([[this.#record, null]]);
175
+ stack.forEach((hold, index) => {
176
+ const names = stack.slice(0, index).map((under) => under.record);
177
+ const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
178
+ const marker = hold.linked || beneath.length === 0 ? [] : [false];
179
+ records.set(
180
+ hold.record,
181
+ hold.written === hold.original && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([hold.original, hold.written, ...marker, ...beneath])
182
+ );
183
+ });
184
+ for (const [name, recorded] of records) {
185
+ setAttributeIfChanged(element, name, recorded);
186
+ }
187
+ }
188
+ #reflect(element, value) {
189
+ setAttributeIfChanged(element, this.#attribute, value);
190
+ }
191
+ };
192
+
193
+ var ClickVerdicts = class {
194
+ #verdicts = /* @__PURE__ */ new WeakMap();
195
+ record(event, entries, refused) {
196
+ this.#verdicts.set(event, { entries, refused });
197
+ }
198
+ for(event, entry) {
199
+ const verdict = event && this.#verdicts.get(event);
200
+ if (!verdict?.entries.includes(entry)) return void 0;
201
+ return verdict.refused;
202
+ }
203
+ };
10
204
 
11
- // src/utils/escape_layer.ts
12
205
  function claimsWhileFocusWithin(element) {
13
206
  return () => {
14
207
  const active = element.ownerDocument.activeElement;
@@ -16,125 +209,109 @@ function claimsWhileFocusWithin(element) {
16
209
  };
17
210
  }
18
211
  var EscapeLayer = class _EscapeLayer {
19
- static #registries = /* @__PURE__ */ new WeakMap();
20
- #ownerDocument = null;
21
- /** Dismissal callback while active; `null` when inactive. */
22
- #onDismiss = null;
23
- /** Live predicate deciding whether the layer claims a press; `null` = always. */
24
- #claims = null;
25
- /**
26
- * Activates this layer at the top of its document's Escape stack, installing
27
- * the document's shared resolver listener if this is its first layer.
28
- * Re-activating an already-active layer moves it to the top.
29
- */
212
+ static #registries = sharedRegistry(
213
+ "stimeo-ui.escape-layer.registry.v1",
214
+ () => /* @__PURE__ */ new WeakMap()
215
+ );
216
+ #active = null;
30
217
  activate(ownerDocument = document, options) {
31
218
  this.deactivate();
32
- let registry = _EscapeLayer.#registries.get(ownerDocument);
33
- if (!registry) {
34
- registry = _EscapeLayer.#createRegistry();
35
- _EscapeLayer.#registries.set(ownerDocument, registry);
36
- ownerDocument.addEventListener("keydown", registry.onKeydown);
219
+ let registry2 = _EscapeLayer.#registries.get(ownerDocument);
220
+ if (!registry2) {
221
+ registry2 = _EscapeLayer.#createRegistry();
222
+ _EscapeLayer.#registries.set(ownerDocument, registry2);
223
+ ownerDocument.addEventListener("keydown", registry2.onKeydown);
37
224
  }
38
- registry.stack.push(this);
39
- this.#ownerDocument = ownerDocument;
40
- this.#onDismiss = options.onDismiss;
41
- this.#claims = options.claims ?? null;
42
- }
43
- /**
44
- * Removes this layer from its document's Escape stack, uninstalling the
45
- * shared listener when the stack empties. Safe to call when inactive.
46
- */
225
+ const entry = { onDismiss: options.onDismiss, claims: options.claims ?? null };
226
+ registry2.stack.push(entry);
227
+ this.#active = { document: ownerDocument, entry };
228
+ }
47
229
  deactivate() {
48
- const ownerDocument = this.#ownerDocument;
49
- if (!ownerDocument) return;
50
- const registry = _EscapeLayer.#registries.get(ownerDocument);
51
- if (registry) {
52
- const index = registry.stack.lastIndexOf(this);
53
- if (index >= 0) registry.stack.splice(index, 1);
54
- if (registry.stack.length === 0) {
55
- ownerDocument.removeEventListener("keydown", registry.onKeydown);
56
- _EscapeLayer.#registries.delete(ownerDocument);
230
+ const active = this.#active;
231
+ if (!active) return;
232
+ const registry2 = _EscapeLayer.#registries.get(active.document);
233
+ if (registry2) {
234
+ const index = registry2.stack.lastIndexOf(active.entry);
235
+ if (index >= 0) registry2.stack.splice(index, 1);
236
+ if (registry2.stack.length === 0) {
237
+ active.document.removeEventListener("keydown", registry2.onKeydown);
238
+ _EscapeLayer.#registries.delete(active.document);
57
239
  }
58
240
  }
59
- this.#ownerDocument = null;
60
- this.#onDismiss = null;
61
- this.#claims = null;
62
- }
63
- /**
64
- * Whether this active layer would own a press right now: it is the topmost
65
- * layer whose {@link EscapeLayerOptions.claims} passes. Exposed for tests
66
- * and diagnostics — production dismissal goes through the shared listener.
67
- */
241
+ this.#active = null;
242
+ }
68
243
  get ownsEscape() {
69
- const ownerDocument = this.#ownerDocument;
70
- if (!ownerDocument) return false;
71
- const registry = _EscapeLayer.#registries.get(ownerDocument);
72
- if (!registry) return false;
73
- return _EscapeLayer.#resolveOwner(registry.stack) === this;
244
+ const active = this.#active;
245
+ if (!active) return false;
246
+ const registry2 = _EscapeLayer.#registries.get(active.document);
247
+ if (!registry2) return false;
248
+ return _EscapeLayer.#resolveOwner(registry2.stack) === active.entry;
74
249
  }
75
- /** Builds a document's registry with its shared resolver listener. */
76
250
  static #createRegistry() {
77
- const registry = {
251
+ const registry2 = {
78
252
  stack: [],
79
253
  onKeydown: (event) => {
80
254
  if (event.key !== "Escape" || event.defaultPrevented || event.isComposing) return;
81
- const owner = _EscapeLayer.#resolveOwner(registry.stack);
255
+ const owner = _EscapeLayer.#resolveOwner(registry2.stack);
82
256
  if (!owner) return;
83
257
  event.preventDefault();
84
- owner.#onDismiss?.();
258
+ owner.onDismiss();
85
259
  }
86
260
  };
87
- return registry;
261
+ return registry2;
88
262
  }
89
- /** The topmost stack layer whose claims predicate passes, or `null`. */
90
263
  static #resolveOwner(stack) {
91
264
  for (let index = stack.length - 1; index >= 0; index--) {
92
265
  const layer = stack[index];
93
266
  if (!layer) continue;
94
- if (layer.#claims && !layer.#claims()) continue;
267
+ if (layer.claims && !layer.claims()) continue;
95
268
  return layer;
96
269
  }
97
270
  return null;
98
271
  }
99
272
  };
100
273
 
101
- // src/utils/safe_timeout.ts
274
+ function ownerIndex(candidates, node) {
275
+ if (!(node instanceof Node)) return -1;
276
+ return candidates.findIndex((candidate) => candidate.contains(node));
277
+ }
278
+ function ownerOf(candidates, node) {
279
+ return candidates[ownerIndex(candidates, node)] ?? null;
280
+ }
281
+ function ownersOf(candidates, node) {
282
+ if (!(node instanceof Node)) return [];
283
+ return candidates.filter((candidate) => candidate.contains(node));
284
+ }
285
+
286
+ var ListenerSet = class {
287
+ #abort = new AbortController();
288
+ add(target, type, handler, options) {
289
+ target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
290
+ }
291
+ dispose() {
292
+ this.#abort.abort();
293
+ this.#abort = new AbortController();
294
+ }
295
+ };
296
+
102
297
  var TimerRegistry = class {
103
- /** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
104
298
  ids = /* @__PURE__ */ new Set();
105
- /**
106
- * Cancels a single tracked timer.
107
- *
108
- * No-ops if the id is unknown (already cleared, fired, or never owned by this
109
- * registry), so callers can clear defensively without guarding.
110
- */
111
299
  clear(id) {
112
300
  if (this.ids.delete(id)) {
113
301
  this.cancel(id);
114
302
  }
115
303
  }
116
- /**
117
- * Cancels every tracked timer. Call this from a controller's `disconnect()`
118
- * to guarantee no timer outlives the element.
119
- */
120
304
  clearAll() {
121
305
  for (const id of this.ids) {
122
306
  this.cancel(id);
123
307
  }
124
308
  this.ids.clear();
125
309
  }
126
- /** Number of timers currently tracked (pending). */
127
310
  get size() {
128
311
  return this.ids.size;
129
312
  }
130
313
  };
131
314
  var SafeTimeout = class extends TimerRegistry {
132
- /**
133
- * Schedules `callback` after `delay` ms and returns the timer id.
134
- *
135
- * The id is removed from the registry automatically when the timeout fires,
136
- * so {@link TimerRegistry.size | size} reflects only still-pending timers.
137
- */
138
315
  set(callback, delay) {
139
316
  const id = this.schedule(() => {
140
317
  this.ids.delete(id);
@@ -151,52 +328,60 @@ var SafeTimeout = class extends TimerRegistry {
151
328
  }
152
329
  };
153
330
 
154
- // src/utils/state_reason.ts
155
- var FOCUS_EVENTS = /* @__PURE__ */ new Set(["blur", "focus", "focusin", "focusout"]);
156
- var POINTER_EVENTS = /* @__PURE__ */ new Set(["mouseenter", "mouseleave", "pointerenter", "pointerleave"]);
157
- function stateReasonFor(event) {
158
- if (!event) return "api";
159
- if (FOCUS_EVENTS.has(event.type)) return "focus";
160
- if (POINTER_EVENTS.has(event.type)) return "pointer";
161
- return "user";
162
- }
163
-
164
- // src/controllers/context_menu_controller.ts
165
- var ContextMenuController = class extends Controller {
331
+ var ContextMenuController = class _ContextMenuController extends Controller {
332
+ static #COORDINATE = ["--stimeo--context-menu-x", "--stimeo--context-menu-y"];
166
333
  static targets = ["region", "menu", "item"];
167
334
  static actions = ["activate", "onItemKeydown", "onRegionKeydown", "open"];
168
335
  static events = ["close", "open"];
169
336
  #timers = new SafeTimeout();
170
- /** Escape-stack membership while open; the shared resolver dismisses via it. */
171
337
  #escapeLayer = new EscapeLayer();
172
- /** Whether state moves are reported: set once `connect()` settled the baseline. */
338
+ #menuHidden = new AttributeLease("hidden", this.identifier);
339
+ #regionState = new AttributeLease("data-state", this.identifier);
340
+ #menu = null;
341
+ #connected = false;
173
342
  #reporting = false;
174
- /** Starts closed and registers delegated activation and outside-pointer listeners. */
343
+ #clickVerdicts = new ClickVerdicts();
344
+ #listeners = new ListenerSet();
175
345
  connect() {
176
346
  this.#closeMenu("api");
177
- this.element.addEventListener("click", this.#onItemClickCapture, true);
178
- document.addEventListener("click", this.#onOutsidePointer, true);
179
- document.addEventListener("contextmenu", this.#onOutsidePointer, true);
347
+ this.#listeners.add(this.element, "click", this.#onItemClickCapture, { capture: true });
348
+ this.#listeners.add(document, "click", this.#onOutsidePointer, { capture: true });
349
+ this.#listeners.add(document, "contextmenu", this.#onOutsidePointer, { capture: true });
350
+ this.#connected = true;
180
351
  this.#reporting = true;
181
352
  }
182
- /** Releases the listeners, stack membership, and pending Tab-close task. */
183
353
  disconnect() {
354
+ this.#connected = false;
184
355
  this.#reporting = false;
185
356
  this.#timers.clearAll();
186
357
  this.#escapeLayer.deactivate();
187
- this.element.removeEventListener("click", this.#onItemClickCapture, true);
188
- document.removeEventListener("click", this.#onOutsidePointer, true);
189
- document.removeEventListener("contextmenu", this.#onOutsidePointer, true);
190
- }
191
- /**
192
- * Opens the menu from a `contextmenu` event: suppresses the native menu and
193
- * places this one at the pointer coordinate.
194
- */
195
- open(event) {
196
- event.preventDefault();
197
- this.#openAt(event.clientX, event.clientY, stateReasonFor(event));
358
+ this.#listeners.dispose();
359
+ }
360
+ regionTargetConnected() {
361
+ if (this.#connected) this.#reflectRegion();
362
+ }
363
+ regionTargetDisconnected(region) {
364
+ if (!this.regionTargets.includes(region)) this.#regionState.return(region);
365
+ if (this.#connected) this.#reflectRegion();
366
+ }
367
+ menuTargetConnected() {
368
+ this.#adoptMenu();
369
+ }
370
+ menuTargetDisconnected(menu) {
371
+ this.#adoptMenu();
372
+ if (!this.menuTargets.includes(menu)) this.#menuHidden.return(menu);
373
+ }
374
+ open(input) {
375
+ const source = actionSource(input);
376
+ source.event?.preventDefault();
377
+ if (source.event instanceof MouseEvent) {
378
+ this.#openAt(source.event.clientX, source.event.clientY, source.reason);
379
+ return;
380
+ }
381
+ const anchor = source.host ?? (this.hasRegionTarget ? this.regionTarget : null);
382
+ const rect = anchor?.getBoundingClientRect() ?? { left: 0, top: 0, width: 0, height: 0 };
383
+ this.#openAt(rect.left + rect.width / 2, rect.top + rect.height / 2, source.reason);
198
384
  }
199
- /** Keyboard entry on the region: `Shift+F10` / `ContextMenu` open at center. */
200
385
  onRegionKeydown(event) {
201
386
  if (event.defaultPrevented) return;
202
387
  const isContextKey = event.key === "ContextMenu" || event.key === "F10" && event.shiftKey;
@@ -205,10 +390,10 @@ var ContextMenuController = class extends Controller {
205
390
  const rect = this.hasRegionTarget ? this.regionTarget.getBoundingClientRect() : { left: 0, top: 0, width: 0, height: 0 };
206
391
  this.#openAt(rect.left + rect.width / 2, rect.top + rect.height / 2, stateReasonFor(event));
207
392
  }
208
- /** Roving focus and closing keys inside the menu. */
209
393
  onItemKeydown(event) {
210
394
  if (event.defaultPrevented) return;
211
395
  if (isReservedArrowChord(event)) return;
396
+ if ((event.key === "Home" || event.key === "End") && hasModifierChord(event)) return;
212
397
  const items = this.#navigableItems;
213
398
  const currentIndex = items.indexOf(event.currentTarget);
214
399
  switch (event.key) {
@@ -240,93 +425,101 @@ var ContextMenuController = class extends Controller {
240
425
  break;
241
426
  }
242
427
  }
243
- /** Closes after an item is activated and restores focus to the region. */
244
- activate() {
428
+ activate(event) {
429
+ const item = ownerOf(this.itemTargets, event?.target);
430
+ if (item !== null && this.#refuses(item, event)) return;
245
431
  this.#closeAndRestore("select");
246
432
  }
247
- /** Opens the menu at viewport coordinates `(x, y)` and focuses the first item. */
433
+ #refuses(item, event) {
434
+ const recorded = this.#clickVerdicts.for(event, item);
435
+ if (recorded !== void 0) return recorded;
436
+ return ownersOf(this.itemTargets, event?.target).some(
437
+ (owner) => this.#isActivationDisabled(owner)
438
+ );
439
+ }
248
440
  #openAt(x, y, reason) {
249
441
  if (!this.hasMenuTarget) return;
250
442
  this.#timers.clearAll();
443
+ const menu = this.menuTarget;
251
444
  const was = this.#isOpen;
252
445
  this.#escapeLayer.activate(document, {
253
446
  onDismiss: () => this.#closeAndRestore("escape"),
254
447
  claims: claimsWhileFocusWithin(this.element)
255
448
  });
256
- this.menuTarget.style.setProperty("--stimeo--context-menu-x", `${x}px`);
257
- this.menuTarget.style.setProperty("--stimeo--context-menu-y", `${y}px`);
258
- this.menuTarget.hidden = false;
259
- if (this.hasRegionTarget) this.regionTarget.setAttribute("data-state", "open");
449
+ menu.style.setProperty(_ContextMenuController.#COORDINATE[0], `${x}px`);
450
+ menu.style.setProperty(_ContextMenuController.#COORDINATE[1], `${y}px`);
451
+ this.#menuHidden.write(menu, null);
452
+ this.#menu = menu;
453
+ if (this.hasRegionTarget) this.#regionState.write(this.regionTarget, "open");
260
454
  if (!was && this.#reporting) this.dispatch("open", { detail: { reason }, cancelable: false });
261
455
  if (!this.#isOpen) return;
262
456
  this.#navigableItems[0]?.focus();
263
457
  }
264
- /** Hides the menu, reflects the collapsed state on the region, and reports a move. */
265
458
  #closeMenu(reason) {
266
459
  this.#timers.clearAll();
267
460
  this.#escapeLayer.deactivate();
268
- if (!this.hasMenuTarget) return;
461
+ const menu = this.hasMenuTarget ? this.menuTarget : null;
462
+ this.#menu = menu;
463
+ if (!menu) return;
269
464
  const was = this.#isOpen;
270
- this.menuTarget.hidden = true;
271
- if (this.hasRegionTarget) this.regionTarget.setAttribute("data-state", "closed");
465
+ this.#menuHidden.write(menu, "");
466
+ if (this.hasRegionTarget) this.#regionState.write(this.regionTarget, "closed");
272
467
  if (was && this.#reporting) this.dispatch("close", { detail: { reason }, cancelable: false });
273
468
  }
274
- /** Closes the menu and returns focus to the region (Escape / activation). */
469
+ #adoptMenu() {
470
+ if (!this.#connected) return;
471
+ const menu = this.hasMenuTarget ? this.menuTarget : null;
472
+ const previous = this.#menu;
473
+ this.#menu = menu;
474
+ if (!menu) {
475
+ this.#escapeLayer.deactivate();
476
+ } else if (menu !== previous) {
477
+ const open = previous !== null && !previous.hidden;
478
+ if (open) {
479
+ for (const property of _ContextMenuController.#COORDINATE) {
480
+ menu.style.setProperty(property, previous.style.getPropertyValue(property));
481
+ }
482
+ }
483
+ this.#menuHidden.write(menu, open ? null : "");
484
+ }
485
+ this.#reflectRegion();
486
+ }
487
+ #reflectRegion() {
488
+ if (!this.hasRegionTarget) return;
489
+ this.#regionState.write(this.regionTarget, this.#isOpen ? "open" : "closed");
490
+ }
275
491
  #closeAndRestore(reason) {
276
492
  this.#closeMenu(reason);
277
493
  if (this.hasRegionTarget) this.regionTarget.focus();
278
494
  }
279
- /**
280
- * Closes when a click or context-menu invocation lands outside this instance.
281
- * Both subscriptions observe in the capture phase, so the target is judged
282
- * against the tree the user actually pressed even when a consumer handler
283
- * detaches it, and application code that stops bubbling cannot leave the menu
284
- * open.
285
- */
286
495
  #onOutsidePointer = (event) => {
287
496
  if (this.#isOpen && !this.element.contains(event.target)) this.#closeMenu("outside");
288
497
  };
289
- /**
290
- * Captures clicks so `aria-disabled` commands cannot reach consumer handlers.
291
- * Native Enter/Space activation also synthesizes a click and is blocked here.
292
- */
293
498
  #onItemClickCapture = (event) => {
294
- const target = event.target;
295
- if (!(target instanceof Node)) return;
296
- const disabled = this.itemTargets.some(
297
- (item) => item.getAttribute("aria-disabled") === "true" && item.contains(target)
499
+ const items = ownersOf(this.itemTargets, event.target);
500
+ this.#clickVerdicts.record(
501
+ event,
502
+ items,
503
+ items.some((item) => this.#isActivationDisabled(item))
298
504
  );
299
- if (!disabled) return;
505
+ if (!items.some((item) => isAriaDisabled(item))) return;
300
506
  event.preventDefault();
301
507
  event.stopImmediatePropagation();
302
508
  };
303
- /** Menu items eligible for roving focus (excludes hidden / natively disabled). */
304
509
  get #navigableItems() {
305
510
  return this.itemTargets.filter((item) => this.#isNavigable(item));
306
511
  }
307
- /**
308
- * An item can take roving focus unless it is `hidden` or a natively `disabled`
309
- * form control. CSS-only visibility is not detectable here and is the
310
- * consumer's responsibility.
311
- *
312
- * **`aria-disabled="true"` stays reachable.** APG separates the two attributes
313
- * by intent: `disabled` is for controls whose existence can be inferred from a
314
- * neighbour (a greyed Next next to a Prev), while `aria-disabled` marks a
315
- * control that must stay *discoverable* — and it names menu items as the
316
- * example. Skipping it would hide the command's existence from a keyboard user
317
- * entirely. Activation is suppressed separately, so the item announces itself
318
- * and does nothing.
319
- */
320
512
  #isNavigable(item) {
321
513
  if (item.hasAttribute("hidden")) return false;
322
514
  return !item.disabled;
323
515
  }
324
- /** Whether the menu is currently visible. */
516
+ #isActivationDisabled(item) {
517
+ return !this.#isNavigable(item) || isAriaDisabled(item);
518
+ }
325
519
  get #isOpen() {
326
520
  return this.hasMenuTarget && !this.menuTarget.hidden;
327
521
  }
328
522
  };
329
523
 
330
524
  export { ContextMenuController };
331
- //# sourceMappingURL=context_menu_controller.js.map
332
525
  //# sourceMappingURL=context_menu_controller.js.map