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,14 +1,185 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
function isAriaDisabled(element) {
|
|
4
|
+
for (let current = element; current; current = current.parentElement) {
|
|
5
|
+
if (current.getAttribute("aria-disabled") === "true") return true;
|
|
6
|
+
}
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
4
9
|
|
|
5
|
-
// src/utils/arrow_step.ts
|
|
6
10
|
function isReservedArrowChord(event, allow = []) {
|
|
7
11
|
if (!event.key.startsWith("Arrow")) return false;
|
|
8
12
|
return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
|
|
9
13
|
}
|
|
14
|
+
function hasModifierChord(event) {
|
|
15
|
+
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
19
|
+
if (element.getAttribute(name) === value) return false;
|
|
20
|
+
if (value === null) element.removeAttribute(name);
|
|
21
|
+
else element.setAttribute(name, value);
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function sharedRegistry(key, create) {
|
|
26
|
+
const symbol = Symbol.for(key);
|
|
27
|
+
const scope = globalThis;
|
|
28
|
+
const existing = scope[symbol];
|
|
29
|
+
if (existing !== void 0) return existing;
|
|
30
|
+
const registry2 = create();
|
|
31
|
+
Object.defineProperty(globalThis, symbol, { value: registry2 });
|
|
32
|
+
return registry2;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
var registry = sharedRegistry(
|
|
36
|
+
"stimeo-ui.attribute-lease.registry.v1",
|
|
37
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
38
|
+
);
|
|
39
|
+
function isAttributeValue(value) {
|
|
40
|
+
return value === null || typeof value === "string";
|
|
41
|
+
}
|
|
42
|
+
function readLeaseRecord(element, record) {
|
|
43
|
+
try {
|
|
44
|
+
const parsed = JSON.parse(element.getAttribute(record) ?? "null");
|
|
45
|
+
if (!Array.isArray(parsed)) return void 0;
|
|
46
|
+
const [original, written, ...rest] = parsed;
|
|
47
|
+
const linked = rest[0] !== false;
|
|
48
|
+
const beneath = linked ? rest : rest.slice(1);
|
|
49
|
+
if (!beneath.every((under) => typeof under === "string")) return void 0;
|
|
50
|
+
return isAttributeValue(original) && isAttributeValue(written) ? { original, written, linked, beneath } : void 0;
|
|
51
|
+
} catch {
|
|
52
|
+
return void 0;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function attributeStack(element, attribute) {
|
|
56
|
+
const byAttribute = registry.stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
57
|
+
registry.stacks.set(element, byAttribute);
|
|
58
|
+
const known = byAttribute.get(attribute);
|
|
59
|
+
if (known) return known;
|
|
60
|
+
const found = [];
|
|
61
|
+
for (const record of registry.names.get(attribute) ?? []) {
|
|
62
|
+
const read = readLeaseRecord(element, record);
|
|
63
|
+
if (read) found.push({ ...read, record });
|
|
64
|
+
}
|
|
65
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
66
|
+
const stack = found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
67
|
+
lease: null,
|
|
68
|
+
record,
|
|
69
|
+
written,
|
|
70
|
+
original,
|
|
71
|
+
linked: linked && index > 0
|
|
72
|
+
}));
|
|
73
|
+
byAttribute.set(attribute, stack);
|
|
74
|
+
return stack;
|
|
75
|
+
}
|
|
76
|
+
function findHold(stack, lease, record) {
|
|
77
|
+
return stack.find((held) => held.lease === lease) ?? stack.find((held) => held.lease === null && held.record === record);
|
|
78
|
+
}
|
|
79
|
+
var AttributeLease = class {
|
|
80
|
+
#attribute;
|
|
81
|
+
#record;
|
|
82
|
+
#base;
|
|
83
|
+
#preserveAuthor;
|
|
84
|
+
#held = /* @__PURE__ */ new Set();
|
|
85
|
+
constructor(attribute, owner, options = {}) {
|
|
86
|
+
this.#attribute = attribute;
|
|
87
|
+
this.#record = `data-${owner}-${attribute}-lease`;
|
|
88
|
+
this.#base = options.base === true;
|
|
89
|
+
this.#preserveAuthor = options.preserveAuthor === true;
|
|
90
|
+
const names = registry.names;
|
|
91
|
+
names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
92
|
+
}
|
|
93
|
+
write(element, value) {
|
|
94
|
+
const stack = attributeStack(element, this.#attribute);
|
|
95
|
+
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
96
|
+
this.#held.add(element);
|
|
97
|
+
const shows = !this.#covered(element, stack, hold);
|
|
98
|
+
hold.written = value;
|
|
99
|
+
this.#mark(element, stack);
|
|
100
|
+
if (shows) this.#reflect(element, value);
|
|
101
|
+
}
|
|
102
|
+
return(element) {
|
|
103
|
+
const held = this.#held.delete(element);
|
|
104
|
+
const known = registry.stacks.get(element)?.has(this.#attribute);
|
|
105
|
+
const stack = held || known || element.hasAttribute(this.#record) ? attributeStack(element, this.#attribute) : [];
|
|
106
|
+
const hold = this.#take(stack);
|
|
107
|
+
if (!hold) return false;
|
|
108
|
+
const carries = element.getAttribute(this.#attribute) === hold.written;
|
|
109
|
+
const owns = carries && !this.#covered(element, stack, hold);
|
|
110
|
+
const index = stack.indexOf(hold);
|
|
111
|
+
stack.splice(index, 1);
|
|
112
|
+
const above = stack[index];
|
|
113
|
+
if (above) above.linked &&= hold.linked;
|
|
114
|
+
this.#mark(element, stack);
|
|
115
|
+
if (!owns) return true;
|
|
116
|
+
const below = hold.linked ? stack[index - 1] : void 0;
|
|
117
|
+
this.#reflect(element, below ? below.written : hold.original);
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
returnAll() {
|
|
121
|
+
for (const element of Array.from(this.#held)) this.return(element);
|
|
122
|
+
}
|
|
123
|
+
#take(stack) {
|
|
124
|
+
const hold = findHold(stack, this, this.#record);
|
|
125
|
+
if (hold) hold.lease = this;
|
|
126
|
+
return hold;
|
|
127
|
+
}
|
|
128
|
+
#acquire(element, stack) {
|
|
129
|
+
const current = element.getAttribute(this.#attribute);
|
|
130
|
+
const top = stack.at(-1);
|
|
131
|
+
const bottom = stack[0];
|
|
132
|
+
const over = top?.written === current ? top : void 0;
|
|
133
|
+
const from = this.#base ? this.#preserveAuthor && !stack.some((held) => held.written === current) ? void 0 : bottom : over;
|
|
134
|
+
const hold = {
|
|
135
|
+
lease: this,
|
|
136
|
+
record: this.#record,
|
|
137
|
+
written: current,
|
|
138
|
+
original: from ? from.original : current,
|
|
139
|
+
linked: !this.#base && over !== void 0
|
|
140
|
+
};
|
|
141
|
+
if (this.#base && bottom) {
|
|
142
|
+
bottom.linked = true;
|
|
143
|
+
stack.unshift(hold);
|
|
144
|
+
} else stack.push(hold);
|
|
145
|
+
return hold;
|
|
146
|
+
}
|
|
147
|
+
#covered(element, stack, hold) {
|
|
148
|
+
const current = element.getAttribute(this.#attribute);
|
|
149
|
+
return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current);
|
|
150
|
+
}
|
|
151
|
+
#mark(element, stack) {
|
|
152
|
+
const records = /* @__PURE__ */ new Map([[this.#record, null]]);
|
|
153
|
+
stack.forEach((hold, index) => {
|
|
154
|
+
const names = stack.slice(0, index).map((under) => under.record);
|
|
155
|
+
const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
|
|
156
|
+
const marker = hold.linked || beneath.length === 0 ? [] : [false];
|
|
157
|
+
records.set(
|
|
158
|
+
hold.record,
|
|
159
|
+
hold.written === hold.original && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([hold.original, hold.written, ...marker, ...beneath])
|
|
160
|
+
);
|
|
161
|
+
});
|
|
162
|
+
for (const [name, recorded] of records) {
|
|
163
|
+
setAttributeIfChanged(element, name, recorded);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
#reflect(element, value) {
|
|
167
|
+
setAttributeIfChanged(element, this.#attribute, value);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
var ClickVerdicts = class {
|
|
172
|
+
#verdicts = /* @__PURE__ */ new WeakMap();
|
|
173
|
+
record(event, entries, refused) {
|
|
174
|
+
this.#verdicts.set(event, { entries, refused });
|
|
175
|
+
}
|
|
176
|
+
for(event, entry) {
|
|
177
|
+
const verdict = event && this.#verdicts.get(event);
|
|
178
|
+
if (!verdict?.entries.includes(entry)) return void 0;
|
|
179
|
+
return verdict.refused;
|
|
180
|
+
}
|
|
181
|
+
};
|
|
10
182
|
|
|
11
|
-
// src/utils/escape_layer.ts
|
|
12
183
|
function claimsWhileFocusWithin(element) {
|
|
13
184
|
return () => {
|
|
14
185
|
const active = element.ownerDocument.activeElement;
|
|
@@ -16,89 +187,68 @@ function claimsWhileFocusWithin(element) {
|
|
|
16
187
|
};
|
|
17
188
|
}
|
|
18
189
|
var EscapeLayer = class _EscapeLayer {
|
|
19
|
-
static #registries =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
#claims = null;
|
|
25
|
-
/**
|
|
26
|
-
* Activates this layer at the top of its document's Escape stack, installing
|
|
27
|
-
* the document's shared resolver listener if this is its first layer.
|
|
28
|
-
* Re-activating an already-active layer moves it to the top.
|
|
29
|
-
*/
|
|
190
|
+
static #registries = sharedRegistry(
|
|
191
|
+
"stimeo-ui.escape-layer.registry.v1",
|
|
192
|
+
() => /* @__PURE__ */ new WeakMap()
|
|
193
|
+
);
|
|
194
|
+
#active = null;
|
|
30
195
|
activate(ownerDocument = document, options) {
|
|
31
196
|
this.deactivate();
|
|
32
|
-
let
|
|
33
|
-
if (!
|
|
34
|
-
|
|
35
|
-
_EscapeLayer.#registries.set(ownerDocument,
|
|
36
|
-
ownerDocument.addEventListener("keydown",
|
|
197
|
+
let registry2 = _EscapeLayer.#registries.get(ownerDocument);
|
|
198
|
+
if (!registry2) {
|
|
199
|
+
registry2 = _EscapeLayer.#createRegistry();
|
|
200
|
+
_EscapeLayer.#registries.set(ownerDocument, registry2);
|
|
201
|
+
ownerDocument.addEventListener("keydown", registry2.onKeydown);
|
|
37
202
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
this.#
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Removes this layer from its document's Escape stack, uninstalling the
|
|
45
|
-
* shared listener when the stack empties. Safe to call when inactive.
|
|
46
|
-
*/
|
|
203
|
+
const entry = { onDismiss: options.onDismiss, claims: options.claims ?? null };
|
|
204
|
+
registry2.stack.push(entry);
|
|
205
|
+
this.#active = { document: ownerDocument, entry };
|
|
206
|
+
}
|
|
47
207
|
deactivate() {
|
|
48
|
-
const
|
|
49
|
-
if (!
|
|
50
|
-
const
|
|
51
|
-
if (
|
|
52
|
-
const index =
|
|
53
|
-
if (index >= 0)
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
_EscapeLayer.#registries.delete(
|
|
208
|
+
const active = this.#active;
|
|
209
|
+
if (!active) return;
|
|
210
|
+
const registry2 = _EscapeLayer.#registries.get(active.document);
|
|
211
|
+
if (registry2) {
|
|
212
|
+
const index = registry2.stack.lastIndexOf(active.entry);
|
|
213
|
+
if (index >= 0) registry2.stack.splice(index, 1);
|
|
214
|
+
if (registry2.stack.length === 0) {
|
|
215
|
+
active.document.removeEventListener("keydown", registry2.onKeydown);
|
|
216
|
+
_EscapeLayer.#registries.delete(active.document);
|
|
57
217
|
}
|
|
58
218
|
}
|
|
59
|
-
this.#
|
|
60
|
-
|
|
61
|
-
this.#claims = null;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Whether this active layer would own a press right now: it is the topmost
|
|
65
|
-
* layer whose {@link EscapeLayerOptions.claims} passes. Exposed for tests
|
|
66
|
-
* and diagnostics — production dismissal goes through the shared listener.
|
|
67
|
-
*/
|
|
219
|
+
this.#active = null;
|
|
220
|
+
}
|
|
68
221
|
get ownsEscape() {
|
|
69
|
-
const
|
|
70
|
-
if (!
|
|
71
|
-
const
|
|
72
|
-
if (!
|
|
73
|
-
return _EscapeLayer.#resolveOwner(
|
|
222
|
+
const active = this.#active;
|
|
223
|
+
if (!active) return false;
|
|
224
|
+
const registry2 = _EscapeLayer.#registries.get(active.document);
|
|
225
|
+
if (!registry2) return false;
|
|
226
|
+
return _EscapeLayer.#resolveOwner(registry2.stack) === active.entry;
|
|
74
227
|
}
|
|
75
|
-
/** Builds a document's registry with its shared resolver listener. */
|
|
76
228
|
static #createRegistry() {
|
|
77
|
-
const
|
|
229
|
+
const registry2 = {
|
|
78
230
|
stack: [],
|
|
79
231
|
onKeydown: (event) => {
|
|
80
232
|
if (event.key !== "Escape" || event.defaultPrevented || event.isComposing) return;
|
|
81
|
-
const owner = _EscapeLayer.#resolveOwner(
|
|
233
|
+
const owner = _EscapeLayer.#resolveOwner(registry2.stack);
|
|
82
234
|
if (!owner) return;
|
|
83
235
|
event.preventDefault();
|
|
84
|
-
owner
|
|
236
|
+
owner.onDismiss();
|
|
85
237
|
}
|
|
86
238
|
};
|
|
87
|
-
return
|
|
239
|
+
return registry2;
|
|
88
240
|
}
|
|
89
|
-
/** The topmost stack layer whose claims predicate passes, or `null`. */
|
|
90
241
|
static #resolveOwner(stack) {
|
|
91
242
|
for (let index = stack.length - 1; index >= 0; index--) {
|
|
92
243
|
const layer = stack[index];
|
|
93
244
|
if (!layer) continue;
|
|
94
|
-
if (layer
|
|
245
|
+
if (layer.claims && !layer.claims()) continue;
|
|
95
246
|
return layer;
|
|
96
247
|
}
|
|
97
248
|
return null;
|
|
98
249
|
}
|
|
99
250
|
};
|
|
100
251
|
|
|
101
|
-
// src/utils/event_owner.ts
|
|
102
252
|
function ownerIndex(candidates, node) {
|
|
103
253
|
if (!(node instanceof Node)) return -1;
|
|
104
254
|
return candidates.findIndex((candidate) => candidate.contains(node));
|
|
@@ -106,44 +256,40 @@ function ownerIndex(candidates, node) {
|
|
|
106
256
|
function ownerOf(candidates, node) {
|
|
107
257
|
return candidates[ownerIndex(candidates, node)] ?? null;
|
|
108
258
|
}
|
|
259
|
+
function ownersOf(candidates, node) {
|
|
260
|
+
if (!(node instanceof Node)) return [];
|
|
261
|
+
return candidates.filter((candidate) => candidate.contains(node));
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
var ListenerSet = class {
|
|
265
|
+
#abort = new AbortController();
|
|
266
|
+
add(target, type, handler, options) {
|
|
267
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
268
|
+
}
|
|
269
|
+
dispose() {
|
|
270
|
+
this.#abort.abort();
|
|
271
|
+
this.#abort = new AbortController();
|
|
272
|
+
}
|
|
273
|
+
};
|
|
109
274
|
|
|
110
|
-
// src/utils/safe_timeout.ts
|
|
111
275
|
var TimerRegistry = class {
|
|
112
|
-
/** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
|
|
113
276
|
ids = /* @__PURE__ */ new Set();
|
|
114
|
-
/**
|
|
115
|
-
* Cancels a single tracked timer.
|
|
116
|
-
*
|
|
117
|
-
* No-ops if the id is unknown (already cleared, fired, or never owned by this
|
|
118
|
-
* registry), so callers can clear defensively without guarding.
|
|
119
|
-
*/
|
|
120
277
|
clear(id) {
|
|
121
278
|
if (this.ids.delete(id)) {
|
|
122
279
|
this.cancel(id);
|
|
123
280
|
}
|
|
124
281
|
}
|
|
125
|
-
/**
|
|
126
|
-
* Cancels every tracked timer. Call this from a controller's `disconnect()`
|
|
127
|
-
* to guarantee no timer outlives the element.
|
|
128
|
-
*/
|
|
129
282
|
clearAll() {
|
|
130
283
|
for (const id of this.ids) {
|
|
131
284
|
this.cancel(id);
|
|
132
285
|
}
|
|
133
286
|
this.ids.clear();
|
|
134
287
|
}
|
|
135
|
-
/** Number of timers currently tracked (pending). */
|
|
136
288
|
get size() {
|
|
137
289
|
return this.ids.size;
|
|
138
290
|
}
|
|
139
291
|
};
|
|
140
292
|
var SafeTimeout = class extends TimerRegistry {
|
|
141
|
-
/**
|
|
142
|
-
* Schedules `callback` after `delay` ms and returns the timer id.
|
|
143
|
-
*
|
|
144
|
-
* The id is removed from the registry automatically when the timeout fires,
|
|
145
|
-
* so {@link TimerRegistry.size | size} reflects only still-pending timers.
|
|
146
|
-
*/
|
|
147
293
|
set(callback, delay) {
|
|
148
294
|
const id = this.schedule(() => {
|
|
149
295
|
this.ids.delete(id);
|
|
@@ -160,7 +306,6 @@ var SafeTimeout = class extends TimerRegistry {
|
|
|
160
306
|
}
|
|
161
307
|
};
|
|
162
308
|
|
|
163
|
-
// src/utils/state_reason.ts
|
|
164
309
|
var FOCUS_EVENTS = /* @__PURE__ */ new Set(["blur", "focus", "focusin", "focusout"]);
|
|
165
310
|
var POINTER_EVENTS = /* @__PURE__ */ new Set(["mouseenter", "mouseleave", "pointerenter", "pointerleave"]);
|
|
166
311
|
function stateReasonFor(event) {
|
|
@@ -170,7 +315,6 @@ function stateReasonFor(event) {
|
|
|
170
315
|
return "user";
|
|
171
316
|
}
|
|
172
317
|
|
|
173
|
-
// src/controllers/menu_controller.ts
|
|
174
318
|
var MenuController = class extends Controller {
|
|
175
319
|
static targets = ["trigger", "menu", "item"];
|
|
176
320
|
static actions = [
|
|
@@ -183,38 +327,46 @@ var MenuController = class extends Controller {
|
|
|
183
327
|
];
|
|
184
328
|
static events = ["close", "open"];
|
|
185
329
|
#timers = new SafeTimeout();
|
|
186
|
-
/** Escape-stack membership while open; the shared resolver dismisses via it. */
|
|
187
330
|
#escapeLayer = new EscapeLayer();
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
* in between and may detach the item.
|
|
192
|
-
*/
|
|
331
|
+
#menuHidden = new AttributeLease("hidden", this.identifier);
|
|
332
|
+
#expanded = new AttributeLease("aria-expanded", this.identifier);
|
|
333
|
+
#menu = null;
|
|
193
334
|
#clickOwner = null;
|
|
194
|
-
|
|
335
|
+
#clickVerdicts = new ClickVerdicts();
|
|
195
336
|
#activated = /* @__PURE__ */ new WeakSet();
|
|
196
|
-
|
|
337
|
+
#connected = false;
|
|
197
338
|
#reporting = false;
|
|
198
|
-
|
|
339
|
+
#listeners = new ListenerSet();
|
|
199
340
|
connect() {
|
|
200
341
|
this.#close("api");
|
|
201
|
-
this.element
|
|
202
|
-
this.element
|
|
203
|
-
this.element
|
|
204
|
-
|
|
342
|
+
this.#listeners.add(this.element, "click", this.#onItemClickCapture, { capture: true });
|
|
343
|
+
this.#listeners.add(this.element, "click", this.#onDelegatedItemClick);
|
|
344
|
+
this.#listeners.add(this.element, "keydown", this.#onDelegatedItemKeydown);
|
|
345
|
+
this.#listeners.add(document, "click", this.#onOutsideClick, { capture: true });
|
|
346
|
+
this.#connected = true;
|
|
205
347
|
this.#reporting = true;
|
|
206
348
|
}
|
|
207
|
-
/** Releases the listeners, stack membership, and any pending Tab-close task. */
|
|
208
349
|
disconnect() {
|
|
350
|
+
this.#connected = false;
|
|
209
351
|
this.#reporting = false;
|
|
210
352
|
this.#timers.clearAll();
|
|
211
353
|
this.#escapeLayer.deactivate();
|
|
212
|
-
this.
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
354
|
+
this.#listeners.dispose();
|
|
355
|
+
}
|
|
356
|
+
triggerTargetConnected() {
|
|
357
|
+
if (this.#connected) this.#reflectTrigger();
|
|
358
|
+
}
|
|
359
|
+
triggerTargetDisconnected(trigger) {
|
|
360
|
+
if (!this.triggerTargets.includes(trigger)) this.#expanded.return(trigger);
|
|
361
|
+
if (this.#connected) this.#reflectTrigger();
|
|
362
|
+
}
|
|
363
|
+
menuTargetConnected() {
|
|
364
|
+
this.#adoptMenu();
|
|
365
|
+
}
|
|
366
|
+
menuTargetDisconnected(menu) {
|
|
367
|
+
this.#adoptMenu();
|
|
368
|
+
if (!this.menuTargets.includes(menu)) this.#menuHidden.return(menu);
|
|
216
369
|
}
|
|
217
|
-
/** Toggles the menu open/closed. Bound via `data-action` (click). */
|
|
218
370
|
toggle(event) {
|
|
219
371
|
if (this.#isOpen) {
|
|
220
372
|
this.close(event);
|
|
@@ -223,45 +375,52 @@ var MenuController = class extends Controller {
|
|
|
223
375
|
this.#focusFirst();
|
|
224
376
|
}
|
|
225
377
|
}
|
|
226
|
-
/** Opens the menu and reflects the expanded state on the trigger. */
|
|
227
378
|
open(event) {
|
|
228
379
|
this.#open(stateReasonFor(event));
|
|
229
380
|
}
|
|
230
|
-
/** Closes the menu and reflects the collapsed state on the trigger. */
|
|
231
381
|
close(event) {
|
|
232
382
|
this.#close(stateReasonFor(event));
|
|
233
383
|
}
|
|
234
|
-
/** Opens the menu, reflects the expanded state, and reports a move. */
|
|
235
384
|
#open(reason) {
|
|
236
385
|
this.#timers.clearAll();
|
|
237
386
|
if (!this.hasMenuTarget) return;
|
|
387
|
+
const menu = this.menuTarget;
|
|
238
388
|
const was = this.#isOpen;
|
|
239
389
|
this.#escapeLayer.activate(document, {
|
|
240
390
|
onDismiss: () => this.#closeAndRestore("escape"),
|
|
241
391
|
claims: claimsWhileFocusWithin(this.element)
|
|
242
392
|
});
|
|
243
|
-
this.
|
|
244
|
-
|
|
393
|
+
this.#menuHidden.write(menu, null);
|
|
394
|
+
this.#menu = menu;
|
|
395
|
+
if (this.hasTriggerTarget) this.#expanded.write(this.triggerTarget, "true");
|
|
245
396
|
if (!was && this.#reporting) this.dispatch("open", { detail: { reason }, cancelable: false });
|
|
246
397
|
}
|
|
247
|
-
/** Closes the menu, reflects the collapsed state, and reports a move. */
|
|
248
398
|
#close(reason) {
|
|
249
399
|
this.#timers.clearAll();
|
|
250
400
|
this.#escapeLayer.deactivate();
|
|
251
|
-
|
|
401
|
+
const menu = this.hasMenuTarget ? this.menuTarget : null;
|
|
402
|
+
this.#menu = menu;
|
|
403
|
+
if (!menu) return;
|
|
252
404
|
const was = this.#isOpen;
|
|
253
|
-
this.
|
|
254
|
-
if (this.hasTriggerTarget) this.triggerTarget
|
|
405
|
+
this.#menuHidden.write(menu, "");
|
|
406
|
+
if (this.hasTriggerTarget) this.#expanded.write(this.triggerTarget, "false");
|
|
255
407
|
if (was && this.#reporting) this.dispatch("close", { detail: { reason }, cancelable: false });
|
|
256
408
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
409
|
+
#adoptMenu() {
|
|
410
|
+
if (!this.#connected) return;
|
|
411
|
+
const menu = this.hasMenuTarget ? this.menuTarget : null;
|
|
412
|
+
const previous = this.#menu;
|
|
413
|
+
this.#menu = menu;
|
|
414
|
+
if (!menu) {
|
|
415
|
+
this.#escapeLayer.deactivate();
|
|
416
|
+
} else if (menu !== previous) {
|
|
417
|
+
this.#menuHidden.write(menu, previous?.hidden ?? true ? "" : null);
|
|
418
|
+
}
|
|
419
|
+
this.#reflectTrigger();
|
|
420
|
+
}
|
|
421
|
+
#reflectTrigger() {
|
|
422
|
+
if (this.hasTriggerTarget) this.#expanded.write(this.triggerTarget, String(this.#isOpen));
|
|
423
|
+
}
|
|
265
424
|
onTriggerKeydown(event) {
|
|
266
425
|
if (event.defaultPrevented) return;
|
|
267
426
|
if (isReservedArrowChord(event)) return;
|
|
@@ -275,18 +434,13 @@ var MenuController = class extends Controller {
|
|
|
275
434
|
this.#focusLast();
|
|
276
435
|
}
|
|
277
436
|
}
|
|
278
|
-
/** Implements roving focus and closing keys inside the menu. */
|
|
279
437
|
onItemKeydown(event) {
|
|
280
438
|
this.#handleItemKeydown(event, event.currentTarget);
|
|
281
439
|
}
|
|
282
|
-
/**
|
|
283
|
-
* The roving-focus body, shared by the per-element action and its delegated
|
|
284
|
-
* twin. `from` is the item the key belongs to: the bound element for the
|
|
285
|
-
* action, the resolved owner of the event target for the delegate.
|
|
286
|
-
*/
|
|
287
440
|
#handleItemKeydown(event, from) {
|
|
288
441
|
if (event.defaultPrevented) return;
|
|
289
442
|
if (isReservedArrowChord(event)) return;
|
|
443
|
+
if ((event.key === "Home" || event.key === "End") && hasModifierChord(event)) return;
|
|
290
444
|
const items = this.#navigableItems;
|
|
291
445
|
const currentIndex = items.indexOf(from);
|
|
292
446
|
switch (event.key) {
|
|
@@ -312,120 +466,80 @@ var MenuController = class extends Controller {
|
|
|
312
466
|
break;
|
|
313
467
|
}
|
|
314
468
|
}
|
|
315
|
-
/**
|
|
316
|
-
* Closes the menu after an item is activated. Bound via `data-action`, and
|
|
317
|
-
* also reached from the delegated listener.
|
|
318
|
-
*
|
|
319
|
-
* Markup that carries the per-element action *and* gets the delegate would run
|
|
320
|
-
* this twice for one gesture. `close()` writes the state hooks (`hidden`,
|
|
321
|
-
* `aria-expanded`), and an identical reassign still queues a MutationRecord,
|
|
322
|
-
* so a second pass is observable to anyone watching them. The event is
|
|
323
|
-
* therefore claimed: the path that gets there first does the work, the other
|
|
324
|
-
* one finds it claimed and returns. A programmatic call with no event always
|
|
325
|
-
* runs.
|
|
326
|
-
*/
|
|
327
469
|
activate(event) {
|
|
328
|
-
if (event
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
470
|
+
if (event === void 0) this.#closeAndRestore("select");
|
|
471
|
+
else this.#activateItem(this.#itemFrom(event.target), event);
|
|
472
|
+
}
|
|
473
|
+
#activateItem(item, event) {
|
|
474
|
+
if (item !== null && this.#refuses(item, event)) return;
|
|
475
|
+
if (this.#activated.has(event)) return;
|
|
476
|
+
this.#activated.add(event);
|
|
332
477
|
this.#closeAndRestore("select");
|
|
333
478
|
}
|
|
334
|
-
|
|
479
|
+
#refuses(item, event) {
|
|
480
|
+
const recorded = this.#clickVerdicts.for(event, item);
|
|
481
|
+
if (recorded !== void 0) return recorded;
|
|
482
|
+
return ownersOf(this.itemTargets, event.target).some(
|
|
483
|
+
(owner) => this.#isActivationDisabled(owner)
|
|
484
|
+
);
|
|
485
|
+
}
|
|
335
486
|
#closeAndRestore(reason) {
|
|
336
487
|
this.#close(reason);
|
|
337
488
|
if (this.hasTriggerTarget) this.triggerTarget.focus();
|
|
338
489
|
}
|
|
339
|
-
/** Closes the menu when a click lands outside the controller's element. */
|
|
340
490
|
#onOutsideClick = (event) => {
|
|
341
491
|
if (this.#isOpen && !this.element.contains(event.target)) this.#close("outside");
|
|
342
492
|
};
|
|
343
|
-
/**
|
|
344
|
-
* Delegated twin of {@link onItemKeydown}, bound on the controller element.
|
|
345
|
-
*
|
|
346
|
-
* An item that arrives *after* connect — `stimeo--overflow-menu` moves toolbar controls
|
|
347
|
-
* into this menu at runtime — carries whatever `data-action` its author wrote,
|
|
348
|
-
* and that is exactly the binding a consumer forgets, because the markup that
|
|
349
|
-
* declares the item lives nowhere near the menu. Listening on the container
|
|
350
|
-
* makes membership in the `item` target enough to be operable. The per-element
|
|
351
|
-
* action stays supported and is not double-handled: see
|
|
352
|
-
* {@link #handleItemKeydown}.
|
|
353
|
-
*/
|
|
354
493
|
#onDelegatedItemKeydown = (event) => {
|
|
355
494
|
const item = this.#itemFrom(event.target);
|
|
356
495
|
if (item === null) return;
|
|
357
496
|
this.#handleItemKeydown(event, item);
|
|
358
497
|
};
|
|
359
|
-
/**
|
|
360
|
-
* Delegated twin of {@link activate}, for the same reason as the keydown one.
|
|
361
|
-
*
|
|
362
|
-
* It works from the item the capture pass recorded, not from a fresh lookup:
|
|
363
|
-
* by the time a click bubbles up here, a consumer handler may already have
|
|
364
|
-
* detached the row it lives in, and `itemTargets` is a live query that would
|
|
365
|
-
* then resolve nothing — the activation would be lost and the menu left open
|
|
366
|
-
* over an item that no longer exists. `aria-disabled` items never reach this
|
|
367
|
-
* listener at all: the capture pass stops the click outright.
|
|
368
|
-
*/
|
|
369
498
|
#onDelegatedItemClick = (event) => {
|
|
370
499
|
const item = this.#clickOwner;
|
|
371
500
|
this.#clickOwner = null;
|
|
372
501
|
if (item === null) return;
|
|
373
|
-
this
|
|
502
|
+
this.#activateItem(item, event);
|
|
374
503
|
};
|
|
375
|
-
/** The item target that is, or contains, `node`; `null` when it is neither. */
|
|
376
504
|
#itemFrom(node) {
|
|
377
505
|
return ownerOf(this.itemTargets, node);
|
|
378
506
|
}
|
|
379
|
-
/**
|
|
380
|
-
* First look at every click inside the controller, and the only point at which
|
|
381
|
-
* the DOM is still the one the user clicked. Two jobs: record which item owns
|
|
382
|
-
* the click for the delegate above, and stop an `aria-disabled` command before
|
|
383
|
-
* it reaches consumer handlers (native Enter/Space activation synthesizes a
|
|
384
|
-
* click and is blocked here too).
|
|
385
|
-
*/
|
|
386
507
|
#onItemClickCapture = (event) => {
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
if (
|
|
508
|
+
const items = ownersOf(this.itemTargets, event.target);
|
|
509
|
+
this.#clickOwner = items[0] ?? null;
|
|
510
|
+
this.#clickVerdicts.record(
|
|
511
|
+
event,
|
|
512
|
+
items,
|
|
513
|
+
items.some((item) => this.#isActivationDisabled(item))
|
|
514
|
+
);
|
|
515
|
+
if (!items.some((item) => isAriaDisabled(item))) return;
|
|
395
516
|
this.#clickOwner = null;
|
|
396
517
|
event.preventDefault();
|
|
397
518
|
event.stopImmediatePropagation();
|
|
398
519
|
};
|
|
399
|
-
/** Moves focus to the first navigable item (no-op if none). */
|
|
400
520
|
#focusFirst() {
|
|
401
521
|
if (!this.#isOpen) return;
|
|
402
522
|
this.#navigableItems[0]?.focus();
|
|
403
523
|
}
|
|
404
|
-
/** Moves focus to the last navigable item (no-op if none). */
|
|
405
524
|
#focusLast() {
|
|
406
525
|
if (!this.#isOpen) return;
|
|
407
526
|
const items = this.#navigableItems;
|
|
408
527
|
items[items.length - 1]?.focus();
|
|
409
528
|
}
|
|
410
|
-
/** Menu items eligible for roving focus (excludes disabled / hidden). */
|
|
411
529
|
get #navigableItems() {
|
|
412
530
|
return this.itemTargets.filter((item) => this.#isNavigable(item));
|
|
413
531
|
}
|
|
414
|
-
/**
|
|
415
|
-
* An item can take roving focus unless it is `hidden` or a natively `disabled`
|
|
416
|
-
* form control. `aria-disabled` remains focusable for discoverability; capture
|
|
417
|
-
* suppresses activation. CSS-only visibility is the consumer's responsibility.
|
|
418
|
-
*/
|
|
419
532
|
#isNavigable(item) {
|
|
420
533
|
if (item.hasAttribute("hidden")) return false;
|
|
421
534
|
return !item.disabled;
|
|
422
535
|
}
|
|
423
|
-
|
|
536
|
+
#isActivationDisabled(item) {
|
|
537
|
+
return !this.#isNavigable(item) || isAriaDisabled(item);
|
|
538
|
+
}
|
|
424
539
|
get #isOpen() {
|
|
425
540
|
return this.hasMenuTarget && !this.menuTarget.hidden;
|
|
426
541
|
}
|
|
427
542
|
};
|
|
428
543
|
|
|
429
544
|
export { MenuController };
|
|
430
|
-
//# sourceMappingURL=menu_controller.js.map
|
|
431
545
|
//# sourceMappingURL=menu_controller.js.map
|