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