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,34 +16,37 @@ function announce(message, options = {}) {
|
|
|
12
16
|
})
|
|
13
17
|
);
|
|
14
18
|
}
|
|
15
|
-
function fillTemplate(template, values) {
|
|
16
|
-
return template.replace(/\{([a-zA-Z][a-zA-Z0-9]*)\}/g, (match, name) => {
|
|
17
|
-
const replacement = values[name];
|
|
18
|
-
return replacement === void 0 ? match : String(replacement);
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
var ListenerSet = class {
|
|
21
|
+
#abort = new AbortController();
|
|
22
|
+
add(target, type, handler, options) {
|
|
23
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
24
|
+
}
|
|
25
|
+
dispose() {
|
|
26
|
+
this.#abort.abort();
|
|
27
|
+
this.#abort = new AbortController();
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
23
31
|
var MicrotaskCoalescer = class {
|
|
24
32
|
#run;
|
|
25
33
|
#queued = false;
|
|
26
34
|
#active = false;
|
|
27
35
|
#generation = 0;
|
|
28
|
-
/** @param run - the single reconciliation pass, invoked at most once per batch. */
|
|
29
36
|
constructor(run) {
|
|
30
37
|
this.#run = run;
|
|
31
38
|
}
|
|
32
|
-
/** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
|
|
33
39
|
activate() {
|
|
34
40
|
this.#active = true;
|
|
35
41
|
}
|
|
36
|
-
/** Closes the window and drops any pending pass; call from `disconnect()`. */
|
|
37
42
|
cancel() {
|
|
38
43
|
this.#active = false;
|
|
39
44
|
this.#queued = false;
|
|
40
45
|
this.#generation += 1;
|
|
41
46
|
}
|
|
42
|
-
|
|
47
|
+
get pending() {
|
|
48
|
+
return this.#queued;
|
|
49
|
+
}
|
|
43
50
|
schedule() {
|
|
44
51
|
if (!this.#active || this.#queued) return;
|
|
45
52
|
this.#queued = true;
|
|
@@ -52,38 +59,187 @@ var MicrotaskCoalescer = class {
|
|
|
52
59
|
}
|
|
53
60
|
};
|
|
54
61
|
|
|
55
|
-
|
|
62
|
+
var MorphRenderWatcher = class {
|
|
63
|
+
#listeners = new ListenerSet();
|
|
64
|
+
#pass;
|
|
65
|
+
#element = null;
|
|
66
|
+
#onMorph = () => this.#pass.schedule();
|
|
67
|
+
constructor(run) {
|
|
68
|
+
this.#pass = new MicrotaskCoalescer(run);
|
|
69
|
+
}
|
|
70
|
+
observe(element) {
|
|
71
|
+
if (this.#element === element) return;
|
|
72
|
+
this.disconnect();
|
|
73
|
+
this.#element = element;
|
|
74
|
+
this.#pass.activate();
|
|
75
|
+
this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
|
|
76
|
+
}
|
|
77
|
+
schedule() {
|
|
78
|
+
this.#pass.schedule();
|
|
79
|
+
}
|
|
80
|
+
get pending() {
|
|
81
|
+
return this.#pass.pending;
|
|
82
|
+
}
|
|
83
|
+
disconnect() {
|
|
84
|
+
this.#listeners.dispose();
|
|
85
|
+
this.#pass.cancel();
|
|
86
|
+
this.#element = null;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
91
|
+
|
|
92
|
+
var NUMBER_BOUNDS = {
|
|
93
|
+
positiveTimer: { finite: true, exclusiveMin: 0, max: MAX_TIMER_DELAY_MS }
|
|
94
|
+
};
|
|
95
|
+
function matchesNumberBounds(value, bounds) {
|
|
96
|
+
if (!Number.isFinite(value)) {
|
|
97
|
+
const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
|
|
98
|
+
if (direction === null) return false;
|
|
99
|
+
if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
|
|
100
|
+
}
|
|
101
|
+
if (bounds.min !== void 0 && value < bounds.min) return false;
|
|
102
|
+
if (bounds.max !== void 0 && value > bounds.max) return false;
|
|
103
|
+
if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
|
|
104
|
+
if (bounds.integer && !Number.isInteger(value)) return false;
|
|
105
|
+
if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function readNumber(raw, fallback, bounds) {
|
|
110
|
+
return matchesNumberBounds(raw, bounds) ? raw : fallback;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
var NumberValueReader = class {
|
|
114
|
+
#lastRejected = /* @__PURE__ */ new Map();
|
|
115
|
+
read(owner, name, raw, fallback, bounds) {
|
|
116
|
+
const resolved = readNumber(raw, fallback, bounds);
|
|
117
|
+
if (matchesNumberBounds(raw, bounds)) {
|
|
118
|
+
this.#lastRejected.delete(name);
|
|
119
|
+
return resolved;
|
|
120
|
+
}
|
|
121
|
+
const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
|
|
122
|
+
const literal = owner.element.getAttribute(attribute);
|
|
123
|
+
if (literal === null) {
|
|
124
|
+
this.#lastRejected.delete(name);
|
|
125
|
+
return resolved;
|
|
126
|
+
}
|
|
127
|
+
if (this.#lastRejected.get(name) !== literal) {
|
|
128
|
+
this.#lastRejected.set(name, literal);
|
|
129
|
+
console.warn(
|
|
130
|
+
`Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
return resolved;
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
138
|
+
if (element.getAttribute(name) === value) return false;
|
|
139
|
+
if (value === null) element.removeAttribute(name);
|
|
140
|
+
else element.setAttribute(name, value);
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
var OwnedText = class {
|
|
145
|
+
#attribute;
|
|
146
|
+
#channel;
|
|
147
|
+
#guard;
|
|
148
|
+
#writes = /* @__PURE__ */ new WeakMap();
|
|
149
|
+
constructor(attribute, channel = "text", guard = () => true) {
|
|
150
|
+
this.#attribute = attribute;
|
|
151
|
+
this.#channel = channel;
|
|
152
|
+
this.#guard = guard;
|
|
153
|
+
}
|
|
154
|
+
hasRecord(element) {
|
|
155
|
+
return element.hasAttribute(this.#attribute);
|
|
156
|
+
}
|
|
157
|
+
read(element, evidence = {}) {
|
|
158
|
+
if (evidence.source === "live") return this.#writes.get(element) ?? null;
|
|
159
|
+
const raw = element.getAttribute(this.#attribute);
|
|
160
|
+
if (raw === null) return null;
|
|
161
|
+
try {
|
|
162
|
+
const record = JSON.parse(raw);
|
|
163
|
+
if (!Array.isArray(record) || record.length !== 3 || record[0] !== this.#channel || typeof record[1] !== "string" || typeof record[2] !== "string")
|
|
164
|
+
return null;
|
|
165
|
+
return { original: record[1], written: record[2] };
|
|
166
|
+
} catch {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
owns(element, evidence = {}) {
|
|
171
|
+
return this.#ownedRecord(element, evidence) !== null;
|
|
172
|
+
}
|
|
173
|
+
#ownedRecord(element, evidence) {
|
|
174
|
+
const record = this.read(element, evidence);
|
|
175
|
+
if (record === null || !this.#guard(element)) return null;
|
|
176
|
+
if (this.#channel === "text" && element.firstElementChild !== null) return null;
|
|
177
|
+
const current = this.#current(element);
|
|
178
|
+
return current === record.written || evidence.source === "live" && evidence.allowOriginal === true && current === record.original ? record : null;
|
|
179
|
+
}
|
|
180
|
+
write(element, written, original, force = false) {
|
|
181
|
+
const current = this.#current(element);
|
|
182
|
+
if (current === null) return;
|
|
183
|
+
const before = original ?? this.#writes.get(element)?.original ?? this.read(element)?.original ?? current;
|
|
184
|
+
if (force || current !== written) this.#put(element, written);
|
|
185
|
+
this.remember(element, written, before);
|
|
186
|
+
}
|
|
187
|
+
remember(element, written, original) {
|
|
188
|
+
const current = this.#current(element);
|
|
189
|
+
if (current === null) return;
|
|
190
|
+
const before = original ?? this.#writes.get(element)?.original ?? this.read(element)?.original ?? current;
|
|
191
|
+
this.#writes.set(element, { original: before, written });
|
|
192
|
+
setAttributeIfChanged(
|
|
193
|
+
element,
|
|
194
|
+
this.#attribute,
|
|
195
|
+
JSON.stringify([this.#channel, before, written])
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
clear(element, evidence = {}) {
|
|
199
|
+
if (!this.owns(element, evidence)) return false;
|
|
200
|
+
if (this.#current(element) !== "") this.#put(element, "");
|
|
201
|
+
this.forget(element);
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
restore(element, evidence = {}) {
|
|
205
|
+
const record = this.#ownedRecord(element, evidence);
|
|
206
|
+
if (record === null) return false;
|
|
207
|
+
if (this.#current(element) !== record.original) this.#put(element, record.original);
|
|
208
|
+
this.forget(element);
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
forget(element) {
|
|
212
|
+
setAttributeIfChanged(element, this.#attribute, null);
|
|
213
|
+
this.#writes.delete(element);
|
|
214
|
+
}
|
|
215
|
+
#current(element) {
|
|
216
|
+
if (this.#channel === "text") return element.textContent ?? "";
|
|
217
|
+
return element instanceof HTMLInputElement ? element.value : null;
|
|
218
|
+
}
|
|
219
|
+
#put(element, text) {
|
|
220
|
+
if (this.#channel === "text") element.textContent = text;
|
|
221
|
+
else if (element instanceof HTMLInputElement) element.value = text;
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
56
225
|
var TimerRegistry = class {
|
|
57
|
-
/** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
|
|
58
226
|
ids = /* @__PURE__ */ new Set();
|
|
59
|
-
/**
|
|
60
|
-
* Cancels a single tracked timer.
|
|
61
|
-
*
|
|
62
|
-
* No-ops if the id is unknown (already cleared, fired, or never owned by this
|
|
63
|
-
* registry), so callers can clear defensively without guarding.
|
|
64
|
-
*/
|
|
65
227
|
clear(id) {
|
|
66
228
|
if (this.ids.delete(id)) {
|
|
67
229
|
this.cancel(id);
|
|
68
230
|
}
|
|
69
231
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Cancels every tracked timer. Call this from a controller's `disconnect()`
|
|
72
|
-
* to guarantee no timer outlives the element.
|
|
73
|
-
*/
|
|
74
232
|
clearAll() {
|
|
75
233
|
for (const id of this.ids) {
|
|
76
234
|
this.cancel(id);
|
|
77
235
|
}
|
|
78
236
|
this.ids.clear();
|
|
79
237
|
}
|
|
80
|
-
/** Number of timers currently tracked (pending). */
|
|
81
238
|
get size() {
|
|
82
239
|
return this.ids.size;
|
|
83
240
|
}
|
|
84
241
|
};
|
|
85
242
|
var SafeInterval = class extends TimerRegistry {
|
|
86
|
-
/** Schedules a repeating `callback` every `delay` ms and returns the timer id. */
|
|
87
243
|
set(callback, delay) {
|
|
88
244
|
const id = this.schedule(callback, delay);
|
|
89
245
|
this.ids.add(id);
|
|
@@ -97,11 +253,10 @@ var SafeInterval = class extends TimerRegistry {
|
|
|
97
253
|
}
|
|
98
254
|
};
|
|
99
255
|
|
|
100
|
-
// src/controllers/countdown_controller.ts
|
|
101
256
|
var SECOND_MS = 1e3;
|
|
102
257
|
var OWNED_STATUS = "owns-status";
|
|
103
|
-
var CountdownController = class extends Controller {
|
|
104
|
-
|
|
258
|
+
var CountdownController = class _CountdownController extends Controller {
|
|
259
|
+
#numbers = new NumberValueReader();
|
|
105
260
|
get #ownedStatus() {
|
|
106
261
|
return `data-${this.identifier}-${OWNED_STATUS}`;
|
|
107
262
|
}
|
|
@@ -114,114 +269,121 @@ var CountdownController = class extends Controller {
|
|
|
114
269
|
completeLabel: { type: String, default: "" },
|
|
115
270
|
announceText: { type: String, default: "" }
|
|
116
271
|
};
|
|
272
|
+
static valueConstraints = {
|
|
273
|
+
interval: NUMBER_BOUNDS.positiveTimer
|
|
274
|
+
};
|
|
117
275
|
static actions = ["pause", "reset", "resume", "start"];
|
|
118
276
|
static events = ["complete", "tick"];
|
|
119
277
|
#intervals = new SafeInterval();
|
|
120
278
|
#intervalId = null;
|
|
121
|
-
|
|
122
|
-
#resync = new
|
|
123
|
-
/**
|
|
124
|
-
* Whether `connect()` has run for this connection. Stimulus delivers Value
|
|
125
|
-
* callbacks ahead of it, while the run state is still the markup's own and not
|
|
126
|
-
* yet settled; `connect()` brings the status up to date once it is.
|
|
127
|
-
*/
|
|
279
|
+
#armedPeriod = 0;
|
|
280
|
+
#resync = new MorphRenderWatcher(() => this.#resyncToValues());
|
|
128
281
|
#connected = false;
|
|
129
|
-
/** Epoch-ms anchor: the deadline (down) or the count-up origin (up). */
|
|
130
282
|
#reference = 0;
|
|
131
|
-
/** Amount (ms) captured at pause, so resume can restore the same display. */
|
|
132
283
|
#pausedAmount = 0;
|
|
133
|
-
/**
|
|
134
|
-
* The amount the slots are currently showing, floored to the second they render.
|
|
135
|
-
* It lags {@link #currentAmount} by up to one tick, and it — not the live reading —
|
|
136
|
-
* is what a pause has to preserve: storing the fraction behind the display instead
|
|
137
|
-
* makes the first tick after a resume step by two units.
|
|
138
|
-
*/
|
|
139
284
|
#renderedAmount = 0;
|
|
285
|
+
#phase = "paused";
|
|
286
|
+
#valuesDirty = false;
|
|
287
|
+
#statusText = new OwnedText(this.#ownedStatus);
|
|
140
288
|
connect() {
|
|
141
289
|
this.#connected = true;
|
|
142
|
-
this.#resync.
|
|
290
|
+
this.#resync.observe(this.element);
|
|
291
|
+
this.#valuesDirty = false;
|
|
143
292
|
this.#initReference();
|
|
144
293
|
const amount = this.#currentAmount();
|
|
145
294
|
this.#render(amount);
|
|
146
295
|
this.#pausedAmount = this.#renderedAmount;
|
|
147
296
|
const authored = this.element.getAttribute("data-state");
|
|
297
|
+
this.#phase = authored ?? "paused";
|
|
148
298
|
const settled = authored === "complete" && this.#isSettled(amount);
|
|
149
299
|
if (authored === null) {
|
|
150
300
|
if (this.autostartValue && this.#isValidDeadline) this.start();
|
|
151
|
-
else this
|
|
301
|
+
else this.#setPhase("paused");
|
|
152
302
|
} else if (!settled) {
|
|
153
|
-
this
|
|
303
|
+
this.#setPhase("paused");
|
|
154
304
|
if (authored === "running") this.start();
|
|
155
305
|
}
|
|
156
306
|
this.#syncStatus();
|
|
157
307
|
}
|
|
158
308
|
disconnect() {
|
|
159
309
|
this.#connected = false;
|
|
160
|
-
this.#resync.
|
|
310
|
+
this.#resync.disconnect();
|
|
161
311
|
this.#intervals.clearAll();
|
|
162
312
|
this.#intervalId = null;
|
|
163
313
|
}
|
|
164
|
-
|
|
314
|
+
daysTargetConnected() {
|
|
315
|
+
this.#resync.schedule();
|
|
316
|
+
}
|
|
317
|
+
daysTargetDisconnected() {
|
|
318
|
+
this.#resync.schedule();
|
|
319
|
+
}
|
|
320
|
+
hoursTargetConnected() {
|
|
321
|
+
this.#resync.schedule();
|
|
322
|
+
}
|
|
323
|
+
hoursTargetDisconnected() {
|
|
324
|
+
this.#resync.schedule();
|
|
325
|
+
}
|
|
326
|
+
minutesTargetConnected() {
|
|
327
|
+
this.#resync.schedule();
|
|
328
|
+
}
|
|
329
|
+
minutesTargetDisconnected() {
|
|
330
|
+
this.#resync.schedule();
|
|
331
|
+
}
|
|
332
|
+
secondsTargetConnected() {
|
|
333
|
+
this.#resync.schedule();
|
|
334
|
+
}
|
|
335
|
+
secondsTargetDisconnected() {
|
|
336
|
+
this.#resync.schedule();
|
|
337
|
+
}
|
|
338
|
+
statusTargetConnected() {
|
|
339
|
+
this.#resync.schedule();
|
|
340
|
+
}
|
|
341
|
+
statusTargetDisconnected(status) {
|
|
342
|
+
if (!this.statusTargets.includes(status) && this.#ownsStatus(status)) {
|
|
343
|
+
this.#statusText.forget(status);
|
|
344
|
+
}
|
|
345
|
+
this.#resync.schedule();
|
|
346
|
+
}
|
|
165
347
|
deadlineValueChanged() {
|
|
348
|
+
this.#valuesDirty = true;
|
|
166
349
|
this.#resync.schedule();
|
|
167
350
|
}
|
|
168
|
-
/** Re-derives the display when a morph flips the counting direction in place. */
|
|
169
351
|
directionValueChanged() {
|
|
352
|
+
this.#valuesDirty = true;
|
|
170
353
|
this.#resync.schedule();
|
|
171
354
|
}
|
|
172
|
-
/**
|
|
173
|
-
* Follows a completion label swapped in place by a morph.
|
|
174
|
-
*
|
|
175
|
-
* Render only: `complete` is neither dispatched nor announced again. The status
|
|
176
|
-
* changes only after the countdown has completed, and only while it still shows
|
|
177
|
-
* the text this controller wrote there and nothing else, so text or an element
|
|
178
|
-
* the consumer put in the slot stays. A change delivered ahead of `connect()` is
|
|
179
|
-
* left to `connect()`.
|
|
180
|
-
*/
|
|
181
355
|
completeLabelValueChanged() {
|
|
182
356
|
if (this.#connected) this.#syncStatus();
|
|
183
357
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
*
|
|
190
|
-
* @stimeoRenderRoot
|
|
191
|
-
*/
|
|
358
|
+
intervalValueChanged() {
|
|
359
|
+
if (this.#intervalId === null || this.#armedPeriod === this.#safeInterval) return;
|
|
360
|
+
this.#teardownInterval();
|
|
361
|
+
this.#armTick();
|
|
362
|
+
}
|
|
192
363
|
#syncStatus() {
|
|
193
364
|
if (!this.hasStatusTarget || !this.#ownsStatus(this.statusTarget)) return;
|
|
194
365
|
if (this.#state === "complete") this.#writeStatus(this.statusTarget, this.completeLabelValue);
|
|
195
366
|
else this.#releaseStatus(this.statusTarget);
|
|
196
367
|
}
|
|
197
|
-
/**
|
|
198
|
-
* Points the anchor at the current `deadline` / `direction` and repaints.
|
|
199
|
-
*
|
|
200
|
-
* Render only: it starts no interval and emits no event, so a morph cannot make a
|
|
201
|
-
* paused timer run or replay a milestone. A running one needs no restart either —
|
|
202
|
-
* every tick reads the anchor, so moving it is enough. While paused the stored
|
|
203
|
-
* amount follows the new reading, or resume would continue from the old deadline.
|
|
204
|
-
* A completion the new reading no longer settles (a deadline moved forward, or a
|
|
205
|
-
* count turned `up`) is handed back paused, as `connect()` hands back a restored
|
|
206
|
-
* one, so `resume()` counts again; the completion text this controller wrote goes
|
|
207
|
-
* with it, from a status slot that still shows it and nothing else.
|
|
208
|
-
*
|
|
209
|
-
* @stimeoRenderRoot
|
|
210
|
-
*/
|
|
211
368
|
#resyncToValues() {
|
|
369
|
+
this.#setPhase(this.#state);
|
|
370
|
+
if (!this.#valuesDirty) {
|
|
371
|
+
this.#render(this.#renderedAmount);
|
|
372
|
+
this.#syncStatus();
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
this.#valuesDirty = false;
|
|
212
376
|
this.#initReference();
|
|
213
377
|
const amount = this.#currentAmount();
|
|
214
378
|
this.#render(amount);
|
|
215
|
-
if (this.#state === "
|
|
216
|
-
this
|
|
217
|
-
this.#
|
|
379
|
+
if (this.#state === "running" && !this.#isValidDeadline) {
|
|
380
|
+
this.#teardownInterval();
|
|
381
|
+
this.#setPhase("paused");
|
|
218
382
|
}
|
|
383
|
+
if (this.#state === "complete" && !this.#isSettled(amount)) this.#setPhase("paused");
|
|
219
384
|
if (this.#state !== "running") this.#pausedAmount = this.#renderedAmount;
|
|
385
|
+
this.#syncStatus();
|
|
220
386
|
}
|
|
221
|
-
/**
|
|
222
|
-
* Starts (or restarts after pause) ticking toward the deadline. Counting on from a
|
|
223
|
-
* completion takes this controller's completion text back out of the status.
|
|
224
|
-
*/
|
|
225
387
|
start() {
|
|
226
388
|
if (this.#state === "running" || !this.#isValidDeadline) return;
|
|
227
389
|
if (this.#isDown && this.#currentAmount() <= 0) {
|
|
@@ -230,36 +392,25 @@ var CountdownController = class extends Controller {
|
|
|
230
392
|
}
|
|
231
393
|
this.#runInterval();
|
|
232
394
|
}
|
|
233
|
-
/** Pauses ticking, preserving the currently displayed amount. */
|
|
234
395
|
pause() {
|
|
235
396
|
if (this.#state !== "running") return;
|
|
236
397
|
this.#pausedAmount = this.#renderedAmount;
|
|
237
398
|
this.#teardownInterval();
|
|
238
|
-
this
|
|
399
|
+
this.#setPhase("paused");
|
|
239
400
|
}
|
|
240
|
-
/** Resumes from a pause, continuing from the preserved amount. */
|
|
241
401
|
resume() {
|
|
242
402
|
if (this.#state !== "paused" || !this.#isValidDeadline) return;
|
|
243
403
|
const now = Date.now();
|
|
244
404
|
this.#reference = this.#isDown ? now + this.#pausedAmount : now - this.#pausedAmount;
|
|
245
405
|
this.start();
|
|
246
406
|
}
|
|
247
|
-
/**
|
|
248
|
-
* Re-syncs to the deadline and clears any pause offset, **preserving the current
|
|
249
|
-
* run state**: a running timer keeps counting down from the reset amount, while a
|
|
250
|
-
* paused (or completed) one resets the displayed amount but stays paused until the
|
|
251
|
-
* user resumes — it never silently restarts. The run state is read from the DOM,
|
|
252
|
-
* not re-derived from the declarative `autostart` Value (which governs only markup
|
|
253
|
-
* that states no run state at all); re-deriving it would override a user's pause —
|
|
254
|
-
* the DOM, not a re-run of declarative config, is the source of truth.
|
|
255
|
-
*/
|
|
256
407
|
reset() {
|
|
257
408
|
const wasRunning = this.#state === "running";
|
|
258
409
|
this.#teardownInterval();
|
|
259
410
|
this.#initReference();
|
|
260
411
|
const amount = this.#currentAmount();
|
|
261
412
|
this.#render(amount);
|
|
262
|
-
this
|
|
413
|
+
this.#setPhase("paused");
|
|
263
414
|
this.#syncStatus();
|
|
264
415
|
if (wasRunning && this.#isValidDeadline) {
|
|
265
416
|
this.#pausedAmount = 0;
|
|
@@ -268,29 +419,21 @@ var CountdownController = class extends Controller {
|
|
|
268
419
|
this.#pausedAmount = this.#renderedAmount;
|
|
269
420
|
}
|
|
270
421
|
}
|
|
271
|
-
/**
|
|
272
|
-
* Schedules the repeating tick and marks the timer running. This is the one way
|
|
273
|
-
* into `running`, and a running timer keeps none of this controller's completion
|
|
274
|
-
* text in the status, so the status is settled here as on every other way out of
|
|
275
|
-
* `complete`: `start()` leaves a completion directly when `direction` flips to
|
|
276
|
-
* `up` and `start()` runs in the same task, ahead of the direction callback.
|
|
277
|
-
*
|
|
278
|
-
* @stimeoRuntimeOnly `interval` is the period of the one timer this call arms; the running state
|
|
279
|
-
* it writes does not depend on a Value.
|
|
280
|
-
*/
|
|
281
422
|
#runInterval() {
|
|
282
|
-
this
|
|
423
|
+
this.#setPhase("running");
|
|
283
424
|
this.#syncStatus();
|
|
284
|
-
this.#
|
|
425
|
+
this.#armTick();
|
|
426
|
+
}
|
|
427
|
+
#armTick() {
|
|
428
|
+
this.#armedPeriod = this.#safeInterval;
|
|
429
|
+
this.#intervalId = this.#intervals.set(() => this.#tick(), this.#armedPeriod);
|
|
285
430
|
}
|
|
286
|
-
/** Cancels the repeating tick, if any. */
|
|
287
431
|
#teardownInterval() {
|
|
288
432
|
if (this.#intervalId !== null) {
|
|
289
433
|
this.#intervals.clear(this.#intervalId);
|
|
290
434
|
this.#intervalId = null;
|
|
291
435
|
}
|
|
292
436
|
}
|
|
293
|
-
/** Recomputes, renders, emits `tick`, and completes when a countdown hits 0. */
|
|
294
437
|
#tick() {
|
|
295
438
|
const amount = this.#currentAmount();
|
|
296
439
|
this.#render(amount);
|
|
@@ -301,26 +444,14 @@ var CountdownController = class extends Controller {
|
|
|
301
444
|
this.#complete();
|
|
302
445
|
}
|
|
303
446
|
}
|
|
304
|
-
/**
|
|
305
|
-
* Stops at zero, marks completion, writes the completion label, emits `complete`,
|
|
306
|
-
* and announces it.
|
|
307
|
-
*
|
|
308
|
-
* @stimeoRenderRoot
|
|
309
|
-
*/
|
|
310
447
|
#complete() {
|
|
311
448
|
this.#teardownInterval();
|
|
312
449
|
this.#render(0);
|
|
313
|
-
this
|
|
450
|
+
this.#setPhase("complete");
|
|
314
451
|
this.#claimStatus();
|
|
315
452
|
this.dispatch("complete", { detail: {} });
|
|
316
453
|
this.#announceCompletion();
|
|
317
454
|
}
|
|
318
|
-
/**
|
|
319
|
-
* Writes the label in force into the status slot as this controller's text. An
|
|
320
|
-
* empty label puts no text there: it claims a slot that is already empty — no
|
|
321
|
-
* text and no element — empties one that is still this controller's, and leaves
|
|
322
|
-
* any other slot, the consumer's, alone.
|
|
323
|
-
*/
|
|
324
455
|
#claimStatus() {
|
|
325
456
|
if (!this.hasStatusTarget) return;
|
|
326
457
|
const status = this.statusTarget;
|
|
@@ -328,54 +459,36 @@ var CountdownController = class extends Controller {
|
|
|
328
459
|
if (label === "" && !this.#isEmpty(status) && !this.#ownsStatus(status)) return;
|
|
329
460
|
this.#writeStatus(status, label);
|
|
330
461
|
}
|
|
331
|
-
/**
|
|
332
|
-
* Whether the status slot shows the text this controller wrote there and nothing
|
|
333
|
-
* else: the text matches the marker, and the slot holds no element. Writing the
|
|
334
|
-
* slot's text replaces every child node, so an element the consumer puts in the
|
|
335
|
-
* slot makes it theirs even while the text still matches. An empty marker
|
|
336
|
-
* matches the slot whenever it is empty.
|
|
337
|
-
*/
|
|
338
462
|
#ownsStatus(status) {
|
|
339
|
-
return
|
|
463
|
+
return this.#statusText.owns(status) || !this.#statusText.hasRecord(status) && this.#statusText.owns(status, { source: "live", allowOriginal: true });
|
|
340
464
|
}
|
|
341
|
-
/** Whether the status slot holds nothing at all: no text and no element. */
|
|
342
465
|
#isEmpty(status) {
|
|
343
466
|
return status.textContent === "" && status.firstElementChild === null;
|
|
344
467
|
}
|
|
345
|
-
/** Puts `text` into the status slot and records it as this controller's. */
|
|
346
468
|
#writeStatus(status, text) {
|
|
347
|
-
|
|
348
|
-
status.setAttribute(this.#ownedStatus, text);
|
|
469
|
+
this.#statusText.write(status, text);
|
|
349
470
|
}
|
|
350
|
-
/** Takes this controller's text out of the status slot, marker and all. */
|
|
351
471
|
#releaseStatus(status) {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
*
|
|
358
|
-
* @stimeoRuntimeOnly `announceText` words the one announcement a completion makes.
|
|
359
|
-
*/
|
|
472
|
+
this.#statusText.clear(
|
|
473
|
+
status,
|
|
474
|
+
this.#statusText.hasRecord(status) ? {} : { source: "live", allowOriginal: true }
|
|
475
|
+
);
|
|
476
|
+
}
|
|
360
477
|
#announceCompletion() {
|
|
361
478
|
announce(fillTemplate(this.announceTextValue, {}));
|
|
362
479
|
}
|
|
363
|
-
/** Sets the time anchor from the `deadline` value. */
|
|
364
480
|
#initReference() {
|
|
365
481
|
this.#reference = Date.parse(this.deadlineValue);
|
|
366
482
|
}
|
|
367
|
-
/** Whether a reading of `amount` leaves nothing to count: only a countdown at zero. */
|
|
368
483
|
#isSettled(amount) {
|
|
369
484
|
return this.#isDown && amount <= 0;
|
|
370
485
|
}
|
|
371
|
-
/** Remaining (down) or elapsed (up) ms, never negative. */
|
|
372
486
|
#currentAmount() {
|
|
373
487
|
if (!this.#isValidDeadline) return 0;
|
|
374
488
|
const now = Date.now();
|
|
375
489
|
const raw = this.#isDown ? this.#reference - now : now - this.#reference;
|
|
376
490
|
return Math.max(0, raw);
|
|
377
491
|
}
|
|
378
|
-
/** Writes the amount into the day/hour/minute/second slots. */
|
|
379
492
|
#render(amount) {
|
|
380
493
|
const totalSeconds = Math.floor(amount / SECOND_MS);
|
|
381
494
|
this.#renderedAmount = totalSeconds * SECOND_MS;
|
|
@@ -388,7 +501,6 @@ var CountdownController = class extends Controller {
|
|
|
388
501
|
if (this.hasMinutesTarget) this.minutesTarget.textContent = this.#pad(minutes);
|
|
389
502
|
if (this.hasSecondsTarget) this.secondsTarget.textContent = this.#pad(seconds);
|
|
390
503
|
}
|
|
391
|
-
/** Zero-pads a unit to two digits. */
|
|
392
504
|
#pad(unit) {
|
|
393
505
|
return String(unit).padStart(2, "0");
|
|
394
506
|
}
|
|
@@ -398,12 +510,23 @@ var CountdownController = class extends Controller {
|
|
|
398
510
|
get #isValidDeadline() {
|
|
399
511
|
return !Number.isNaN(this.#reference);
|
|
400
512
|
}
|
|
401
|
-
|
|
513
|
+
#setPhase(phase) {
|
|
514
|
+
this.#phase = phase;
|
|
515
|
+
this.element.setAttribute("data-state", phase);
|
|
516
|
+
}
|
|
402
517
|
get #state() {
|
|
403
|
-
return this.element.getAttribute("data-state") ??
|
|
518
|
+
return this.element.getAttribute("data-state") ?? this.#phase;
|
|
519
|
+
}
|
|
520
|
+
get #safeInterval() {
|
|
521
|
+
return this.#numbers.read(
|
|
522
|
+
this,
|
|
523
|
+
"interval",
|
|
524
|
+
this.intervalValue,
|
|
525
|
+
_CountdownController.values.interval.default,
|
|
526
|
+
_CountdownController.valueConstraints.interval
|
|
527
|
+
);
|
|
404
528
|
}
|
|
405
529
|
};
|
|
406
530
|
|
|
407
531
|
export { CountdownController };
|
|
408
|
-
//# sourceMappingURL=countdown_controller.js.map
|
|
409
532
|
//# sourceMappingURL=countdown_controller.js.map
|