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,30 +1,173 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
4
|
+
if (element.getAttribute(name) === value) return false;
|
|
5
|
+
if (value === null) element.removeAttribute(name);
|
|
6
|
+
else element.setAttribute(name, value);
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function sharedRegistry(key, create) {
|
|
11
|
+
const symbol = Symbol.for(key);
|
|
12
|
+
const scope = globalThis;
|
|
13
|
+
const existing = scope[symbol];
|
|
14
|
+
if (existing !== void 0) return existing;
|
|
15
|
+
const registry2 = create();
|
|
16
|
+
Object.defineProperty(globalThis, symbol, { value: registry2 });
|
|
17
|
+
return registry2;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
var registry = sharedRegistry(
|
|
21
|
+
"stimeo-ui.attribute-lease.registry.v1",
|
|
22
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
23
|
+
);
|
|
24
|
+
function isAttributeValue(value) {
|
|
25
|
+
return value === null || typeof value === "string";
|
|
26
|
+
}
|
|
27
|
+
function readLeaseRecord(element, record) {
|
|
28
|
+
try {
|
|
29
|
+
const parsed = JSON.parse(element.getAttribute(record) ?? "null");
|
|
30
|
+
if (!Array.isArray(parsed)) return void 0;
|
|
31
|
+
const [original, written, ...rest] = parsed;
|
|
32
|
+
const linked = rest[0] !== false;
|
|
33
|
+
const beneath = linked ? rest : rest.slice(1);
|
|
34
|
+
if (!beneath.every((under) => typeof under === "string")) return void 0;
|
|
35
|
+
return isAttributeValue(original) && isAttributeValue(written) ? { original, written, linked, beneath } : void 0;
|
|
36
|
+
} catch {
|
|
37
|
+
return void 0;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function attributeStack(element, attribute) {
|
|
41
|
+
const byAttribute = registry.stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
42
|
+
registry.stacks.set(element, byAttribute);
|
|
43
|
+
const known = byAttribute.get(attribute);
|
|
44
|
+
if (known) return known;
|
|
45
|
+
const found = [];
|
|
46
|
+
for (const record of registry.names.get(attribute) ?? []) {
|
|
47
|
+
const read = readLeaseRecord(element, record);
|
|
48
|
+
if (read) found.push({ ...read, record });
|
|
49
|
+
}
|
|
50
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
51
|
+
const stack = found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
52
|
+
lease: null,
|
|
53
|
+
record,
|
|
54
|
+
written,
|
|
55
|
+
original,
|
|
56
|
+
linked: linked && index > 0
|
|
57
|
+
}));
|
|
58
|
+
byAttribute.set(attribute, stack);
|
|
59
|
+
return stack;
|
|
60
|
+
}
|
|
61
|
+
function findHold(stack, lease, record) {
|
|
62
|
+
return stack.find((held) => held.lease === lease) ?? stack.find((held) => held.lease === null && held.record === record);
|
|
63
|
+
}
|
|
64
|
+
var AttributeLease = class {
|
|
65
|
+
#attribute;
|
|
66
|
+
#record;
|
|
67
|
+
#base;
|
|
68
|
+
#preserveAuthor;
|
|
69
|
+
#held = /* @__PURE__ */ new Set();
|
|
70
|
+
constructor(attribute, owner, options = {}) {
|
|
71
|
+
this.#attribute = attribute;
|
|
72
|
+
this.#record = `data-${owner}-${attribute}-lease`;
|
|
73
|
+
this.#base = options.base === true;
|
|
74
|
+
this.#preserveAuthor = options.preserveAuthor === true;
|
|
75
|
+
const names = registry.names;
|
|
76
|
+
names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
77
|
+
}
|
|
78
|
+
write(element, value) {
|
|
79
|
+
const stack = attributeStack(element, this.#attribute);
|
|
80
|
+
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
81
|
+
this.#held.add(element);
|
|
82
|
+
const shows = !this.#covered(element, stack, hold);
|
|
83
|
+
hold.written = value;
|
|
84
|
+
this.#mark(element, stack);
|
|
85
|
+
if (shows) this.#reflect(element, value);
|
|
86
|
+
}
|
|
87
|
+
return(element) {
|
|
88
|
+
const held = this.#held.delete(element);
|
|
89
|
+
const known = registry.stacks.get(element)?.has(this.#attribute);
|
|
90
|
+
const stack = held || known || element.hasAttribute(this.#record) ? attributeStack(element, this.#attribute) : [];
|
|
91
|
+
const hold = this.#take(stack);
|
|
92
|
+
if (!hold) return false;
|
|
93
|
+
const carries = element.getAttribute(this.#attribute) === hold.written;
|
|
94
|
+
const owns = carries && !this.#covered(element, stack, hold);
|
|
95
|
+
const index = stack.indexOf(hold);
|
|
96
|
+
stack.splice(index, 1);
|
|
97
|
+
const above = stack[index];
|
|
98
|
+
if (above) above.linked &&= hold.linked;
|
|
99
|
+
this.#mark(element, stack);
|
|
100
|
+
if (!owns) return true;
|
|
101
|
+
const below = hold.linked ? stack[index - 1] : void 0;
|
|
102
|
+
this.#reflect(element, below ? below.written : hold.original);
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
returnAll() {
|
|
106
|
+
for (const element of Array.from(this.#held)) this.return(element);
|
|
107
|
+
}
|
|
108
|
+
#take(stack) {
|
|
109
|
+
const hold = findHold(stack, this, this.#record);
|
|
110
|
+
if (hold) hold.lease = this;
|
|
111
|
+
return hold;
|
|
112
|
+
}
|
|
113
|
+
#acquire(element, stack) {
|
|
114
|
+
const current = element.getAttribute(this.#attribute);
|
|
115
|
+
const top = stack.at(-1);
|
|
116
|
+
const bottom = stack[0];
|
|
117
|
+
const over = top?.written === current ? top : void 0;
|
|
118
|
+
const from = this.#base ? this.#preserveAuthor && !stack.some((held) => held.written === current) ? void 0 : bottom : over;
|
|
119
|
+
const hold = {
|
|
120
|
+
lease: this,
|
|
121
|
+
record: this.#record,
|
|
122
|
+
written: current,
|
|
123
|
+
original: from ? from.original : current,
|
|
124
|
+
linked: !this.#base && over !== void 0
|
|
125
|
+
};
|
|
126
|
+
if (this.#base && bottom) {
|
|
127
|
+
bottom.linked = true;
|
|
128
|
+
stack.unshift(hold);
|
|
129
|
+
} else stack.push(hold);
|
|
130
|
+
return hold;
|
|
131
|
+
}
|
|
132
|
+
#covered(element, stack, hold) {
|
|
133
|
+
const current = element.getAttribute(this.#attribute);
|
|
134
|
+
return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current);
|
|
135
|
+
}
|
|
136
|
+
#mark(element, stack) {
|
|
137
|
+
const records = /* @__PURE__ */ new Map([[this.#record, null]]);
|
|
138
|
+
stack.forEach((hold, index) => {
|
|
139
|
+
const names = stack.slice(0, index).map((under) => under.record);
|
|
140
|
+
const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
|
|
141
|
+
const marker = hold.linked || beneath.length === 0 ? [] : [false];
|
|
142
|
+
records.set(
|
|
143
|
+
hold.record,
|
|
144
|
+
hold.written === hold.original && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([hold.original, hold.written, ...marker, ...beneath])
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
for (const [name, recorded] of records) {
|
|
148
|
+
setAttributeIfChanged(element, name, recorded);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
#reflect(element, value) {
|
|
152
|
+
setAttributeIfChanged(element, this.#attribute, value);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
4
155
|
|
|
5
|
-
// src/utils/blur_deferral.ts
|
|
6
156
|
var BlurDeferral = class {
|
|
7
|
-
/** Elements currently holding an update back, mapped to their `blur` listener. */
|
|
8
157
|
#pending = /* @__PURE__ */ new Map();
|
|
9
|
-
/** Called after a pending element blurs and has been detached. */
|
|
10
158
|
#onRelease;
|
|
11
|
-
/** @param onRelease - Invoked once `element` actually blurs; never on `release`. */
|
|
12
159
|
constructor(onRelease) {
|
|
13
160
|
this.#onRelease = onRelease;
|
|
14
161
|
}
|
|
15
|
-
/** Number of elements currently holding an update back. */
|
|
16
162
|
get size() {
|
|
17
163
|
return this.#pending.size;
|
|
18
164
|
}
|
|
19
|
-
/** Snapshot of the pending elements, safe to iterate while releasing them. */
|
|
20
165
|
get elements() {
|
|
21
166
|
return [...this.#pending.keys()];
|
|
22
167
|
}
|
|
23
|
-
/** Whether `element` is currently holding an update back. */
|
|
24
168
|
has(element) {
|
|
25
169
|
return this.#pending.has(element);
|
|
26
170
|
}
|
|
27
|
-
/** Holds an update back until `element` blurs. Idempotent (no stacked listeners). */
|
|
28
171
|
defer(element) {
|
|
29
172
|
if (this.#pending.has(element)) return;
|
|
30
173
|
const onBlur = () => {
|
|
@@ -34,22 +177,18 @@ var BlurDeferral = class {
|
|
|
34
177
|
this.#pending.set(element, onBlur);
|
|
35
178
|
element.addEventListener("blur", onBlur);
|
|
36
179
|
}
|
|
37
|
-
/** Defers `element` as the only pending entry, cancelling any others. */
|
|
38
180
|
deferOnly(element) {
|
|
39
181
|
for (const pending of this.elements) {
|
|
40
182
|
if (pending !== element) this.#detach(pending);
|
|
41
183
|
}
|
|
42
184
|
this.defer(element);
|
|
43
185
|
}
|
|
44
|
-
/** Cancels `element`'s deferral without completing it; no-ops when not pending. */
|
|
45
186
|
release(element) {
|
|
46
187
|
this.#detach(element);
|
|
47
188
|
}
|
|
48
|
-
/** Cancels every deferral without completing any of them. */
|
|
49
189
|
releaseAll() {
|
|
50
190
|
for (const element of this.elements) this.#detach(element);
|
|
51
191
|
}
|
|
52
|
-
/** Removes the `blur` listener for `element` and forgets it. */
|
|
53
192
|
#detach(element) {
|
|
54
193
|
const onBlur = this.#pending.get(element);
|
|
55
194
|
if (onBlur) element.removeEventListener("blur", onBlur);
|
|
@@ -57,7 +196,6 @@ var BlurDeferral = class {
|
|
|
57
196
|
}
|
|
58
197
|
};
|
|
59
198
|
|
|
60
|
-
// src/utils/declared_value.ts
|
|
61
199
|
function parseDeclared(raw, parse, fallback) {
|
|
62
200
|
try {
|
|
63
201
|
return parse(raw);
|
|
@@ -77,14 +215,8 @@ function validSelector(element, raw, fallback) {
|
|
|
77
215
|
);
|
|
78
216
|
}
|
|
79
217
|
|
|
80
|
-
// src/utils/frame_coalescer.ts
|
|
81
218
|
var FrameCoalescer = class {
|
|
82
219
|
#frame = null;
|
|
83
|
-
/**
|
|
84
|
-
* Runs `run` on the next frame, unless a frame is already pending — the first
|
|
85
|
-
* request of a burst wins and the rest are dropped. The pending frame is
|
|
86
|
-
* released before `run`, so `run` may request the next one.
|
|
87
|
-
*/
|
|
88
220
|
schedule(run) {
|
|
89
221
|
if (this.#frame !== null) return;
|
|
90
222
|
this.#frame = requestAnimationFrame(() => {
|
|
@@ -92,14 +224,6 @@ var FrameCoalescer = class {
|
|
|
92
224
|
run();
|
|
93
225
|
});
|
|
94
226
|
}
|
|
95
|
-
/**
|
|
96
|
-
* Drops the pending frame, and reaches the platform only when there is one.
|
|
97
|
-
*
|
|
98
|
-
* There is no handle value that stands for "nothing pending":
|
|
99
|
-
* `cancelAnimationFrame` takes an `unsigned long`, so a negative placeholder
|
|
100
|
-
* arrives as a large positive number that the same allocator can hand out, and
|
|
101
|
-
* an idle cancel would then drop a frame belonging to someone else.
|
|
102
|
-
*/
|
|
103
227
|
cancel() {
|
|
104
228
|
if (this.#frame === null) return;
|
|
105
229
|
cancelAnimationFrame(this.#frame);
|
|
@@ -107,12 +231,124 @@ var FrameCoalescer = class {
|
|
|
107
231
|
}
|
|
108
232
|
};
|
|
109
233
|
|
|
110
|
-
|
|
234
|
+
var ListenerSet = class {
|
|
235
|
+
#abort = new AbortController();
|
|
236
|
+
add(target, type, handler, options) {
|
|
237
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
238
|
+
}
|
|
239
|
+
dispose() {
|
|
240
|
+
this.#abort.abort();
|
|
241
|
+
this.#abort = new AbortController();
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
var MicrotaskCoalescer = class {
|
|
246
|
+
#run;
|
|
247
|
+
#queued = false;
|
|
248
|
+
#active = false;
|
|
249
|
+
#generation = 0;
|
|
250
|
+
constructor(run) {
|
|
251
|
+
this.#run = run;
|
|
252
|
+
}
|
|
253
|
+
activate() {
|
|
254
|
+
this.#active = true;
|
|
255
|
+
}
|
|
256
|
+
cancel() {
|
|
257
|
+
this.#active = false;
|
|
258
|
+
this.#queued = false;
|
|
259
|
+
this.#generation += 1;
|
|
260
|
+
}
|
|
261
|
+
get pending() {
|
|
262
|
+
return this.#queued;
|
|
263
|
+
}
|
|
264
|
+
schedule() {
|
|
265
|
+
if (!this.#active || this.#queued) return;
|
|
266
|
+
this.#queued = true;
|
|
267
|
+
const generation = this.#generation;
|
|
268
|
+
queueMicrotask(() => {
|
|
269
|
+
if (generation !== this.#generation || !this.#queued || !this.#active) return;
|
|
270
|
+
this.#queued = false;
|
|
271
|
+
this.#run();
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
var MorphRenderWatcher = class {
|
|
277
|
+
#listeners = new ListenerSet();
|
|
278
|
+
#pass;
|
|
279
|
+
#element = null;
|
|
280
|
+
#onMorph = () => this.#pass.schedule();
|
|
281
|
+
constructor(run) {
|
|
282
|
+
this.#pass = new MicrotaskCoalescer(run);
|
|
283
|
+
}
|
|
284
|
+
observe(element) {
|
|
285
|
+
if (this.#element === element) return;
|
|
286
|
+
this.disconnect();
|
|
287
|
+
this.#element = element;
|
|
288
|
+
this.#pass.activate();
|
|
289
|
+
this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
|
|
290
|
+
}
|
|
291
|
+
schedule() {
|
|
292
|
+
this.#pass.schedule();
|
|
293
|
+
}
|
|
294
|
+
get pending() {
|
|
295
|
+
return this.#pass.pending;
|
|
296
|
+
}
|
|
297
|
+
disconnect() {
|
|
298
|
+
this.#listeners.dispose();
|
|
299
|
+
this.#pass.cancel();
|
|
300
|
+
this.#element = null;
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
var NUMBER_BOUNDS = {
|
|
305
|
+
finite: { finite: true }};
|
|
306
|
+
function matchesNumberBounds(value, bounds) {
|
|
307
|
+
if (!Number.isFinite(value)) {
|
|
308
|
+
const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
|
|
309
|
+
if (direction === null) return false;
|
|
310
|
+
if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
|
|
311
|
+
}
|
|
312
|
+
if (bounds.min !== void 0 && value < bounds.min) return false;
|
|
313
|
+
if (bounds.max !== void 0 && value > bounds.max) return false;
|
|
314
|
+
if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
|
|
315
|
+
if (bounds.integer && !Number.isInteger(value)) return false;
|
|
316
|
+
if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function readNumber(raw, fallback, bounds) {
|
|
321
|
+
return matchesNumberBounds(raw, bounds) ? raw : fallback;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
var NumberValueReader = class {
|
|
325
|
+
#lastRejected = /* @__PURE__ */ new Map();
|
|
326
|
+
read(owner, name, raw, fallback, bounds) {
|
|
327
|
+
const resolved = readNumber(raw, fallback, bounds);
|
|
328
|
+
if (matchesNumberBounds(raw, bounds)) {
|
|
329
|
+
this.#lastRejected.delete(name);
|
|
330
|
+
return resolved;
|
|
331
|
+
}
|
|
332
|
+
const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
|
|
333
|
+
const literal = owner.element.getAttribute(attribute);
|
|
334
|
+
if (literal === null) {
|
|
335
|
+
this.#lastRejected.delete(name);
|
|
336
|
+
return resolved;
|
|
337
|
+
}
|
|
338
|
+
if (this.#lastRejected.get(name) !== literal) {
|
|
339
|
+
this.#lastRejected.set(name, literal);
|
|
340
|
+
console.warn(
|
|
341
|
+
`Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
return resolved;
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
|
|
111
348
|
function prefersReducedMotion() {
|
|
112
349
|
return typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
113
350
|
}
|
|
114
351
|
|
|
115
|
-
// src/utils/scroll_source.ts
|
|
116
352
|
function resolveScrollContainer(selector) {
|
|
117
353
|
const match = selector ? document.querySelector(selector) : null;
|
|
118
354
|
return match instanceof HTMLElement ? match : null;
|
|
@@ -123,70 +359,135 @@ function resolveScrollSource(selector) {
|
|
|
123
359
|
function scrollOffset(source) {
|
|
124
360
|
return source === window ? window.scrollY ?? window.pageYOffset ?? 0 : source.scrollTop;
|
|
125
361
|
}
|
|
362
|
+
function deepActiveElement(ownerDocument) {
|
|
363
|
+
let active = ownerDocument.activeElement;
|
|
364
|
+
while (active?.shadowRoot?.activeElement) active = active.shadowRoot.activeElement;
|
|
365
|
+
return active;
|
|
366
|
+
}
|
|
126
367
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
this.#rewind = rewind;
|
|
139
|
-
}
|
|
140
|
-
/** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */
|
|
141
|
-
activate() {
|
|
142
|
-
const first = _BeforeCacheReset.#subscribers.size === 0;
|
|
143
|
-
_BeforeCacheReset.#subscribers.add(this);
|
|
144
|
-
if (first) {
|
|
145
|
-
document.addEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
|
|
368
|
+
function queryOpenDescendants(root, selector) {
|
|
369
|
+
const matches = [];
|
|
370
|
+
const roots = [root];
|
|
371
|
+
for (const scope of roots) {
|
|
372
|
+
matches.push(...scope.querySelectorAll(selector));
|
|
373
|
+
if (scope.nodeType === Node.ELEMENT_NODE) {
|
|
374
|
+
const shadow = scope.shadowRoot;
|
|
375
|
+
if (shadow) roots.push(shadow);
|
|
376
|
+
}
|
|
377
|
+
for (const element of scope.querySelectorAll("*")) {
|
|
378
|
+
if (element.shadowRoot) roots.push(element.shadowRoot);
|
|
146
379
|
}
|
|
147
380
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
_BeforeCacheReset.#subscribers.delete(this);
|
|
151
|
-
if (_BeforeCacheReset.#subscribers.size > 0) return;
|
|
152
|
-
document.removeEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
|
|
153
|
-
}
|
|
154
|
-
};
|
|
381
|
+
return matches;
|
|
382
|
+
}
|
|
155
383
|
|
|
156
|
-
|
|
157
|
-
|
|
384
|
+
function holdsFocus(element) {
|
|
385
|
+
return element.matches(":focus") || deepActiveElement(element.ownerDocument) === element;
|
|
386
|
+
}
|
|
387
|
+
var TabindexLoan = class _TabindexLoan {
|
|
388
|
+
static #registry = sharedRegistry(
|
|
389
|
+
"stimeo-ui.tabindex-loan.registry.v1",
|
|
390
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Set() })
|
|
391
|
+
);
|
|
158
392
|
#value;
|
|
393
|
+
#record;
|
|
394
|
+
#preserveFocus;
|
|
159
395
|
#lent = /* @__PURE__ */ new Set();
|
|
160
|
-
|
|
161
|
-
#beforeCache = new BeforeCacheReset(() => this.returnAll());
|
|
162
|
-
/**
|
|
163
|
-
* @param value - the `tabindex` to lend. `"-1"` (the default) is
|
|
164
|
-
* programmatically focusable but not a Tab stop; `"0"` is a real Tab stop,
|
|
165
|
-
* which a scroll region with no focusable content of its own needs.
|
|
166
|
-
*/
|
|
167
|
-
constructor(value = "-1") {
|
|
396
|
+
constructor(value, owner, options = {}) {
|
|
168
397
|
this.#value = value;
|
|
398
|
+
this.#record = `data-${owner}-tabindex-loan`;
|
|
399
|
+
this.#preserveFocus = options.preserveFocus === true;
|
|
400
|
+
_TabindexLoan.#registry.names.add(this.#record);
|
|
169
401
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
402
|
+
lend(element, options = {}) {
|
|
403
|
+
const stack = this.#stack(element);
|
|
404
|
+
const current = element.getAttribute("tabindex");
|
|
405
|
+
const held = stack.find((hold) => hold.loan === this) ?? stack.find(
|
|
406
|
+
(hold) => hold.loan === null && hold.record === this.#record && hold.value === this.#value
|
|
407
|
+
);
|
|
408
|
+
const linked = stack.at(-1)?.value === current;
|
|
409
|
+
if (!held && options.onlyIfUnfocusable && (current !== null || element.tabIndex >= 0)) return;
|
|
410
|
+
if (!held && current !== null && !linked) return;
|
|
174
411
|
this.#lent.add(element);
|
|
175
|
-
|
|
412
|
+
if (held) held.loan = this;
|
|
413
|
+
else stack.push({ loan: this, record: this.#record, value: this.#value, linked });
|
|
414
|
+
this.#mark(element, stack);
|
|
415
|
+
if (current === null || !held && current !== this.#value) {
|
|
416
|
+
element.setAttribute("tabindex", this.#value);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return(element) {
|
|
420
|
+
const stack = this.#stack(element);
|
|
421
|
+
const hold = stack.find((held) => held.loan === this) ?? stack.find(
|
|
422
|
+
(held) => held.loan === null && held.record === this.#record && held.value === this.#value
|
|
423
|
+
);
|
|
424
|
+
if (!hold) return false;
|
|
425
|
+
if (!this.#release(element, stack, hold, this.#preserveFocus)) {
|
|
426
|
+
hold.loan = this;
|
|
427
|
+
this.#lent.add(element);
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
this.#lent.delete(element);
|
|
431
|
+
return true;
|
|
176
432
|
}
|
|
177
|
-
/** Takes back every loan whose value is still the one that was lent. */
|
|
178
433
|
returnAll() {
|
|
179
|
-
for (const element of this.#lent)
|
|
180
|
-
|
|
434
|
+
for (const element of Array.from(this.#lent)) this.return(element);
|
|
435
|
+
}
|
|
436
|
+
reclaim(element) {
|
|
437
|
+
if (element.getAttribute(this.#record) !== this.#value) return;
|
|
438
|
+
const stack = this.#stack(element);
|
|
439
|
+
const hold = stack.find((held) => held.loan === null && held.record === this.#record);
|
|
440
|
+
if (hold && !holdsFocus(element)) this.#release(element, stack, hold);
|
|
441
|
+
}
|
|
442
|
+
reclaimWithin(root) {
|
|
443
|
+
for (const element of queryOpenDescendants(root, `[${this.#record}]`)) {
|
|
444
|
+
this.reclaim(element);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
#stack(element) {
|
|
448
|
+
const stacks = _TabindexLoan.#registry.stacks;
|
|
449
|
+
const stack = stacks.get(element) ?? this.#seed(element);
|
|
450
|
+
stacks.set(element, stack);
|
|
451
|
+
return stack;
|
|
452
|
+
}
|
|
453
|
+
#seed(element) {
|
|
454
|
+
const current = element.getAttribute("tabindex");
|
|
455
|
+
const holds = [];
|
|
456
|
+
for (const record of _TabindexLoan.#registry.names) {
|
|
457
|
+
const value = element.getAttribute(record);
|
|
458
|
+
if (value !== null) holds.push({ loan: null, record, value, linked: true });
|
|
459
|
+
}
|
|
460
|
+
holds.sort((one, other) => Number(one.value === current) - Number(other.value === current));
|
|
461
|
+
for (const [index, hold] of holds.entries()) hold.linked = index > 0;
|
|
462
|
+
return holds;
|
|
463
|
+
}
|
|
464
|
+
#release(element, stack, hold, preserveFocus = false) {
|
|
465
|
+
const current = element.getAttribute("tabindex");
|
|
466
|
+
const index = stack.indexOf(hold);
|
|
467
|
+
const owns = current === hold.value && !stack.slice(index + 1).some((above2) => above2.value === current);
|
|
468
|
+
if (owns && preserveFocus && holdsFocus(element)) return false;
|
|
469
|
+
stack.splice(index, 1);
|
|
470
|
+
const above = stack[index];
|
|
471
|
+
if (above) above.linked &&= hold.linked;
|
|
472
|
+
this.#mark(element, stack);
|
|
473
|
+
if (!owns) return true;
|
|
474
|
+
const below = hold.linked ? stack[index - 1] : void 0;
|
|
475
|
+
if (!below) element.removeAttribute("tabindex");
|
|
476
|
+
else if (below.value !== current) element.setAttribute("tabindex", below.value);
|
|
477
|
+
return true;
|
|
478
|
+
}
|
|
479
|
+
#mark(element, stack) {
|
|
480
|
+
const records = /* @__PURE__ */ new Map([[this.#record, null]]);
|
|
481
|
+
for (const hold of stack) records.set(hold.record, hold.value);
|
|
482
|
+
for (const [name, recorded] of records) {
|
|
483
|
+
setAttributeIfChanged(element, name, recorded);
|
|
181
484
|
}
|
|
182
|
-
this.#lent.clear();
|
|
183
|
-
this.#beforeCache.deactivate();
|
|
184
485
|
}
|
|
185
486
|
};
|
|
186
487
|
|
|
187
|
-
// src/controllers/scroll_visibility_controller.ts
|
|
188
488
|
var DEFAULT_OFFSET = 400;
|
|
189
|
-
var ScrollVisibilityController = class extends Controller {
|
|
489
|
+
var ScrollVisibilityController = class _ScrollVisibilityController extends Controller {
|
|
490
|
+
#numbers = new NumberValueReader();
|
|
190
491
|
static targets = ["element"];
|
|
191
492
|
static values = {
|
|
192
493
|
offset: { type: Number, default: DEFAULT_OFFSET },
|
|
@@ -194,95 +495,70 @@ var ScrollVisibilityController = class extends Controller {
|
|
|
194
495
|
focusSelector: { type: String, default: "" },
|
|
195
496
|
root: { type: String, default: "" }
|
|
196
497
|
};
|
|
498
|
+
static valueConstraints = {
|
|
499
|
+
offset: NUMBER_BOUNDS.finite
|
|
500
|
+
};
|
|
197
501
|
static actions = ["toTop"];
|
|
198
502
|
static events = ["change"];
|
|
199
|
-
/** Coalesces scroll bursts into one measurement per frame. */
|
|
200
503
|
#frames = new FrameCoalescer();
|
|
201
|
-
/** Previous scroll position, for `direction` mode delta detection. */
|
|
202
504
|
#lastScrollY = 0;
|
|
203
|
-
/** Current visibility, tracked to dispatch `change` only on real transitions. */
|
|
204
505
|
#visible = null;
|
|
205
|
-
/**
|
|
206
|
-
* The observed scroll source: a container element when `root` resolves, else
|
|
207
|
-
* the window. Captured on connect so teardown detaches from the same source.
|
|
208
|
-
*/
|
|
209
506
|
#scrollSource = window;
|
|
210
|
-
|
|
211
|
-
* Gates the declaration callbacks to the connected window.
|
|
212
|
-
*
|
|
213
|
-
* Stimulus delivers a Value callback ahead of `connect()` and again for every
|
|
214
|
-
* runtime change; without the gate, merely connecting would evaluate — and
|
|
215
|
-
* announce — before `connect()` runs its own first reflection.
|
|
216
|
-
*/
|
|
507
|
+
#scrollListeners = new ListenerSet();
|
|
217
508
|
#connected = false;
|
|
218
|
-
/** Validated threshold; a non-finite declaration reads as the default. */
|
|
219
509
|
#offset = DEFAULT_OFFSET;
|
|
220
|
-
/** Validated `root` selector; an unparsable declaration reads as absent. */
|
|
221
510
|
#rootSelector = "";
|
|
222
|
-
/** Validated `focusSelector`; an unparsable declaration reads as absent. */
|
|
223
511
|
#focusSelector = "";
|
|
224
|
-
|
|
225
|
-
#
|
|
226
|
-
/**
|
|
227
|
-
* The hide held back while the control itself owns focus.
|
|
228
|
-
*
|
|
229
|
-
* Completing the deferral re-runs the ordinary evaluation rather than applying
|
|
230
|
-
* the stale decision: by the time focus leaves, the scroll position may have
|
|
231
|
-
* moved back past the threshold.
|
|
232
|
-
*/
|
|
512
|
+
#tabindex = new TabindexLoan("-1", this.identifier);
|
|
513
|
+
#hidden = new AttributeLease("hidden", this.identifier);
|
|
233
514
|
#pendingHide = new BlurDeferral(() => {
|
|
234
515
|
if (this.#connected) this.#evaluate();
|
|
235
516
|
});
|
|
236
517
|
#onScroll = () => this.#frames.schedule(() => this.#evaluate());
|
|
518
|
+
#morphRender = new MorphRenderWatcher(() => {
|
|
519
|
+
this.#followSource();
|
|
520
|
+
this.#evaluate();
|
|
521
|
+
});
|
|
237
522
|
connect() {
|
|
238
|
-
this.#
|
|
239
|
-
this.#
|
|
240
|
-
this.#
|
|
523
|
+
this.#tabindex.reclaimWithin(document);
|
|
524
|
+
this.#morphRender.observe(this.element);
|
|
525
|
+
this.#listenTo(resolveScrollSource(this.#rootSelector));
|
|
241
526
|
this.#evaluate(false);
|
|
242
527
|
this.#connected = true;
|
|
243
528
|
}
|
|
244
529
|
disconnect() {
|
|
530
|
+
this.#morphRender.disconnect();
|
|
245
531
|
this.#connected = false;
|
|
246
|
-
this.#
|
|
532
|
+
this.#scrollListeners.dispose();
|
|
247
533
|
this.#frames.cancel();
|
|
248
534
|
this.#pendingHide.releaseAll();
|
|
249
535
|
this.#tabindex.returnAll();
|
|
250
536
|
this.#visible = null;
|
|
251
537
|
}
|
|
252
|
-
/** Writes the current visibility onto a control that arrives after connect. */
|
|
253
538
|
elementTargetConnected(element) {
|
|
254
|
-
if (this.#visible !== null) element
|
|
539
|
+
if (this.#visible !== null) this.#show(element, this.#visible);
|
|
255
540
|
}
|
|
256
|
-
|
|
257
|
-
elementTargetDisconnected() {
|
|
541
|
+
elementTargetDisconnected(element) {
|
|
258
542
|
this.#pendingHide.releaseAll();
|
|
543
|
+
if (!this.elementTargets.includes(element)) this.#hidden.return(element);
|
|
544
|
+
if (this.#visible !== null && this.hasElementTarget) {
|
|
545
|
+
this.#show(this.elementTarget, this.#visible);
|
|
546
|
+
}
|
|
259
547
|
}
|
|
260
|
-
/**
|
|
261
|
-
* Validates `offset` once, then re-renders.
|
|
262
|
-
*
|
|
263
|
-
* Re-renders when application code (or a Turbo morph) changes `offset` at
|
|
264
|
-
* runtime. A declaration that is not a finite number reads as the default, so
|
|
265
|
-
* the comparison path never sees `NaN` — which would answer `false` to every
|
|
266
|
-
* comparison and strand the element (in `direction` mode, even the guarantee
|
|
267
|
-
* that the very top always reveals).
|
|
268
|
-
*/
|
|
269
548
|
offsetValueChanged() {
|
|
270
|
-
this.#offset =
|
|
271
|
-
|
|
549
|
+
this.#offset = this.#safeOffset;
|
|
550
|
+
this.#morphRender.schedule();
|
|
272
551
|
}
|
|
273
|
-
/** Re-renders when application code (or a Turbo morph) changes `mode` at runtime. */
|
|
274
552
|
modeValueChanged() {
|
|
275
|
-
|
|
553
|
+
this.#morphRender.schedule();
|
|
276
554
|
}
|
|
277
|
-
/** Validates `root` once so connect never parses a selector that throws. */
|
|
278
555
|
rootValueChanged() {
|
|
279
556
|
this.#rootSelector = validSelector(this.element, this.rootValue, "");
|
|
557
|
+
this.#morphRender.schedule();
|
|
280
558
|
}
|
|
281
|
-
/** Validates `focusSelector` once so `toTop` never parses a selector that throws. */
|
|
282
559
|
focusSelectorValueChanged() {
|
|
283
560
|
this.#focusSelector = validSelector(this.element, this.focusSelectorValue, "");
|
|
284
561
|
}
|
|
285
|
-
/** Scrolls the source to the top and, optionally, moves focus to a safe target. */
|
|
286
562
|
toTop() {
|
|
287
563
|
const behavior = prefersReducedMotion() ? "instant" : "smooth";
|
|
288
564
|
this.#scrollSource.scrollTo({ top: 0, behavior });
|
|
@@ -294,14 +570,17 @@ var ScrollVisibilityController = class extends Controller {
|
|
|
294
570
|
}
|
|
295
571
|
}
|
|
296
572
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
573
|
+
#followSource() {
|
|
574
|
+
const source = resolveScrollSource(this.#rootSelector);
|
|
575
|
+
if (source === this.#scrollSource) return;
|
|
576
|
+
this.#scrollListeners.dispose();
|
|
577
|
+
this.#listenTo(source);
|
|
578
|
+
}
|
|
579
|
+
#listenTo(source) {
|
|
580
|
+
this.#scrollSource = source;
|
|
581
|
+
this.#lastScrollY = scrollOffset(source);
|
|
582
|
+
this.#scrollListeners.add(source, "scroll", this.#onScroll, { passive: true });
|
|
583
|
+
}
|
|
305
584
|
#evaluate(notify = true) {
|
|
306
585
|
const y = scrollOffset(this.#scrollSource);
|
|
307
586
|
let nextVisible;
|
|
@@ -309,6 +588,7 @@ var ScrollVisibilityController = class extends Controller {
|
|
|
309
588
|
if (y <= this.#offset) {
|
|
310
589
|
nextVisible = true;
|
|
311
590
|
} else if (y === this.#lastScrollY) {
|
|
591
|
+
this.#setVisible(this.#visible ?? true, notify);
|
|
312
592
|
return;
|
|
313
593
|
} else {
|
|
314
594
|
nextVisible = y < this.#lastScrollY;
|
|
@@ -319,33 +599,36 @@ var ScrollVisibilityController = class extends Controller {
|
|
|
319
599
|
this.#lastScrollY = y;
|
|
320
600
|
this.#setVisible(nextVisible, notify);
|
|
321
601
|
}
|
|
322
|
-
/** Applies visibility to the target, syncing `hidden`, `data-state`, `change`. */
|
|
323
602
|
#setVisible(next, notify) {
|
|
324
|
-
|
|
603
|
+
const changed = next !== this.#visible;
|
|
325
604
|
const focused = !next && this.hasElementTarget ? this.#focusedWithin() : null;
|
|
326
605
|
if (focused) {
|
|
327
606
|
this.#pendingHide.deferOnly(focused);
|
|
328
607
|
return;
|
|
329
608
|
}
|
|
330
609
|
this.#visible = next;
|
|
331
|
-
if (this.hasElementTarget) this.elementTarget
|
|
610
|
+
if (this.hasElementTarget) this.#show(this.elementTarget, next);
|
|
332
611
|
this.element.setAttribute("data-state", next ? "visible" : "hidden");
|
|
333
|
-
if (notify) this.dispatch("change", { detail: { visible: next } });
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
* `blur` does not bubble, so the deferral has to ride the focused element
|
|
339
|
-
* itself: waiting on a container that never receives the event would hold the
|
|
340
|
-
* hide forever.
|
|
341
|
-
*/
|
|
612
|
+
if (notify && changed) this.dispatch("change", { detail: { visible: next } });
|
|
613
|
+
}
|
|
614
|
+
#show(control, visible) {
|
|
615
|
+
this.#hidden.write(control, visible ? null : "");
|
|
616
|
+
}
|
|
342
617
|
#focusedWithin() {
|
|
343
618
|
const focused = document.activeElement;
|
|
344
619
|
if (focused instanceof HTMLElement && this.elementTarget.contains(focused)) return focused;
|
|
345
620
|
return null;
|
|
346
621
|
}
|
|
622
|
+
get #safeOffset() {
|
|
623
|
+
return this.#numbers.read(
|
|
624
|
+
this,
|
|
625
|
+
"offset",
|
|
626
|
+
this.offsetValue,
|
|
627
|
+
_ScrollVisibilityController.values.offset.default,
|
|
628
|
+
_ScrollVisibilityController.valueConstraints.offset
|
|
629
|
+
);
|
|
630
|
+
}
|
|
347
631
|
};
|
|
348
632
|
|
|
349
633
|
export { ScrollVisibilityController };
|
|
350
|
-
//# sourceMappingURL=scroll_visibility_controller.js.map
|
|
351
634
|
//# sourceMappingURL=scroll_visibility_controller.js.map
|