stimeo-ui 0.14.0 → 0.16.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 (279) hide show
  1. package/CHANGELOG.md +212 -0
  2. package/README.md +120 -0
  3. package/dist/cable/index.js +123 -29
  4. package/dist/cable/index.js.map +1 -1
  5. package/dist/controllers/accordion_controller.d.ts +30 -3
  6. package/dist/controllers/accordion_controller.js +98 -9
  7. package/dist/controllers/accordion_controller.js.map +1 -1
  8. package/dist/controllers/alert_dialog_controller.d.ts +8 -7
  9. package/dist/controllers/alert_dialog_controller.js.map +1 -1
  10. package/dist/controllers/announcer_controller.d.ts +3 -2
  11. package/dist/controllers/announcer_controller.js +96 -62
  12. package/dist/controllers/announcer_controller.js.map +1 -1
  13. package/dist/controllers/auto_submit_controller.js +83 -7
  14. package/dist/controllers/auto_submit_controller.js.map +1 -1
  15. package/dist/controllers/avatar_controller.js +1 -1
  16. package/dist/controllers/avatar_controller.js.map +1 -1
  17. package/dist/controllers/breadcrumb_controller.d.ts +10 -7
  18. package/dist/controllers/breadcrumb_controller.js +38 -11
  19. package/dist/controllers/breadcrumb_controller.js.map +1 -1
  20. package/dist/controllers/bulk_select_controller.d.ts +4 -4
  21. package/dist/controllers/bulk_select_controller.js +7 -6
  22. package/dist/controllers/bulk_select_controller.js.map +1 -1
  23. package/dist/controllers/calendar_controller.d.ts +101 -23
  24. package/dist/controllers/calendar_controller.js +340 -123
  25. package/dist/controllers/calendar_controller.js.map +1 -1
  26. package/dist/controllers/carousel_controller.d.ts +67 -22
  27. package/dist/controllers/carousel_controller.js +263 -38
  28. package/dist/controllers/carousel_controller.js.map +1 -1
  29. package/dist/controllers/character_counter_controller.d.ts +1 -1
  30. package/dist/controllers/character_counter_controller.js +40 -2
  31. package/dist/controllers/character_counter_controller.js.map +1 -1
  32. package/dist/controllers/checkbox_controller.js +81 -12
  33. package/dist/controllers/checkbox_controller.js.map +1 -1
  34. package/dist/controllers/clipboard_controller.d.ts +28 -2
  35. package/dist/controllers/clipboard_controller.js +63 -5
  36. package/dist/controllers/clipboard_controller.js.map +1 -1
  37. package/dist/controllers/collapsible_controller.d.ts +25 -1
  38. package/dist/controllers/collapsible_controller.js +99 -14
  39. package/dist/controllers/collapsible_controller.js.map +1 -1
  40. package/dist/controllers/color_picker_controller.d.ts +29 -8
  41. package/dist/controllers/color_picker_controller.js +80 -34
  42. package/dist/controllers/color_picker_controller.js.map +1 -1
  43. package/dist/controllers/combobox_controller.d.ts +10 -1
  44. package/dist/controllers/combobox_controller.js +106 -16
  45. package/dist/controllers/combobox_controller.js.map +1 -1
  46. package/dist/controllers/command_palette_controller.d.ts +3 -3
  47. package/dist/controllers/command_palette_controller.js +35 -3
  48. package/dist/controllers/command_palette_controller.js.map +1 -1
  49. package/dist/controllers/conditional_fields_controller.js +85 -17
  50. package/dist/controllers/conditional_fields_controller.js.map +1 -1
  51. package/dist/controllers/confirm_controller.js +3 -0
  52. package/dist/controllers/confirm_controller.js.map +1 -1
  53. package/dist/controllers/context_menu_controller.d.ts +6 -0
  54. package/dist/controllers/context_menu_controller.js +32 -12
  55. package/dist/controllers/context_menu_controller.js.map +1 -1
  56. package/dist/controllers/count_up_controller.js.map +1 -1
  57. package/dist/controllers/countdown_controller.d.ts +30 -1
  58. package/dist/controllers/countdown_controller.js +129 -26
  59. package/dist/controllers/countdown_controller.js.map +1 -1
  60. package/dist/controllers/currency_input_controller.d.ts +77 -16
  61. package/dist/controllers/currency_input_controller.js +221 -67
  62. package/dist/controllers/currency_input_controller.js.map +1 -1
  63. package/dist/controllers/data_grid_controller.d.ts +63 -18
  64. package/dist/controllers/data_grid_controller.js +195 -29
  65. package/dist/controllers/data_grid_controller.js.map +1 -1
  66. package/dist/controllers/date_range_picker_controller.d.ts +41 -6
  67. package/dist/controllers/date_range_picker_controller.js +151 -30
  68. package/dist/controllers/date_range_picker_controller.js.map +1 -1
  69. package/dist/controllers/dialog_controller.d.ts +10 -3
  70. package/dist/controllers/dialog_controller.js +35 -8
  71. package/dist/controllers/dialog_controller.js.map +1 -1
  72. package/dist/controllers/direct_upload_controller.js +22 -4
  73. package/dist/controllers/direct_upload_controller.js.map +1 -1
  74. package/dist/controllers/dirty_form_controller.d.ts +2 -2
  75. package/dist/controllers/dirty_form_controller.js +46 -13
  76. package/dist/controllers/dirty_form_controller.js.map +1 -1
  77. package/dist/controllers/dismissible_controller.js +1 -0
  78. package/dist/controllers/dismissible_controller.js.map +1 -1
  79. package/dist/controllers/drawer_controller.d.ts +18 -10
  80. package/dist/controllers/drawer_controller.js +54 -19
  81. package/dist/controllers/drawer_controller.js.map +1 -1
  82. package/dist/controllers/dropdown_controller.d.ts +9 -3
  83. package/dist/controllers/dropdown_controller.js +36 -9
  84. package/dist/controllers/dropdown_controller.js.map +1 -1
  85. package/dist/controllers/editable_controller.js +34 -0
  86. package/dist/controllers/editable_controller.js.map +1 -1
  87. package/dist/controllers/file_dropzone_controller.js +144 -51
  88. package/dist/controllers/file_dropzone_controller.js.map +1 -1
  89. package/dist/controllers/filter_controller.d.ts +10 -4
  90. package/dist/controllers/filter_controller.js +20 -6
  91. package/dist/controllers/filter_controller.js.map +1 -1
  92. package/dist/controllers/flash_controller.d.ts +26 -6
  93. package/dist/controllers/flash_controller.js +432 -71
  94. package/dist/controllers/flash_controller.js.map +1 -1
  95. package/dist/controllers/focus_controller.js +1 -0
  96. package/dist/controllers/focus_controller.js.map +1 -1
  97. package/dist/controllers/form_field_controller.js +7 -5
  98. package/dist/controllers/form_field_controller.js.map +1 -1
  99. package/dist/controllers/form_validation_controller.js +19 -13
  100. package/dist/controllers/form_validation_controller.js.map +1 -1
  101. package/dist/controllers/frame_loading_controller.js +45 -8
  102. package/dist/controllers/frame_loading_controller.js.map +1 -1
  103. package/dist/controllers/highlight_controller.js +82 -25
  104. package/dist/controllers/highlight_controller.js.map +1 -1
  105. package/dist/controllers/hover_card_controller.d.ts +10 -2
  106. package/dist/controllers/hover_card_controller.js +40 -14
  107. package/dist/controllers/hover_card_controller.js.map +1 -1
  108. package/dist/controllers/idle_controller.d.ts +16 -3
  109. package/dist/controllers/idle_controller.js +90 -5
  110. package/dist/controllers/idle_controller.js.map +1 -1
  111. package/dist/controllers/input_mask_controller.d.ts +5 -2
  112. package/dist/controllers/input_mask_controller.js +65 -9
  113. package/dist/controllers/input_mask_controller.js.map +1 -1
  114. package/dist/controllers/intersection_controller.js +3 -0
  115. package/dist/controllers/intersection_controller.js.map +1 -1
  116. package/dist/controllers/lazy_frame_controller.js +11 -2
  117. package/dist/controllers/lazy_frame_controller.js.map +1 -1
  118. package/dist/controllers/listbox_controller.d.ts +50 -8
  119. package/dist/controllers/listbox_controller.js +203 -45
  120. package/dist/controllers/listbox_controller.js.map +1 -1
  121. package/dist/controllers/local_time_controller.js +10 -5
  122. package/dist/controllers/local_time_controller.js.map +1 -1
  123. package/dist/controllers/masonry_controller.d.ts +3 -3
  124. package/dist/controllers/masonry_controller.js +31 -15
  125. package/dist/controllers/masonry_controller.js.map +1 -1
  126. package/dist/controllers/menu_controller.d.ts +9 -3
  127. package/dist/controllers/menu_controller.js +45 -16
  128. package/dist/controllers/menu_controller.js.map +1 -1
  129. package/dist/controllers/menubar_controller.d.ts +11 -0
  130. package/dist/controllers/menubar_controller.js +58 -24
  131. package/dist/controllers/menubar_controller.js.map +1 -1
  132. package/dist/controllers/meter_controller.js +9 -5
  133. package/dist/controllers/meter_controller.js.map +1 -1
  134. package/dist/controllers/multi_select_controller.d.ts +18 -3
  135. package/dist/controllers/multi_select_controller.js +278 -104
  136. package/dist/controllers/multi_select_controller.js.map +1 -1
  137. package/dist/controllers/navigation_menu_controller.d.ts +11 -0
  138. package/dist/controllers/navigation_menu_controller.js +48 -15
  139. package/dist/controllers/navigation_menu_controller.js.map +1 -1
  140. package/dist/controllers/nested_form_controller.js +37 -8
  141. package/dist/controllers/nested_form_controller.js.map +1 -1
  142. package/dist/controllers/network_status_controller.js +9 -1
  143. package/dist/controllers/network_status_controller.js.map +1 -1
  144. package/dist/controllers/number_input_controller.d.ts +36 -8
  145. package/dist/controllers/number_input_controller.js +124 -21
  146. package/dist/controllers/number_input_controller.js.map +1 -1
  147. package/dist/controllers/optimistic_controller.js +42 -5
  148. package/dist/controllers/optimistic_controller.js.map +1 -1
  149. package/dist/controllers/otp_controller.d.ts +22 -7
  150. package/dist/controllers/otp_controller.js +198 -55
  151. package/dist/controllers/otp_controller.js.map +1 -1
  152. package/dist/controllers/overflow_indicator_controller.d.ts +8 -12
  153. package/dist/controllers/overflow_indicator_controller.js +115 -21
  154. package/dist/controllers/overflow_indicator_controller.js.map +1 -1
  155. package/dist/controllers/overflow_menu_controller.d.ts +26 -6
  156. package/dist/controllers/overflow_menu_controller.js +141 -44
  157. package/dist/controllers/overflow_menu_controller.js.map +1 -1
  158. package/dist/controllers/pagination_controller.d.ts +19 -11
  159. package/dist/controllers/pagination_controller.js +74 -28
  160. package/dist/controllers/pagination_controller.js.map +1 -1
  161. package/dist/controllers/password_reveal_controller.d.ts +15 -1
  162. package/dist/controllers/password_reveal_controller.js +59 -2
  163. package/dist/controllers/password_reveal_controller.js.map +1 -1
  164. package/dist/controllers/persist_controller.js +30 -8
  165. package/dist/controllers/persist_controller.js.map +1 -1
  166. package/dist/controllers/pointer_drag_controller.js +131 -52
  167. package/dist/controllers/pointer_drag_controller.js.map +1 -1
  168. package/dist/controllers/popover_controller.d.ts +9 -3
  169. package/dist/controllers/popover_controller.js +45 -11
  170. package/dist/controllers/popover_controller.js.map +1 -1
  171. package/dist/controllers/portal_controller.d.ts +1 -1
  172. package/dist/controllers/portal_controller.js +6 -2
  173. package/dist/controllers/portal_controller.js.map +1 -1
  174. package/dist/controllers/preview_guard_controller.js +16 -1
  175. package/dist/controllers/preview_guard_controller.js.map +1 -1
  176. package/dist/controllers/progress_controller.js +8 -4
  177. package/dist/controllers/progress_controller.js.map +1 -1
  178. package/dist/controllers/radio_group_controller.d.ts +6 -4
  179. package/dist/controllers/radio_group_controller.js +42 -17
  180. package/dist/controllers/radio_group_controller.js.map +1 -1
  181. package/dist/controllers/range_slider_controller.d.ts +49 -1
  182. package/dist/controllers/range_slider_controller.js +88 -42
  183. package/dist/controllers/range_slider_controller.js.map +1 -1
  184. package/dist/controllers/rating_controller.d.ts +14 -3
  185. package/dist/controllers/rating_controller.js +39 -15
  186. package/dist/controllers/rating_controller.js.map +1 -1
  187. package/dist/controllers/read_more_controller.d.ts +24 -2
  188. package/dist/controllers/read_more_controller.js +100 -7
  189. package/dist/controllers/read_more_controller.js.map +1 -1
  190. package/dist/controllers/reading_progress_controller.js +65 -19
  191. package/dist/controllers/reading_progress_controller.js.map +1 -1
  192. package/dist/controllers/relative_time_controller.js +10 -5
  193. package/dist/controllers/relative_time_controller.js.map +1 -1
  194. package/dist/controllers/resizable_controller.d.ts +16 -2
  195. package/dist/controllers/resizable_controller.js +82 -22
  196. package/dist/controllers/resizable_controller.js.map +1 -1
  197. package/dist/controllers/scroll_area_controller.js +75 -27
  198. package/dist/controllers/scroll_area_controller.js.map +1 -1
  199. package/dist/controllers/scroll_restore_controller.js +37 -16
  200. package/dist/controllers/scroll_restore_controller.js.map +1 -1
  201. package/dist/controllers/scroll_visibility_controller.js +49 -30
  202. package/dist/controllers/scroll_visibility_controller.js.map +1 -1
  203. package/dist/controllers/scrollspy_controller.d.ts +3 -2
  204. package/dist/controllers/scrollspy_controller.js +71 -26
  205. package/dist/controllers/scrollspy_controller.js.map +1 -1
  206. package/dist/controllers/separator_controller.d.ts +41 -14
  207. package/dist/controllers/separator_controller.js +66 -37
  208. package/dist/controllers/separator_controller.js.map +1 -1
  209. package/dist/controllers/sidebar_controller.d.ts +20 -3
  210. package/dist/controllers/sidebar_controller.js +77 -18
  211. package/dist/controllers/sidebar_controller.js.map +1 -1
  212. package/dist/controllers/skeleton_controller.js +6 -1
  213. package/dist/controllers/skeleton_controller.js.map +1 -1
  214. package/dist/controllers/slider_controller.d.ts +45 -7
  215. package/dist/controllers/slider_controller.js +82 -47
  216. package/dist/controllers/slider_controller.js.map +1 -1
  217. package/dist/controllers/smart_sticky_header_controller.js +60 -26
  218. package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
  219. package/dist/controllers/sortable_controller.js +17 -2
  220. package/dist/controllers/sortable_controller.js.map +1 -1
  221. package/dist/controllers/spinner_controller.js +10 -2
  222. package/dist/controllers/spinner_controller.js.map +1 -1
  223. package/dist/controllers/step_indicator_controller.d.ts +19 -17
  224. package/dist/controllers/step_indicator_controller.js +18 -17
  225. package/dist/controllers/step_indicator_controller.js.map +1 -1
  226. package/dist/controllers/stepper_controller.d.ts +34 -9
  227. package/dist/controllers/stepper_controller.js +101 -19
  228. package/dist/controllers/stepper_controller.js.map +1 -1
  229. package/dist/controllers/stick_to_bottom_controller.d.ts +19 -0
  230. package/dist/controllers/stick_to_bottom_controller.js +104 -8
  231. package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
  232. package/dist/controllers/submit_once_controller.d.ts +3 -2
  233. package/dist/controllers/submit_once_controller.js +45 -9
  234. package/dist/controllers/submit_once_controller.js.map +1 -1
  235. package/dist/controllers/switch_controller.d.ts +29 -7
  236. package/dist/controllers/switch_controller.js +101 -10
  237. package/dist/controllers/switch_controller.js.map +1 -1
  238. package/dist/controllers/tabs_controller.d.ts +12 -0
  239. package/dist/controllers/tabs_controller.js +21 -2
  240. package/dist/controllers/tabs_controller.js.map +1 -1
  241. package/dist/controllers/tags_input_controller.d.ts +15 -3
  242. package/dist/controllers/tags_input_controller.js +209 -59
  243. package/dist/controllers/tags_input_controller.js.map +1 -1
  244. package/dist/controllers/textarea_autosize_controller.js +29 -3
  245. package/dist/controllers/textarea_autosize_controller.js.map +1 -1
  246. package/dist/controllers/theme_controller.d.ts +20 -3
  247. package/dist/controllers/theme_controller.js +64 -14
  248. package/dist/controllers/theme_controller.js.map +1 -1
  249. package/dist/controllers/time_picker_controller.js +23 -8
  250. package/dist/controllers/time_picker_controller.js.map +1 -1
  251. package/dist/controllers/toast_controller.d.ts +55 -15
  252. package/dist/controllers/toast_controller.js +451 -105
  253. package/dist/controllers/toast_controller.js.map +1 -1
  254. package/dist/controllers/toggle_group_controller.d.ts +49 -7
  255. package/dist/controllers/toggle_group_controller.js +159 -23
  256. package/dist/controllers/toggle_group_controller.js.map +1 -1
  257. package/dist/controllers/toolbar_controller.js +32 -0
  258. package/dist/controllers/toolbar_controller.js.map +1 -1
  259. package/dist/controllers/tooltip_controller.d.ts +8 -0
  260. package/dist/controllers/tooltip_controller.js +39 -13
  261. package/dist/controllers/tooltip_controller.js.map +1 -1
  262. package/dist/controllers/transition_controller.js +4 -0
  263. package/dist/controllers/transition_controller.js.map +1 -1
  264. package/dist/controllers/tree_view_controller.d.ts +39 -8
  265. package/dist/controllers/tree_view_controller.js +169 -16
  266. package/dist/controllers/tree_view_controller.js.map +1 -1
  267. package/dist/index.d.ts +28 -1
  268. package/dist/index.js +5002 -1911
  269. package/dist/index.js.map +1 -1
  270. package/dist/inspector/cli.d.ts +72 -6
  271. package/dist/inspector/cli.js +262 -51
  272. package/dist/inspector/cli.js.map +1 -1
  273. package/dist/inspector/cli_bin.js +309 -51
  274. package/dist/inspector/cli_bin.js.map +1 -1
  275. package/dist/inspector/examples.json +40 -40
  276. package/dist/inspector/manifest.json +529 -61
  277. package/dist/positioning/index.js +2 -0
  278. package/dist/positioning/index.js.map +1 -1
  279. package/package.json +2 -2
@@ -200,6 +200,16 @@ var SafeTimeout = class extends TimerRegistry {
200
200
  }
201
201
  };
202
202
 
203
+ // src/utils/state_reason.ts
204
+ var FOCUS_EVENTS = /* @__PURE__ */ new Set(["blur", "focus", "focusin", "focusout"]);
205
+ var POINTER_EVENTS = /* @__PURE__ */ new Set(["mouseenter", "mouseleave", "pointerenter", "pointerleave"]);
206
+ function stateReasonFor(event) {
207
+ if (!event) return "api";
208
+ if (FOCUS_EVENTS.has(event.type)) return "focus";
209
+ if (POINTER_EVENTS.has(event.type)) return "pointer";
210
+ return "user";
211
+ }
212
+
203
213
  // src/utils/typeahead.ts
204
214
  var TYPEAHEAD_RESET_MS = 500;
205
215
  var Typeahead = class {
@@ -263,6 +273,7 @@ var STATE_ATTRIBUTES = ["disabled", "hidden"];
263
273
  var MenubarController = class extends Controller {
264
274
  static targets = ["top", "menu", "item"];
265
275
  static actions = ["activate", "onItemKeydown", "onTopKeydown", "toggle"];
276
+ static events = ["close", "open"];
266
277
  /** Roving tabindex across the top-level menuitems (one Tab stop). */
267
278
  #roving = new RovingTabindex(() => this.topTargets);
268
279
  /** Typeahead query and its idle-reset timer (scoped to the open menu). */
@@ -281,6 +292,8 @@ var MenubarController = class extends Controller {
281
292
  * stop on mount and from resurrecting one after teardown.
282
293
  */
283
294
  #connected = false;
295
+ /** Whether state moves are reported: set once `connect()` settled the baseline. */
296
+ #reporting = false;
284
297
  /** The element inside the menubar that last took DOM focus, if any. */
285
298
  #focused = null;
286
299
  /**
@@ -314,7 +327,7 @@ var MenubarController = class extends Controller {
314
327
  * close the menu.
315
328
  */
316
329
  connect() {
317
- this.#closeAllMenus();
330
+ this.#closeAllMenus("api");
318
331
  this.#reconcile();
319
332
  this.element.addEventListener("click", this.#onDisabledClickCapture, true);
320
333
  this.element.addEventListener("focusin", this.#onFocusIn);
@@ -330,10 +343,12 @@ var MenubarController = class extends Controller {
330
343
  });
331
344
  }
332
345
  this.#connected = true;
346
+ this.#reporting = true;
333
347
  }
334
348
  /** Removes the listeners, stack membership, and any pending timer (typeahead / Tab close). */
335
349
  disconnect() {
336
350
  this.#connected = false;
351
+ this.#reporting = false;
337
352
  this.#escapeLayer.deactivate();
338
353
  this.#layerActive = false;
339
354
  this.element.removeEventListener("click", this.#onDisabledClickCapture, true);
@@ -395,10 +410,11 @@ var MenubarController = class extends Controller {
395
410
  /** Toggles a top item's menu. Bound via `data-action` (click on the top item). */
396
411
  toggle(event) {
397
412
  const top = event.currentTarget;
413
+ const reason = stateReasonFor(event);
398
414
  if (this.#isExpanded(top)) {
399
- this.#closeMenu(top);
415
+ this.#closeMenu(top, reason);
400
416
  } else {
401
- this.#openMenu(top, "first");
417
+ this.#openMenu(top, "first", reason);
402
418
  }
403
419
  }
404
420
  /** Keyboard handling while focus is on a top item. */
@@ -414,27 +430,27 @@ var MenubarController = class extends Controller {
414
430
  switch (event.key) {
415
431
  case "ArrowRight":
416
432
  event.preventDefault();
417
- this.#gotoTop(tops[(index + step + length) % length], anyOpen);
433
+ this.#gotoTop(tops[(index + step + length) % length], anyOpen, "user");
418
434
  break;
419
435
  case "ArrowLeft":
420
436
  event.preventDefault();
421
- this.#gotoTop(tops[(index - step + length) % length], anyOpen);
437
+ this.#gotoTop(tops[(index - step + length) % length], anyOpen, "user");
422
438
  break;
423
439
  case "ArrowDown":
424
440
  event.preventDefault();
425
- this.#openMenu(tops[index], "first");
441
+ this.#openMenu(tops[index], "first", "user");
426
442
  break;
427
443
  case "ArrowUp":
428
444
  event.preventDefault();
429
- this.#openMenu(tops[index], "last");
445
+ this.#openMenu(tops[index], "last", "user");
430
446
  break;
431
447
  case "Home":
432
448
  event.preventDefault();
433
- this.#gotoTop(tops[0], anyOpen);
449
+ this.#gotoTop(tops[0], anyOpen, "user");
434
450
  break;
435
451
  case "End":
436
452
  event.preventDefault();
437
- this.#gotoTop(tops[length - 1], anyOpen);
453
+ this.#gotoTop(tops[length - 1], anyOpen, "user");
438
454
  break;
439
455
  case "Tab":
440
456
  this.#closeMenusSoon();
@@ -492,14 +508,14 @@ var MenubarController = class extends Controller {
492
508
  const item = event.currentTarget;
493
509
  const menu = item.closest("[role='menu']");
494
510
  const top = this.#topFor(menu);
495
- this.#closeAllMenus();
511
+ this.#closeAllMenus("select");
496
512
  this.#focusTop(top);
497
513
  }
498
514
  /** Moves the roving focus to `top`, opening its menu when one was open. */
499
- #gotoTop(top, reopen) {
515
+ #gotoTop(top, reopen, reason) {
500
516
  if (!top) return;
501
517
  if (reopen) {
502
- this.#openMenu(top, "first");
518
+ this.#openMenu(top, "first", reason);
503
519
  } else {
504
520
  this.#roving.setActive(this.topTargets.indexOf(top), { focus: true });
505
521
  }
@@ -526,20 +542,23 @@ var MenubarController = class extends Controller {
526
542
  * this "open a menu" path. A dangling top is still an ordinary roving
527
543
  * destination while nothing is open.
528
544
  */
529
- #openMenu(top, focus) {
545
+ #openMenu(top, focus, reason) {
530
546
  if (!top) return;
531
547
  const menu = this.#menuFor(top);
532
548
  if (!menu || this.#isActivationBlocked(top)) {
533
549
  if (menu || !top.hasAttribute("aria-controls")) {
534
- this.#closeAllMenus();
550
+ this.#closeAllMenus(reason);
535
551
  this.#focusTop(top);
536
552
  }
537
553
  return;
538
554
  }
539
555
  this.#timers.clearAll();
540
- this.#closeAllMenus();
556
+ const was = this.#isExpanded(top);
557
+ this.#closeAllMenus(reason, top);
541
558
  menu.hidden = false;
542
559
  top.setAttribute("aria-expanded", "true");
560
+ if (!was) this.#report("open", top, menu, reason);
561
+ if (!this.#isExpanded(top)) return;
543
562
  this.#escapeLayer.activate(document, {
544
563
  onDismiss: () => this.#dismissOpenMenu(),
545
564
  claims: claimsWhileFocusWithin(this.element)
@@ -554,19 +573,32 @@ var MenubarController = class extends Controller {
554
573
  * no menu (a plain command in an otherwise popup-bearing menubar) is left alone
555
574
  * — stamping `aria-expanded="false"` on it would announce a popup it lacks.
556
575
  */
557
- #closeMenu(top) {
576
+ #closeMenu(top, reason, silent = false) {
558
577
  if (!top) return;
559
578
  const menu = this.#menuFor(top);
560
579
  if (!menu) return;
580
+ const was = this.#isExpanded(top);
561
581
  menu.hidden = true;
562
582
  top.setAttribute("aria-expanded", "false");
583
+ if (was && !silent) this.#report("close", top, menu, reason);
563
584
  this.#syncEscapeLayer();
564
585
  }
565
- /** Closes every menu and resets the typeahead query. */
566
- #closeAllMenus() {
567
- for (const top of this.topTargets) this.#closeMenu(top);
586
+ /**
587
+ * Closes every menu and resets the typeahead query. `except` still has its
588
+ * attributes rewritten — the caller is about to reopen it — but its move is
589
+ * left for that caller to report.
590
+ */
591
+ #closeAllMenus(reason, except = null) {
592
+ for (const top of this.topTargets) this.#closeMenu(top, reason, top === except);
568
593
  this.#typeahead.reset();
569
594
  }
595
+ /** Names the menu that moved, so a subscriber does not have to re-derive it. */
596
+ #report(name, top, menu, reason) {
597
+ if (!this.#reporting) return;
598
+ const detail = { reason, index: this.topTargets.indexOf(top), menu };
599
+ if (name === "open") this.dispatch("open", { detail, cancelable: false });
600
+ else this.dispatch("close", { detail, cancelable: false });
601
+ }
570
602
  /**
571
603
  * Closes every menu on the next task instead of synchronously.
572
604
  *
@@ -577,7 +609,7 @@ var MenubarController = class extends Controller {
577
609
  #closeMenusSoon() {
578
610
  if (!this.#isAnyOpen) return;
579
611
  this.#timers.clearAll();
580
- this.#timers.set(() => this.#closeAllMenus(), 0);
612
+ this.#timers.set(() => this.#closeAllMenus("focus"), 0);
581
613
  }
582
614
  /**
583
615
  * Escape path, invoked by the shared resolver: pressed inside an open menu it
@@ -589,11 +621,11 @@ var MenubarController = class extends Controller {
589
621
  const menu = ownerOf(this.menuTargets, document.activeElement);
590
622
  if (menu) {
591
623
  const top = this.#topFor(menu);
592
- this.#closeMenu(top);
624
+ this.#closeMenu(top, "escape");
593
625
  this.#focusTop(top);
594
626
  return;
595
627
  }
596
- this.#closeAllMenus();
628
+ this.#closeAllMenus("escape");
597
629
  }
598
630
  /** Opens the menu of the navigable top item `delta` steps from `menu`'s owner. */
599
631
  #moveToAdjacentMenu(menu, delta) {
@@ -603,7 +635,7 @@ var MenubarController = class extends Controller {
603
635
  const current = tops.indexOf(top);
604
636
  if (current === -1) return;
605
637
  const next = (current + delta + tops.length) % tops.length;
606
- this.#openMenu(tops[next], "first");
638
+ this.#openMenu(tops[next], "first", "user");
607
639
  }
608
640
  /**
609
641
  * Closes when a click lands outside the controller's element. Focus is left on
@@ -611,7 +643,9 @@ var MenubarController = class extends Controller {
611
643
  * docs.
612
644
  */
613
645
  #onOutsideClick = (event) => {
614
- if (this.#isAnyOpen && !this.element.contains(event.target)) this.#closeAllMenus();
646
+ if (this.#isAnyOpen && !this.element.contains(event.target)) {
647
+ this.#closeAllMenus("outside");
648
+ }
615
649
  };
616
650
  /**
617
651
  * Captures clicks so `aria-disabled` top items and commands cannot reach