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.
- package/CHANGELOG.md +136 -0
- package/README.md +27 -11
- package/dist/cable/index.d.ts +88 -31
- package/dist/cable/index.js +384 -449
- package/dist/cable/index.js.map +1 -1
- package/dist/coerce-JtZVNG5h.d.ts +20 -0
- package/dist/controllers/accordion_controller.d.ts +4 -2
- package/dist/controllers/accordion_controller.js +174 -55
- package/dist/controllers/accordion_controller.js.map +1 -1
- package/dist/controllers/alert_dialog_controller.d.ts +12 -2
- package/dist/controllers/alert_dialog_controller.js +903 -235
- package/dist/controllers/alert_dialog_controller.js.map +1 -1
- package/dist/controllers/announcer_controller.d.ts +37 -5
- package/dist/controllers/announcer_controller.js +238 -205
- package/dist/controllers/announcer_controller.js.map +1 -1
- package/dist/controllers/aspect_ratio_controller.js +0 -10
- package/dist/controllers/aspect_ratio_controller.js.map +1 -1
- package/dist/controllers/auto_submit_controller.d.ts +30 -6
- package/dist/controllers/auto_submit_controller.js +414 -145
- package/dist/controllers/auto_submit_controller.js.map +1 -1
- package/dist/controllers/avatar_controller.js +185 -107
- package/dist/controllers/avatar_controller.js.map +1 -1
- package/dist/controllers/breadcrumb_controller.js +0 -130
- package/dist/controllers/breadcrumb_controller.js.map +1 -1
- package/dist/controllers/bulk_select_controller.d.ts +21 -3
- package/dist/controllers/bulk_select_controller.js +282 -58
- package/dist/controllers/bulk_select_controller.js.map +1 -1
- package/dist/controllers/calendar_controller.d.ts +38 -16
- package/dist/controllers/calendar_controller.js +228 -260
- package/dist/controllers/calendar_controller.js.map +1 -1
- package/dist/controllers/carousel_controller.d.ts +43 -12
- package/dist/controllers/carousel_controller.js +536 -436
- package/dist/controllers/carousel_controller.js.map +1 -1
- package/dist/controllers/character_counter_controller.d.ts +44 -7
- package/dist/controllers/character_counter_controller.js +493 -207
- package/dist/controllers/character_counter_controller.js.map +1 -1
- package/dist/controllers/checkbox_controller.d.ts +7 -2
- package/dist/controllers/checkbox_controller.js +38 -74
- package/dist/controllers/checkbox_controller.js.map +1 -1
- package/dist/controllers/clipboard_controller.d.ts +16 -5
- package/dist/controllers/clipboard_controller.js +261 -149
- package/dist/controllers/clipboard_controller.js.map +1 -1
- package/dist/controllers/collapsible_controller.d.ts +17 -5
- package/dist/controllers/collapsible_controller.js +304 -120
- package/dist/controllers/collapsible_controller.js.map +1 -1
- package/dist/controllers/color_picker_controller.d.ts +18 -6
- package/dist/controllers/color_picker_controller.js +178 -146
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/combobox_controller.d.ts +24 -6
- package/dist/controllers/combobox_controller.js +522 -156
- package/dist/controllers/combobox_controller.js.map +1 -1
- package/dist/controllers/command_palette_controller.d.ts +51 -20
- package/dist/controllers/command_palette_controller.js +1156 -395
- package/dist/controllers/command_palette_controller.js.map +1 -1
- package/dist/controllers/conditional_fields_controller.d.ts +15 -2
- package/dist/controllers/conditional_fields_controller.js +300 -171
- package/dist/controllers/conditional_fields_controller.js.map +1 -1
- package/dist/controllers/confirm_controller.d.ts +49 -12
- package/dist/controllers/confirm_controller.js +980 -262
- package/dist/controllers/confirm_controller.js.map +1 -1
- package/dist/controllers/context_menu_controller.d.ts +80 -18
- package/dist/controllers/context_menu_controller.js +346 -153
- package/dist/controllers/context_menu_controller.js.map +1 -1
- package/dist/controllers/count_up_controller.d.ts +13 -1
- package/dist/controllers/count_up_controller.js +73 -21
- package/dist/controllers/count_up_controller.js.map +1 -1
- package/dist/controllers/countdown_controller.d.ts +47 -3
- package/dist/controllers/countdown_controller.js +281 -158
- package/dist/controllers/countdown_controller.js.map +1 -1
- package/dist/controllers/currency_input_controller.d.ts +93 -10
- package/dist/controllers/currency_input_controller.js +575 -225
- package/dist/controllers/currency_input_controller.js.map +1 -1
- package/dist/controllers/data_grid_controller.d.ts +25 -12
- package/dist/controllers/data_grid_controller.js +248 -214
- package/dist/controllers/data_grid_controller.js.map +1 -1
- package/dist/controllers/date_range_picker_controller.d.ts +42 -14
- package/dist/controllers/date_range_picker_controller.js +338 -235
- package/dist/controllers/date_range_picker_controller.js.map +1 -1
- package/dist/controllers/dialog_controller.d.ts +17 -6
- package/dist/controllers/dialog_controller.js +899 -237
- package/dist/controllers/dialog_controller.js.map +1 -1
- package/dist/controllers/direct_upload_controller.d.ts +25 -8
- package/dist/controllers/direct_upload_controller.js +97 -167
- package/dist/controllers/direct_upload_controller.js.map +1 -1
- package/dist/controllers/dirty_form_controller.d.ts +6 -1
- package/dist/controllers/dirty_form_controller.js +72 -69
- package/dist/controllers/dirty_form_controller.js.map +1 -1
- package/dist/controllers/dismissible_controller.d.ts +19 -0
- package/dist/controllers/dismissible_controller.js +196 -24
- package/dist/controllers/dismissible_controller.js.map +1 -1
- package/dist/controllers/drawer_controller.d.ts +39 -11
- package/dist/controllers/drawer_controller.js +974 -355
- package/dist/controllers/drawer_controller.js.map +1 -1
- package/dist/controllers/dropdown_controller.d.ts +31 -1
- package/dist/controllers/dropdown_controller.js +339 -96
- package/dist/controllers/dropdown_controller.js.map +1 -1
- package/dist/controllers/editable_controller.d.ts +12 -1
- package/dist/controllers/editable_controller.js +315 -88
- package/dist/controllers/editable_controller.js.map +1 -1
- package/dist/controllers/empty_state_controller.js +79 -58
- package/dist/controllers/empty_state_controller.js.map +1 -1
- package/dist/controllers/file_dropzone_controller.d.ts +63 -18
- package/dist/controllers/file_dropzone_controller.js +322 -211
- package/dist/controllers/file_dropzone_controller.js.map +1 -1
- package/dist/controllers/filter_controller.js +77 -42
- package/dist/controllers/filter_controller.js.map +1 -1
- package/dist/controllers/flash_controller.d.ts +35 -12
- package/dist/controllers/flash_controller.js +238 -347
- package/dist/controllers/flash_controller.js.map +1 -1
- package/dist/controllers/focus_controller.d.ts +15 -6
- package/dist/controllers/focus_controller.js +679 -240
- package/dist/controllers/focus_controller.js.map +1 -1
- package/dist/controllers/form_field_controller.js +156 -132
- package/dist/controllers/form_field_controller.js.map +1 -1
- package/dist/controllers/form_validation_controller.d.ts +3 -3
- package/dist/controllers/form_validation_controller.js +31 -97
- package/dist/controllers/form_validation_controller.js.map +1 -1
- package/dist/controllers/frame_loading_controller.d.ts +47 -14
- package/dist/controllers/frame_loading_controller.js +275 -217
- package/dist/controllers/frame_loading_controller.js.map +1 -1
- package/dist/controllers/highlight_controller.d.ts +27 -6
- package/dist/controllers/highlight_controller.js +107 -75
- package/dist/controllers/highlight_controller.js.map +1 -1
- package/dist/controllers/hover_card_controller.d.ts +60 -4
- package/dist/controllers/hover_card_controller.js +327 -130
- package/dist/controllers/hover_card_controller.js.map +1 -1
- package/dist/controllers/idle_controller.d.ts +48 -6
- package/dist/controllers/idle_controller.js +271 -101
- package/dist/controllers/idle_controller.js.map +1 -1
- package/dist/controllers/input_mask_controller.d.ts +30 -13
- package/dist/controllers/input_mask_controller.js +483 -97
- package/dist/controllers/input_mask_controller.js.map +1 -1
- package/dist/controllers/intersection_controller.d.ts +32 -13
- package/dist/controllers/intersection_controller.js +150 -106
- package/dist/controllers/intersection_controller.js.map +1 -1
- package/dist/controllers/lazy_frame_controller.d.ts +19 -2
- package/dist/controllers/lazy_frame_controller.js +24 -68
- package/dist/controllers/lazy_frame_controller.js.map +1 -1
- package/dist/controllers/listbox_controller.d.ts +44 -9
- package/dist/controllers/listbox_controller.js +523 -240
- package/dist/controllers/listbox_controller.js.map +1 -1
- package/dist/controllers/local_time_controller.d.ts +9 -7
- package/dist/controllers/local_time_controller.js +102 -77
- package/dist/controllers/local_time_controller.js.map +1 -1
- package/dist/controllers/masonry_controller.d.ts +11 -3
- package/dist/controllers/masonry_controller.js +80 -96
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/menu_controller.d.ts +55 -11
- package/dist/controllers/menu_controller.js +302 -188
- package/dist/controllers/menu_controller.js.map +1 -1
- package/dist/controllers/menubar_controller.d.ts +51 -9
- package/dist/controllers/menubar_controller.js +232 -345
- package/dist/controllers/menubar_controller.js.map +1 -1
- package/dist/controllers/meter_controller.d.ts +33 -20
- package/dist/controllers/meter_controller.js +417 -87
- package/dist/controllers/meter_controller.js.map +1 -1
- package/dist/controllers/multi_select_controller.d.ts +48 -18
- package/dist/controllers/multi_select_controller.js +785 -393
- package/dist/controllers/multi_select_controller.js.map +1 -1
- package/dist/controllers/navigation_menu_controller.d.ts +27 -6
- package/dist/controllers/navigation_menu_controller.js +190 -250
- package/dist/controllers/navigation_menu_controller.js.map +1 -1
- package/dist/controllers/nested_form_controller.d.ts +10 -0
- package/dist/controllers/nested_form_controller.js +396 -192
- package/dist/controllers/nested_form_controller.js.map +1 -1
- package/dist/controllers/network_status_controller.d.ts +23 -0
- package/dist/controllers/network_status_controller.js +268 -62
- package/dist/controllers/network_status_controller.js.map +1 -1
- package/dist/controllers/number_input_controller.d.ts +50 -8
- package/dist/controllers/number_input_controller.js +610 -303
- package/dist/controllers/number_input_controller.js.map +1 -1
- package/dist/controllers/optimistic_controller.d.ts +8 -5
- package/dist/controllers/optimistic_controller.js +45 -87
- package/dist/controllers/optimistic_controller.js.map +1 -1
- package/dist/controllers/otp_controller.d.ts +55 -8
- package/dist/controllers/otp_controller.js +658 -255
- package/dist/controllers/otp_controller.js.map +1 -1
- package/dist/controllers/overflow_indicator_controller.d.ts +5 -0
- package/dist/controllers/overflow_indicator_controller.js +122 -113
- package/dist/controllers/overflow_indicator_controller.js.map +1 -1
- package/dist/controllers/overflow_menu_controller.d.ts +58 -20
- package/dist/controllers/overflow_menu_controller.js +470 -295
- package/dist/controllers/overflow_menu_controller.js.map +1 -1
- package/dist/controllers/pagination_controller.d.ts +37 -7
- package/dist/controllers/pagination_controller.js +332 -123
- package/dist/controllers/pagination_controller.js.map +1 -1
- package/dist/controllers/password_reveal_controller.d.ts +46 -8
- package/dist/controllers/password_reveal_controller.js +392 -121
- package/dist/controllers/password_reveal_controller.js.map +1 -1
- package/dist/controllers/password_strength_controller.d.ts +15 -6
- package/dist/controllers/password_strength_controller.js +111 -158
- package/dist/controllers/password_strength_controller.js.map +1 -1
- package/dist/controllers/persist_controller.d.ts +11 -4
- package/dist/controllers/persist_controller.js +165 -111
- package/dist/controllers/persist_controller.js.map +1 -1
- package/dist/controllers/pointer_drag_controller.d.ts +35 -12
- package/dist/controllers/pointer_drag_controller.js +434 -188
- package/dist/controllers/pointer_drag_controller.js.map +1 -1
- package/dist/controllers/popover_controller.d.ts +41 -5
- package/dist/controllers/popover_controller.js +269 -113
- package/dist/controllers/popover_controller.js.map +1 -1
- package/dist/controllers/portal_controller.d.ts +44 -4
- package/dist/controllers/portal_controller.js +215 -76
- package/dist/controllers/portal_controller.js.map +1 -1
- package/dist/controllers/preview_guard_controller.d.ts +10 -4
- package/dist/controllers/preview_guard_controller.js +243 -116
- package/dist/controllers/preview_guard_controller.js.map +1 -1
- package/dist/controllers/progress_controller.d.ts +20 -19
- package/dist/controllers/progress_controller.js +391 -78
- package/dist/controllers/progress_controller.js.map +1 -1
- package/dist/controllers/radio_group_controller.d.ts +21 -9
- package/dist/controllers/radio_group_controller.js +278 -211
- package/dist/controllers/radio_group_controller.js.map +1 -1
- package/dist/controllers/range_slider_controller.d.ts +47 -6
- package/dist/controllers/range_slider_controller.js +220 -113
- package/dist/controllers/range_slider_controller.js.map +1 -1
- package/dist/controllers/rating_controller.d.ts +20 -4
- package/dist/controllers/rating_controller.js +458 -211
- package/dist/controllers/rating_controller.js.map +1 -1
- package/dist/controllers/read_more_controller.d.ts +2 -0
- package/dist/controllers/read_more_controller.js +138 -63
- package/dist/controllers/read_more_controller.js.map +1 -1
- package/dist/controllers/reading_progress_controller.d.ts +1 -1
- package/dist/controllers/reading_progress_controller.js +166 -137
- package/dist/controllers/reading_progress_controller.js.map +1 -1
- package/dist/controllers/relative_time_controller.d.ts +20 -6
- package/dist/controllers/relative_time_controller.js +211 -112
- package/dist/controllers/relative_time_controller.js.map +1 -1
- package/dist/controllers/reset_on_restore_controller.d.ts +85 -0
- package/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +103 -38
- package/dist/controllers/reset_on_restore_controller.js.map +1 -0
- package/dist/controllers/resizable_controller.d.ts +31 -2
- package/dist/controllers/resizable_controller.js +299 -150
- package/dist/controllers/resizable_controller.js.map +1 -1
- package/dist/controllers/roving_controller.d.ts +3 -3
- package/dist/controllers/roving_controller.js +49 -88
- package/dist/controllers/roving_controller.js.map +1 -1
- package/dist/controllers/scroll_area_controller.d.ts +7 -3
- package/dist/controllers/scroll_area_controller.js +490 -246
- package/dist/controllers/scroll_area_controller.js.map +1 -1
- package/dist/controllers/scroll_restore_controller.d.ts +3 -3
- package/dist/controllers/scroll_restore_controller.js +14 -55
- package/dist/controllers/scroll_restore_controller.js.map +1 -1
- package/dist/controllers/scroll_visibility_controller.d.ts +28 -12
- package/dist/controllers/scroll_visibility_controller.js +432 -149
- package/dist/controllers/scroll_visibility_controller.js.map +1 -1
- package/dist/controllers/scrollspy_controller.d.ts +6 -1
- package/dist/controllers/scrollspy_controller.js +193 -248
- package/dist/controllers/scrollspy_controller.js.map +1 -1
- package/dist/controllers/separator_controller.d.ts +20 -5
- package/dist/controllers/separator_controller.js +285 -142
- package/dist/controllers/separator_controller.js.map +1 -1
- package/dist/controllers/sidebar_controller.d.ts +65 -8
- package/dist/controllers/sidebar_controller.js +1069 -404
- package/dist/controllers/sidebar_controller.js.map +1 -1
- package/dist/controllers/skeleton_controller.d.ts +23 -0
- package/dist/controllers/skeleton_controller.js +259 -101
- package/dist/controllers/skeleton_controller.js.map +1 -1
- package/dist/controllers/slider_controller.d.ts +29 -2
- package/dist/controllers/slider_controller.js +187 -86
- package/dist/controllers/slider_controller.js.map +1 -1
- package/dist/controllers/smart_sticky_header_controller.d.ts +22 -4
- package/dist/controllers/smart_sticky_header_controller.js +173 -66
- package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
- package/dist/controllers/sortable_controller.d.ts +4 -4
- package/dist/controllers/sortable_controller.js +26 -125
- package/dist/controllers/sortable_controller.js.map +1 -1
- package/dist/controllers/spinner_controller.d.ts +39 -4
- package/dist/controllers/spinner_controller.js +288 -173
- package/dist/controllers/spinner_controller.js.map +1 -1
- package/dist/controllers/step_indicator_controller.d.ts +9 -4
- package/dist/controllers/step_indicator_controller.js +105 -46
- package/dist/controllers/step_indicator_controller.js.map +1 -1
- package/dist/controllers/stepper_controller.d.ts +14 -6
- package/dist/controllers/stepper_controller.js +120 -73
- package/dist/controllers/stepper_controller.js.map +1 -1
- package/dist/controllers/stick_to_bottom_controller.d.ts +9 -1
- package/dist/controllers/stick_to_bottom_controller.js +275 -140
- package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
- package/dist/controllers/sticky_observer_controller.d.ts +11 -0
- package/dist/controllers/sticky_observer_controller.js +220 -49
- package/dist/controllers/sticky_observer_controller.js.map +1 -1
- package/dist/controllers/submit_once_controller.d.ts +24 -8
- package/dist/controllers/submit_once_controller.js +376 -227
- package/dist/controllers/submit_once_controller.js.map +1 -1
- package/dist/controllers/switch_controller.d.ts +18 -4
- package/dist/controllers/switch_controller.js +201 -84
- package/dist/controllers/switch_controller.js.map +1 -1
- package/dist/controllers/tabs_controller.d.ts +9 -6
- package/dist/controllers/tabs_controller.js +41 -30
- package/dist/controllers/tabs_controller.js.map +1 -1
- package/dist/controllers/tags_input_controller.d.ts +16 -3
- package/dist/controllers/tags_input_controller.js +293 -173
- package/dist/controllers/tags_input_controller.js.map +1 -1
- package/dist/controllers/textarea_autosize_controller.d.ts +11 -1
- package/dist/controllers/textarea_autosize_controller.js +108 -74
- package/dist/controllers/textarea_autosize_controller.js.map +1 -1
- package/dist/controllers/theme_controller.d.ts +24 -11
- package/dist/controllers/theme_controller.js +140 -116
- package/dist/controllers/theme_controller.js.map +1 -1
- package/dist/controllers/time_picker_controller.d.ts +55 -5
- package/dist/controllers/time_picker_controller.js +331 -127
- package/dist/controllers/time_picker_controller.js.map +1 -1
- package/dist/controllers/toast_controller.d.ts +40 -16
- package/dist/controllers/toast_controller.js +244 -324
- package/dist/controllers/toast_controller.js.map +1 -1
- package/dist/controllers/toggle_group_controller.d.ts +14 -6
- package/dist/controllers/toggle_group_controller.js +252 -191
- package/dist/controllers/toggle_group_controller.js.map +1 -1
- package/dist/controllers/toolbar_controller.d.ts +8 -6
- package/dist/controllers/toolbar_controller.js +219 -120
- package/dist/controllers/toolbar_controller.js.map +1 -1
- package/dist/controllers/tooltip_controller.d.ts +49 -4
- package/dist/controllers/tooltip_controller.js +158 -124
- package/dist/controllers/tooltip_controller.js.map +1 -1
- package/dist/controllers/transition_controller.d.ts +22 -4
- package/dist/controllers/transition_controller.js +123 -119
- package/dist/controllers/transition_controller.js.map +1 -1
- package/dist/controllers/tree_view_controller.d.ts +22 -12
- package/dist/controllers/tree_view_controller.js +283 -369
- package/dist/controllers/tree_view_controller.js.map +1 -1
- package/dist/index.d.ts +10 -5
- package/dist/index.js +8573 -10410
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.d.ts +38 -14
- package/dist/inspector/cli.js +108 -40
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +145 -64
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +20 -20
- package/dist/inspector/manifest.json +802 -101
- package/dist/positioning/index.d.ts +15 -7
- package/dist/positioning/index.js +154 -47
- package/dist/positioning/index.js.map +1 -1
- package/package.json +11 -10
- package/dist/controllers/reset_before_cache_controller.d.ts +0 -76
- package/dist/controllers/reset_before_cache_controller.js.map +0 -1
|
@@ -1,19 +1,68 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
|
|
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/logical_scroll.ts
|
|
6
32
|
function isRtl(element) {
|
|
7
33
|
return window.getComputedStyle(element).direction === "rtl";
|
|
8
34
|
}
|
|
9
35
|
|
|
10
|
-
// src/utils/arrow_step.ts
|
|
11
36
|
function isReservedArrowChord(event, allow = []) {
|
|
12
37
|
if (!event.key.startsWith("Arrow")) return false;
|
|
13
38
|
return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
|
|
14
39
|
}
|
|
40
|
+
function hasModifierChord(event) {
|
|
41
|
+
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
var ClickVerdicts = class {
|
|
45
|
+
#verdicts = /* @__PURE__ */ new WeakMap();
|
|
46
|
+
record(event, entries, refused) {
|
|
47
|
+
this.#verdicts.set(event, { entries, refused });
|
|
48
|
+
}
|
|
49
|
+
for(event, entry) {
|
|
50
|
+
const verdict = event && this.#verdicts.get(event);
|
|
51
|
+
if (!verdict?.entries.includes(entry)) return void 0;
|
|
52
|
+
return verdict.refused;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
function sharedRegistry(key, create) {
|
|
57
|
+
const symbol = Symbol.for(key);
|
|
58
|
+
const scope = globalThis;
|
|
59
|
+
const existing = scope[symbol];
|
|
60
|
+
if (existing !== void 0) return existing;
|
|
61
|
+
const registry = create();
|
|
62
|
+
Object.defineProperty(globalThis, symbol, { value: registry });
|
|
63
|
+
return registry;
|
|
64
|
+
}
|
|
15
65
|
|
|
16
|
-
// src/utils/escape_layer.ts
|
|
17
66
|
function claimsWhileFocusWithin(element) {
|
|
18
67
|
return () => {
|
|
19
68
|
const active = element.ownerDocument.activeElement;
|
|
@@ -21,17 +70,11 @@ function claimsWhileFocusWithin(element) {
|
|
|
21
70
|
};
|
|
22
71
|
}
|
|
23
72
|
var EscapeLayer = class _EscapeLayer {
|
|
24
|
-
static #registries =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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
|
-
*/
|
|
73
|
+
static #registries = sharedRegistry(
|
|
74
|
+
"stimeo-ui.escape-layer.registry.v1",
|
|
75
|
+
() => /* @__PURE__ */ new WeakMap()
|
|
76
|
+
);
|
|
77
|
+
#active = null;
|
|
35
78
|
activate(ownerDocument = document, options) {
|
|
36
79
|
this.deactivate();
|
|
37
80
|
let registry = _EscapeLayer.#registries.get(ownerDocument);
|
|
@@ -40,44 +83,31 @@ var EscapeLayer = class _EscapeLayer {
|
|
|
40
83
|
_EscapeLayer.#registries.set(ownerDocument, registry);
|
|
41
84
|
ownerDocument.addEventListener("keydown", registry.onKeydown);
|
|
42
85
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
this.#
|
|
46
|
-
|
|
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
|
-
*/
|
|
86
|
+
const entry = { onDismiss: options.onDismiss, claims: options.claims ?? null };
|
|
87
|
+
registry.stack.push(entry);
|
|
88
|
+
this.#active = { document: ownerDocument, entry };
|
|
89
|
+
}
|
|
52
90
|
deactivate() {
|
|
53
|
-
const
|
|
54
|
-
if (!
|
|
55
|
-
const registry = _EscapeLayer.#registries.get(
|
|
91
|
+
const active = this.#active;
|
|
92
|
+
if (!active) return;
|
|
93
|
+
const registry = _EscapeLayer.#registries.get(active.document);
|
|
56
94
|
if (registry) {
|
|
57
|
-
const index = registry.stack.lastIndexOf(
|
|
95
|
+
const index = registry.stack.lastIndexOf(active.entry);
|
|
58
96
|
if (index >= 0) registry.stack.splice(index, 1);
|
|
59
97
|
if (registry.stack.length === 0) {
|
|
60
|
-
|
|
61
|
-
_EscapeLayer.#registries.delete(
|
|
98
|
+
active.document.removeEventListener("keydown", registry.onKeydown);
|
|
99
|
+
_EscapeLayer.#registries.delete(active.document);
|
|
62
100
|
}
|
|
63
101
|
}
|
|
64
|
-
this.#
|
|
65
|
-
|
|
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
|
-
*/
|
|
102
|
+
this.#active = null;
|
|
103
|
+
}
|
|
73
104
|
get ownsEscape() {
|
|
74
|
-
const
|
|
75
|
-
if (!
|
|
76
|
-
const registry = _EscapeLayer.#registries.get(
|
|
105
|
+
const active = this.#active;
|
|
106
|
+
if (!active) return false;
|
|
107
|
+
const registry = _EscapeLayer.#registries.get(active.document);
|
|
77
108
|
if (!registry) return false;
|
|
78
|
-
return _EscapeLayer.#resolveOwner(registry.stack) ===
|
|
109
|
+
return _EscapeLayer.#resolveOwner(registry.stack) === active.entry;
|
|
79
110
|
}
|
|
80
|
-
/** Builds a document's registry with its shared resolver listener. */
|
|
81
111
|
static #createRegistry() {
|
|
82
112
|
const registry = {
|
|
83
113
|
stack: [],
|
|
@@ -86,24 +116,22 @@ var EscapeLayer = class _EscapeLayer {
|
|
|
86
116
|
const owner = _EscapeLayer.#resolveOwner(registry.stack);
|
|
87
117
|
if (!owner) return;
|
|
88
118
|
event.preventDefault();
|
|
89
|
-
owner
|
|
119
|
+
owner.onDismiss();
|
|
90
120
|
}
|
|
91
121
|
};
|
|
92
122
|
return registry;
|
|
93
123
|
}
|
|
94
|
-
/** The topmost stack layer whose claims predicate passes, or `null`. */
|
|
95
124
|
static #resolveOwner(stack) {
|
|
96
125
|
for (let index = stack.length - 1; index >= 0; index--) {
|
|
97
126
|
const layer = stack[index];
|
|
98
127
|
if (!layer) continue;
|
|
99
|
-
if (layer
|
|
128
|
+
if (layer.claims && !layer.claims()) continue;
|
|
100
129
|
return layer;
|
|
101
130
|
}
|
|
102
131
|
return null;
|
|
103
132
|
}
|
|
104
133
|
};
|
|
105
134
|
|
|
106
|
-
// src/utils/event_owner.ts
|
|
107
135
|
function ownerIndex(candidates, node) {
|
|
108
136
|
if (!(node instanceof Node)) return -1;
|
|
109
137
|
return candidates.findIndex((candidate) => candidate.contains(node));
|
|
@@ -111,32 +139,89 @@ function ownerIndex(candidates, node) {
|
|
|
111
139
|
function ownerOf(candidates, node) {
|
|
112
140
|
return candidates[ownerIndex(candidates, node)] ?? null;
|
|
113
141
|
}
|
|
142
|
+
function ownersOf(candidates, node) {
|
|
143
|
+
if (!(node instanceof Node)) return [];
|
|
144
|
+
return candidates.filter((candidate) => candidate.contains(node));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
var ListenerSet = class {
|
|
148
|
+
#abort = new AbortController();
|
|
149
|
+
add(target, type, handler, options) {
|
|
150
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
151
|
+
}
|
|
152
|
+
dispose() {
|
|
153
|
+
this.#abort.abort();
|
|
154
|
+
this.#abort = new AbortController();
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
var MicrotaskCoalescer = class {
|
|
159
|
+
#run;
|
|
160
|
+
#queued = false;
|
|
161
|
+
#active = false;
|
|
162
|
+
#generation = 0;
|
|
163
|
+
constructor(run) {
|
|
164
|
+
this.#run = run;
|
|
165
|
+
}
|
|
166
|
+
activate() {
|
|
167
|
+
this.#active = true;
|
|
168
|
+
}
|
|
169
|
+
cancel() {
|
|
170
|
+
this.#active = false;
|
|
171
|
+
this.#queued = false;
|
|
172
|
+
this.#generation += 1;
|
|
173
|
+
}
|
|
174
|
+
get pending() {
|
|
175
|
+
return this.#queued;
|
|
176
|
+
}
|
|
177
|
+
schedule() {
|
|
178
|
+
if (!this.#active || this.#queued) return;
|
|
179
|
+
this.#queued = true;
|
|
180
|
+
const generation = this.#generation;
|
|
181
|
+
queueMicrotask(() => {
|
|
182
|
+
if (generation !== this.#generation || !this.#queued || !this.#active) return;
|
|
183
|
+
this.#queued = false;
|
|
184
|
+
this.#run();
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
var MorphRenderWatcher = class {
|
|
190
|
+
#listeners = new ListenerSet();
|
|
191
|
+
#pass;
|
|
192
|
+
#element = null;
|
|
193
|
+
#onMorph = () => this.#pass.schedule();
|
|
194
|
+
constructor(run) {
|
|
195
|
+
this.#pass = new MicrotaskCoalescer(run);
|
|
196
|
+
}
|
|
197
|
+
observe(element) {
|
|
198
|
+
if (this.#element === element) return;
|
|
199
|
+
this.disconnect();
|
|
200
|
+
this.#element = element;
|
|
201
|
+
this.#pass.activate();
|
|
202
|
+
this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
|
|
203
|
+
}
|
|
204
|
+
schedule() {
|
|
205
|
+
this.#pass.schedule();
|
|
206
|
+
}
|
|
207
|
+
get pending() {
|
|
208
|
+
return this.#pass.pending;
|
|
209
|
+
}
|
|
210
|
+
disconnect() {
|
|
211
|
+
this.#listeners.dispose();
|
|
212
|
+
this.#pass.cancel();
|
|
213
|
+
this.#element = null;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
114
216
|
|
|
115
|
-
// src/utils/roving_tabindex.ts
|
|
116
217
|
var RovingTabindex = class {
|
|
117
|
-
/** Returns the current ordered item elements; called on every operation. */
|
|
118
218
|
#getItems;
|
|
119
|
-
/**
|
|
120
|
-
* @param getItems - Returns the current ordered item elements. Called on every
|
|
121
|
-
* operation so the live target list is always used.
|
|
122
|
-
*/
|
|
123
219
|
constructor(getItems) {
|
|
124
220
|
this.#getItems = getItems;
|
|
125
221
|
}
|
|
126
|
-
/** Index of the currently tabbable item (`tabindex="0"`), or `-1` if none. */
|
|
127
222
|
get activeIndex() {
|
|
128
223
|
return this.#getItems().findIndex((item) => item.tabIndex === 0);
|
|
129
224
|
}
|
|
130
|
-
/**
|
|
131
|
-
* Makes exactly the item at `index` tabbable (`tabindex="0"`) and removes every
|
|
132
|
-
* other item from the Tab sequence (`tabindex="-1"`). An out-of-range `index`
|
|
133
|
-
* (e.g. `-1`) leaves all items at `-1`, which a controller can use to express
|
|
134
|
-
* "nothing is currently tabbable".
|
|
135
|
-
*
|
|
136
|
-
* @param index - Position of the item to make tabbable.
|
|
137
|
-
* @param options - Pass `{ focus: true }` to also move DOM focus to that item,
|
|
138
|
-
* and `items` to reuse an event-scoped collection snapshot.
|
|
139
|
-
*/
|
|
140
225
|
setActive(index, options = {}) {
|
|
141
226
|
const { focus = false } = options;
|
|
142
227
|
const items = options.items ?? this.#getItems();
|
|
@@ -147,43 +232,24 @@ var RovingTabindex = class {
|
|
|
147
232
|
}
|
|
148
233
|
};
|
|
149
234
|
|
|
150
|
-
// src/utils/safe_timeout.ts
|
|
151
235
|
var TimerRegistry = class {
|
|
152
|
-
/** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
|
|
153
236
|
ids = /* @__PURE__ */ new Set();
|
|
154
|
-
/**
|
|
155
|
-
* Cancels a single tracked timer.
|
|
156
|
-
*
|
|
157
|
-
* No-ops if the id is unknown (already cleared, fired, or never owned by this
|
|
158
|
-
* registry), so callers can clear defensively without guarding.
|
|
159
|
-
*/
|
|
160
237
|
clear(id) {
|
|
161
238
|
if (this.ids.delete(id)) {
|
|
162
239
|
this.cancel(id);
|
|
163
240
|
}
|
|
164
241
|
}
|
|
165
|
-
/**
|
|
166
|
-
* Cancels every tracked timer. Call this from a controller's `disconnect()`
|
|
167
|
-
* to guarantee no timer outlives the element.
|
|
168
|
-
*/
|
|
169
242
|
clearAll() {
|
|
170
243
|
for (const id of this.ids) {
|
|
171
244
|
this.cancel(id);
|
|
172
245
|
}
|
|
173
246
|
this.ids.clear();
|
|
174
247
|
}
|
|
175
|
-
/** Number of timers currently tracked (pending). */
|
|
176
248
|
get size() {
|
|
177
249
|
return this.ids.size;
|
|
178
250
|
}
|
|
179
251
|
};
|
|
180
252
|
var SafeTimeout = class extends TimerRegistry {
|
|
181
|
-
/**
|
|
182
|
-
* Schedules `callback` after `delay` ms and returns the timer id.
|
|
183
|
-
*
|
|
184
|
-
* The id is removed from the registry automatically when the timeout fires,
|
|
185
|
-
* so {@link TimerRegistry.size | size} reflects only still-pending timers.
|
|
186
|
-
*/
|
|
187
253
|
set(callback, delay) {
|
|
188
254
|
const id = this.schedule(() => {
|
|
189
255
|
this.ids.delete(id);
|
|
@@ -200,39 +266,22 @@ var SafeTimeout = class extends TimerRegistry {
|
|
|
200
266
|
}
|
|
201
267
|
};
|
|
202
268
|
|
|
203
|
-
|
|
204
|
-
|
|
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";
|
|
269
|
+
function targetSelector(identifier, name) {
|
|
270
|
+
return `[data-${identifier}-target~="${name}"]`;
|
|
211
271
|
}
|
|
212
272
|
|
|
213
|
-
// src/utils/typeahead.ts
|
|
214
273
|
var TYPEAHEAD_RESET_MS = 500;
|
|
215
274
|
var Typeahead = class {
|
|
216
|
-
/** Timer registry for the pending idle reset; private so `reset()` is the only exit. */
|
|
217
275
|
#timers = new SafeTimeout();
|
|
218
|
-
/** Idle window before the query resets, in milliseconds. */
|
|
219
276
|
#resetMs;
|
|
220
|
-
/** The accumulated lowercase query, empty when idle. */
|
|
221
277
|
#query = "";
|
|
222
|
-
/** Id of the pending reset timer, `0` when none is scheduled. */
|
|
223
278
|
#timerId = 0;
|
|
224
|
-
/** @param options - Overrides for the idle window. */
|
|
225
279
|
constructor({ resetMs = TYPEAHEAD_RESET_MS } = {}) {
|
|
226
280
|
this.#resetMs = resetMs;
|
|
227
281
|
}
|
|
228
|
-
/** The query a search would currently run with; empty while idle. */
|
|
229
282
|
get query() {
|
|
230
283
|
return this.#query;
|
|
231
284
|
}
|
|
232
|
-
/**
|
|
233
|
-
* Folds `key` into the query, restarts the idle window, and returns the query to
|
|
234
|
-
* search with. A repeated character collapses the query to that one character.
|
|
235
|
-
*/
|
|
236
285
|
push(key) {
|
|
237
286
|
const char = key.toLowerCase();
|
|
238
287
|
const repeated = this.#query.length > 0 && [...this.#query].every((c) => c === char);
|
|
@@ -241,7 +290,6 @@ var Typeahead = class {
|
|
|
241
290
|
this.#timerId = this.#timers.set(() => this.reset(), this.#resetMs);
|
|
242
291
|
return this.#query;
|
|
243
292
|
}
|
|
244
|
-
/** Clears the query and cancels the pending idle reset. */
|
|
245
293
|
reset() {
|
|
246
294
|
this.#query = "";
|
|
247
295
|
this.#timers.clear(this.#timerId);
|
|
@@ -268,73 +316,40 @@ function findTypeaheadMatch(items, from, query, label = (item) => typeaheadLabel
|
|
|
268
316
|
return -1;
|
|
269
317
|
}
|
|
270
318
|
|
|
271
|
-
// src/controllers/menubar_controller.ts
|
|
272
319
|
var STATE_ATTRIBUTES = ["disabled", "hidden"];
|
|
273
320
|
var MenubarController = class extends Controller {
|
|
274
321
|
static targets = ["top", "menu", "item"];
|
|
275
322
|
static actions = ["activate", "onItemKeydown", "onTopKeydown", "toggle"];
|
|
276
323
|
static events = ["close", "open"];
|
|
277
|
-
/** Roving tabindex across the top-level menuitems (one Tab stop). */
|
|
278
324
|
#roving = new RovingTabindex(() => this.topTargets);
|
|
279
|
-
/** Typeahead query and its idle-reset timer (scoped to the open menu). */
|
|
280
325
|
#typeahead = new Typeahead();
|
|
281
326
|
#timers = new SafeTimeout();
|
|
282
|
-
/** Escape-stack membership while a menu is open; the shared resolver dismisses via it. */
|
|
283
327
|
#escapeLayer = new EscapeLayer();
|
|
284
|
-
/** Whether {@link #escapeLayer} is currently on the stack (see {@link #syncEscapeLayer}). */
|
|
285
328
|
#layerActive = false;
|
|
286
|
-
/** Watches `disabled`/`hidden` under the menubar; `null` while disconnected. */
|
|
287
329
|
#observer = null;
|
|
288
|
-
/**
|
|
289
|
-
* Live between `connect()` and `disconnect()`. Stimulus reports the *initial*
|
|
290
|
-
* targets before `connect()` and re-reports them as disconnected afterwards;
|
|
291
|
-
* gating on this keeps the target callbacks from clobbering the authored Tab
|
|
292
|
-
* stop on mount and from resurrecting one after teardown.
|
|
293
|
-
*/
|
|
294
330
|
#connected = false;
|
|
295
|
-
/** Whether state moves are reported: set once `connect()` settled the baseline. */
|
|
296
331
|
#reporting = false;
|
|
297
|
-
/** The element inside the menubar that last took DOM focus, if any. */
|
|
298
332
|
#focused = null;
|
|
299
|
-
|
|
300
|
-
* Records where DOM focus sits inside the menubar. `focusin` bubbles, so one
|
|
301
|
-
* listener covers the top items and everything nested in their menus. The
|
|
302
|
-
* record is needed because a top or menu becomes unreachable *before* this
|
|
303
|
-
* controller hears about it, by which point the browser has already reset
|
|
304
|
-
* `document.activeElement`.
|
|
305
|
-
*/
|
|
333
|
+
#clickVerdicts = new ClickVerdicts();
|
|
306
334
|
#onFocusIn = (event) => {
|
|
307
335
|
this.#focused = event.target;
|
|
308
336
|
};
|
|
309
|
-
/**
|
|
310
|
-
* Forgets the record once focus genuinely lands on something else, so a later
|
|
311
|
-
* mutation cannot pull focus back in. A `relatedTarget` of `null` is the case
|
|
312
|
-
* that must be kept: it is what "focus went nowhere" looks like, which is
|
|
313
|
-
* exactly the state the rescue exists for.
|
|
314
|
-
*/
|
|
315
337
|
#onFocusOut = (event) => {
|
|
316
338
|
const next = event.relatedTarget;
|
|
317
339
|
if (next && !this.element.contains(next)) this.#focused = null;
|
|
318
340
|
};
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
* stop when it is still navigable (so a Turbo cache restore preserves the user's
|
|
322
|
-
* position), else fall back to the first navigable top item.
|
|
323
|
-
*
|
|
324
|
-
* The outside-click listener is registered in the **capture** phase: in the
|
|
325
|
-
* bubble phase an inside handler that removes its own click target detaches the
|
|
326
|
-
* node before `contains()` runs, so an *inside* click would read as outside and
|
|
327
|
-
* close the menu.
|
|
328
|
-
*/
|
|
341
|
+
#morph = new MorphRenderWatcher(() => this.#reconcile());
|
|
342
|
+
#listeners = new ListenerSet();
|
|
329
343
|
connect() {
|
|
344
|
+
this.#morph.observe(this.element);
|
|
330
345
|
this.#closeAllMenus("api");
|
|
331
346
|
this.#reconcile();
|
|
332
|
-
this.element
|
|
333
|
-
this.element
|
|
334
|
-
this.element
|
|
335
|
-
|
|
347
|
+
this.#listeners.add(this.element, "click", this.#onClickCapture, { capture: true });
|
|
348
|
+
this.#listeners.add(this.element, "focusin", this.#onFocusIn);
|
|
349
|
+
this.#listeners.add(this.element, "focusout", this.#onFocusOut);
|
|
350
|
+
this.#listeners.add(document, "click", this.#onOutsideClick, { capture: true });
|
|
336
351
|
if (typeof MutationObserver !== "undefined") {
|
|
337
|
-
this.#observer = new MutationObserver(() => this.#
|
|
352
|
+
this.#observer = new MutationObserver(() => this.#morph.schedule());
|
|
338
353
|
this.#observer.observe(this.element, {
|
|
339
354
|
subtree: true,
|
|
340
355
|
childList: true,
|
|
@@ -345,82 +360,57 @@ var MenubarController = class extends Controller {
|
|
|
345
360
|
this.#connected = true;
|
|
346
361
|
this.#reporting = true;
|
|
347
362
|
}
|
|
348
|
-
/** Removes the listeners, stack membership, and any pending timer (typeahead / Tab close). */
|
|
349
363
|
disconnect() {
|
|
364
|
+
this.#morph.disconnect();
|
|
350
365
|
this.#connected = false;
|
|
351
366
|
this.#reporting = false;
|
|
352
367
|
this.#escapeLayer.deactivate();
|
|
353
368
|
this.#layerActive = false;
|
|
354
|
-
this.
|
|
355
|
-
this.element.removeEventListener("focusin", this.#onFocusIn);
|
|
356
|
-
this.element.removeEventListener("focusout", this.#onFocusOut);
|
|
357
|
-
document.removeEventListener("click", this.#onOutsideClick, true);
|
|
369
|
+
this.#listeners.dispose();
|
|
358
370
|
this.#focused = null;
|
|
359
371
|
this.#observer?.disconnect();
|
|
360
372
|
this.#observer = null;
|
|
361
373
|
this.#typeahead.reset();
|
|
362
374
|
this.#timers.clearAll();
|
|
363
375
|
}
|
|
364
|
-
/**
|
|
365
|
-
* A top item added at runtime is dropped out of the Tab sequence first — a fresh
|
|
366
|
-
* `<button>` is tabbable by default, which would leave the menubar with two Tab
|
|
367
|
-
* stops — before the lone stop is re-established.
|
|
368
|
-
*/
|
|
369
376
|
topTargetConnected(top) {
|
|
370
377
|
if (!this.#connected) return;
|
|
371
378
|
top.tabIndex = -1;
|
|
372
379
|
this.#reconcile();
|
|
373
380
|
}
|
|
374
|
-
/**
|
|
375
|
-
* Removing a top item can strand two things: the Tab stop it held, and the menu
|
|
376
|
-
* it owned (which nothing could close afterwards).
|
|
377
|
-
*
|
|
378
|
-
* The departing element is handed back in a neutral state first. A target can
|
|
379
|
-
* leave without leaving the document — a morph that only drops the
|
|
380
|
-
* `data-*-target` token keeps the node — and it would then sit in the page
|
|
381
|
-
* carrying this controller's `tabindex="0"` (a second Tab stop next to the one
|
|
382
|
-
* re-established below) and an `aria-expanded="true"` nothing can collapse.
|
|
383
|
-
* When the node really is gone these writes are harmless no-ops.
|
|
384
|
-
*/
|
|
385
381
|
topTargetDisconnected(top) {
|
|
386
382
|
if (!this.#connected) return;
|
|
387
383
|
top.tabIndex = -1;
|
|
388
384
|
if (this.#isExpanded(top)) top.setAttribute("aria-expanded", "false");
|
|
389
385
|
this.#reconcile();
|
|
390
386
|
}
|
|
391
|
-
/** See {@link MenubarController.menuTargetDisconnected}. */
|
|
392
387
|
menuTargetConnected() {
|
|
393
388
|
if (!this.#connected) return;
|
|
394
389
|
this.#reconcile();
|
|
395
390
|
}
|
|
396
|
-
/**
|
|
397
|
-
* A menu removed while open leaves its owner claiming `aria-expanded="true"` for
|
|
398
|
-
* a popup that no longer exists, and the menubar holding an Escape layer that
|
|
399
|
-
* would swallow presses meant for something else.
|
|
400
|
-
*
|
|
401
|
-
* As with {@link MenubarController.topTargetDisconnected}, the departing menu is
|
|
402
|
-
* closed first: a token-only removal leaves a visible popup in the page that no
|
|
403
|
-
* key and no click can dismiss any more.
|
|
404
|
-
*/
|
|
405
391
|
menuTargetDisconnected(menu) {
|
|
406
392
|
if (!this.#connected) return;
|
|
407
393
|
if (!menu.hidden) menu.hidden = true;
|
|
408
394
|
this.#reconcile();
|
|
409
395
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
const top =
|
|
413
|
-
|
|
396
|
+
toggle(source) {
|
|
397
|
+
const { event, host, origin, reason } = actionSource(source);
|
|
398
|
+
const top = host?.closest(targetSelector(this.identifier, "top"));
|
|
399
|
+
if (!top || !this.topTargets.includes(top)) return;
|
|
400
|
+
if (origin && origin.closest(`[data-controller~="${this.identifier}"]`) !== this.element)
|
|
401
|
+
return;
|
|
402
|
+
if (this.#refuses(top, event, origin)) return;
|
|
403
|
+
const moveFocus = event !== null || this.element.contains(document.activeElement);
|
|
414
404
|
if (this.#isExpanded(top)) {
|
|
415
405
|
this.#closeMenu(top, reason);
|
|
416
406
|
} else {
|
|
417
|
-
this.#openMenu(top, "first", reason);
|
|
407
|
+
this.#openMenu(top, "first", reason, moveFocus, true);
|
|
418
408
|
}
|
|
419
409
|
}
|
|
420
|
-
/** Keyboard handling while focus is on a top item. */
|
|
421
410
|
onTopKeydown(event) {
|
|
422
411
|
if (event.defaultPrevented) return;
|
|
423
412
|
if (isReservedArrowChord(event)) return;
|
|
413
|
+
if ((event.key === "Home" || event.key === "End") && hasModifierChord(event)) return;
|
|
424
414
|
const tops = this.#navigableTops;
|
|
425
415
|
const index = tops.indexOf(event.currentTarget);
|
|
426
416
|
if (index === -1) return;
|
|
@@ -457,10 +447,10 @@ var MenubarController = class extends Controller {
|
|
|
457
447
|
break;
|
|
458
448
|
}
|
|
459
449
|
}
|
|
460
|
-
/** Keyboard handling while focus is on a menu item. */
|
|
461
450
|
onItemKeydown(event) {
|
|
462
451
|
if (event.defaultPrevented) return;
|
|
463
452
|
if (isReservedArrowChord(event)) return;
|
|
453
|
+
if ((event.key === "Home" || event.key === "End") && hasModifierChord(event)) return;
|
|
464
454
|
const item = event.currentTarget;
|
|
465
455
|
const menu = item.closest("[role='menu']");
|
|
466
456
|
if (!menu) return;
|
|
@@ -503,76 +493,61 @@ var MenubarController = class extends Controller {
|
|
|
503
493
|
break;
|
|
504
494
|
}
|
|
505
495
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
const item =
|
|
496
|
+
activate(source) {
|
|
497
|
+
const { event, host, origin } = actionSource(source);
|
|
498
|
+
const item = host?.closest(targetSelector(this.identifier, "item"));
|
|
499
|
+
if (!item || !this.itemTargets.includes(item)) return;
|
|
500
|
+
if (origin && origin.closest(`[data-controller~="${this.identifier}"]`) !== this.element)
|
|
501
|
+
return;
|
|
502
|
+
if (this.#refuses(item, event, origin)) return;
|
|
503
|
+
const moveFocus = event !== null || this.element.contains(document.activeElement);
|
|
509
504
|
const menu = item.closest("[role='menu']");
|
|
510
505
|
const top = this.#topFor(menu);
|
|
511
506
|
this.#closeAllMenus("select");
|
|
512
|
-
this.#focusTop(
|
|
507
|
+
this.#focusTop(
|
|
508
|
+
top,
|
|
509
|
+
moveFocus && (event !== null || this.element.contains(document.activeElement))
|
|
510
|
+
);
|
|
513
511
|
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
if (!top) return;
|
|
512
|
+
#gotoTop(destination, reopen, reason) {
|
|
513
|
+
if (!destination) return;
|
|
517
514
|
if (reopen) {
|
|
518
|
-
this.#openMenu(
|
|
515
|
+
this.#openMenu(destination, "first", reason);
|
|
519
516
|
} else {
|
|
520
|
-
this.#roving.setActive(this.topTargets.indexOf(
|
|
517
|
+
this.#roving.setActive(this.topTargets.indexOf(destination), { focus: true });
|
|
521
518
|
}
|
|
522
519
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
* activation.
|
|
529
|
-
* - **plain command** (no `aria-controls` at all) — a legitimate top item that
|
|
530
|
-
* simply has no popup.
|
|
531
|
-
* - **dangling `aria-controls`** (names a menu that is not a target) — broken
|
|
532
|
-
* markup.
|
|
533
|
-
*
|
|
534
|
-
* The first two still take the roving focus, and any open menu closes: the APG
|
|
535
|
-
* makes closing unconditional for the horizontal move ("closes the submenu,
|
|
536
|
-
* moves focus to the next menubar item, and *optionally* opens that item's
|
|
537
|
-
* submenu"), so only the opening half is skipped. Leaving the old menu open
|
|
538
|
-
* would strand a popup that no longer contains focus.
|
|
539
|
-
*
|
|
540
|
-
* The dangling case instead leaves the open/closed state and focus untouched
|
|
541
|
-
* rather than closing everything and dropping focus to the body — but only on
|
|
542
|
-
* this "open a menu" path. A dangling top is still an ordinary roving
|
|
543
|
-
* destination while nothing is open.
|
|
544
|
-
*/
|
|
545
|
-
#openMenu(top, focus, reason) {
|
|
546
|
-
if (!top) return;
|
|
547
|
-
const menu = this.#menuFor(top);
|
|
548
|
-
if (!menu || this.#isActivationBlocked(top)) {
|
|
549
|
-
if (menu || !top.hasAttribute("aria-controls")) {
|
|
520
|
+
#openMenu(opener, focus, reason, moveFocus = true, judged = false) {
|
|
521
|
+
if (!opener) return;
|
|
522
|
+
const menu = this.#menuFor(opener);
|
|
523
|
+
if (!menu || !judged && isAriaDisabled(opener)) {
|
|
524
|
+
if (menu || !opener.hasAttribute("aria-controls")) {
|
|
550
525
|
this.#closeAllMenus(reason);
|
|
551
|
-
this.#focusTop(
|
|
526
|
+
this.#focusTop(
|
|
527
|
+
opener,
|
|
528
|
+
moveFocus && (reason !== "api" || this.element.contains(document.activeElement))
|
|
529
|
+
);
|
|
552
530
|
}
|
|
553
531
|
return;
|
|
554
532
|
}
|
|
555
533
|
this.#timers.clearAll();
|
|
556
|
-
const was = this.#isExpanded(
|
|
557
|
-
this.#closeAllMenus(reason,
|
|
534
|
+
const was = this.#isExpanded(opener);
|
|
535
|
+
this.#closeAllMenus(reason, opener);
|
|
558
536
|
menu.hidden = false;
|
|
559
|
-
|
|
560
|
-
if (!was) this.#report("open",
|
|
561
|
-
if (!this.#isExpanded(
|
|
537
|
+
opener.setAttribute("aria-expanded", "true");
|
|
538
|
+
if (!was) this.#report("open", opener, menu, reason);
|
|
539
|
+
if (!this.#isExpanded(opener)) return;
|
|
562
540
|
this.#escapeLayer.activate(document, {
|
|
563
541
|
onDismiss: () => this.#dismissOpenMenu(),
|
|
564
542
|
claims: claimsWhileFocusWithin(this.element)
|
|
565
543
|
});
|
|
566
544
|
this.#layerActive = true;
|
|
567
|
-
this.#roving.setActive(this.topTargets.indexOf(
|
|
545
|
+
this.#roving.setActive(this.topTargets.indexOf(opener));
|
|
568
546
|
const items = this.#itemsIn(menu);
|
|
569
|
-
|
|
547
|
+
if (moveFocus && (reason !== "api" || this.element.contains(document.activeElement))) {
|
|
548
|
+
this.#focusAt(items, focus === "first" ? 0 : items.length - 1);
|
|
549
|
+
}
|
|
570
550
|
}
|
|
571
|
-
/**
|
|
572
|
-
* Hides `top`'s menu and reflects the collapsed state. A top item that controls
|
|
573
|
-
* no menu (a plain command in an otherwise popup-bearing menubar) is left alone
|
|
574
|
-
* — stamping `aria-expanded="false"` on it would announce a popup it lacks.
|
|
575
|
-
*/
|
|
576
551
|
#closeMenu(top, reason, silent = false) {
|
|
577
552
|
if (!top) return;
|
|
578
553
|
const menu = this.#menuFor(top);
|
|
@@ -583,40 +558,21 @@ var MenubarController = class extends Controller {
|
|
|
583
558
|
if (was && !silent) this.#report("close", top, menu, reason);
|
|
584
559
|
this.#syncEscapeLayer();
|
|
585
560
|
}
|
|
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
561
|
#closeAllMenus(reason, except = null) {
|
|
592
562
|
for (const top of this.topTargets) this.#closeMenu(top, reason, top === except);
|
|
593
563
|
this.#typeahead.reset();
|
|
594
564
|
}
|
|
595
|
-
/** Names the menu that moved, so a subscriber does not have to re-derive it. */
|
|
596
565
|
#report(name, top, menu, reason) {
|
|
597
566
|
if (!this.#reporting) return;
|
|
598
567
|
const detail = { reason, index: this.topTargets.indexOf(top), menu };
|
|
599
568
|
if (name === "open") this.dispatch("open", { detail, cancelable: false });
|
|
600
569
|
else this.dispatch("close", { detail, cancelable: false });
|
|
601
570
|
}
|
|
602
|
-
/**
|
|
603
|
-
* Closes every menu on the next task instead of synchronously.
|
|
604
|
-
*
|
|
605
|
-
* Used by `Tab`: closing right away removes the focused element before the
|
|
606
|
-
* browser performs its own Tab move, which can restart traversal at the
|
|
607
|
-
* document head and lose the user's place in the Tab order.
|
|
608
|
-
*/
|
|
609
571
|
#closeMenusSoon() {
|
|
610
572
|
if (!this.#isAnyOpen) return;
|
|
611
573
|
this.#timers.clearAll();
|
|
612
574
|
this.#timers.set(() => this.#closeAllMenus("focus"), 0);
|
|
613
575
|
}
|
|
614
|
-
/**
|
|
615
|
-
* Escape path, invoked by the shared resolver: pressed inside an open menu it
|
|
616
|
-
* closes that menu and returns focus to its top item (the APG behavior);
|
|
617
|
-
* pressed while focus is on a top item (or fell to the body) it closes every
|
|
618
|
-
* menu without moving focus.
|
|
619
|
-
*/
|
|
620
576
|
#dismissOpenMenu() {
|
|
621
577
|
const menu = ownerOf(this.menuTargets, document.activeElement);
|
|
622
578
|
if (menu) {
|
|
@@ -627,54 +583,31 @@ var MenubarController = class extends Controller {
|
|
|
627
583
|
}
|
|
628
584
|
this.#closeAllMenus("escape");
|
|
629
585
|
}
|
|
630
|
-
/** Opens the menu of the navigable top item `delta` steps from `menu`'s owner. */
|
|
631
586
|
#moveToAdjacentMenu(menu, delta) {
|
|
632
|
-
const
|
|
633
|
-
if (!
|
|
587
|
+
const ownerTop = this.#topFor(menu);
|
|
588
|
+
if (!ownerTop) return;
|
|
634
589
|
const tops = this.#navigableTops;
|
|
635
|
-
const current = tops.indexOf(
|
|
590
|
+
const current = tops.indexOf(ownerTop);
|
|
636
591
|
if (current === -1) return;
|
|
637
592
|
const next = (current + delta + tops.length) % tops.length;
|
|
638
593
|
this.#openMenu(tops[next], "first", "user");
|
|
639
594
|
}
|
|
640
|
-
/**
|
|
641
|
-
* Closes when a click lands outside the controller's element. Focus is left on
|
|
642
|
-
* whatever the user clicked — see the focus-restoration contract in the class
|
|
643
|
-
* docs.
|
|
644
|
-
*/
|
|
645
595
|
#onOutsideClick = (event) => {
|
|
646
596
|
if (this.#isAnyOpen && !this.element.contains(event.target)) {
|
|
647
597
|
this.#closeAllMenus("outside");
|
|
648
598
|
}
|
|
649
599
|
};
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
#onDisabledClickCapture = (event) => {
|
|
657
|
-
const target = event.target;
|
|
658
|
-
if (!(target instanceof Node)) return;
|
|
659
|
-
const blocked = [...this.topTargets, ...this.itemTargets].some(
|
|
660
|
-
(element) => this.#isActivationBlocked(element) && element.contains(target)
|
|
600
|
+
#onClickCapture = (event) => {
|
|
601
|
+
const entries = ownersOf(this.#entries, event.target);
|
|
602
|
+
this.#clickVerdicts.record(
|
|
603
|
+
event,
|
|
604
|
+
entries,
|
|
605
|
+
entries.some((entry) => this.#isActivationDisabled(entry))
|
|
661
606
|
);
|
|
662
|
-
if (!
|
|
607
|
+
if (!entries.some((entry) => isAriaDisabled(entry))) return;
|
|
663
608
|
event.preventDefault();
|
|
664
609
|
event.stopImmediatePropagation();
|
|
665
610
|
};
|
|
666
|
-
/**
|
|
667
|
-
* Re-derives every piece of state this controller owns from the live targets:
|
|
668
|
-
* expanded flags, menu visibility, the single Tab stop, and Escape-stack
|
|
669
|
-
* membership. Runtime DOM edits can leave those out of step with each other — a
|
|
670
|
-
* top can claim `aria-expanded="true"` after its menu target was removed or after
|
|
671
|
-
* being hidden itself, a menu can stay visible after its owning top was removed,
|
|
672
|
-
* an open pair can appear from a morph with no layer registered for it, and the
|
|
673
|
-
* Tab stop can end up on a now-inert top, on a runtime-added one, or on none at
|
|
674
|
-
* all. The only state carried between calls is the tracked focus record and which side
|
|
675
|
-
* of the Escape stack this layer is on (which the stack itself does not expose), so the outcome is the
|
|
676
|
-
* same whichever mutation arrived and calling it more often than needed is free.
|
|
677
|
-
*/
|
|
678
611
|
#reconcile() {
|
|
679
612
|
for (const top of this.topTargets) {
|
|
680
613
|
const own = this.#menuFor(top);
|
|
@@ -691,20 +624,6 @@ var MenubarController = class extends Controller {
|
|
|
691
624
|
this.#rescueFocus();
|
|
692
625
|
this.#syncEscapeLayer();
|
|
693
626
|
}
|
|
694
|
-
/**
|
|
695
|
-
* Returns DOM focus to the menubar when the element holding it became
|
|
696
|
-
* unreachable — hidden, natively disabled, or removed — and the document had
|
|
697
|
-
* nowhere to put it. The destination is the top item that now owns the Tab
|
|
698
|
-
* stop, which is where `Escape` from a closed menu would have left the user.
|
|
699
|
-
*
|
|
700
|
-
* Focus is only *restored*, never *stolen*: it moves solely when the tracked
|
|
701
|
-
* element can no longer take it **and** focus is either already gone or still
|
|
702
|
-
* sitting on that element. The second half is what makes a `hidden` ancestor
|
|
703
|
-
* work — a browser blurs the element it hides on its next style pass, not when
|
|
704
|
-
* the attribute is written, so waiting to observe `<body>` here would always
|
|
705
|
-
* come too early. Removal is the other side of the same condition: the browser
|
|
706
|
-
* has already fallen back to the body, or left a detached `activeElement`.
|
|
707
|
-
*/
|
|
708
627
|
#rescueFocus() {
|
|
709
628
|
const focused = this.#focused;
|
|
710
629
|
if (!focused) return;
|
|
@@ -720,22 +639,6 @@ var MenubarController = class extends Controller {
|
|
|
720
639
|
const top = index === -1 ? void 0 : this.topTargets[index];
|
|
721
640
|
if (top && top !== focused && !focused.contains(top)) top.focus();
|
|
722
641
|
}
|
|
723
|
-
/**
|
|
724
|
-
* Brings Escape-stack membership back in line with what the DOM now says is
|
|
725
|
-
* open, in both directions.
|
|
726
|
-
*
|
|
727
|
-
* The deactivate half is the common one (something closed). The activate half
|
|
728
|
-
* covers a menu that became open *without* going through {@link #openMenu} —
|
|
729
|
-
* a Turbo morph that patches `aria-expanded` and the menu's `hidden` in place,
|
|
730
|
-
* which is legitimate here because the DOM is this controller's only source of
|
|
731
|
-
* truth. Without it the popup is visible but `Escape` does nothing, since no
|
|
732
|
-
* layer is registered to claim the press.
|
|
733
|
-
*
|
|
734
|
-
* `#layerActive` exists because re-activating an already-active layer moves it
|
|
735
|
-
* to the top of the stack, which would reshuffle nested layers on every
|
|
736
|
-
* unrelated mutation. Registering only on the false→true edge keeps activation
|
|
737
|
-
* ordered by when each layer actually opened.
|
|
738
|
-
*/
|
|
739
642
|
#syncEscapeLayer() {
|
|
740
643
|
const open = this.#isAnyOpen;
|
|
741
644
|
if (open === this.#layerActive) return;
|
|
@@ -749,13 +652,6 @@ var MenubarController = class extends Controller {
|
|
|
749
652
|
}
|
|
750
653
|
this.#layerActive = open;
|
|
751
654
|
}
|
|
752
|
-
/**
|
|
753
|
-
* Re-establishes the single Tab stop: keep the current one while it is still
|
|
754
|
-
* navigable, else hand it to the first navigable top item. Every other top is
|
|
755
|
-
* explicitly removed from the Tab sequence, so a top that arrived tabbable
|
|
756
|
-
* cannot leave two stops behind. No Tab stop at all (`-1`) happens only when
|
|
757
|
-
* every top is inert, and is recovered from as soon as one becomes navigable.
|
|
758
|
-
*/
|
|
759
655
|
#ensureTabStop() {
|
|
760
656
|
const active = this.#roving.activeIndex;
|
|
761
657
|
const activeTop = active === -1 ? void 0 : this.topTargets[active];
|
|
@@ -766,58 +662,50 @@ var MenubarController = class extends Controller {
|
|
|
766
662
|
const first = this.#navigableTops[0];
|
|
767
663
|
this.#roving.setActive(first ? this.topTargets.indexOf(first) : -1);
|
|
768
664
|
}
|
|
769
|
-
/** The menu element controlled by `top` (matched by `aria-controls`/`id`). */
|
|
770
665
|
#menuFor(top) {
|
|
771
666
|
const id = top.getAttribute("aria-controls");
|
|
772
667
|
return id ? this.menuTargets.find((menu) => menu.id === id) ?? null : null;
|
|
773
668
|
}
|
|
774
|
-
/** The top item that controls `menu` (reverse of `#menuFor`). */
|
|
775
669
|
#topFor(menu) {
|
|
776
670
|
if (!menu) return null;
|
|
777
671
|
return this.topTargets.find((top) => top.getAttribute("aria-controls") === menu.id) ?? null;
|
|
778
672
|
}
|
|
779
|
-
/** The navigable item targets that live inside `menu`, in DOM order. */
|
|
780
673
|
#itemsIn(menu) {
|
|
781
674
|
return this.itemTargets.filter((item) => menu.contains(item) && this.#isNavigable(item));
|
|
782
675
|
}
|
|
783
|
-
|
|
676
|
+
get #entries() {
|
|
677
|
+
return [...this.topTargets, ...this.itemTargets];
|
|
678
|
+
}
|
|
784
679
|
get #navigableTops() {
|
|
785
680
|
return this.topTargets.filter((top) => this.#isNavigable(top));
|
|
786
681
|
}
|
|
787
|
-
/**
|
|
788
|
-
* Whether `element` can take roving focus: `hidden` and natively `disabled`
|
|
789
|
-
* controls are out of reach and are skipped. `aria-disabled` is deliberately
|
|
790
|
-
* **not** checked — the APG keeps such items focusable so they stay
|
|
791
|
-
* discoverable, and {@link MenubarController.#isActivationBlocked} is what
|
|
792
|
-
* suppresses acting on them. CSS-only visibility is not detectable headlessly
|
|
793
|
-
* and stays the consumer's responsibility.
|
|
794
|
-
*/
|
|
795
682
|
#isNavigable(element) {
|
|
796
683
|
if (element.hasAttribute("hidden")) return false;
|
|
797
684
|
return !element.disabled;
|
|
798
685
|
}
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
686
|
+
#isActivationDisabled(element) {
|
|
687
|
+
return !this.#isNavigable(element) || isAriaDisabled(element);
|
|
688
|
+
}
|
|
689
|
+
#refuses(entry, event, origin) {
|
|
690
|
+
const recorded = this.#clickVerdicts.for(event, entry);
|
|
691
|
+
if (recorded !== void 0) return recorded;
|
|
692
|
+
if (this.#isActivationDisabled(entry)) return true;
|
|
693
|
+
const target = event ? event.target : origin;
|
|
694
|
+
return ownersOf(this.#entries, target).some((owner) => this.#isActivationDisabled(owner));
|
|
802
695
|
}
|
|
803
|
-
/** Moves DOM focus to the item at `index` (no-op if out of range). */
|
|
804
696
|
#focusAt(items, index) {
|
|
805
697
|
items[index]?.focus();
|
|
806
698
|
}
|
|
807
|
-
|
|
808
|
-
#focusTop(top) {
|
|
699
|
+
#focusTop(top, focus = true) {
|
|
809
700
|
if (!top) return;
|
|
810
|
-
this.#roving.setActive(this.topTargets.indexOf(top), { focus
|
|
701
|
+
this.#roving.setActive(this.topTargets.indexOf(top), { focus });
|
|
811
702
|
}
|
|
812
|
-
/** Whether `top`'s menu is currently expanded. */
|
|
813
703
|
#isExpanded(top) {
|
|
814
704
|
return top.getAttribute("aria-expanded") === "true";
|
|
815
705
|
}
|
|
816
|
-
/** Whether any top item's menu is currently open. */
|
|
817
706
|
get #isAnyOpen() {
|
|
818
707
|
return this.topTargets.some((top) => this.#isExpanded(top));
|
|
819
708
|
}
|
|
820
|
-
/** Advances focus to the next item in `items` matching the accumulated query. */
|
|
821
709
|
#typeaheadTo(items, current, key) {
|
|
822
710
|
const index = findTypeaheadMatch(items, current, this.#typeahead.push(key));
|
|
823
711
|
if (index !== -1) items[index]?.focus();
|
|
@@ -825,5 +713,4 @@ var MenubarController = class extends Controller {
|
|
|
825
713
|
};
|
|
826
714
|
|
|
827
715
|
export { MenubarController };
|
|
828
|
-
//# sourceMappingURL=menubar_controller.js.map
|
|
829
716
|
//# sourceMappingURL=menubar_controller.js.map
|