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,73 +1,62 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
static
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
/** Subscribes to `turbo:before-cache`; call from `connect()`. Idempotent. */
|
|
19
|
-
activate() {
|
|
20
|
-
const first = _BeforeCacheReset.#subscribers.size === 0;
|
|
21
|
-
_BeforeCacheReset.#subscribers.add(this);
|
|
22
|
-
if (first) {
|
|
23
|
-
document.addEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
|
|
3
|
+
var DetachGate = class _DetachGate {
|
|
4
|
+
#pending = false;
|
|
5
|
+
get pending() {
|
|
6
|
+
return this.#pending;
|
|
7
|
+
}
|
|
8
|
+
static isDetached(host) {
|
|
9
|
+
return !host.element.isConnected || !_DetachGate.#listed(host);
|
|
10
|
+
}
|
|
11
|
+
disconnected(host, teardown) {
|
|
12
|
+
const carried = _DetachGate.#carried(host);
|
|
13
|
+
if (!carried && _DetachGate.isDetached(host)) {
|
|
14
|
+
this.#pending = false;
|
|
15
|
+
teardown();
|
|
16
|
+
return;
|
|
24
17
|
}
|
|
18
|
+
this.#pending = true;
|
|
19
|
+
const probe = () => {
|
|
20
|
+
if (!this.#pending) return;
|
|
21
|
+
this.#pending = false;
|
|
22
|
+
teardown();
|
|
23
|
+
};
|
|
24
|
+
if (carried) setTimeout(probe, 0);
|
|
25
|
+
else queueMicrotask(probe);
|
|
26
|
+
}
|
|
27
|
+
static #carried(host) {
|
|
28
|
+
const element = host.element;
|
|
29
|
+
return !element.isConnected && element.closest("[data-turbo-permanent]") !== null && _DetachGate.#listed(host);
|
|
30
|
+
}
|
|
31
|
+
static #listed(host) {
|
|
32
|
+
const tokens = (host.element.getAttribute("data-controller") ?? "").split(/\s+/);
|
|
33
|
+
return tokens.includes(host.identifier);
|
|
25
34
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
_BeforeCacheReset.#subscribers.delete(this);
|
|
29
|
-
if (_BeforeCacheReset.#subscribers.size > 0) return;
|
|
30
|
-
document.removeEventListener("turbo:before-cache", _BeforeCacheReset.#onBeforeCache);
|
|
35
|
+
cancel() {
|
|
36
|
+
this.#pending = false;
|
|
31
37
|
}
|
|
32
38
|
};
|
|
33
39
|
|
|
34
|
-
|
|
40
|
+
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
41
|
+
|
|
35
42
|
var TimerRegistry = class {
|
|
36
|
-
/** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
|
|
37
43
|
ids = /* @__PURE__ */ new Set();
|
|
38
|
-
/**
|
|
39
|
-
* Cancels a single tracked timer.
|
|
40
|
-
*
|
|
41
|
-
* No-ops if the id is unknown (already cleared, fired, or never owned by this
|
|
42
|
-
* registry), so callers can clear defensively without guarding.
|
|
43
|
-
*/
|
|
44
44
|
clear(id) {
|
|
45
45
|
if (this.ids.delete(id)) {
|
|
46
46
|
this.cancel(id);
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
/**
|
|
50
|
-
* Cancels every tracked timer. Call this from a controller's `disconnect()`
|
|
51
|
-
* to guarantee no timer outlives the element.
|
|
52
|
-
*/
|
|
53
49
|
clearAll() {
|
|
54
50
|
for (const id of this.ids) {
|
|
55
51
|
this.cancel(id);
|
|
56
52
|
}
|
|
57
53
|
this.ids.clear();
|
|
58
54
|
}
|
|
59
|
-
/** Number of timers currently tracked (pending). */
|
|
60
55
|
get size() {
|
|
61
56
|
return this.ids.size;
|
|
62
57
|
}
|
|
63
58
|
};
|
|
64
59
|
var SafeTimeout = class extends TimerRegistry {
|
|
65
|
-
/**
|
|
66
|
-
* Schedules `callback` after `delay` ms and returns the timer id.
|
|
67
|
-
*
|
|
68
|
-
* The id is removed from the registry automatically when the timeout fires,
|
|
69
|
-
* so {@link TimerRegistry.size | size} reflects only still-pending timers.
|
|
70
|
-
*/
|
|
71
60
|
set(callback, delay) {
|
|
72
61
|
const id = this.schedule(() => {
|
|
73
62
|
this.ids.delete(id);
|
|
@@ -84,16 +73,9 @@ var SafeTimeout = class extends TimerRegistry {
|
|
|
84
73
|
}
|
|
85
74
|
};
|
|
86
75
|
|
|
87
|
-
// src/utils/keyed_timers.ts
|
|
88
76
|
var KeyedTimers = class {
|
|
89
77
|
#timers = new SafeTimeout();
|
|
90
|
-
/** The pending timer of each key; an entry lives exactly as long as its timer. */
|
|
91
78
|
#pending = /* @__PURE__ */ new Map();
|
|
92
|
-
/**
|
|
93
|
-
* Arms `callback` after `delay` ms for `key`, cancelling the timer `key` had
|
|
94
|
-
* pending. The entry is dropped before the callback runs, so the callback sees
|
|
95
|
-
* the key unarmed and may arm it again for the next round.
|
|
96
|
-
*/
|
|
97
79
|
set(key, callback, delay) {
|
|
98
80
|
this.clear(key);
|
|
99
81
|
const id = this.#timers.set(() => {
|
|
@@ -102,52 +84,49 @@ var KeyedTimers = class {
|
|
|
102
84
|
}, delay);
|
|
103
85
|
this.#pending.set(key, id);
|
|
104
86
|
}
|
|
105
|
-
/**
|
|
106
|
-
* Cancels `key`'s pending timer, if it has one.
|
|
107
|
-
*
|
|
108
|
-
* A timer id is a positive integer, so `-1` stands for "nothing pending" and
|
|
109
|
-
* the registry ignores an id it does not own — the unarmed case needs no
|
|
110
|
-
* branch of its own, and no other key's timer can be reached from here.
|
|
111
|
-
*/
|
|
112
87
|
clear(key) {
|
|
113
88
|
this.#timers.clear(this.#pending.get(key) ?? -1);
|
|
114
89
|
this.#pending.delete(key);
|
|
115
90
|
}
|
|
116
|
-
/**
|
|
117
|
-
* Cancels every pending timer and forgets every key. Call this from a
|
|
118
|
-
* controller's `disconnect()` so no timer, and no entry, outlives the element.
|
|
119
|
-
*/
|
|
120
91
|
clearAll() {
|
|
121
92
|
this.#timers.clearAll();
|
|
122
93
|
this.#pending.clear();
|
|
123
94
|
}
|
|
124
|
-
/** Whether `key` has a timer pending. */
|
|
125
95
|
has(key) {
|
|
126
96
|
return this.#pending.has(key);
|
|
127
97
|
}
|
|
128
98
|
};
|
|
129
99
|
|
|
130
|
-
|
|
100
|
+
var ListenerSet = class {
|
|
101
|
+
#abort = new AbortController();
|
|
102
|
+
add(target, type, handler, options) {
|
|
103
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
104
|
+
}
|
|
105
|
+
dispose() {
|
|
106
|
+
this.#abort.abort();
|
|
107
|
+
this.#abort = new AbortController();
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
131
111
|
var MicrotaskCoalescer = class {
|
|
132
112
|
#run;
|
|
133
113
|
#queued = false;
|
|
134
114
|
#active = false;
|
|
135
115
|
#generation = 0;
|
|
136
|
-
/** @param run - the single reconciliation pass, invoked at most once per batch. */
|
|
137
116
|
constructor(run) {
|
|
138
117
|
this.#run = run;
|
|
139
118
|
}
|
|
140
|
-
/** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
|
|
141
119
|
activate() {
|
|
142
120
|
this.#active = true;
|
|
143
121
|
}
|
|
144
|
-
/** Closes the window and drops any pending pass; call from `disconnect()`. */
|
|
145
122
|
cancel() {
|
|
146
123
|
this.#active = false;
|
|
147
124
|
this.#queued = false;
|
|
148
125
|
this.#generation += 1;
|
|
149
126
|
}
|
|
150
|
-
|
|
127
|
+
get pending() {
|
|
128
|
+
return this.#queued;
|
|
129
|
+
}
|
|
151
130
|
schedule() {
|
|
152
131
|
if (!this.#active || this.#queued) return;
|
|
153
132
|
this.#queued = true;
|
|
@@ -160,49 +139,168 @@ var MicrotaskCoalescer = class {
|
|
|
160
139
|
}
|
|
161
140
|
};
|
|
162
141
|
|
|
163
|
-
|
|
142
|
+
var NUMBER_BOUNDS = {
|
|
143
|
+
timer: { finite: true, min: 0, max: MAX_TIMER_DELAY_MS }};
|
|
144
|
+
function matchesNumberBounds(value, bounds) {
|
|
145
|
+
if (!Number.isFinite(value)) {
|
|
146
|
+
const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
|
|
147
|
+
if (direction === null) return false;
|
|
148
|
+
if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
|
|
149
|
+
}
|
|
150
|
+
if (bounds.min !== void 0 && value < bounds.min) return false;
|
|
151
|
+
if (bounds.max !== void 0 && value > bounds.max) return false;
|
|
152
|
+
if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
|
|
153
|
+
if (bounds.integer && !Number.isInteger(value)) return false;
|
|
154
|
+
if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function readNumber(raw, fallback, bounds) {
|
|
159
|
+
return matchesNumberBounds(raw, bounds) ? raw : fallback;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
var NumberValueReader = class {
|
|
163
|
+
#lastRejected = /* @__PURE__ */ new Map();
|
|
164
|
+
read(owner, name, raw, fallback, bounds) {
|
|
165
|
+
const resolved = readNumber(raw, fallback, bounds);
|
|
166
|
+
if (matchesNumberBounds(raw, bounds)) {
|
|
167
|
+
this.#lastRejected.delete(name);
|
|
168
|
+
return resolved;
|
|
169
|
+
}
|
|
170
|
+
const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
|
|
171
|
+
const literal = owner.element.getAttribute(attribute);
|
|
172
|
+
if (literal === null) {
|
|
173
|
+
this.#lastRejected.delete(name);
|
|
174
|
+
return resolved;
|
|
175
|
+
}
|
|
176
|
+
if (this.#lastRejected.get(name) !== literal) {
|
|
177
|
+
this.#lastRejected.set(name, literal);
|
|
178
|
+
console.warn(
|
|
179
|
+
`Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
return resolved;
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
187
|
+
if (element.getAttribute(name) === value) return false;
|
|
188
|
+
if (value === null) element.removeAttribute(name);
|
|
189
|
+
else element.setAttribute(name, value);
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
var OwnedText = class {
|
|
194
|
+
#attribute;
|
|
195
|
+
#channel;
|
|
196
|
+
#guard;
|
|
197
|
+
#writes = /* @__PURE__ */ new WeakMap();
|
|
198
|
+
constructor(attribute, channel = "text", guard = () => true) {
|
|
199
|
+
this.#attribute = attribute;
|
|
200
|
+
this.#channel = channel;
|
|
201
|
+
this.#guard = guard;
|
|
202
|
+
}
|
|
203
|
+
hasRecord(element) {
|
|
204
|
+
return element.hasAttribute(this.#attribute);
|
|
205
|
+
}
|
|
206
|
+
read(element, evidence = {}) {
|
|
207
|
+
if (evidence.source === "live") return this.#writes.get(element) ?? null;
|
|
208
|
+
const raw = element.getAttribute(this.#attribute);
|
|
209
|
+
if (raw === null) return null;
|
|
210
|
+
try {
|
|
211
|
+
const record = JSON.parse(raw);
|
|
212
|
+
if (!Array.isArray(record) || record.length !== 3 || record[0] !== this.#channel || typeof record[1] !== "string" || typeof record[2] !== "string")
|
|
213
|
+
return null;
|
|
214
|
+
return { original: record[1], written: record[2] };
|
|
215
|
+
} catch {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
owns(element, evidence = {}) {
|
|
220
|
+
return this.#ownedRecord(element, evidence) !== null;
|
|
221
|
+
}
|
|
222
|
+
#ownedRecord(element, evidence) {
|
|
223
|
+
const record = this.read(element, evidence);
|
|
224
|
+
if (record === null || !this.#guard(element)) return null;
|
|
225
|
+
if (this.#channel === "text" && element.firstElementChild !== null) return null;
|
|
226
|
+
const current = this.#current(element);
|
|
227
|
+
return current === record.written || evidence.source === "live" && evidence.allowOriginal === true && current === record.original ? record : null;
|
|
228
|
+
}
|
|
229
|
+
write(element, written, original, force = false) {
|
|
230
|
+
const current = this.#current(element);
|
|
231
|
+
if (current === null) return;
|
|
232
|
+
const before = original ?? this.#writes.get(element)?.original ?? this.read(element)?.original ?? current;
|
|
233
|
+
if (force || current !== written) this.#put(element, written);
|
|
234
|
+
this.remember(element, written, before);
|
|
235
|
+
}
|
|
236
|
+
remember(element, written, original) {
|
|
237
|
+
const current = this.#current(element);
|
|
238
|
+
if (current === null) return;
|
|
239
|
+
const before = original ?? this.#writes.get(element)?.original ?? this.read(element)?.original ?? current;
|
|
240
|
+
this.#writes.set(element, { original: before, written });
|
|
241
|
+
setAttributeIfChanged(
|
|
242
|
+
element,
|
|
243
|
+
this.#attribute,
|
|
244
|
+
JSON.stringify([this.#channel, before, written])
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
clear(element, evidence = {}) {
|
|
248
|
+
if (!this.owns(element, evidence)) return false;
|
|
249
|
+
if (this.#current(element) !== "") this.#put(element, "");
|
|
250
|
+
this.forget(element);
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
restore(element, evidence = {}) {
|
|
254
|
+
const record = this.#ownedRecord(element, evidence);
|
|
255
|
+
if (record === null) return false;
|
|
256
|
+
if (this.#current(element) !== record.original) this.#put(element, record.original);
|
|
257
|
+
this.forget(element);
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
forget(element) {
|
|
261
|
+
setAttributeIfChanged(element, this.#attribute, null);
|
|
262
|
+
this.#writes.delete(element);
|
|
263
|
+
}
|
|
264
|
+
#current(element) {
|
|
265
|
+
if (this.#channel === "text") return element.textContent ?? "";
|
|
266
|
+
return element instanceof HTMLInputElement ? element.value : null;
|
|
267
|
+
}
|
|
268
|
+
#put(element, text) {
|
|
269
|
+
if (this.#channel === "text") element.textContent = text;
|
|
270
|
+
else if (element instanceof HTMLInputElement) element.value = text;
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
|
|
164
274
|
var LEVELS = ["polite", "assertive"];
|
|
165
|
-
var
|
|
275
|
+
var STAND_IN = "stand-in";
|
|
276
|
+
var ANNOUNCED = "announced";
|
|
277
|
+
var AnnouncerController = class _AnnouncerController extends Controller {
|
|
278
|
+
#numbers = new NumberValueReader();
|
|
166
279
|
static targets = ["polite", "assertive"];
|
|
167
280
|
static values = {
|
|
168
281
|
clearAfter: { type: Number, default: 1e3 },
|
|
169
282
|
dedupeReannounce: { type: Boolean, default: true }
|
|
170
283
|
};
|
|
284
|
+
static valueConstraints = {
|
|
285
|
+
clearAfter: NUMBER_BOUNDS.timer
|
|
286
|
+
};
|
|
171
287
|
static actions = ["announce"];
|
|
172
|
-
/** Drain timers, which belong to a politeness level rather than to a region. */
|
|
173
288
|
#timers = new SafeTimeout();
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
* auto-clear. A region carries at most one, and the registry releases the
|
|
177
|
-
* previous one whenever a newer message takes the region over.
|
|
178
|
-
*/
|
|
289
|
+
#gate = new DetachGate();
|
|
290
|
+
#listeners = new ListenerSet();
|
|
179
291
|
#regionTimers = new KeyedTimers();
|
|
180
|
-
/** Live regions generated to stand in for absent targets, for teardown. */
|
|
181
292
|
#generated = /* @__PURE__ */ new Map();
|
|
182
|
-
|
|
293
|
+
get #standIn() {
|
|
294
|
+
return `data-${this.identifier}-${STAND_IN}`;
|
|
295
|
+
}
|
|
296
|
+
#messageText = new OwnedText(`data-${this.identifier}-${ANNOUNCED}`);
|
|
183
297
|
#queues = /* @__PURE__ */ new Map();
|
|
184
|
-
/** Politeness levels whose next drain is already armed. */
|
|
185
298
|
#draining = /* @__PURE__ */ new Set();
|
|
186
|
-
/** Collapses a batch of target callbacks (and morph removals) into one pass. */
|
|
187
299
|
#reconcile = new MicrotaskCoalescer(() => this.#reconcileRegions());
|
|
188
|
-
/**
|
|
189
|
-
* Watches the host's own children for a generated region disappearing. A morph
|
|
190
|
-
* drops it — the server's HTML never had it — and no target callback reports
|
|
191
|
-
* that, because a generated region carries no target attribute. `subtree` stays
|
|
192
|
-
* off so writing a message inside a region does not re-enter this pass.
|
|
193
|
-
*/
|
|
194
300
|
#hostWatch = new MutationObserver(() => {
|
|
195
301
|
this.#reconcile.schedule();
|
|
196
302
|
});
|
|
197
|
-
/** Rewinds to an announceable initial state for the snapshot; see the remarks. */
|
|
198
|
-
#beforeCache = new BeforeCacheReset(() => this.#rewindForCache());
|
|
199
|
-
/**
|
|
200
|
-
* Guards against handling the same CustomEvent twice. An event dispatched on
|
|
201
|
-
* the controller element with `bubbles: true` reaches both the element and the
|
|
202
|
-
* `window` listener; this WeakSet ensures it announces only once.
|
|
203
|
-
*/
|
|
204
303
|
#handled = /* @__PURE__ */ new WeakSet();
|
|
205
|
-
/** Receives programmatic announcements at the element or bubbled to `window`. */
|
|
206
304
|
#onAnnounceEvent = (event) => {
|
|
207
305
|
if (this.#handled.has(event)) return;
|
|
208
306
|
this.#handled.add(event);
|
|
@@ -212,58 +310,47 @@ var AnnouncerController = class extends Controller {
|
|
|
212
310
|
this.#announce(message, this.#assertiveFromDetail(detail));
|
|
213
311
|
};
|
|
214
312
|
connect() {
|
|
313
|
+
const moved = this.#gate.pending;
|
|
314
|
+
this.#gate.cancel();
|
|
315
|
+
if (moved) return;
|
|
215
316
|
this.#reconcile.activate();
|
|
216
|
-
this.#
|
|
317
|
+
this.#dropInheritedStandIns();
|
|
318
|
+
this.#emptyInheritedMessages();
|
|
217
319
|
this.#reconcileRegions();
|
|
218
320
|
this.#hostWatch.observe(this.element, { childList: true });
|
|
219
|
-
this.element
|
|
220
|
-
|
|
321
|
+
this.#listeners.add(this.element, "stimeo--announcer:announce", this.#onAnnounceEvent);
|
|
322
|
+
this.#listeners.add(window, "stimeo--announcer:announce", this.#onAnnounceEvent);
|
|
221
323
|
}
|
|
222
324
|
disconnect() {
|
|
325
|
+
this.#gate.disconnected(this, () => this.#teardown());
|
|
326
|
+
}
|
|
327
|
+
#teardown() {
|
|
223
328
|
this.#reconcile.cancel();
|
|
224
329
|
this.#hostWatch.disconnect();
|
|
225
|
-
this.#
|
|
226
|
-
this.element.removeEventListener("stimeo--announcer:announce", this.#onAnnounceEvent);
|
|
227
|
-
window.removeEventListener("stimeo--announcer:announce", this.#onAnnounceEvent);
|
|
330
|
+
this.#listeners.dispose();
|
|
228
331
|
this.#timers.clearAll();
|
|
229
332
|
this.#regionTimers.clearAll();
|
|
230
333
|
this.#queues.clear();
|
|
231
334
|
this.#draining.clear();
|
|
232
335
|
this.#removeGenerated();
|
|
233
336
|
}
|
|
234
|
-
/** Retires the stand-in once the consumer supplies a polite region. */
|
|
235
337
|
politeTargetConnected() {
|
|
236
338
|
this.#reconcile.schedule();
|
|
237
339
|
}
|
|
238
|
-
/** Materialises a stand-in once the consumer's polite region goes away. */
|
|
239
340
|
politeTargetDisconnected() {
|
|
240
341
|
this.#reconcile.schedule();
|
|
241
342
|
}
|
|
242
|
-
/** Retires the stand-in once the consumer supplies an assertive region. */
|
|
243
343
|
assertiveTargetConnected() {
|
|
244
344
|
this.#reconcile.schedule();
|
|
245
345
|
}
|
|
246
|
-
/** Materialises a stand-in once the consumer's assertive region goes away. */
|
|
247
346
|
assertiveTargetDisconnected() {
|
|
248
347
|
this.#reconcile.schedule();
|
|
249
348
|
}
|
|
250
|
-
/**
|
|
251
|
-
* Brings the region set back to exactly one region per politeness and reports
|
|
252
|
-
* whether anything had to be created.
|
|
253
|
-
*
|
|
254
|
-
* A region created here is not written to in the same task: assistive tech
|
|
255
|
-
* reports changes to regions it already knows about, so {@link drain} waits a
|
|
256
|
-
* task whenever this says a region is new.
|
|
257
|
-
*/
|
|
258
349
|
#reconcileRegions() {
|
|
259
350
|
let created = false;
|
|
260
351
|
for (const level of LEVELS) {
|
|
261
352
|
if (this.#hasTargetFor(level)) {
|
|
262
|
-
|
|
263
|
-
if (generated) {
|
|
264
|
-
generated.remove();
|
|
265
|
-
this.#generated.delete(level);
|
|
266
|
-
}
|
|
353
|
+
this.#generated.get(level)?.remove();
|
|
267
354
|
continue;
|
|
268
355
|
}
|
|
269
356
|
const existing = this.#generated.get(level);
|
|
@@ -273,38 +360,31 @@ var AnnouncerController = class extends Controller {
|
|
|
273
360
|
}
|
|
274
361
|
return created;
|
|
275
362
|
}
|
|
276
|
-
/** Whether the consumer supplied a target for `level`. */
|
|
277
363
|
#hasTargetFor(level) {
|
|
278
364
|
return level === "assertive" ? this.hasAssertiveTarget : this.hasPoliteTarget;
|
|
279
365
|
}
|
|
280
|
-
/** Builds a visually hidden live region for `level` and attaches it. */
|
|
281
366
|
#createRegion(level) {
|
|
282
367
|
const region = document.createElement("div");
|
|
283
368
|
region.setAttribute("aria-live", level);
|
|
284
369
|
region.setAttribute("aria-atomic", "true");
|
|
370
|
+
region.setAttribute(this.#standIn, "");
|
|
285
371
|
visuallyHide(region);
|
|
286
372
|
this.element.appendChild(region);
|
|
287
373
|
return region;
|
|
288
374
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
region.remove();
|
|
375
|
+
#dropInheritedStandIns() {
|
|
376
|
+
for (const child of Array.from(this.element.children)) {
|
|
377
|
+
if (child.hasAttribute(this.#standIn)) child.remove();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
#emptyInheritedMessages() {
|
|
381
|
+
for (const region of [...this.politeTargets, ...this.assertiveTargets]) {
|
|
382
|
+
this.#messageText.clear(region);
|
|
298
383
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
* (`message`, plus optional `assertive`) for attribute-only triggers, falling
|
|
304
|
-
* back to a CustomEvent `detail` when the same handler is wired to an event.
|
|
305
|
-
* An empty/non-string message is ignored so untrusted payloads cannot blank
|
|
306
|
-
* the region.
|
|
307
|
-
*/
|
|
384
|
+
}
|
|
385
|
+
#removeGenerated() {
|
|
386
|
+
for (const region of this.#generated.values()) region.remove();
|
|
387
|
+
}
|
|
308
388
|
announce(event) {
|
|
309
389
|
const params = event.params;
|
|
310
390
|
const fromParam = params?.message;
|
|
@@ -313,13 +393,6 @@ var AnnouncerController = class extends Controller {
|
|
|
313
393
|
const assertive = params?.assertive === true || this.#assertiveFromDetail(event.detail);
|
|
314
394
|
this.#announce(message, assertive);
|
|
315
395
|
}
|
|
316
|
-
/**
|
|
317
|
-
* Queues `message` for its politeness and arms the drain.
|
|
318
|
-
*
|
|
319
|
-
* Queuing is what makes a burst audible: assistive tech announces the changes it
|
|
320
|
-
* observes, so several messages written into one region within a single task are
|
|
321
|
-
* one change and only the last is read.
|
|
322
|
-
*/
|
|
323
396
|
#announce(message, assertive) {
|
|
324
397
|
const level = assertive ? "assertive" : "polite";
|
|
325
398
|
const queue = this.#queues.get(level);
|
|
@@ -330,7 +403,6 @@ var AnnouncerController = class extends Controller {
|
|
|
330
403
|
}
|
|
331
404
|
this.#scheduleDrain(level);
|
|
332
405
|
}
|
|
333
|
-
/** Arms one drain pass for `level`; further messages ride the pass already armed. */
|
|
334
406
|
#scheduleDrain(level) {
|
|
335
407
|
if (this.#draining.has(level)) return;
|
|
336
408
|
this.#draining.add(level);
|
|
@@ -339,89 +411,43 @@ var AnnouncerController = class extends Controller {
|
|
|
339
411
|
this.#drain(level);
|
|
340
412
|
}, 0);
|
|
341
413
|
}
|
|
342
|
-
/**
|
|
343
|
-
* Writes one queued message, then arms the next pass while the queue holds more.
|
|
344
|
-
*
|
|
345
|
-
* Two steps take a whole pass without consuming the message: materialising a
|
|
346
|
-
* region (it has to be in the accessibility tree before the text arrives) and
|
|
347
|
-
* emptying a region that already holds this exact text (an unchanged node is not
|
|
348
|
-
* re-read, so `dedupeReannounce` clears first and writes on the following pass).
|
|
349
|
-
*
|
|
350
|
-
* @stimeoRuntimeOnly `dedupeReannounce` decides whether one queued message is spoken again; the
|
|
351
|
-
* region's text is the message itself.
|
|
352
|
-
*/
|
|
353
414
|
#drain(level) {
|
|
354
415
|
const queue = this.#queues.get(level);
|
|
355
416
|
const message = queue?.[0];
|
|
356
417
|
if (queue === void 0 || message === void 0) return;
|
|
357
|
-
|
|
418
|
+
const created = this.#reconcileRegions();
|
|
419
|
+
const region = this.#regionFor(level);
|
|
420
|
+
if (created || region === void 0) {
|
|
358
421
|
this.#scheduleDrain(level);
|
|
359
422
|
return;
|
|
360
423
|
}
|
|
361
|
-
const region = this.#regionFor(level);
|
|
362
424
|
if (this.dedupeReannounceValue && region.textContent === message) {
|
|
363
|
-
this.#regionTimers.clear(region);
|
|
364
425
|
region.textContent = "";
|
|
426
|
+
this.#messageText.forget(region);
|
|
365
427
|
this.#scheduleDrain(level);
|
|
366
428
|
return;
|
|
367
429
|
}
|
|
368
430
|
queue.shift();
|
|
369
431
|
this.#regionTimers.clear(region);
|
|
370
|
-
region
|
|
371
|
-
this.#scheduleClear(region
|
|
432
|
+
this.#messageText.write(region, message, void 0, true);
|
|
433
|
+
this.#scheduleClear(region);
|
|
372
434
|
if (queue.length > 0) this.#scheduleDrain(level);
|
|
373
435
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
*
|
|
377
|
-
* @stimeoRuntimeOnly `clearAfter` is the delay of the one clearing timer this call arms.
|
|
378
|
-
*/
|
|
379
|
-
#scheduleClear(region, message) {
|
|
380
|
-
if (this.clearAfterValue <= 0) return;
|
|
436
|
+
#scheduleClear(region) {
|
|
437
|
+
if (this.#safeClearAfter <= 0) return;
|
|
381
438
|
this.#regionTimers.set(
|
|
382
439
|
region,
|
|
383
440
|
() => {
|
|
384
|
-
|
|
441
|
+
this.#messageText.clear(region);
|
|
385
442
|
},
|
|
386
|
-
this
|
|
443
|
+
this.#safeClearAfter
|
|
387
444
|
);
|
|
388
445
|
}
|
|
389
|
-
/**
|
|
390
|
-
* Resolves the live region for a politeness level.
|
|
391
|
-
*
|
|
392
|
-
* The remembered stand-in is used only while it is still in the document: a morph
|
|
393
|
-
* can drop it, and writing into the detached node would announce nothing at all.
|
|
394
|
-
*/
|
|
395
446
|
#regionFor(level) {
|
|
396
447
|
if (level === "assertive" && this.hasAssertiveTarget) return this.assertiveTarget;
|
|
397
448
|
if (level === "polite" && this.hasPoliteTarget) return this.politeTarget;
|
|
398
|
-
|
|
399
|
-
if (existing?.isConnected) return existing;
|
|
400
|
-
const region = this.#createRegion(level);
|
|
401
|
-
this.#generated.set(level, region);
|
|
402
|
-
return region;
|
|
403
|
-
}
|
|
404
|
-
/**
|
|
405
|
-
* Restores the announceable initial state for the snapshot Turbo is about to
|
|
406
|
-
* take: queued and displayed messages go, generated regions go, and the live
|
|
407
|
-
* page — which keeps running when a visit is aborted — gets its regions back on
|
|
408
|
-
* the next task, after the clone.
|
|
409
|
-
*/
|
|
410
|
-
#rewindForCache() {
|
|
411
|
-
this.#queues.clear();
|
|
412
|
-
this.#draining.clear();
|
|
413
|
-
this.#timers.clearAll();
|
|
414
|
-
this.#regionTimers.clearAll();
|
|
415
|
-
for (const level of LEVELS) {
|
|
416
|
-
if (this.#hasTargetFor(level)) {
|
|
417
|
-
const target = level === "assertive" ? this.assertiveTarget : this.politeTarget;
|
|
418
|
-
target.textContent = "";
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
this.#removeGenerated();
|
|
422
|
-
this.#timers.set(() => this.#reconcileRegions(), 0);
|
|
449
|
+
return this.#generated.get(level);
|
|
423
450
|
}
|
|
424
|
-
/** Extracts a non-empty string `message` from a CustomEvent detail, else null. */
|
|
425
451
|
#messageFromDetail(detail) {
|
|
426
452
|
if (detail && typeof detail === "object" && "message" in detail) {
|
|
427
453
|
const value = detail.message;
|
|
@@ -429,10 +455,18 @@ var AnnouncerController = class extends Controller {
|
|
|
429
455
|
}
|
|
430
456
|
return null;
|
|
431
457
|
}
|
|
432
|
-
/** Reads an `assertive === true` flag from a CustomEvent detail (default polite). */
|
|
433
458
|
#assertiveFromDetail(detail) {
|
|
434
459
|
return !!detail && typeof detail === "object" && detail.assertive === true;
|
|
435
460
|
}
|
|
461
|
+
get #safeClearAfter() {
|
|
462
|
+
return this.#numbers.read(
|
|
463
|
+
this,
|
|
464
|
+
"clearAfter",
|
|
465
|
+
this.clearAfterValue,
|
|
466
|
+
_AnnouncerController.values.clearAfter.default,
|
|
467
|
+
_AnnouncerController.valueConstraints.clearAfter
|
|
468
|
+
);
|
|
469
|
+
}
|
|
436
470
|
};
|
|
437
471
|
function visuallyHide(node) {
|
|
438
472
|
const { style } = node;
|
|
@@ -449,5 +483,4 @@ function visuallyHide(node) {
|
|
|
449
483
|
}
|
|
450
484
|
|
|
451
485
|
export { AnnouncerController, visuallyHide };
|
|
452
|
-
//# sourceMappingURL=announcer_controller.js.map
|
|
453
486
|
//# sourceMappingURL=announcer_controller.js.map
|