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,8 +1,12 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
function fillTemplate(template, values) {
|
|
4
|
+
return template.replace(/\{([a-zA-Z][a-zA-Z0-9]*)\}/g, (match, name) => {
|
|
5
|
+
const replacement = Object.hasOwn(values, name) ? values[name] : void 0;
|
|
6
|
+
return replacement === void 0 ? match : String(replacement);
|
|
7
|
+
});
|
|
8
|
+
}
|
|
4
9
|
|
|
5
|
-
// src/utils/announce.ts
|
|
6
10
|
function announce(message, options = {}) {
|
|
7
11
|
const text = message.trim();
|
|
8
12
|
if (text.length === 0) return;
|
|
@@ -12,148 +16,221 @@ function announce(message, options = {}) {
|
|
|
12
16
|
})
|
|
13
17
|
);
|
|
14
18
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
19
|
+
|
|
20
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
21
|
+
if (element.getAttribute(name) === value) return false;
|
|
22
|
+
if (value === null) element.removeAttribute(name);
|
|
23
|
+
else element.setAttribute(name, value);
|
|
24
|
+
return true;
|
|
20
25
|
}
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
27
|
+
function sharedRegistry(key, create) {
|
|
28
|
+
const symbol = Symbol.for(key);
|
|
29
|
+
const scope = globalThis;
|
|
30
|
+
const existing = scope[symbol];
|
|
31
|
+
if (existing !== void 0) return existing;
|
|
32
|
+
const registry2 = create();
|
|
33
|
+
Object.defineProperty(globalThis, symbol, { value: registry2 });
|
|
34
|
+
return registry2;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var registry = sharedRegistry(
|
|
38
|
+
"stimeo-ui.attribute-lease.registry.v1",
|
|
39
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
40
|
+
);
|
|
41
|
+
function isAttributeValue(value) {
|
|
42
|
+
return value === null || typeof value === "string";
|
|
43
|
+
}
|
|
44
|
+
function readLeaseRecord(element, record) {
|
|
45
|
+
try {
|
|
46
|
+
const parsed = JSON.parse(element.getAttribute(record) ?? "null");
|
|
47
|
+
if (!Array.isArray(parsed)) return void 0;
|
|
48
|
+
const [original, written, ...rest] = parsed;
|
|
49
|
+
const linked = rest[0] !== false;
|
|
50
|
+
const beneath = linked ? rest : rest.slice(1);
|
|
51
|
+
if (!beneath.every((under) => typeof under === "string")) return void 0;
|
|
52
|
+
return isAttributeValue(original) && isAttributeValue(written) ? { original, written, linked, beneath } : void 0;
|
|
53
|
+
} catch {
|
|
54
|
+
return void 0;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function attributeStack(element, attribute) {
|
|
58
|
+
const byAttribute = registry.stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
59
|
+
registry.stacks.set(element, byAttribute);
|
|
60
|
+
const known = byAttribute.get(attribute);
|
|
61
|
+
if (known) return known;
|
|
62
|
+
const found = [];
|
|
63
|
+
for (const record of registry.names.get(attribute) ?? []) {
|
|
64
|
+
const read = readLeaseRecord(element, record);
|
|
65
|
+
if (read) found.push({ ...read, record });
|
|
66
|
+
}
|
|
67
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
68
|
+
const stack = found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
69
|
+
lease: null,
|
|
70
|
+
record,
|
|
71
|
+
written,
|
|
72
|
+
original,
|
|
73
|
+
linked: linked && index > 0
|
|
74
|
+
}));
|
|
75
|
+
byAttribute.set(attribute, stack);
|
|
76
|
+
return stack;
|
|
77
|
+
}
|
|
78
|
+
function findHold(stack, lease, record) {
|
|
79
|
+
return stack.find((held) => held.lease === lease) ?? stack.find((held) => held.lease === null && held.record === record);
|
|
80
|
+
}
|
|
81
|
+
var AttributeLease = class {
|
|
82
|
+
#attribute;
|
|
83
|
+
#record;
|
|
84
|
+
#base;
|
|
85
|
+
#preserveAuthor;
|
|
86
|
+
#held = /* @__PURE__ */ new Set();
|
|
87
|
+
constructor(attribute, owner, options = {}) {
|
|
88
|
+
this.#attribute = attribute;
|
|
89
|
+
this.#record = `data-${owner}-${attribute}-lease`;
|
|
90
|
+
this.#base = options.base === true;
|
|
91
|
+
this.#preserveAuthor = options.preserveAuthor === true;
|
|
92
|
+
const names = registry.names;
|
|
93
|
+
names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
94
|
+
}
|
|
95
|
+
write(element, value) {
|
|
96
|
+
const stack = attributeStack(element, this.#attribute);
|
|
97
|
+
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
98
|
+
this.#held.add(element);
|
|
99
|
+
const shows = !this.#covered(element, stack, hold);
|
|
100
|
+
hold.written = value;
|
|
101
|
+
this.#mark(element, stack);
|
|
102
|
+
if (shows) this.#reflect(element, value);
|
|
103
|
+
}
|
|
104
|
+
return(element) {
|
|
105
|
+
const held = this.#held.delete(element);
|
|
106
|
+
const known = registry.stacks.get(element)?.has(this.#attribute);
|
|
107
|
+
const stack = held || known || element.hasAttribute(this.#record) ? attributeStack(element, this.#attribute) : [];
|
|
108
|
+
const hold = this.#take(stack);
|
|
109
|
+
if (!hold) return false;
|
|
110
|
+
const carries = element.getAttribute(this.#attribute) === hold.written;
|
|
111
|
+
const owns = carries && !this.#covered(element, stack, hold);
|
|
112
|
+
const index = stack.indexOf(hold);
|
|
113
|
+
stack.splice(index, 1);
|
|
114
|
+
const above = stack[index];
|
|
115
|
+
if (above) above.linked &&= hold.linked;
|
|
116
|
+
this.#mark(element, stack);
|
|
117
|
+
if (!owns) return true;
|
|
118
|
+
const below = hold.linked ? stack[index - 1] : void 0;
|
|
119
|
+
this.#reflect(element, below ? below.written : hold.original);
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
returnAll() {
|
|
123
|
+
for (const element of Array.from(this.#held)) this.return(element);
|
|
124
|
+
}
|
|
125
|
+
#take(stack) {
|
|
126
|
+
const hold = findHold(stack, this, this.#record);
|
|
127
|
+
if (hold) hold.lease = this;
|
|
128
|
+
return hold;
|
|
129
|
+
}
|
|
130
|
+
#acquire(element, stack) {
|
|
131
|
+
const current = element.getAttribute(this.#attribute);
|
|
132
|
+
const top = stack.at(-1);
|
|
133
|
+
const bottom = stack[0];
|
|
134
|
+
const over = top?.written === current ? top : void 0;
|
|
135
|
+
const from = this.#base ? this.#preserveAuthor && !stack.some((held) => held.written === current) ? void 0 : bottom : over;
|
|
136
|
+
const hold = {
|
|
137
|
+
lease: this,
|
|
138
|
+
record: this.#record,
|
|
139
|
+
written: current,
|
|
140
|
+
original: from ? from.original : current,
|
|
141
|
+
linked: !this.#base && over !== void 0
|
|
142
|
+
};
|
|
143
|
+
if (this.#base && bottom) {
|
|
144
|
+
bottom.linked = true;
|
|
145
|
+
stack.unshift(hold);
|
|
146
|
+
} else stack.push(hold);
|
|
147
|
+
return hold;
|
|
148
|
+
}
|
|
149
|
+
#covered(element, stack, hold) {
|
|
150
|
+
const current = element.getAttribute(this.#attribute);
|
|
151
|
+
return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current);
|
|
152
|
+
}
|
|
153
|
+
#mark(element, stack) {
|
|
154
|
+
const records = /* @__PURE__ */ new Map([[this.#record, null]]);
|
|
155
|
+
stack.forEach((hold, index) => {
|
|
156
|
+
const names = stack.slice(0, index).map((under) => under.record);
|
|
157
|
+
const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
|
|
158
|
+
const marker = hold.linked || beneath.length === 0 ? [] : [false];
|
|
159
|
+
records.set(
|
|
160
|
+
hold.record,
|
|
161
|
+
hold.written === hold.original && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([hold.original, hold.written, ...marker, ...beneath])
|
|
162
|
+
);
|
|
163
|
+
});
|
|
164
|
+
for (const [name, recorded] of records) {
|
|
165
|
+
setAttributeIfChanged(element, name, recorded);
|
|
41
166
|
}
|
|
42
167
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
_BeforeCacheReset.#subscribers.delete(this);
|
|
46
|
-
if (_BeforeCacheReset.#subscribers.size > 0) return;
|
|
47
|
-
document.removeEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
|
|
168
|
+
#reflect(element, value) {
|
|
169
|
+
setAttributeIfChanged(element, this.#attribute, value);
|
|
48
170
|
}
|
|
49
171
|
};
|
|
50
172
|
|
|
51
|
-
// src/utils/detach_gate.ts
|
|
52
173
|
var DetachGate = class _DetachGate {
|
|
53
|
-
/** Set while a probe is queued, waiting for a reconnect to cancel it. */
|
|
54
174
|
#pending = false;
|
|
55
|
-
/**
|
|
56
|
-
* True while a probe is queued — the last disconnect was ambiguous and no
|
|
57
|
-
* reconnect has cancelled it yet. Read it from `connect()` to tell the
|
|
58
|
-
* reconnect half of an in-page move from a first connect: a controller whose
|
|
59
|
-
* initialisation restarts a measurement (a min-duration floor, an elapsed
|
|
60
|
-
* counter) must skip it for the move, where nothing actually restarted.
|
|
61
|
-
*/
|
|
62
175
|
get pending() {
|
|
63
176
|
return this.#pending;
|
|
64
177
|
}
|
|
65
|
-
/**
|
|
66
|
-
* True when the disconnect is definitely a real detach — the element left
|
|
67
|
-
* the document, or `data-controller` no longer lists the identifier. False
|
|
68
|
-
* means ambiguous (in-page move or observed-root exit), NOT "alive".
|
|
69
|
-
*/
|
|
70
178
|
static isDetached(host) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return !tokens.includes(host.identifier);
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Call from `disconnect()`: runs `teardown` synchronously on a definite
|
|
77
|
-
* detach (fast path), otherwise defers it one microtask — a reconnect
|
|
78
|
-
* ({@link cancel} from `connect()`) keeps the state, no reconnect runs it.
|
|
79
|
-
* One microtask is the whole probe window: Stimulus reconnects a moved
|
|
80
|
-
* element within the same mutation batch, before the checkpoint drains.
|
|
81
|
-
*/
|
|
179
|
+
return !host.element.isConnected || !_DetachGate.#listed(host);
|
|
180
|
+
}
|
|
82
181
|
disconnected(host, teardown) {
|
|
83
|
-
|
|
182
|
+
const carried = _DetachGate.#carried(host);
|
|
183
|
+
if (!carried && _DetachGate.isDetached(host)) {
|
|
84
184
|
this.#pending = false;
|
|
85
185
|
teardown();
|
|
86
186
|
return;
|
|
87
187
|
}
|
|
88
188
|
this.#pending = true;
|
|
89
|
-
|
|
189
|
+
const probe = () => {
|
|
90
190
|
if (!this.#pending) return;
|
|
91
191
|
this.#pending = false;
|
|
92
192
|
teardown();
|
|
93
|
-
}
|
|
193
|
+
};
|
|
194
|
+
if (carried) setTimeout(probe, 0);
|
|
195
|
+
else queueMicrotask(probe);
|
|
196
|
+
}
|
|
197
|
+
static #carried(host) {
|
|
198
|
+
const element = host.element;
|
|
199
|
+
return !element.isConnected && element.closest("[data-turbo-permanent]") !== null && _DetachGate.#listed(host);
|
|
200
|
+
}
|
|
201
|
+
static #listed(host) {
|
|
202
|
+
const tokens = (host.element.getAttribute("data-controller") ?? "").split(/\s+/);
|
|
203
|
+
return tokens.includes(host.identifier);
|
|
94
204
|
}
|
|
95
|
-
/**
|
|
96
|
-
* Disarms a pending probe. Call from `connect()` (the reconnect that proves
|
|
97
|
-
* an in-page move) and from the head of any teardown path not routed through
|
|
98
|
-
* {@link disconnected} (disabled-toggle, Escape), so an orphaned probe can
|
|
99
|
-
* never run the teardown a second time.
|
|
100
|
-
*/
|
|
101
205
|
cancel() {
|
|
102
206
|
this.#pending = false;
|
|
103
207
|
}
|
|
104
208
|
};
|
|
105
209
|
|
|
106
|
-
// src/utils/listener_set.ts
|
|
107
210
|
var ListenerSet = class {
|
|
108
|
-
/** The generation every `add` joins until the next `dispose()`. */
|
|
109
211
|
#abort = new AbortController();
|
|
110
|
-
/**
|
|
111
|
-
* Attaches `handler` to the open generation, exactly as the caller spelled it.
|
|
112
|
-
*
|
|
113
|
-
* The set supplies the signal, so `options` carries everything else the DOM
|
|
114
|
-
* accepts — `capture` included, which has to match at release time and no
|
|
115
|
-
* longer has a second place to drift from.
|
|
116
|
-
*/
|
|
117
212
|
add(target, type, handler, options) {
|
|
118
213
|
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
119
214
|
}
|
|
120
|
-
/**
|
|
121
|
-
* Releases every listener of the open generation, synchronously, and opens the
|
|
122
|
-
* next one. Idempotent, and safe before anything has been added.
|
|
123
|
-
*/
|
|
124
215
|
dispose() {
|
|
125
216
|
this.#abort.abort();
|
|
126
217
|
this.#abort = new AbortController();
|
|
127
218
|
}
|
|
128
219
|
};
|
|
129
220
|
|
|
130
|
-
// src/utils/min_duration_floor.ts
|
|
131
221
|
var MinDurationFloor = class {
|
|
132
222
|
#timers;
|
|
133
|
-
/** Pending finish timer id, or `null` when nothing is held back. */
|
|
134
223
|
#timerId = null;
|
|
135
|
-
/** Epoch ms the floor is measured from. */
|
|
136
224
|
#since = 0;
|
|
137
|
-
/** @param timers - the controller's registry; the floor schedules into it. */
|
|
138
225
|
constructor(timers) {
|
|
139
226
|
this.#timers = timers;
|
|
140
227
|
}
|
|
141
|
-
/** Starts the floor: call when the state being held becomes visible. */
|
|
142
228
|
begin() {
|
|
143
229
|
this.#since = Date.now();
|
|
144
230
|
}
|
|
145
|
-
/** True while a finish is held back waiting for the floor to elapse. */
|
|
146
231
|
get pending() {
|
|
147
232
|
return this.#timerId !== null;
|
|
148
233
|
}
|
|
149
|
-
/**
|
|
150
|
-
* Runs `finish` once the floor has elapsed, immediately when it already has.
|
|
151
|
-
*
|
|
152
|
-
* A held-back finish is **replaced**, never stacked: only the most recently
|
|
153
|
-
* queued id is cancellable, so a second timer would outlive every cancel and
|
|
154
|
-
* end a state that has since restarted. Controllers that want the first signal
|
|
155
|
-
* to win guard on {@link pending} before calling.
|
|
156
|
-
*/
|
|
157
234
|
schedule(minDuration, finish) {
|
|
158
235
|
this.cancel();
|
|
159
236
|
const remaining = minDuration - (Date.now() - this.#since);
|
|
@@ -166,7 +243,6 @@ var MinDurationFloor = class {
|
|
|
166
243
|
finish();
|
|
167
244
|
}
|
|
168
245
|
}
|
|
169
|
-
/** Drops a held-back finish. Safe when none is queued, or after a bulk clear. */
|
|
170
246
|
cancel() {
|
|
171
247
|
if (this.#timerId !== null) {
|
|
172
248
|
this.#timers.clear(this.#timerId);
|
|
@@ -175,43 +251,70 @@ var MinDurationFloor = class {
|
|
|
175
251
|
}
|
|
176
252
|
};
|
|
177
253
|
|
|
178
|
-
|
|
254
|
+
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
255
|
+
|
|
256
|
+
var NUMBER_BOUNDS = {
|
|
257
|
+
timer: { finite: true, min: 0, max: MAX_TIMER_DELAY_MS }};
|
|
258
|
+
function matchesNumberBounds(value, bounds) {
|
|
259
|
+
if (!Number.isFinite(value)) {
|
|
260
|
+
const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
|
|
261
|
+
if (direction === null) return false;
|
|
262
|
+
if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
|
|
263
|
+
}
|
|
264
|
+
if (bounds.min !== void 0 && value < bounds.min) return false;
|
|
265
|
+
if (bounds.max !== void 0 && value > bounds.max) return false;
|
|
266
|
+
if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
|
|
267
|
+
if (bounds.integer && !Number.isInteger(value)) return false;
|
|
268
|
+
if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function readNumber(raw, fallback, bounds) {
|
|
273
|
+
return matchesNumberBounds(raw, bounds) ? raw : fallback;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
var NumberValueReader = class {
|
|
277
|
+
#lastRejected = /* @__PURE__ */ new Map();
|
|
278
|
+
read(owner, name, raw, fallback, bounds) {
|
|
279
|
+
const resolved = readNumber(raw, fallback, bounds);
|
|
280
|
+
if (matchesNumberBounds(raw, bounds)) {
|
|
281
|
+
this.#lastRejected.delete(name);
|
|
282
|
+
return resolved;
|
|
283
|
+
}
|
|
284
|
+
const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
|
|
285
|
+
const literal = owner.element.getAttribute(attribute);
|
|
286
|
+
if (literal === null) {
|
|
287
|
+
this.#lastRejected.delete(name);
|
|
288
|
+
return resolved;
|
|
289
|
+
}
|
|
290
|
+
if (this.#lastRejected.get(name) !== literal) {
|
|
291
|
+
this.#lastRejected.set(name, literal);
|
|
292
|
+
console.warn(
|
|
293
|
+
`Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
return resolved;
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
|
|
179
300
|
var TimerRegistry = class {
|
|
180
|
-
/** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
|
|
181
301
|
ids = /* @__PURE__ */ new Set();
|
|
182
|
-
/**
|
|
183
|
-
* Cancels a single tracked timer.
|
|
184
|
-
*
|
|
185
|
-
* No-ops if the id is unknown (already cleared, fired, or never owned by this
|
|
186
|
-
* registry), so callers can clear defensively without guarding.
|
|
187
|
-
*/
|
|
188
302
|
clear(id) {
|
|
189
303
|
if (this.ids.delete(id)) {
|
|
190
304
|
this.cancel(id);
|
|
191
305
|
}
|
|
192
306
|
}
|
|
193
|
-
/**
|
|
194
|
-
* Cancels every tracked timer. Call this from a controller's `disconnect()`
|
|
195
|
-
* to guarantee no timer outlives the element.
|
|
196
|
-
*/
|
|
197
307
|
clearAll() {
|
|
198
308
|
for (const id of this.ids) {
|
|
199
309
|
this.cancel(id);
|
|
200
310
|
}
|
|
201
311
|
this.ids.clear();
|
|
202
312
|
}
|
|
203
|
-
/** Number of timers currently tracked (pending). */
|
|
204
313
|
get size() {
|
|
205
314
|
return this.ids.size;
|
|
206
315
|
}
|
|
207
316
|
};
|
|
208
317
|
var SafeTimeout = class extends TimerRegistry {
|
|
209
|
-
/**
|
|
210
|
-
* Schedules `callback` after `delay` ms and returns the timer id.
|
|
211
|
-
*
|
|
212
|
-
* The id is removed from the registry automatically when the timeout fires,
|
|
213
|
-
* so {@link TimerRegistry.size | size} reflects only still-pending timers.
|
|
214
|
-
*/
|
|
215
318
|
set(callback, delay) {
|
|
216
319
|
const id = this.schedule(() => {
|
|
217
320
|
this.ids.delete(id);
|
|
@@ -228,8 +331,8 @@ var SafeTimeout = class extends TimerRegistry {
|
|
|
228
331
|
}
|
|
229
332
|
};
|
|
230
333
|
|
|
231
|
-
|
|
232
|
-
|
|
334
|
+
var FrameLoadingController = class _FrameLoadingController extends Controller {
|
|
335
|
+
#numbers = new NumberValueReader();
|
|
233
336
|
static targets = ["content", "skeleton", "overlay"];
|
|
234
337
|
static values = {
|
|
235
338
|
announceText: { type: String, default: "" },
|
|
@@ -237,147 +340,109 @@ var FrameLoadingController = class extends Controller {
|
|
|
237
340
|
minDuration: { type: Number, default: 0 },
|
|
238
341
|
restoreFocus: { type: Boolean, default: true }
|
|
239
342
|
};
|
|
343
|
+
static valueConstraints = {
|
|
344
|
+
minDuration: NUMBER_BOUNDS.timer
|
|
345
|
+
};
|
|
240
346
|
static events = ["start", "end", "reconcile"];
|
|
241
347
|
#timeouts = new SafeTimeout();
|
|
242
348
|
#floor = new MinDurationFloor(this.#timeouts);
|
|
243
349
|
#gate = new DetachGate();
|
|
244
|
-
#beforeCache = new BeforeCacheReset(() => this.#rewindForCache());
|
|
245
350
|
#listeners = new ListenerSet();
|
|
351
|
+
#busy = new AttributeLease("aria-busy", this.identifier);
|
|
352
|
+
#loadingHook = new AttributeLease("data-frame-loading", this.identifier);
|
|
353
|
+
#hidden = new AttributeLease("hidden", this.identifier);
|
|
354
|
+
#inert = new AttributeLease("inert", this.identifier);
|
|
246
355
|
#loading = false;
|
|
247
|
-
/**
|
|
248
|
-
* The optional targets this controller revealed, and the content it marked inert.
|
|
249
|
-
* Held as references rather than re-resolved on the way out: a detach that keeps
|
|
250
|
-
* the element takes the identifier off `data-controller` first, and a scope
|
|
251
|
-
* without its identifier stops resolving targets — the elements to tidy would be
|
|
252
|
-
* unreachable exactly when the tidying matters. They double as the ownership
|
|
253
|
-
* marker, so a `hidden` or an `inert` the consumer wrote is never taken over.
|
|
254
|
-
*/
|
|
255
356
|
#revealedSkeleton = null;
|
|
256
357
|
#revealedOverlay = null;
|
|
257
358
|
#inertTarget = null;
|
|
258
359
|
#previousFocus = null;
|
|
259
|
-
/** The id of the retreated element, used to re-find it if the load replaced it. */
|
|
260
360
|
#previousFocusId = "";
|
|
261
361
|
#onStart = () => {
|
|
262
362
|
this.#floor.cancel();
|
|
263
363
|
if (!this.#loading) this.#begin();
|
|
264
364
|
};
|
|
265
|
-
/**
|
|
266
|
-
* @stimeoRuntimeOnly `minDuration` holds the loading state at least this long for the one load
|
|
267
|
-
* that ended.
|
|
268
|
-
*/
|
|
269
365
|
#onEnd = () => {
|
|
270
366
|
if (!this.#loading) return;
|
|
271
|
-
this.#floor.schedule(this
|
|
367
|
+
this.#floor.schedule(this.#safeMinDuration, () => this.#finish());
|
|
272
368
|
};
|
|
273
369
|
connect() {
|
|
274
370
|
this.#gate.cancel();
|
|
275
|
-
this.#beforeCache.activate();
|
|
276
371
|
this.#listeners.add(this.element, "turbo:before-fetch-request", this.#onStart);
|
|
277
372
|
this.#listeners.add(this.element, "turbo:frame-load", this.#onEnd);
|
|
278
373
|
this.#listeners.add(this.element, "turbo:fetch-request-error", this.#onEnd);
|
|
374
|
+
if (this.#loading) return;
|
|
375
|
+
const stale = this.element.hasAttribute("data-frame-loading");
|
|
376
|
+
this.#returnCopied();
|
|
377
|
+
if (stale) this.dispatch("reconcile", { detail: {} });
|
|
378
|
+
}
|
|
379
|
+
#returnCopied() {
|
|
380
|
+
this.#busy.return(this.element);
|
|
381
|
+
this.#loadingHook.return(this.element);
|
|
382
|
+
for (const region of [...this.skeletonTargets, ...this.overlayTargets]) {
|
|
383
|
+
this.#hidden.return(region);
|
|
384
|
+
}
|
|
385
|
+
for (const content of this.contentTargets) this.#inert.return(content);
|
|
279
386
|
}
|
|
280
387
|
disconnect() {
|
|
281
388
|
this.#listeners.dispose();
|
|
282
|
-
this.#beforeCache.deactivate();
|
|
283
389
|
this.#gate.disconnected(this, () => this.#teardown());
|
|
284
390
|
}
|
|
285
|
-
/**
|
|
286
|
-
* Drops the held finish and the loading bookkeeping on a real detach, returning
|
|
287
|
-
* the frame to its idle form. No reconnect is coming, so nothing is left that
|
|
288
|
-
* could finish the load and clear the hooks — a detach that keeps the element
|
|
289
|
-
* (a morph dropping the identifier, an exit from a scoped observed root) would
|
|
290
|
-
* otherwise strand it busy and inert. Focus is left where it is: the element is
|
|
291
|
-
* leaving this controller's care, and moving it now would be an unexplained jump.
|
|
292
|
-
*/
|
|
293
391
|
#teardown() {
|
|
294
|
-
this.#gate.cancel();
|
|
295
392
|
this.#timeouts.clearAll();
|
|
296
|
-
this.#floor.cancel();
|
|
297
393
|
if (this.#loading) this.#rewindHooks();
|
|
298
394
|
this.#loading = false;
|
|
299
395
|
this.#previousFocus = null;
|
|
300
396
|
}
|
|
301
|
-
/**
|
|
302
|
-
* Returns the frame to its idle form for the snapshot Turbo is about to take, so
|
|
303
|
-
* a page reached with the Back button does not restore a frame that is busy and
|
|
304
|
-
* inert with nothing left to finish it. State only — no `end` event and no focus
|
|
305
|
-
* move, because the load did not actually complete.
|
|
306
|
-
*
|
|
307
|
-
* The load is abandoned rather than paused, so the flag and any finish the floor
|
|
308
|
-
* still holds drop along with the hooks. A kept finish would surface after the
|
|
309
|
-
* rewind as exactly the three things this pass exists to avoid — an `end`, a
|
|
310
|
-
* completion announcement, and a focus move — and a kept flag would leave the
|
|
311
|
-
* next fetch on a page that survives a cancelled visit skipping the loading
|
|
312
|
-
* state, its idempotence guard already satisfied.
|
|
313
|
-
*/
|
|
314
|
-
#rewindForCache() {
|
|
315
|
-
if (!this.#loading) return;
|
|
316
|
-
this.#loading = false;
|
|
317
|
-
this.#floor.cancel();
|
|
318
|
-
this.#rewindHooks();
|
|
319
|
-
this.dispatch("reconcile", { detail: {} });
|
|
320
|
-
}
|
|
321
|
-
/**
|
|
322
|
-
* Clears every hook the loading state writes. Shared by the three ways a load can
|
|
323
|
-
* stop — completion, detach, snapshot — so none of them can drift into tidying
|
|
324
|
-
* only part of it.
|
|
325
|
-
*/
|
|
326
397
|
#rewindHooks() {
|
|
327
|
-
this.element
|
|
328
|
-
this.element
|
|
329
|
-
if (this.#revealedSkeleton) this.#revealedSkeleton
|
|
330
|
-
if (this.#revealedOverlay) this.#revealedOverlay
|
|
398
|
+
this.#busy.return(this.element);
|
|
399
|
+
this.#loadingHook.return(this.element);
|
|
400
|
+
if (this.#revealedSkeleton) this.#hidden.return(this.#revealedSkeleton);
|
|
401
|
+
if (this.#revealedOverlay) this.#hidden.return(this.#revealedOverlay);
|
|
331
402
|
this.#revealedSkeleton = null;
|
|
332
403
|
this.#revealedOverlay = null;
|
|
333
404
|
this.#clearInert();
|
|
334
405
|
}
|
|
335
|
-
/**
|
|
336
|
-
* Re-shows a `skeleton` that arrived mid-load. Turbo's frame renderer empties the
|
|
337
|
-
* frame and re-inserts the response's children, so a response's authored (hidden)
|
|
338
|
-
* skeleton can land while a later fetch is still running, and only the controller
|
|
339
|
-
* knows the frame is still busy.
|
|
340
|
-
*/
|
|
341
406
|
skeletonTargetConnected() {
|
|
342
407
|
if (this.#loading) this.#revealSkeleton();
|
|
343
408
|
}
|
|
344
|
-
|
|
409
|
+
skeletonTargetDisconnected(skeleton) {
|
|
410
|
+
if (this.#loading && !this.skeletonTargets.includes(skeleton)) this.#revealSkeleton();
|
|
411
|
+
}
|
|
345
412
|
overlayTargetConnected() {
|
|
346
413
|
if (this.#loading) this.#revealOverlay();
|
|
347
414
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
* an `inert` the replacement authored stays the consumer's.
|
|
352
|
-
*/
|
|
415
|
+
overlayTargetDisconnected(overlay) {
|
|
416
|
+
if (this.#loading && !this.overlayTargets.includes(overlay)) this.#revealOverlay();
|
|
417
|
+
}
|
|
353
418
|
contentTargetConnected() {
|
|
354
419
|
if (!this.#loading) return;
|
|
355
420
|
this.#clearInert();
|
|
356
421
|
this.#applyInert();
|
|
357
422
|
}
|
|
358
|
-
|
|
423
|
+
contentTargetDisconnected(content) {
|
|
424
|
+
if (!this.#loading || this.contentTargets.includes(content)) return;
|
|
425
|
+
this.#clearInert();
|
|
426
|
+
this.#applyInert();
|
|
427
|
+
}
|
|
359
428
|
#revealSkeleton() {
|
|
360
|
-
|
|
361
|
-
this.#revealedSkeleton = this
|
|
362
|
-
this.skeletonTarget.hidden = false;
|
|
429
|
+
const next = this.hasSkeletonTarget ? this.skeletonTarget : null;
|
|
430
|
+
this.#revealedSkeleton = this.#reveal(this.#revealedSkeleton, next);
|
|
363
431
|
}
|
|
364
|
-
/** Reveals the optional `overlay`, noting it as this controller's to hide again. */
|
|
365
432
|
#revealOverlay() {
|
|
366
|
-
|
|
367
|
-
this.#revealedOverlay = this
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
* decides whether focus leaves the frame it covers.
|
|
375
|
-
*/
|
|
433
|
+
const next = this.hasOverlayTarget ? this.overlayTarget : null;
|
|
434
|
+
this.#revealedOverlay = this.#reveal(this.#revealedOverlay, next);
|
|
435
|
+
}
|
|
436
|
+
#reveal(revealed, next) {
|
|
437
|
+
if (revealed && revealed !== next) this.#hidden.return(revealed);
|
|
438
|
+
if (next) this.#hidden.write(next, null);
|
|
439
|
+
return next;
|
|
440
|
+
}
|
|
376
441
|
#begin() {
|
|
377
442
|
this.#loading = true;
|
|
378
443
|
this.#floor.begin();
|
|
379
|
-
this.element
|
|
380
|
-
this.element
|
|
444
|
+
this.#busy.write(this.element, "true");
|
|
445
|
+
this.#loadingHook.write(this.element, "true");
|
|
381
446
|
this.#revealSkeleton();
|
|
382
447
|
this.#revealOverlay();
|
|
383
448
|
this.#applyInert();
|
|
@@ -385,12 +450,6 @@ var FrameLoadingController = class extends Controller {
|
|
|
385
450
|
this.dispatch("start", { detail: {} });
|
|
386
451
|
announce(fillTemplate(this.announceTextValue, {}));
|
|
387
452
|
}
|
|
388
|
-
/**
|
|
389
|
-
* Leaves the loading state: restore hooks, hide skeleton/overlay, restore focus.
|
|
390
|
-
*
|
|
391
|
-
* @stimeoRuntimeOnly `announceReadyText` words the one announcement of this finished load and
|
|
392
|
-
* `restoreFocus` decides whether focus goes back.
|
|
393
|
-
*/
|
|
394
453
|
#finish() {
|
|
395
454
|
this.#loading = false;
|
|
396
455
|
this.#rewindHooks();
|
|
@@ -398,17 +457,15 @@ var FrameLoadingController = class extends Controller {
|
|
|
398
457
|
this.dispatch("end", { detail: {} });
|
|
399
458
|
announce(fillTemplate(this.announceReadyTextValue, {}));
|
|
400
459
|
}
|
|
401
|
-
/** Marks the content inert to block double-submits while stale (if we own it). */
|
|
402
460
|
#applyInert() {
|
|
403
461
|
if (!this.hasContentTarget || this.contentTarget.hasAttribute("inert")) return;
|
|
404
|
-
this.contentTarget
|
|
462
|
+
this.#inert.write(this.contentTarget, "");
|
|
405
463
|
this.#inertTarget = this.contentTarget;
|
|
406
464
|
}
|
|
407
465
|
#clearInert() {
|
|
408
|
-
this.#inertTarget
|
|
466
|
+
if (this.#inertTarget) this.#inert.return(this.#inertTarget);
|
|
409
467
|
this.#inertTarget = null;
|
|
410
468
|
}
|
|
411
|
-
/** Saves and blurs focus if it sits inside the frame about to go stale. */
|
|
412
469
|
#retreatFocus() {
|
|
413
470
|
this.#previousFocus = null;
|
|
414
471
|
this.#previousFocusId = "";
|
|
@@ -420,13 +477,6 @@ var FrameLoadingController = class extends Controller {
|
|
|
420
477
|
active.blur();
|
|
421
478
|
}
|
|
422
479
|
}
|
|
423
|
-
/**
|
|
424
|
-
* Restores focus after the load. The same node when it survived (e.g. a
|
|
425
|
-
* non-replacing update), else the element re-rendered with the same id inside the
|
|
426
|
-
* frame — Turbo frames typically re-emit the same controls. When neither is present
|
|
427
|
-
* (an anonymous control was replaced) focus is left where the browser put it, to
|
|
428
|
-
* avoid an unexpected jump (WCAG 3.2.x).
|
|
429
|
-
*/
|
|
430
480
|
#restoreFocus() {
|
|
431
481
|
const target = this.#previousFocus;
|
|
432
482
|
const id = this.#previousFocusId;
|
|
@@ -442,8 +492,16 @@ var FrameLoadingController = class extends Controller {
|
|
|
442
492
|
if (replacement && this.element.contains(replacement)) replacement.focus();
|
|
443
493
|
}
|
|
444
494
|
}
|
|
495
|
+
get #safeMinDuration() {
|
|
496
|
+
return this.#numbers.read(
|
|
497
|
+
this,
|
|
498
|
+
"minDuration",
|
|
499
|
+
this.minDurationValue,
|
|
500
|
+
_FrameLoadingController.values.minDuration.default,
|
|
501
|
+
_FrameLoadingController.valueConstraints.minDuration
|
|
502
|
+
);
|
|
503
|
+
}
|
|
445
504
|
};
|
|
446
505
|
|
|
447
506
|
export { FrameLoadingController };
|
|
448
|
-
//# sourceMappingURL=frame_loading_controller.js.map
|
|
449
507
|
//# sourceMappingURL=frame_loading_controller.js.map
|