stimeo-ui 0.16.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 (328) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +8 -1
  3. package/dist/cable/index.d.ts +79 -23
  4. package/dist/cable/index.js +363 -436
  5. package/dist/cable/index.js.map +1 -1
  6. package/dist/controllers/accordion_controller.d.ts +4 -2
  7. package/dist/controllers/accordion_controller.js +166 -55
  8. package/dist/controllers/accordion_controller.js.map +1 -1
  9. package/dist/controllers/alert_dialog_controller.d.ts +12 -2
  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 +35 -5
  13. package/dist/controllers/announcer_controller.js +135 -198
  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 +271 -127
  19. package/dist/controllers/auto_submit_controller.js.map +1 -1
  20. package/dist/controllers/avatar_controller.js +171 -105
  21. package/dist/controllers/avatar_controller.js.map +1 -1
  22. package/dist/controllers/breadcrumb_controller.js +0 -130
  23. package/dist/controllers/breadcrumb_controller.js.map +1 -1
  24. package/dist/controllers/bulk_select_controller.d.ts +18 -0
  25. package/dist/controllers/bulk_select_controller.js +262 -52
  26. package/dist/controllers/bulk_select_controller.js.map +1 -1
  27. package/dist/controllers/calendar_controller.d.ts +24 -5
  28. package/dist/controllers/calendar_controller.js +175 -209
  29. package/dist/controllers/calendar_controller.js.map +1 -1
  30. package/dist/controllers/carousel_controller.d.ts +34 -7
  31. package/dist/controllers/carousel_controller.js +461 -399
  32. package/dist/controllers/carousel_controller.js.map +1 -1
  33. package/dist/controllers/character_counter_controller.d.ts +17 -1
  34. package/dist/controllers/character_counter_controller.js +246 -156
  35. package/dist/controllers/character_counter_controller.js.map +1 -1
  36. package/dist/controllers/checkbox_controller.d.ts +7 -2
  37. package/dist/controllers/checkbox_controller.js +32 -74
  38. package/dist/controllers/checkbox_controller.js.map +1 -1
  39. package/dist/controllers/clipboard_controller.d.ts +16 -5
  40. package/dist/controllers/clipboard_controller.js +168 -147
  41. package/dist/controllers/clipboard_controller.js.map +1 -1
  42. package/dist/controllers/collapsible_controller.d.ts +16 -4
  43. package/dist/controllers/collapsible_controller.js +301 -120
  44. package/dist/controllers/collapsible_controller.js.map +1 -1
  45. package/dist/controllers/color_picker_controller.d.ts +18 -6
  46. package/dist/controllers/color_picker_controller.js +149 -139
  47. package/dist/controllers/color_picker_controller.js.map +1 -1
  48. package/dist/controllers/combobox_controller.d.ts +23 -5
  49. package/dist/controllers/combobox_controller.js +360 -133
  50. package/dist/controllers/combobox_controller.js.map +1 -1
  51. package/dist/controllers/command_palette_controller.d.ts +45 -14
  52. package/dist/controllers/command_palette_controller.js +970 -358
  53. package/dist/controllers/command_palette_controller.js.map +1 -1
  54. package/dist/controllers/conditional_fields_controller.d.ts +15 -2
  55. package/dist/controllers/conditional_fields_controller.js +166 -124
  56. package/dist/controllers/conditional_fields_controller.js.map +1 -1
  57. package/dist/controllers/confirm_controller.d.ts +49 -12
  58. package/dist/controllers/confirm_controller.js +939 -248
  59. package/dist/controllers/confirm_controller.js.map +1 -1
  60. package/dist/controllers/context_menu_controller.d.ts +31 -4
  61. package/dist/controllers/context_menu_controller.js +256 -128
  62. package/dist/controllers/context_menu_controller.js.map +1 -1
  63. package/dist/controllers/count_up_controller.d.ts +13 -1
  64. package/dist/controllers/count_up_controller.js +73 -21
  65. package/dist/controllers/count_up_controller.js.map +1 -1
  66. package/dist/controllers/countdown_controller.d.ts +45 -1
  67. package/dist/controllers/countdown_controller.js +183 -148
  68. package/dist/controllers/countdown_controller.js.map +1 -1
  69. package/dist/controllers/currency_input_controller.d.ts +21 -2
  70. package/dist/controllers/currency_input_controller.js +134 -158
  71. package/dist/controllers/currency_input_controller.js.map +1 -1
  72. package/dist/controllers/data_grid_controller.d.ts +15 -4
  73. package/dist/controllers/data_grid_controller.js +114 -186
  74. package/dist/controllers/data_grid_controller.js.map +1 -1
  75. package/dist/controllers/date_range_picker_controller.d.ts +30 -5
  76. package/dist/controllers/date_range_picker_controller.js +288 -206
  77. package/dist/controllers/date_range_picker_controller.js.map +1 -1
  78. package/dist/controllers/dialog_controller.d.ts +13 -1
  79. package/dist/controllers/dialog_controller.js +858 -223
  80. package/dist/controllers/dialog_controller.js.map +1 -1
  81. package/dist/controllers/direct_upload_controller.d.ts +24 -7
  82. package/dist/controllers/direct_upload_controller.js +73 -153
  83. package/dist/controllers/direct_upload_controller.js.map +1 -1
  84. package/dist/controllers/dirty_form_controller.js +14 -48
  85. package/dist/controllers/dirty_form_controller.js.map +1 -1
  86. package/dist/controllers/dismissible_controller.d.ts +19 -0
  87. package/dist/controllers/dismissible_controller.js +175 -21
  88. package/dist/controllers/dismissible_controller.js.map +1 -1
  89. package/dist/controllers/drawer_controller.d.ts +39 -11
  90. package/dist/controllers/drawer_controller.js +933 -341
  91. package/dist/controllers/drawer_controller.js.map +1 -1
  92. package/dist/controllers/dropdown_controller.d.ts +31 -1
  93. package/dist/controllers/dropdown_controller.js +312 -82
  94. package/dist/controllers/dropdown_controller.js.map +1 -1
  95. package/dist/controllers/editable_controller.d.ts +12 -1
  96. package/dist/controllers/editable_controller.js +158 -68
  97. package/dist/controllers/editable_controller.js.map +1 -1
  98. package/dist/controllers/empty_state_controller.js +67 -53
  99. package/dist/controllers/empty_state_controller.js.map +1 -1
  100. package/dist/controllers/file_dropzone_controller.d.ts +60 -18
  101. package/dist/controllers/file_dropzone_controller.js +311 -207
  102. package/dist/controllers/file_dropzone_controller.js.map +1 -1
  103. package/dist/controllers/filter_controller.js +67 -39
  104. package/dist/controllers/filter_controller.js.map +1 -1
  105. package/dist/controllers/flash_controller.d.ts +31 -8
  106. package/dist/controllers/flash_controller.js +172 -314
  107. package/dist/controllers/flash_controller.js.map +1 -1
  108. package/dist/controllers/focus_controller.d.ts +12 -3
  109. package/dist/controllers/focus_controller.js +654 -240
  110. package/dist/controllers/focus_controller.js.map +1 -1
  111. package/dist/controllers/form_field_controller.js +147 -132
  112. package/dist/controllers/form_field_controller.js.map +1 -1
  113. package/dist/controllers/form_validation_controller.js +13 -86
  114. package/dist/controllers/form_validation_controller.js.map +1 -1
  115. package/dist/controllers/frame_loading_controller.d.ts +41 -9
  116. package/dist/controllers/frame_loading_controller.js +264 -213
  117. package/dist/controllers/frame_loading_controller.js.map +1 -1
  118. package/dist/controllers/highlight_controller.d.ts +22 -2
  119. package/dist/controllers/highlight_controller.js +107 -75
  120. package/dist/controllers/highlight_controller.js.map +1 -1
  121. package/dist/controllers/hover_card_controller.d.ts +56 -3
  122. package/dist/controllers/hover_card_controller.js +309 -118
  123. package/dist/controllers/hover_card_controller.js.map +1 -1
  124. package/dist/controllers/idle_controller.d.ts +42 -1
  125. package/dist/controllers/idle_controller.js +267 -101
  126. package/dist/controllers/idle_controller.js.map +1 -1
  127. package/dist/controllers/input_mask_controller.js +71 -72
  128. package/dist/controllers/input_mask_controller.js.map +1 -1
  129. package/dist/controllers/intersection_controller.d.ts +32 -13
  130. package/dist/controllers/intersection_controller.js +147 -106
  131. package/dist/controllers/intersection_controller.js.map +1 -1
  132. package/dist/controllers/lazy_frame_controller.d.ts +16 -0
  133. package/dist/controllers/lazy_frame_controller.js +9 -65
  134. package/dist/controllers/lazy_frame_controller.js.map +1 -1
  135. package/dist/controllers/listbox_controller.d.ts +34 -2
  136. package/dist/controllers/listbox_controller.js +306 -204
  137. package/dist/controllers/listbox_controller.js.map +1 -1
  138. package/dist/controllers/local_time_controller.d.ts +1 -1
  139. package/dist/controllers/local_time_controller.js +54 -64
  140. package/dist/controllers/local_time_controller.js.map +1 -1
  141. package/dist/controllers/masonry_controller.d.ts +11 -3
  142. package/dist/controllers/masonry_controller.js +70 -93
  143. package/dist/controllers/masonry_controller.js.map +1 -1
  144. package/dist/controllers/menu_controller.d.ts +32 -7
  145. package/dist/controllers/menu_controller.js +214 -156
  146. package/dist/controllers/menu_controller.js.map +1 -1
  147. package/dist/controllers/menubar_controller.d.ts +4 -4
  148. package/dist/controllers/menubar_controller.js +170 -329
  149. package/dist/controllers/menubar_controller.js.map +1 -1
  150. package/dist/controllers/meter_controller.d.ts +20 -0
  151. package/dist/controllers/meter_controller.js +151 -67
  152. package/dist/controllers/meter_controller.js.map +1 -1
  153. package/dist/controllers/multi_select_controller.d.ts +32 -4
  154. package/dist/controllers/multi_select_controller.js +593 -358
  155. package/dist/controllers/multi_select_controller.js.map +1 -1
  156. package/dist/controllers/navigation_menu_controller.d.ts +8 -1
  157. package/dist/controllers/navigation_menu_controller.js +124 -232
  158. package/dist/controllers/navigation_menu_controller.js.map +1 -1
  159. package/dist/controllers/nested_form_controller.d.ts +10 -0
  160. package/dist/controllers/nested_form_controller.js +352 -182
  161. package/dist/controllers/nested_form_controller.js.map +1 -1
  162. package/dist/controllers/network_status_controller.d.ts +23 -0
  163. package/dist/controllers/network_status_controller.js +242 -54
  164. package/dist/controllers/network_status_controller.js.map +1 -1
  165. package/dist/controllers/number_input_controller.d.ts +26 -2
  166. package/dist/controllers/number_input_controller.js +320 -263
  167. package/dist/controllers/number_input_controller.js.map +1 -1
  168. package/dist/controllers/optimistic_controller.js +16 -76
  169. package/dist/controllers/optimistic_controller.js.map +1 -1
  170. package/dist/controllers/otp_controller.d.ts +20 -4
  171. package/dist/controllers/otp_controller.js +198 -193
  172. package/dist/controllers/otp_controller.js.map +1 -1
  173. package/dist/controllers/overflow_indicator_controller.d.ts +5 -0
  174. package/dist/controllers/overflow_indicator_controller.js +116 -113
  175. package/dist/controllers/overflow_indicator_controller.js.map +1 -1
  176. package/dist/controllers/overflow_menu_controller.d.ts +48 -11
  177. package/dist/controllers/overflow_menu_controller.js +343 -283
  178. package/dist/controllers/overflow_menu_controller.js.map +1 -1
  179. package/dist/controllers/pagination_controller.d.ts +35 -6
  180. package/dist/controllers/pagination_controller.js +295 -119
  181. package/dist/controllers/pagination_controller.js.map +1 -1
  182. package/dist/controllers/password_reveal_controller.d.ts +45 -8
  183. package/dist/controllers/password_reveal_controller.js +389 -121
  184. package/dist/controllers/password_reveal_controller.js.map +1 -1
  185. package/dist/controllers/password_strength_controller.d.ts +14 -5
  186. package/dist/controllers/password_strength_controller.js +99 -153
  187. package/dist/controllers/password_strength_controller.js.map +1 -1
  188. package/dist/controllers/persist_controller.d.ts +11 -4
  189. package/dist/controllers/persist_controller.js +237 -103
  190. package/dist/controllers/persist_controller.js.map +1 -1
  191. package/dist/controllers/pointer_drag_controller.d.ts +19 -7
  192. package/dist/controllers/pointer_drag_controller.js +185 -165
  193. package/dist/controllers/pointer_drag_controller.js.map +1 -1
  194. package/dist/controllers/popover_controller.d.ts +38 -2
  195. package/dist/controllers/popover_controller.js +236 -97
  196. package/dist/controllers/popover_controller.js.map +1 -1
  197. package/dist/controllers/portal_controller.d.ts +44 -4
  198. package/dist/controllers/portal_controller.js +209 -76
  199. package/dist/controllers/portal_controller.js.map +1 -1
  200. package/dist/controllers/preview_guard_controller.d.ts +10 -4
  201. package/dist/controllers/preview_guard_controller.js +232 -116
  202. package/dist/controllers/preview_guard_controller.js.map +1 -1
  203. package/dist/controllers/progress_controller.d.ts +11 -0
  204. package/dist/controllers/progress_controller.js +125 -56
  205. package/dist/controllers/progress_controller.js.map +1 -1
  206. package/dist/controllers/radio_group_controller.d.ts +14 -5
  207. package/dist/controllers/radio_group_controller.js +117 -137
  208. package/dist/controllers/radio_group_controller.js.map +1 -1
  209. package/dist/controllers/range_slider_controller.d.ts +43 -3
  210. package/dist/controllers/range_slider_controller.js +192 -105
  211. package/dist/controllers/range_slider_controller.js.map +1 -1
  212. package/dist/controllers/rating_controller.d.ts +20 -4
  213. package/dist/controllers/rating_controller.js +418 -207
  214. package/dist/controllers/rating_controller.js.map +1 -1
  215. package/dist/controllers/read_more_controller.d.ts +2 -0
  216. package/dist/controllers/read_more_controller.js +134 -63
  217. package/dist/controllers/read_more_controller.js.map +1 -1
  218. package/dist/controllers/reading_progress_controller.d.ts +1 -1
  219. package/dist/controllers/reading_progress_controller.js +147 -135
  220. package/dist/controllers/reading_progress_controller.js.map +1 -1
  221. package/dist/controllers/relative_time_controller.d.ts +18 -4
  222. package/dist/controllers/relative_time_controller.js +145 -110
  223. package/dist/controllers/relative_time_controller.js.map +1 -1
  224. package/dist/controllers/reset_on_restore_controller.d.ts +85 -0
  225. package/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +97 -38
  226. package/dist/controllers/reset_on_restore_controller.js.map +1 -0
  227. package/dist/controllers/resizable_controller.d.ts +28 -2
  228. package/dist/controllers/resizable_controller.js +255 -139
  229. package/dist/controllers/resizable_controller.js.map +1 -1
  230. package/dist/controllers/roving_controller.js +39 -84
  231. package/dist/controllers/roving_controller.js.map +1 -1
  232. package/dist/controllers/scroll_area_controller.d.ts +7 -3
  233. package/dist/controllers/scroll_area_controller.js +428 -225
  234. package/dist/controllers/scroll_area_controller.js.map +1 -1
  235. package/dist/controllers/scroll_restore_controller.js +0 -53
  236. package/dist/controllers/scroll_restore_controller.js.map +1 -1
  237. package/dist/controllers/scroll_visibility_controller.d.ts +28 -12
  238. package/dist/controllers/scroll_visibility_controller.js +395 -145
  239. package/dist/controllers/scroll_visibility_controller.js.map +1 -1
  240. package/dist/controllers/scrollspy_controller.d.ts +6 -1
  241. package/dist/controllers/scrollspy_controller.js +181 -242
  242. package/dist/controllers/scrollspy_controller.js.map +1 -1
  243. package/dist/controllers/separator_controller.d.ts +19 -4
  244. package/dist/controllers/separator_controller.js +267 -140
  245. package/dist/controllers/separator_controller.js.map +1 -1
  246. package/dist/controllers/sidebar_controller.d.ts +64 -7
  247. package/dist/controllers/sidebar_controller.js +1023 -386
  248. package/dist/controllers/sidebar_controller.js.map +1 -1
  249. package/dist/controllers/skeleton_controller.d.ts +23 -0
  250. package/dist/controllers/skeleton_controller.js +248 -97
  251. package/dist/controllers/skeleton_controller.js.map +1 -1
  252. package/dist/controllers/slider_controller.d.ts +27 -1
  253. package/dist/controllers/slider_controller.js +159 -79
  254. package/dist/controllers/slider_controller.js.map +1 -1
  255. package/dist/controllers/smart_sticky_header_controller.d.ts +21 -3
  256. package/dist/controllers/smart_sticky_header_controller.js +162 -63
  257. package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
  258. package/dist/controllers/sortable_controller.js +0 -112
  259. package/dist/controllers/sortable_controller.js.map +1 -1
  260. package/dist/controllers/spinner_controller.d.ts +39 -4
  261. package/dist/controllers/spinner_controller.js +277 -169
  262. package/dist/controllers/spinner_controller.js.map +1 -1
  263. package/dist/controllers/step_indicator_controller.d.ts +5 -0
  264. package/dist/controllers/step_indicator_controller.js +99 -46
  265. package/dist/controllers/step_indicator_controller.js.map +1 -1
  266. package/dist/controllers/stepper_controller.d.ts +12 -3
  267. package/dist/controllers/stepper_controller.js +114 -73
  268. package/dist/controllers/stepper_controller.js.map +1 -1
  269. package/dist/controllers/stick_to_bottom_controller.d.ts +6 -0
  270. package/dist/controllers/stick_to_bottom_controller.js +262 -138
  271. package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
  272. package/dist/controllers/sticky_observer_controller.d.ts +11 -0
  273. package/dist/controllers/sticky_observer_controller.js +214 -49
  274. package/dist/controllers/sticky_observer_controller.js.map +1 -1
  275. package/dist/controllers/submit_once_controller.d.ts +23 -8
  276. package/dist/controllers/submit_once_controller.js +294 -205
  277. package/dist/controllers/submit_once_controller.js.map +1 -1
  278. package/dist/controllers/switch_controller.d.ts +12 -1
  279. package/dist/controllers/switch_controller.js +33 -60
  280. package/dist/controllers/switch_controller.js.map +1 -1
  281. package/dist/controllers/tabs_controller.d.ts +2 -2
  282. package/dist/controllers/tabs_controller.js +35 -29
  283. package/dist/controllers/tabs_controller.js.map +1 -1
  284. package/dist/controllers/tags_input_controller.d.ts +12 -0
  285. package/dist/controllers/tags_input_controller.js +136 -145
  286. package/dist/controllers/tags_input_controller.js.map +1 -1
  287. package/dist/controllers/textarea_autosize_controller.d.ts +10 -0
  288. package/dist/controllers/textarea_autosize_controller.js +71 -58
  289. package/dist/controllers/textarea_autosize_controller.js.map +1 -1
  290. package/dist/controllers/theme_controller.d.ts +21 -9
  291. package/dist/controllers/theme_controller.js +130 -112
  292. package/dist/controllers/theme_controller.js.map +1 -1
  293. package/dist/controllers/time_picker_controller.d.ts +18 -1
  294. package/dist/controllers/time_picker_controller.js +146 -80
  295. package/dist/controllers/time_picker_controller.js.map +1 -1
  296. package/dist/controllers/toast_controller.d.ts +36 -11
  297. package/dist/controllers/toast_controller.js +186 -297
  298. package/dist/controllers/toast_controller.js.map +1 -1
  299. package/dist/controllers/toggle_group_controller.d.ts +12 -3
  300. package/dist/controllers/toggle_group_controller.js +95 -136
  301. package/dist/controllers/toggle_group_controller.js.map +1 -1
  302. package/dist/controllers/toolbar_controller.js +68 -98
  303. package/dist/controllers/toolbar_controller.js.map +1 -1
  304. package/dist/controllers/tooltip_controller.d.ts +45 -3
  305. package/dist/controllers/tooltip_controller.js +158 -124
  306. package/dist/controllers/tooltip_controller.js.map +1 -1
  307. package/dist/controllers/transition_controller.d.ts +22 -4
  308. package/dist/controllers/transition_controller.js +123 -119
  309. package/dist/controllers/transition_controller.js.map +1 -1
  310. package/dist/controllers/tree_view_controller.d.ts +21 -11
  311. package/dist/controllers/tree_view_controller.js +150 -345
  312. package/dist/controllers/tree_view_controller.js.map +1 -1
  313. package/dist/index.d.ts +8 -5
  314. package/dist/index.js +6370 -9346
  315. package/dist/index.js.map +1 -1
  316. package/dist/inspector/cli.d.ts +23 -3
  317. package/dist/inspector/cli.js +92 -37
  318. package/dist/inspector/cli.js.map +1 -1
  319. package/dist/inspector/cli_bin.js +92 -56
  320. package/dist/inspector/cli_bin.js.map +1 -1
  321. package/dist/inspector/examples.json +8 -8
  322. package/dist/inspector/manifest.json +787 -100
  323. package/dist/positioning/index.d.ts +8 -0
  324. package/dist/positioning/index.js +148 -47
  325. package/dist/positioning/index.js.map +1 -1
  326. package/package.json +6 -6
  327. package/dist/controllers/reset_before_cache_controller.d.ts +0 -76
  328. package/dist/controllers/reset_before_cache_controller.js.map +0 -1
@@ -97,6 +97,13 @@ declare class NavigationMenuController extends Controller<HTMLElement> {
97
97
  default: number;
98
98
  };
99
99
  };
100
+ static valueConstraints: {
101
+ hoverDelay: {
102
+ readonly finite: true;
103
+ readonly min: 0;
104
+ readonly max: 2147483647;
105
+ };
106
+ };
100
107
  static actions: readonly ["onTriggerKeydown", "toggle"];
101
108
  static events: readonly ["close", "open"];
102
109
  readonly triggerTargets: HTMLElement[];
@@ -140,7 +147,7 @@ declare class NavigationMenuController extends Controller<HTMLElement> {
140
147
  * activation (pointer elsewhere) still toggles it closed, and `Escape` and
141
148
  * outside clicks dismiss either way.
142
149
  */
143
- toggle(event: Event): void;
150
+ toggle(source: Event | HTMLElement): void;
144
151
  /**
145
152
  * `ArrowLeft`/`ArrowRight` move focus between triggers (keeping Tab order).
146
153
  *
@@ -1,19 +1,46 @@
1
1
  import { Controller } from '@hotwired/stimulus';
2
2
 
3
- // src/controllers/navigation_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
+ }
4
24
 
5
- // src/utils/logical_scroll.ts
6
25
  function isRtl(element) {
7
26
  return window.getComputedStyle(element).direction === "rtl";
8
27
  }
9
28
 
10
- // src/utils/arrow_step.ts
11
29
  function isReservedArrowChord(event, allow = []) {
12
30
  if (!event.key.startsWith("Arrow")) return false;
13
31
  return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
14
32
  }
15
33
 
16
- // src/utils/escape_layer.ts
34
+ function sharedRegistry(key, create) {
35
+ const symbol = Symbol.for(key);
36
+ const scope = globalThis;
37
+ const existing = scope[symbol];
38
+ if (existing !== void 0) return existing;
39
+ const registry = create();
40
+ Object.defineProperty(globalThis, symbol, { value: registry });
41
+ return registry;
42
+ }
43
+
17
44
  function claimsWhileFocusWithin(element) {
18
45
  return () => {
19
46
  const active = element.ownerDocument.activeElement;
@@ -21,17 +48,11 @@ function claimsWhileFocusWithin(element) {
21
48
  };
22
49
  }
23
50
  var EscapeLayer = class _EscapeLayer {
24
- static #registries = /* @__PURE__ */ new WeakMap();
25
- #ownerDocument = null;
26
- /** Dismissal callback while active; `null` when inactive. */
27
- #onDismiss = null;
28
- /** Live predicate deciding whether the layer claims a press; `null` = always. */
29
- #claims = null;
30
- /**
31
- * Activates this layer at the top of its document's Escape stack, installing
32
- * the document's shared resolver listener if this is its first layer.
33
- * Re-activating an already-active layer moves it to the top.
34
- */
51
+ static #registries = sharedRegistry(
52
+ "stimeo-ui.escape-layer.registry.v1",
53
+ () => /* @__PURE__ */ new WeakMap()
54
+ );
55
+ #active = null;
35
56
  activate(ownerDocument = document, options) {
36
57
  this.deactivate();
37
58
  let registry = _EscapeLayer.#registries.get(ownerDocument);
@@ -40,44 +61,31 @@ var EscapeLayer = class _EscapeLayer {
40
61
  _EscapeLayer.#registries.set(ownerDocument, registry);
41
62
  ownerDocument.addEventListener("keydown", registry.onKeydown);
42
63
  }
43
- registry.stack.push(this);
44
- this.#ownerDocument = ownerDocument;
45
- this.#onDismiss = options.onDismiss;
46
- this.#claims = options.claims ?? null;
47
- }
48
- /**
49
- * Removes this layer from its document's Escape stack, uninstalling the
50
- * shared listener when the stack empties. Safe to call when inactive.
51
- */
64
+ const entry = { onDismiss: options.onDismiss, claims: options.claims ?? null };
65
+ registry.stack.push(entry);
66
+ this.#active = { document: ownerDocument, entry };
67
+ }
52
68
  deactivate() {
53
- const ownerDocument = this.#ownerDocument;
54
- if (!ownerDocument) return;
55
- const registry = _EscapeLayer.#registries.get(ownerDocument);
69
+ const active = this.#active;
70
+ if (!active) return;
71
+ const registry = _EscapeLayer.#registries.get(active.document);
56
72
  if (registry) {
57
- const index = registry.stack.lastIndexOf(this);
73
+ const index = registry.stack.lastIndexOf(active.entry);
58
74
  if (index >= 0) registry.stack.splice(index, 1);
59
75
  if (registry.stack.length === 0) {
60
- ownerDocument.removeEventListener("keydown", registry.onKeydown);
61
- _EscapeLayer.#registries.delete(ownerDocument);
76
+ active.document.removeEventListener("keydown", registry.onKeydown);
77
+ _EscapeLayer.#registries.delete(active.document);
62
78
  }
63
79
  }
64
- this.#ownerDocument = null;
65
- this.#onDismiss = null;
66
- this.#claims = null;
67
- }
68
- /**
69
- * Whether this active layer would own a press right now: it is the topmost
70
- * layer whose {@link EscapeLayerOptions.claims} passes. Exposed for tests
71
- * and diagnostics — production dismissal goes through the shared listener.
72
- */
80
+ this.#active = null;
81
+ }
73
82
  get ownsEscape() {
74
- const ownerDocument = this.#ownerDocument;
75
- if (!ownerDocument) return false;
76
- const registry = _EscapeLayer.#registries.get(ownerDocument);
83
+ const active = this.#active;
84
+ if (!active) return false;
85
+ const registry = _EscapeLayer.#registries.get(active.document);
77
86
  if (!registry) return false;
78
- return _EscapeLayer.#resolveOwner(registry.stack) === this;
87
+ return _EscapeLayer.#resolveOwner(registry.stack) === active.entry;
79
88
  }
80
- /** Builds a document's registry with its shared resolver listener. */
81
89
  static #createRegistry() {
82
90
  const registry = {
83
91
  stack: [],
@@ -86,66 +94,91 @@ var EscapeLayer = class _EscapeLayer {
86
94
  const owner = _EscapeLayer.#resolveOwner(registry.stack);
87
95
  if (!owner) return;
88
96
  event.preventDefault();
89
- owner.#onDismiss?.();
97
+ owner.onDismiss();
90
98
  }
91
99
  };
92
100
  return registry;
93
101
  }
94
- /** The topmost stack layer whose claims predicate passes, or `null`. */
95
102
  static #resolveOwner(stack) {
96
103
  for (let index = stack.length - 1; index >= 0; index--) {
97
104
  const layer = stack[index];
98
105
  if (!layer) continue;
99
- if (layer.#claims && !layer.#claims()) continue;
106
+ if (layer.claims && !layer.claims()) continue;
100
107
  return layer;
101
108
  }
102
109
  return null;
103
110
  }
104
111
  };
105
112
 
106
- // src/utils/event_owner.ts
107
113
  function ownerIndex(candidates, node) {
108
114
  if (!(node instanceof Node)) return -1;
109
115
  return candidates.findIndex((candidate) => candidate.contains(node));
110
116
  }
111
117
 
112
- // src/utils/safe_timeout.ts
118
+ var MAX_TIMER_DELAY_MS = 2147483647;
119
+
120
+ var NUMBER_BOUNDS = {
121
+ timer: { finite: true, min: 0, max: MAX_TIMER_DELAY_MS }};
122
+ function matchesNumberBounds(value, bounds) {
123
+ if (!Number.isFinite(value)) {
124
+ const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
125
+ if (direction === null) return false;
126
+ if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
127
+ }
128
+ if (bounds.min !== void 0 && value < bounds.min) return false;
129
+ if (bounds.max !== void 0 && value > bounds.max) return false;
130
+ if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
131
+ if (bounds.integer && !Number.isInteger(value)) return false;
132
+ if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
133
+ return true;
134
+ }
135
+
136
+ function readNumber(raw, fallback, bounds) {
137
+ return matchesNumberBounds(raw, bounds) ? raw : fallback;
138
+ }
139
+
140
+ var NumberValueReader = class {
141
+ #lastRejected = /* @__PURE__ */ new Map();
142
+ read(owner, name, raw, fallback, bounds) {
143
+ const resolved = readNumber(raw, fallback, bounds);
144
+ if (matchesNumberBounds(raw, bounds)) {
145
+ this.#lastRejected.delete(name);
146
+ return resolved;
147
+ }
148
+ const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
149
+ const literal = owner.element.getAttribute(attribute);
150
+ if (literal === null) {
151
+ this.#lastRejected.delete(name);
152
+ return resolved;
153
+ }
154
+ if (this.#lastRejected.get(name) !== literal) {
155
+ this.#lastRejected.set(name, literal);
156
+ console.warn(
157
+ `Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
158
+ );
159
+ }
160
+ return resolved;
161
+ }
162
+ };
163
+
113
164
  var TimerRegistry = class {
114
- /** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
115
165
  ids = /* @__PURE__ */ new Set();
116
- /**
117
- * Cancels a single tracked timer.
118
- *
119
- * No-ops if the id is unknown (already cleared, fired, or never owned by this
120
- * registry), so callers can clear defensively without guarding.
121
- */
122
166
  clear(id) {
123
167
  if (this.ids.delete(id)) {
124
168
  this.cancel(id);
125
169
  }
126
170
  }
127
- /**
128
- * Cancels every tracked timer. Call this from a controller's `disconnect()`
129
- * to guarantee no timer outlives the element.
130
- */
131
171
  clearAll() {
132
172
  for (const id of this.ids) {
133
173
  this.cancel(id);
134
174
  }
135
175
  this.ids.clear();
136
176
  }
137
- /** Number of timers currently tracked (pending). */
138
177
  get size() {
139
178
  return this.ids.size;
140
179
  }
141
180
  };
142
181
  var SafeTimeout = class extends TimerRegistry {
143
- /**
144
- * Schedules `callback` after `delay` ms and returns the timer id.
145
- *
146
- * The id is removed from the registry automatically when the timeout fires,
147
- * so {@link TimerRegistry.size | size} reflects only still-pending timers.
148
- */
149
182
  set(callback, delay) {
150
183
  const id = this.schedule(() => {
151
184
  this.ids.delete(id);
@@ -162,50 +195,28 @@ var SafeTimeout = class extends TimerRegistry {
162
195
  }
163
196
  };
164
197
 
165
- // src/utils/state_reason.ts
166
- var FOCUS_EVENTS = /* @__PURE__ */ new Set(["blur", "focus", "focusin", "focusout"]);
167
- var POINTER_EVENTS = /* @__PURE__ */ new Set(["mouseenter", "mouseleave", "pointerenter", "pointerleave"]);
168
- function stateReasonFor(event) {
169
- if (!event) return "api";
170
- if (FOCUS_EVENTS.has(event.type)) return "focus";
171
- if (POINTER_EVENTS.has(event.type)) return "pointer";
172
- return "user";
198
+ function targetSelector(identifier, name) {
199
+ return `[data-${identifier}-target~="${name}"]`;
173
200
  }
174
201
 
175
- // src/controllers/navigation_menu_controller.ts
176
- var NavigationMenuController = class extends Controller {
202
+ var NavigationMenuController = class _NavigationMenuController extends Controller {
203
+ #numbers = new NumberValueReader();
177
204
  static targets = ["trigger", "panel", "hoverArea"];
178
205
  static values = {
179
206
  openOnHover: { type: Boolean, default: false },
180
207
  hoverDelay: { type: Number, default: 150 }
181
208
  };
209
+ static valueConstraints = {
210
+ hoverDelay: NUMBER_BOUNDS.timer
211
+ };
182
212
  static actions = ["onTriggerKeydown", "toggle"];
183
213
  static events = ["close", "open"];
184
- /** Open/close delay timers for hover mode; cleared together on disconnect. */
185
214
  #hoverTimers = new SafeTimeout();
186
- /**
187
- * Elements currently carrying hover listeners. Removal always mirrors this
188
- * set (not a recomputed target snapshot), so a rebuild driven by target churn
189
- * can never strand a listener on an element that stopped being a target.
190
- */
191
215
  #hoverWired = /* @__PURE__ */ new Set();
192
- /**
193
- * The trigger whose hover region the pointer currently occupies, if any. Only
194
- * the click semantics under `openOnHover` read it (see {@link toggle}).
195
- */
196
216
  #hoveredTrigger = null;
197
- /**
198
- * Whether the controller is between `connect()` and `disconnect()`. Stimulus
199
- * disconnects the controller **before** disconnecting its targets, so the
200
- * target callbacks below also fire during teardown; without this flag their
201
- * rebuild would re-wire hover listeners onto an already-disconnected nav.
202
- */
203
217
  #connected = false;
204
- /** Whether state moves are reported: set once `connect()` settled the baseline. */
205
218
  #reporting = false;
206
- /** Escape-stack membership while any panel is open; the shared resolver dismisses via it. */
207
219
  #escapeLayer = new EscapeLayer();
208
- /** Establishes the closed baseline and the dismissal listeners. */
209
220
  connect() {
210
221
  this.#connected = true;
211
222
  this.#closeAll("api");
@@ -214,7 +225,6 @@ var NavigationMenuController = class extends Controller {
214
225
  if (this.openOnHoverValue) this.#addHoverListeners();
215
226
  this.#reporting = true;
216
227
  }
217
- /** Removes every listener, pending hover timer, and stack membership taken while connected. */
218
228
  disconnect() {
219
229
  this.#connected = false;
220
230
  this.#reporting = false;
@@ -224,57 +234,35 @@ var NavigationMenuController = class extends Controller {
224
234
  this.#removeHoverListeners();
225
235
  this.#hoverTimers.clearAll();
226
236
  }
227
- /**
228
- * Follows a runtime flip of `openOnHover` (a morph or a scripted attribute
229
- * change) by wiring or unwiring the hover listeners in place. Stimulus also
230
- * fires this once before `connect()`, which the `#connected` guard skips —
231
- * `connect()` owns the initial wiring.
232
- */
233
237
  openOnHoverValueChanged() {
234
238
  if (!this.#connected) return;
235
239
  if (this.openOnHoverValue) this.#addHoverListeners();
236
240
  else this.#removeHoverListeners();
237
241
  }
238
- /** Re-wires hover listeners when a target is added after connect (Turbo Streams etc.). */
239
242
  triggerTargetConnected() {
240
243
  this.#rewireHoverListeners();
241
244
  }
242
- /** Re-wires hover listeners when a target is removed while connected. */
243
245
  triggerTargetDisconnected() {
244
246
  this.#rewireHoverListeners();
245
247
  }
246
- /** See {@link NavigationMenuController.triggerTargetConnected}. */
247
248
  panelTargetConnected() {
248
249
  this.#rewireHoverListeners();
249
250
  }
250
- /** See {@link NavigationMenuController.triggerTargetDisconnected}. */
251
251
  panelTargetDisconnected() {
252
252
  this.#rewireHoverListeners();
253
253
  }
254
- /** See {@link NavigationMenuController.triggerTargetConnected}. */
255
254
  hoverAreaTargetConnected() {
256
255
  this.#rewireHoverListeners();
257
256
  }
258
- /** See {@link NavigationMenuController.triggerTargetDisconnected}. */
259
257
  hoverAreaTargetDisconnected() {
260
258
  this.#rewireHoverListeners();
261
259
  }
262
- /**
263
- * Toggles a trigger's panel (single-open). Bound via `data-action` (click).
264
- *
265
- * An explicit activation always wins over a scheduled hover open/close, so any
266
- * pending hover timer is dropped first — otherwise a close scheduled just
267
- * before the click would fire into the freshly opened panel.
268
- *
269
- * Under `openOnHover`, closing a panel the pointer itself is holding open is
270
- * refused: the pointer stays put, `mouseenter` does not re-fire, and the panel
271
- * would be unopenable until the pointer left and came back. Keyboard
272
- * activation (pointer elsewhere) still toggles it closed, and `Escape` and
273
- * outside clicks dismiss either way.
274
- */
275
- toggle(event) {
276
- const trigger = event.currentTarget;
277
- const reason = stateReasonFor(event);
260
+ toggle(source) {
261
+ const { host, origin, reason } = actionSource(source);
262
+ const trigger = host?.closest(targetSelector(this.identifier, "trigger"));
263
+ if (!trigger || !this.triggerTargets.includes(trigger)) return;
264
+ if (origin && origin.closest(`[data-controller~="${this.identifier}"]`) !== this.element)
265
+ return;
278
266
  this.#hoverTimers.clearAll();
279
267
  if (!this.#isExpanded(trigger)) {
280
268
  this.#openPanel(trigger, reason);
@@ -283,16 +271,6 @@ var NavigationMenuController = class extends Controller {
283
271
  if (this.openOnHoverValue && this.#hoveredTrigger === trigger) return;
284
272
  this.#closePanel(trigger, reason);
285
273
  }
286
- /**
287
- * `ArrowLeft`/`ArrowRight` move focus between triggers (keeping Tab order).
288
- *
289
- * Only navigable triggers are destinations, so a `hidden` or disabled item
290
- * never swallows the press. A modified arrow belongs to the browser or OS
291
- * (`Alt+←`/`Alt+→` is history back/forward), and with no destination at all
292
- * (a single-trigger nav) the press is left to the page — `preventDefault()` is
293
- * called only when focus actually moves, keeping the scroll-suppression
294
- * contract honest.
295
- */
296
274
  onTriggerKeydown(event) {
297
275
  if (event.defaultPrevented) return;
298
276
  if (event.key !== "ArrowRight" && event.key !== "ArrowLeft") return;
@@ -308,11 +286,6 @@ var NavigationMenuController = class extends Controller {
308
286
  const step = event.key === forward ? 1 : -1;
309
287
  triggers[(index + step + triggers.length) % triggers.length]?.focus();
310
288
  }
311
- /**
312
- * Opens `trigger`'s panel, closing any other open panel first. Re-opening an
313
- * already-open panel only re-asserts the Escape layer: the close/open
314
- * round-trip would rewrite `aria-expanded` and `hidden` for no state change.
315
- */
316
289
  #openPanel(trigger, reason) {
317
290
  if (trigger.getAttribute("aria-disabled") === "true") return;
318
291
  if (this.#isExpanded(trigger)) {
@@ -327,7 +300,6 @@ var NavigationMenuController = class extends Controller {
327
300
  this.#report("open", trigger, panel, reason);
328
301
  this.#syncEscapeLayer();
329
302
  }
330
- /** Closes `trigger`'s panel, reflects the collapsed state, and reports a move. */
331
303
  #closePanel(trigger, reason) {
332
304
  const was = this.#isExpanded(trigger);
333
305
  const panel = this.#panelFor(trigger);
@@ -336,15 +308,9 @@ var NavigationMenuController = class extends Controller {
336
308
  if (was && panel) this.#report("close", trigger, panel, reason);
337
309
  this.#syncEscapeLayer();
338
310
  }
339
- /**
340
- * Closes every open panel and normalizes `aria-expanded="false"` on **all**
341
- * triggers, so a trigger whose panel was hidden by other means cannot keep
342
- * advertising an open panel.
343
- */
344
311
  #closeAll(reason) {
345
312
  for (const trigger of this.triggerTargets) this.#closePanel(trigger, reason);
346
313
  }
347
- /** Names the panel that moved, so a subscriber does not have to re-derive it. */
348
314
  #report(name, trigger, panel, reason) {
349
315
  if (!this.#reporting) return;
350
316
  const index = this.triggerTargets.indexOf(trigger);
@@ -352,27 +318,10 @@ var NavigationMenuController = class extends Controller {
352
318
  if (name === "open") this.dispatch("open", { detail, cancelable: false });
353
319
  else this.dispatch("close", { detail, cancelable: false });
354
320
  }
355
- /**
356
- * Whether a trigger can receive arrow-key focus: not `hidden`, not a natively
357
- * `disabled` control (mirrors `toolbar`). CSS-only visibility cannot be
358
- * detected headlessly and stays the consumer's responsibility.
359
- *
360
- * **`aria-disabled="true"` stays reachable.** APG separates the attributes by
361
- * intent: `disabled` is for controls a neighbour makes inferable, while
362
- * `aria-disabled` marks one that must remain *discoverable* — and a nav
363
- * section the user cannot even arrow to is a section they cannot learn exists.
364
- * Opening is suppressed separately, so the trigger announces itself and does
365
- * nothing.
366
- */
367
321
  #isNavigable(trigger) {
368
322
  if (trigger.hasAttribute("hidden")) return false;
369
323
  return !trigger.disabled;
370
324
  }
371
- /**
372
- * Aligns Escape-stack membership with the open state: joins (or re-asserts to
373
- * the top) while a panel is open, leaves once none is. Re-asserting when the
374
- * user switches panels is deliberate — the nav is again the newest layer.
375
- */
376
325
  #syncEscapeLayer() {
377
326
  if (this.#isAnyOpen) {
378
327
  this.#escapeLayer.activate(document, {
@@ -383,11 +332,6 @@ var NavigationMenuController = class extends Controller {
383
332
  this.#escapeLayer.deactivate();
384
333
  }
385
334
  }
386
- /**
387
- * Closes any open panel and returns focus to its trigger (Escape path). A
388
- * pending hover open would otherwise re-open the panel the user just
389
- * dismissed, so the reservation is dropped with it.
390
- */
391
335
  #closeAndRestore() {
392
336
  const open = this.#openTrigger;
393
337
  if (!open) return;
@@ -395,78 +339,42 @@ var NavigationMenuController = class extends Controller {
395
339
  this.#closePanel(open, "escape");
396
340
  open.focus();
397
341
  }
398
- /** Closes panels when a click lands outside the nav element. */
399
342
  #onOutsideClick = (event) => {
400
343
  if (this.#isAnyOpen && !this.element.contains(event.target)) this.#closeAll("outside");
401
344
  };
402
- /**
403
- * Closes (without restoring focus) when focus leaves the nav for a known
404
- * external destination. A null/non-Node destination is indeterminate:
405
- * browsers use it for clicks on non-focusable content and for window
406
- * deactivation, so those never close the nav here (matching the popover
407
- * convention) — the outside-click handler decides pointer dismissal, and the
408
- * Escape stack's body-focus claim keeps keyboard dismissal working.
409
- */
410
345
  #onFocusOut = (event) => {
411
346
  const next = event.relatedTarget;
412
347
  if (!(next instanceof Node) || this.element.contains(next)) return;
413
348
  this.#closeAll("focus");
414
349
  };
415
- /**
416
- * Opens a trigger's panel after the hover delay (hover mode).
417
- *
418
- * @stimeoRuntimeOnly `hoverDelay` is the delay of the one hover timer this entry arms.
419
- */
420
350
  #onPointerEnter = (event) => {
421
351
  const trigger = this.#triggerForHover(event.currentTarget);
422
352
  if (!trigger) return;
423
353
  this.#hoveredTrigger = trigger;
424
354
  this.#hoverTimers.clearAll();
425
- this.#hoverTimers.set(() => this.#openFromHover(trigger), this.hoverDelayValue);
355
+ this.#hoverTimers.set(() => this.#openFromHover(trigger), this.#safeHoverDelay);
426
356
  };
427
- /**
428
- * Closes the open panel after the hover delay (hover mode) — unless the
429
- * pointer moved directly into another part of the hover region (an adjacent
430
- * trigger, panel, or hoverArea): crossing a shared edge must not schedule a
431
- * spurious close, e.g. a hoverArea whose panel sits outside it as a sibling.
432
- *
433
- * @stimeoRuntimeOnly `hoverDelay` is the delay of the one hover timer this exit arms.
434
- */
435
357
  #onPointerLeave = (event) => {
436
358
  const next = event instanceof MouseEvent ? event.relatedTarget : null;
437
359
  if (ownerIndex(this.#hoverElements, next) !== -1) return;
438
360
  this.#hoveredTrigger = null;
439
361
  this.#hoverTimers.clearAll();
440
- this.#hoverTimers.set(() => this.#closeFromHover(), this.hoverDelayValue);
362
+ this.#hoverTimers.set(() => this.#closeFromHover(), this.#safeHoverDelay);
441
363
  };
442
- /**
443
- * Hover-driven open. Switching panels would hide the outgoing one, so focus
444
- * standing inside it is handed back to its trigger first: pointer movement
445
- * must never send focus to the body (the keyboard user would lose their
446
- * place). Focus outside the closing panel is left alone.
447
- */
448
364
  #openFromHover(trigger) {
449
365
  if (trigger.getAttribute("aria-disabled") === "true") return;
450
366
  const open = this.#openTrigger;
451
367
  if (open && open !== trigger && this.#holdsFocus(this.#panelFor(open))) open.focus();
452
368
  this.#openPanel(trigger, "pointer");
453
369
  }
454
- /**
455
- * Hover-driven close: skipped while focus sits inside the panel it would hide,
456
- * for the same no-focus-loss reason (cf. `hover_card`'s delayed close). The
457
- * panel then stays open until `Escape`, an outside click, or focus leaving the
458
- * nav dismisses it — all of which restore or keep focus deliberately.
459
- */
460
370
  #closeFromHover() {
461
371
  const open = this.#openTrigger;
462
372
  if (open && this.#holdsFocus(this.#panelFor(open))) return;
463
373
  this.#closeAll("pointer");
464
374
  }
465
- /** Whether `panel` exists and currently contains the focused element. */
466
375
  #holdsFocus(panel) {
467
376
  return panel?.contains(document.activeElement) ?? false;
468
377
  }
469
- /** Wires hover open/close on each hover element (opt-in), tracking what was wired. */
470
378
  #addHoverListeners() {
471
379
  for (const element of this.#hoverElements) {
472
380
  element.addEventListener("mouseenter", this.#onPointerEnter);
@@ -474,7 +382,6 @@ var NavigationMenuController = class extends Controller {
474
382
  this.#hoverWired.add(element);
475
383
  }
476
384
  }
477
- /** Removes the hover listeners from exactly the elements that were wired. */
478
385
  #removeHoverListeners() {
479
386
  for (const element of this.#hoverWired) {
480
387
  element.removeEventListener("mouseenter", this.#onPointerEnter);
@@ -483,25 +390,11 @@ var NavigationMenuController = class extends Controller {
483
390
  this.#hoverWired.clear();
484
391
  this.#hoveredTrigger = null;
485
392
  }
486
- /**
487
- * Rebuilds the hover wiring from the current targets. Target callbacks call
488
- * this so items added or removed after connect (e.g. a Turbo Stream append)
489
- * participate in hover; the wired-set removal keeps the rebuild symmetric.
490
- * Stimulus fires those callbacks during teardown too, hence the `#connected`
491
- * guard — a rebuild after `disconnect()` would resurrect the listeners.
492
- */
493
393
  #rewireHoverListeners() {
494
394
  if (!this.#connected || !this.openOnHoverValue) return;
495
395
  this.#removeHoverListeners();
496
396
  this.#addHoverListeners();
497
397
  }
498
- /**
499
- * Elements that participate in hover: each `hoverArea`, plus every trigger and
500
- * panel **not** wrapped by one. A wrapped trigger/panel must defer to its
501
- * wrapper — its own mouseleave would otherwise schedule a close while the
502
- * pointer is still inside the area (mouseenter does not re-fire on the wrapper
503
- * when moving among its descendants), flickering the panel shut.
504
- */
505
398
  get #hoverElements() {
506
399
  const areas = this.hoverAreaTargets;
507
400
  const covered = (element) => ownerIndex(areas, element) !== -1;
@@ -511,11 +404,6 @@ var NavigationMenuController = class extends Controller {
511
404
  ...this.panelTargets.filter((panel) => !covered(panel))
512
405
  ];
513
406
  }
514
- /**
515
- * Resolves the trigger for a hovered element: the trigger itself, the trigger
516
- * controlling a hovered panel, or the first trigger contained in a hovered
517
- * `hoverArea` wrapper.
518
- */
519
407
  #triggerForHover(element) {
520
408
  if (this.triggerTargets.includes(element)) return element;
521
409
  if (this.panelTargets.includes(element)) {
@@ -526,25 +414,29 @@ var NavigationMenuController = class extends Controller {
526
414
  }
527
415
  return null;
528
416
  }
529
- /** The panel controlled by `trigger` (matched by `aria-controls`/`id`). */
530
417
  #panelFor(trigger) {
531
418
  const id = trigger.getAttribute("aria-controls");
532
419
  return id ? this.panelTargets.find((panel) => panel.id === id) ?? null : null;
533
420
  }
534
- /** Whether `trigger`'s panel is currently expanded. */
535
421
  #isExpanded(trigger) {
536
422
  return trigger.getAttribute("aria-expanded") === "true";
537
423
  }
538
- /** The trigger whose panel is currently open, if any. */
539
424
  get #openTrigger() {
540
425
  return this.triggerTargets.find((trigger) => this.#isExpanded(trigger)) ?? null;
541
426
  }
542
- /** Whether any panel is currently open. */
543
427
  get #isAnyOpen() {
544
428
  return this.#openTrigger !== null;
545
429
  }
430
+ get #safeHoverDelay() {
431
+ return this.#numbers.read(
432
+ this,
433
+ "hoverDelay",
434
+ this.hoverDelayValue,
435
+ _NavigationMenuController.values.hoverDelay.default,
436
+ _NavigationMenuController.valueConstraints.hoverDelay
437
+ );
438
+ }
546
439
  };
547
440
 
548
441
  export { NavigationMenuController };
549
- //# sourceMappingURL=navigation_menu_controller.js.map
550
442
  //# sourceMappingURL=navigation_menu_controller.js.map