stimeo-ui 0.15.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +209 -0
- package/README.md +128 -1
- package/dist/cable/index.d.ts +79 -23
- package/dist/cable/index.js +392 -417
- package/dist/cable/index.js.map +1 -1
- package/dist/controllers/accordion_controller.d.ts +34 -5
- package/dist/controllers/accordion_controller.js +228 -28
- package/dist/controllers/accordion_controller.js.map +1 -1
- package/dist/controllers/alert_dialog_controller.d.ts +20 -9
- package/dist/controllers/alert_dialog_controller.js +862 -221
- package/dist/controllers/alert_dialog_controller.js.map +1 -1
- package/dist/controllers/announcer_controller.d.ts +38 -7
- package/dist/controllers/announcer_controller.js +135 -191
- 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 +295 -110
- package/dist/controllers/auto_submit_controller.js.map +1 -1
- package/dist/controllers/avatar_controller.js +172 -106
- package/dist/controllers/avatar_controller.js.map +1 -1
- package/dist/controllers/breadcrumb_controller.d.ts +10 -7
- package/dist/controllers/breadcrumb_controller.js +0 -129
- package/dist/controllers/breadcrumb_controller.js.map +1 -1
- package/dist/controllers/bulk_select_controller.d.ts +22 -4
- package/dist/controllers/bulk_select_controller.js +264 -53
- package/dist/controllers/bulk_select_controller.js.map +1 -1
- package/dist/controllers/calendar_controller.d.ts +109 -28
- package/dist/controllers/calendar_controller.js +346 -180
- package/dist/controllers/calendar_controller.js.map +1 -1
- package/dist/controllers/carousel_controller.d.ts +99 -27
- package/dist/controllers/carousel_controller.js +587 -300
- package/dist/controllers/carousel_controller.js.map +1 -1
- package/dist/controllers/character_counter_controller.d.ts +18 -2
- package/dist/controllers/character_counter_controller.js +271 -143
- 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 +77 -75
- package/dist/controllers/checkbox_controller.js.map +1 -1
- package/dist/controllers/clipboard_controller.d.ts +44 -7
- package/dist/controllers/clipboard_controller.js +187 -108
- package/dist/controllers/clipboard_controller.js.map +1 -1
- package/dist/controllers/collapsible_controller.d.ts +41 -5
- package/dist/controllers/collapsible_controller.js +374 -108
- package/dist/controllers/collapsible_controller.js.map +1 -1
- package/dist/controllers/color_picker_controller.d.ts +47 -14
- package/dist/controllers/color_picker_controller.js +183 -127
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/combobox_controller.d.ts +33 -6
- package/dist/controllers/combobox_controller.js +426 -109
- package/dist/controllers/combobox_controller.js.map +1 -1
- package/dist/controllers/command_palette_controller.d.ts +45 -14
- package/dist/controllers/command_palette_controller.js +994 -350
- 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 +212 -125
- package/dist/controllers/conditional_fields_controller.js.map +1 -1
- package/dist/controllers/confirm_controller.d.ts +49 -12
- package/dist/controllers/confirm_controller.js +939 -245
- package/dist/controllers/confirm_controller.js.map +1 -1
- package/dist/controllers/context_menu_controller.d.ts +36 -3
- package/dist/controllers/context_menu_controller.js +275 -127
- 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 +75 -2
- package/dist/controllers/countdown_controller.js +235 -97
- package/dist/controllers/countdown_controller.js.map +1 -1
- package/dist/controllers/currency_input_controller.d.ts +93 -15
- package/dist/controllers/currency_input_controller.js +241 -118
- package/dist/controllers/currency_input_controller.js.map +1 -1
- package/dist/controllers/data_grid_controller.d.ts +78 -22
- package/dist/controllers/data_grid_controller.js +229 -135
- package/dist/controllers/data_grid_controller.js.map +1 -1
- package/dist/controllers/date_range_picker_controller.d.ts +64 -11
- package/dist/controllers/date_range_picker_controller.js +359 -165
- package/dist/controllers/date_range_picker_controller.js.map +1 -1
- package/dist/controllers/dialog_controller.d.ts +22 -3
- package/dist/controllers/dialog_controller.js +887 -225
- package/dist/controllers/dialog_controller.js.map +1 -1
- package/dist/controllers/direct_upload_controller.d.ts +24 -7
- package/dist/controllers/direct_upload_controller.js +80 -142
- package/dist/controllers/direct_upload_controller.js.map +1 -1
- package/dist/controllers/dirty_form_controller.d.ts +2 -2
- package/dist/controllers/dirty_form_controller.js +26 -47
- package/dist/controllers/dirty_form_controller.js.map +1 -1
- package/dist/controllers/dismissible_controller.d.ts +19 -0
- package/dist/controllers/dismissible_controller.js +175 -20
- package/dist/controllers/dismissible_controller.js.map +1 -1
- package/dist/controllers/drawer_controller.d.ts +52 -16
- package/dist/controllers/drawer_controller.js +963 -336
- package/dist/controllers/drawer_controller.js.map +1 -1
- package/dist/controllers/dropdown_controller.d.ts +39 -3
- package/dist/controllers/dropdown_controller.js +342 -85
- package/dist/controllers/dropdown_controller.js.map +1 -1
- package/dist/controllers/editable_controller.d.ts +12 -1
- package/dist/controllers/editable_controller.js +182 -58
- package/dist/controllers/editable_controller.js.map +1 -1
- package/dist/controllers/empty_state_controller.js +67 -53
- package/dist/controllers/empty_state_controller.js.map +1 -1
- package/dist/controllers/file_dropzone_controller.d.ts +60 -18
- package/dist/controllers/file_dropzone_controller.js +426 -229
- package/dist/controllers/file_dropzone_controller.js.map +1 -1
- package/dist/controllers/filter_controller.d.ts +10 -4
- package/dist/controllers/filter_controller.js +78 -36
- package/dist/controllers/filter_controller.js.map +1 -1
- package/dist/controllers/flash_controller.d.ts +57 -14
- package/dist/controllers/flash_controller.js +328 -211
- package/dist/controllers/flash_controller.js.map +1 -1
- package/dist/controllers/focus_controller.d.ts +12 -3
- package/dist/controllers/focus_controller.js +654 -239
- package/dist/controllers/focus_controller.js.map +1 -1
- package/dist/controllers/form_field_controller.js +153 -136
- package/dist/controllers/form_field_controller.js.map +1 -1
- package/dist/controllers/form_validation_controller.js +29 -96
- package/dist/controllers/form_validation_controller.js.map +1 -1
- package/dist/controllers/frame_loading_controller.d.ts +41 -9
- package/dist/controllers/frame_loading_controller.js +263 -198
- package/dist/controllers/frame_loading_controller.js.map +1 -1
- package/dist/controllers/highlight_controller.d.ts +22 -2
- package/dist/controllers/highlight_controller.js +119 -70
- package/dist/controllers/highlight_controller.js.map +1 -1
- package/dist/controllers/hover_card_controller.d.ts +65 -4
- package/dist/controllers/hover_card_controller.js +335 -118
- package/dist/controllers/hover_card_controller.js.map +1 -1
- package/dist/controllers/idle_controller.d.ts +58 -4
- package/dist/controllers/idle_controller.js +316 -65
- package/dist/controllers/idle_controller.js.map +1 -1
- package/dist/controllers/input_mask_controller.d.ts +5 -2
- package/dist/controllers/input_mask_controller.js +116 -61
- package/dist/controllers/input_mask_controller.js.map +1 -1
- package/dist/controllers/intersection_controller.d.ts +32 -13
- package/dist/controllers/intersection_controller.js +147 -103
- package/dist/controllers/intersection_controller.js.map +1 -1
- package/dist/controllers/lazy_frame_controller.d.ts +16 -0
- package/dist/controllers/lazy_frame_controller.js +9 -56
- package/dist/controllers/lazy_frame_controller.js.map +1 -1
- package/dist/controllers/listbox_controller.d.ts +84 -10
- package/dist/controllers/listbox_controller.js +413 -153
- package/dist/controllers/listbox_controller.js.map +1 -1
- package/dist/controllers/local_time_controller.d.ts +1 -1
- package/dist/controllers/local_time_controller.js +54 -64
- package/dist/controllers/local_time_controller.js.map +1 -1
- package/dist/controllers/masonry_controller.d.ts +11 -3
- package/dist/controllers/masonry_controller.js +70 -95
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/menu_controller.d.ts +40 -9
- package/dist/controllers/menu_controller.js +254 -167
- package/dist/controllers/menu_controller.js.map +1 -1
- package/dist/controllers/menubar_controller.d.ts +15 -4
- package/dist/controllers/menubar_controller.js +206 -331
- package/dist/controllers/menubar_controller.js.map +1 -1
- package/dist/controllers/meter_controller.d.ts +20 -0
- package/dist/controllers/meter_controller.js +159 -71
- package/dist/controllers/meter_controller.js.map +1 -1
- package/dist/controllers/multi_select_controller.d.ts +50 -7
- package/dist/controllers/multi_select_controller.js +797 -388
- package/dist/controllers/multi_select_controller.js.map +1 -1
- package/dist/controllers/navigation_menu_controller.d.ts +19 -1
- package/dist/controllers/navigation_menu_controller.js +156 -231
- 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 +373 -174
- 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 +241 -45
- package/dist/controllers/network_status_controller.js.map +1 -1
- package/dist/controllers/number_input_controller.d.ts +62 -10
- package/dist/controllers/number_input_controller.js +387 -227
- package/dist/controllers/number_input_controller.js.map +1 -1
- package/dist/controllers/optimistic_controller.js +28 -75
- package/dist/controllers/optimistic_controller.js.map +1 -1
- package/dist/controllers/otp_controller.d.ts +38 -7
- package/dist/controllers/otp_controller.js +344 -196
- package/dist/controllers/otp_controller.js.map +1 -1
- package/dist/controllers/overflow_indicator_controller.d.ts +13 -12
- package/dist/controllers/overflow_indicator_controller.js +167 -93
- package/dist/controllers/overflow_indicator_controller.js.map +1 -1
- package/dist/controllers/overflow_menu_controller.d.ts +66 -9
- package/dist/controllers/overflow_menu_controller.js +408 -277
- package/dist/controllers/overflow_menu_controller.js.map +1 -1
- package/dist/controllers/pagination_controller.d.ts +52 -15
- package/dist/controllers/pagination_controller.js +342 -120
- package/dist/controllers/pagination_controller.js.map +1 -1
- package/dist/controllers/password_reveal_controller.d.ts +60 -9
- package/dist/controllers/password_reveal_controller.js +424 -99
- package/dist/controllers/password_reveal_controller.js.map +1 -1
- package/dist/controllers/password_strength_controller.d.ts +14 -5
- package/dist/controllers/password_strength_controller.js +99 -153
- package/dist/controllers/password_strength_controller.js.map +1 -1
- package/dist/controllers/persist_controller.d.ts +11 -4
- package/dist/controllers/persist_controller.js +252 -96
- package/dist/controllers/persist_controller.js.map +1 -1
- package/dist/controllers/pointer_drag_controller.d.ts +19 -7
- package/dist/controllers/pointer_drag_controller.js +263 -164
- package/dist/controllers/pointer_drag_controller.js.map +1 -1
- package/dist/controllers/popover_controller.d.ts +46 -4
- package/dist/controllers/popover_controller.js +267 -94
- package/dist/controllers/popover_controller.js.map +1 -1
- package/dist/controllers/portal_controller.d.ts +44 -4
- package/dist/controllers/portal_controller.js +209 -72
- 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 -112
- package/dist/controllers/preview_guard_controller.js.map +1 -1
- package/dist/controllers/progress_controller.d.ts +11 -0
- package/dist/controllers/progress_controller.js +132 -59
- package/dist/controllers/progress_controller.js.map +1 -1
- package/dist/controllers/radio_group_controller.d.ts +19 -8
- package/dist/controllers/radio_group_controller.js +138 -133
- package/dist/controllers/radio_group_controller.js.map +1 -1
- package/dist/controllers/range_slider_controller.d.ts +92 -4
- package/dist/controllers/range_slider_controller.js +245 -112
- package/dist/controllers/range_slider_controller.js.map +1 -1
- package/dist/controllers/rating_controller.d.ts +33 -6
- package/dist/controllers/rating_controller.js +429 -194
- package/dist/controllers/rating_controller.js.map +1 -1
- package/dist/controllers/read_more_controller.d.ts +26 -2
- package/dist/controllers/read_more_controller.js +185 -47
- package/dist/controllers/read_more_controller.js.map +1 -1
- package/dist/controllers/reading_progress_controller.d.ts +1 -1
- package/dist/controllers/reading_progress_controller.js +147 -135
- package/dist/controllers/reading_progress_controller.js.map +1 -1
- package/dist/controllers/relative_time_controller.d.ts +18 -4
- package/dist/controllers/relative_time_controller.js +145 -110
- package/dist/controllers/relative_time_controller.js.map +1 -1
- package/dist/controllers/reset_on_restore_controller.d.ts +85 -0
- package/dist/controllers/{reset_before_cache_controller.js → reset_on_restore_controller.js} +97 -38
- package/dist/controllers/reset_on_restore_controller.js.map +1 -0
- package/dist/controllers/resizable_controller.d.ts +44 -4
- package/dist/controllers/resizable_controller.js +294 -118
- package/dist/controllers/resizable_controller.js.map +1 -1
- package/dist/controllers/roving_controller.js +39 -84
- package/dist/controllers/roving_controller.js.map +1 -1
- package/dist/controllers/scroll_area_controller.d.ts +7 -3
- package/dist/controllers/scroll_area_controller.js +428 -221
- package/dist/controllers/scroll_area_controller.js.map +1 -1
- package/dist/controllers/scroll_restore_controller.js +0 -53
- package/dist/controllers/scroll_restore_controller.js.map +1 -1
- package/dist/controllers/scroll_visibility_controller.d.ts +28 -12
- package/dist/controllers/scroll_visibility_controller.js +395 -146
- package/dist/controllers/scroll_visibility_controller.js.map +1 -1
- package/dist/controllers/scrollspy_controller.d.ts +9 -3
- package/dist/controllers/scrollspy_controller.js +181 -236
- package/dist/controllers/scrollspy_controller.js.map +1 -1
- package/dist/controllers/separator_controller.d.ts +59 -17
- package/dist/controllers/separator_controller.js +288 -132
- package/dist/controllers/separator_controller.js.map +1 -1
- package/dist/controllers/sidebar_controller.d.ts +81 -7
- package/dist/controllers/sidebar_controller.js +1071 -375
- package/dist/controllers/sidebar_controller.js.map +1 -1
- package/dist/controllers/skeleton_controller.d.ts +23 -0
- package/dist/controllers/skeleton_controller.js +248 -92
- package/dist/controllers/skeleton_controller.js.map +1 -1
- package/dist/controllers/slider_controller.d.ts +72 -8
- package/dist/controllers/slider_controller.js +211 -96
- package/dist/controllers/slider_controller.js.map +1 -1
- package/dist/controllers/smart_sticky_header_controller.d.ts +21 -3
- package/dist/controllers/smart_sticky_header_controller.js +163 -54
- package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
- package/dist/controllers/sortable_controller.js +13 -110
- package/dist/controllers/sortable_controller.js.map +1 -1
- package/dist/controllers/spinner_controller.d.ts +39 -4
- package/dist/controllers/spinner_controller.js +277 -161
- package/dist/controllers/spinner_controller.js.map +1 -1
- package/dist/controllers/step_indicator_controller.d.ts +24 -17
- package/dist/controllers/step_indicator_controller.js +107 -53
- package/dist/controllers/step_indicator_controller.js.map +1 -1
- package/dist/controllers/stepper_controller.d.ts +43 -9
- package/dist/controllers/stepper_controller.js +171 -48
- package/dist/controllers/stepper_controller.js.map +1 -1
- package/dist/controllers/stick_to_bottom_controller.d.ts +25 -0
- package/dist/controllers/stick_to_bottom_controller.js +310 -116
- package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
- package/dist/controllers/sticky_observer_controller.d.ts +11 -0
- package/dist/controllers/sticky_observer_controller.js +214 -49
- package/dist/controllers/sticky_observer_controller.js.map +1 -1
- package/dist/controllers/submit_once_controller.d.ts +22 -6
- package/dist/controllers/submit_once_controller.js +294 -192
- package/dist/controllers/submit_once_controller.js.map +1 -1
- package/dist/controllers/switch_controller.d.ts +40 -7
- package/dist/controllers/switch_controller.js +107 -43
- package/dist/controllers/switch_controller.js.map +1 -1
- package/dist/controllers/tabs_controller.d.ts +13 -1
- package/dist/controllers/tabs_controller.js +50 -25
- package/dist/controllers/tabs_controller.js.map +1 -1
- package/dist/controllers/tags_input_controller.d.ts +27 -3
- package/dist/controllers/tags_input_controller.js +290 -149
- package/dist/controllers/tags_input_controller.js.map +1 -1
- package/dist/controllers/textarea_autosize_controller.d.ts +10 -0
- package/dist/controllers/textarea_autosize_controller.js +71 -58
- package/dist/controllers/textarea_autosize_controller.js.map +1 -1
- package/dist/controllers/theme_controller.d.ts +37 -8
- package/dist/controllers/theme_controller.js +148 -80
- package/dist/controllers/theme_controller.js.map +1 -1
- package/dist/controllers/time_picker_controller.d.ts +18 -1
- package/dist/controllers/time_picker_controller.js +162 -81
- package/dist/controllers/time_picker_controller.js.map +1 -1
- package/dist/controllers/toast_controller.d.ts +85 -23
- package/dist/controllers/toast_controller.js +365 -193
- package/dist/controllers/toast_controller.js.map +1 -1
- package/dist/controllers/toggle_group_controller.d.ts +60 -9
- package/dist/controllers/toggle_group_controller.js +194 -99
- package/dist/controllers/toggle_group_controller.js.map +1 -1
- package/dist/controllers/toolbar_controller.js +92 -90
- package/dist/controllers/toolbar_controller.js.map +1 -1
- package/dist/controllers/tooltip_controller.d.ts +52 -2
- package/dist/controllers/tooltip_controller.js +185 -125
- 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 -115
- package/dist/controllers/transition_controller.js.map +1 -1
- package/dist/controllers/tree_view_controller.d.ts +59 -18
- package/dist/controllers/tree_view_controller.js +248 -290
- package/dist/controllers/tree_view_controller.js.map +1 -1
- package/dist/index.d.ts +33 -3
- package/dist/index.js +8649 -8572
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.d.ts +95 -9
- package/dist/inspector/cli.js +343 -77
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +390 -96
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +45 -45
- package/dist/inspector/manifest.json +1308 -155
- package/dist/positioning/index.d.ts +8 -0
- package/dist/positioning/index.js +148 -45
- package/dist/positioning/index.js.map +1 -1
- package/package.json +7 -7
- package/dist/controllers/reset_before_cache_controller.d.ts +0 -76
- package/dist/controllers/reset_before_cache_controller.js.map +0 -1
|
@@ -24,6 +24,22 @@ import { Controller } from '@hotwired/stimulus';
|
|
|
24
24
|
* slot free of live-region semantics: with `announceText` set it would say the
|
|
25
25
|
* same thing twice.
|
|
26
26
|
*
|
|
27
|
+
* The slot is shared with the consumer. Completion writes the label in force and
|
|
28
|
+
* marks it with `data-<identifier>-owns-status`, whose value is that text; while
|
|
29
|
+
* the slot still shows that text and nothing else, the controller keeps it on the
|
|
30
|
+
* current `completeLabel` and takes it back once the timer leaves the complete
|
|
31
|
+
* state — `reset`, `start()` counting on from it, or a completion the new reading
|
|
32
|
+
* does not settle (a deadline moved forward or a count turned `up`, in place or
|
|
33
|
+
* before a restore). All but `start()` leave it `paused`, so `resume()` counts
|
|
34
|
+
* again.
|
|
35
|
+
* An empty label puts no text there, so it never displaces what the slot already
|
|
36
|
+
* holds; completing with one claims an empty slot — no text and no element — with
|
|
37
|
+
* an empty marker, which owns the slot whenever it is empty. Text the consumer put
|
|
38
|
+
* there stays theirs while it is there, and so does a slot they put an element in,
|
|
39
|
+
* whatever its text: the label is neither followed into it nor taken back out of
|
|
40
|
+
* it, and its marker stays, until the element is gone. Only a completion with a
|
|
41
|
+
* label writes over either.
|
|
42
|
+
*
|
|
27
43
|
* `complete` dispatches `{}`; `tick` dispatches
|
|
28
44
|
* `{ remaining: number, direction: "down" | "up" }`, where `remaining` is in
|
|
29
45
|
* milliseconds.
|
|
@@ -37,7 +53,10 @@ import { Controller } from '@hotwired/stimulus';
|
|
|
37
53
|
* source of truth — `autostart` only decides the state of a timer whose markup does
|
|
38
54
|
* not carry one. The interval is owned by `SafeInterval` and torn down on
|
|
39
55
|
* `disconnect()` (Turbo navigation included); nothing else needs carrying across,
|
|
40
|
-
* because every reading is re-derived from `deadline` and the wall clock.
|
|
56
|
+
* because every reading is re-derived from `deadline` and the wall clock. A change to
|
|
57
|
+
* `interval` while the timer runs re-arms the tick at the new period, keeping the run
|
|
58
|
+
* state, the reading and the completion; a paused or completed timer picks it up when
|
|
59
|
+
* it next runs.
|
|
41
60
|
*/
|
|
42
61
|
declare class CountdownController extends Controller<HTMLElement> {
|
|
43
62
|
#private;
|
|
@@ -68,6 +87,13 @@ declare class CountdownController extends Controller<HTMLElement> {
|
|
|
68
87
|
default: string;
|
|
69
88
|
};
|
|
70
89
|
};
|
|
90
|
+
static valueConstraints: {
|
|
91
|
+
interval: {
|
|
92
|
+
readonly finite: true;
|
|
93
|
+
readonly exclusiveMin: 0;
|
|
94
|
+
readonly max: 2147483647;
|
|
95
|
+
};
|
|
96
|
+
};
|
|
71
97
|
static actions: readonly ["pause", "reset", "resume", "start"];
|
|
72
98
|
static events: readonly ["complete", "tick"];
|
|
73
99
|
readonly daysTarget: HTMLElement;
|
|
@@ -75,6 +101,7 @@ declare class CountdownController extends Controller<HTMLElement> {
|
|
|
75
101
|
readonly minutesTarget: HTMLElement;
|
|
76
102
|
readonly secondsTarget: HTMLElement;
|
|
77
103
|
readonly statusTarget: HTMLElement;
|
|
104
|
+
readonly statusTargets: HTMLElement[];
|
|
78
105
|
readonly hasDaysTarget: boolean;
|
|
79
106
|
readonly hasHoursTarget: boolean;
|
|
80
107
|
readonly hasMinutesTarget: boolean;
|
|
@@ -88,11 +115,57 @@ declare class CountdownController extends Controller<HTMLElement> {
|
|
|
88
115
|
announceTextValue: string;
|
|
89
116
|
connect(): void;
|
|
90
117
|
disconnect(): void;
|
|
118
|
+
/** Writes the reading on screen into a days slot that arrives at runtime. */
|
|
119
|
+
daysTargetConnected(): void;
|
|
120
|
+
/** Writes the reading on screen into the days slot that stays after another leaves. */
|
|
121
|
+
daysTargetDisconnected(): void;
|
|
122
|
+
/** Writes the reading on screen into an hours slot that arrives at runtime. */
|
|
123
|
+
hoursTargetConnected(): void;
|
|
124
|
+
/** Writes the reading on screen into the hours slot that stays after another leaves. */
|
|
125
|
+
hoursTargetDisconnected(): void;
|
|
126
|
+
/** Writes the reading on screen into a minutes slot that arrives at runtime. */
|
|
127
|
+
minutesTargetConnected(): void;
|
|
128
|
+
/** Writes the reading on screen into the minutes slot that stays after another leaves. */
|
|
129
|
+
minutesTargetDisconnected(): void;
|
|
130
|
+
/** Writes the reading on screen into a seconds slot that arrives at runtime. */
|
|
131
|
+
secondsTargetConnected(): void;
|
|
132
|
+
/** Writes the reading on screen into the seconds slot that stays after another leaves. */
|
|
133
|
+
secondsTargetDisconnected(): void;
|
|
134
|
+
/** Brings a status that arrives at runtime, when it shows this controller's text, in line. */
|
|
135
|
+
statusTargetConnected(): void;
|
|
136
|
+
/**
|
|
137
|
+
* Takes the claim off a status that no longer resolves, even after `disconnect()`, when
|
|
138
|
+
* it still shows this controller's text alone; the text stays. Brings the status that
|
|
139
|
+
* stays in line.
|
|
140
|
+
*/
|
|
141
|
+
statusTargetDisconnected(status: HTMLElement): void;
|
|
91
142
|
/** Re-derives the display when a morph swaps the deadline in place. */
|
|
92
143
|
deadlineValueChanged(): void;
|
|
93
144
|
/** Re-derives the display when a morph flips the counting direction in place. */
|
|
94
145
|
directionValueChanged(): void;
|
|
95
|
-
/**
|
|
146
|
+
/**
|
|
147
|
+
* Follows a completion label swapped in place by a morph.
|
|
148
|
+
*
|
|
149
|
+
* Render only: `complete` is neither dispatched nor announced again. The status
|
|
150
|
+
* changes only after the countdown has completed, and only while it still shows
|
|
151
|
+
* the text this controller wrote there and nothing else, so text or an element
|
|
152
|
+
* the consumer put in the slot stays. A change delivered ahead of `connect()` is
|
|
153
|
+
* left to `connect()`.
|
|
154
|
+
*/
|
|
155
|
+
completeLabelValueChanged(): void;
|
|
156
|
+
/**
|
|
157
|
+
* Follows a tick period changed at runtime. A running countdown swaps its one interval
|
|
158
|
+
* for one at the new period, starting from now; its run state, reading, deadline and
|
|
159
|
+
* completion are untouched, and nothing ticks or repaints until the next period ends. A
|
|
160
|
+
* paused or completed countdown starts nothing and uses the new period when it next
|
|
161
|
+
* runs, and a declaration that resolves to the period already running changes nothing.
|
|
162
|
+
* Stimulus also calls this ahead of `connect()`, when no interval runs.
|
|
163
|
+
*/
|
|
164
|
+
intervalValueChanged(): void;
|
|
165
|
+
/**
|
|
166
|
+
* Starts (or restarts after pause) ticking toward the deadline. Counting on from a
|
|
167
|
+
* completion takes this controller's completion text back out of the status.
|
|
168
|
+
*/
|
|
96
169
|
start(): void;
|
|
97
170
|
/** Pauses ticking, preserving the currently displayed amount. */
|
|
98
171
|
pause(): void;
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
// src/controllers/countdown_controller.ts
|
|
4
|
-
|
|
5
|
-
// src/utils/announce.ts
|
|
6
3
|
function announce(message, options = {}) {
|
|
7
4
|
const text = message.trim();
|
|
8
5
|
if (text.length === 0) return;
|
|
@@ -19,27 +16,33 @@ function fillTemplate(template, values) {
|
|
|
19
16
|
});
|
|
20
17
|
}
|
|
21
18
|
|
|
22
|
-
|
|
19
|
+
var ListenerSet = class {
|
|
20
|
+
#abort = new AbortController();
|
|
21
|
+
add(target, type, handler, options) {
|
|
22
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
23
|
+
}
|
|
24
|
+
dispose() {
|
|
25
|
+
this.#abort.abort();
|
|
26
|
+
this.#abort = new AbortController();
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
23
30
|
var MicrotaskCoalescer = class {
|
|
24
31
|
#run;
|
|
25
32
|
#queued = false;
|
|
26
33
|
#active = false;
|
|
27
34
|
#generation = 0;
|
|
28
|
-
/** @param run - the single reconciliation pass, invoked at most once per batch. */
|
|
29
35
|
constructor(run) {
|
|
30
36
|
this.#run = run;
|
|
31
37
|
}
|
|
32
|
-
/** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
|
|
33
38
|
activate() {
|
|
34
39
|
this.#active = true;
|
|
35
40
|
}
|
|
36
|
-
/** Closes the window and drops any pending pass; call from `disconnect()`. */
|
|
37
41
|
cancel() {
|
|
38
42
|
this.#active = false;
|
|
39
43
|
this.#queued = false;
|
|
40
44
|
this.#generation += 1;
|
|
41
45
|
}
|
|
42
|
-
/** Requests one pass after the batch settles. Idempotent; inert outside the window. */
|
|
43
46
|
schedule() {
|
|
44
47
|
if (!this.#active || this.#queued) return;
|
|
45
48
|
this.#queued = true;
|
|
@@ -52,38 +55,96 @@ var MicrotaskCoalescer = class {
|
|
|
52
55
|
}
|
|
53
56
|
};
|
|
54
57
|
|
|
55
|
-
|
|
58
|
+
var MorphRenderWatcher = class {
|
|
59
|
+
#listeners = new ListenerSet();
|
|
60
|
+
#pass;
|
|
61
|
+
#element = null;
|
|
62
|
+
#onMorph = () => this.#pass.schedule();
|
|
63
|
+
constructor(run) {
|
|
64
|
+
this.#pass = new MicrotaskCoalescer(run);
|
|
65
|
+
}
|
|
66
|
+
observe(element) {
|
|
67
|
+
if (this.#element === element) return;
|
|
68
|
+
this.disconnect();
|
|
69
|
+
this.#element = element;
|
|
70
|
+
this.#pass.activate();
|
|
71
|
+
this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
|
|
72
|
+
}
|
|
73
|
+
schedule() {
|
|
74
|
+
this.#pass.schedule();
|
|
75
|
+
}
|
|
76
|
+
disconnect() {
|
|
77
|
+
this.#listeners.dispose();
|
|
78
|
+
this.#pass.cancel();
|
|
79
|
+
this.#element = null;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
var MAX_TIMER_DELAY_MS = 2147483647;
|
|
84
|
+
|
|
85
|
+
var NUMBER_BOUNDS = {
|
|
86
|
+
positiveTimer: { finite: true, exclusiveMin: 0, max: MAX_TIMER_DELAY_MS }
|
|
87
|
+
};
|
|
88
|
+
function matchesNumberBounds(value, bounds) {
|
|
89
|
+
if (!Number.isFinite(value)) {
|
|
90
|
+
const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
|
|
91
|
+
if (direction === null) return false;
|
|
92
|
+
if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
|
|
93
|
+
}
|
|
94
|
+
if (bounds.min !== void 0 && value < bounds.min) return false;
|
|
95
|
+
if (bounds.max !== void 0 && value > bounds.max) return false;
|
|
96
|
+
if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
|
|
97
|
+
if (bounds.integer && !Number.isInteger(value)) return false;
|
|
98
|
+
if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function readNumber(raw, fallback, bounds) {
|
|
103
|
+
return matchesNumberBounds(raw, bounds) ? raw : fallback;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
var NumberValueReader = class {
|
|
107
|
+
#lastRejected = /* @__PURE__ */ new Map();
|
|
108
|
+
read(owner, name, raw, fallback, bounds) {
|
|
109
|
+
const resolved = readNumber(raw, fallback, bounds);
|
|
110
|
+
if (matchesNumberBounds(raw, bounds)) {
|
|
111
|
+
this.#lastRejected.delete(name);
|
|
112
|
+
return resolved;
|
|
113
|
+
}
|
|
114
|
+
const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
|
|
115
|
+
const literal = owner.element.getAttribute(attribute);
|
|
116
|
+
if (literal === null) {
|
|
117
|
+
this.#lastRejected.delete(name);
|
|
118
|
+
return resolved;
|
|
119
|
+
}
|
|
120
|
+
if (this.#lastRejected.get(name) !== literal) {
|
|
121
|
+
this.#lastRejected.set(name, literal);
|
|
122
|
+
console.warn(
|
|
123
|
+
`Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
return resolved;
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
56
130
|
var TimerRegistry = class {
|
|
57
|
-
/** Live timer ids that have not yet been cleared (or, for timeouts, fired). */
|
|
58
131
|
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
132
|
clear(id) {
|
|
66
133
|
if (this.ids.delete(id)) {
|
|
67
134
|
this.cancel(id);
|
|
68
135
|
}
|
|
69
136
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Cancels every tracked timer. Call this from a controller's `disconnect()`
|
|
72
|
-
* to guarantee no timer outlives the element.
|
|
73
|
-
*/
|
|
74
137
|
clearAll() {
|
|
75
138
|
for (const id of this.ids) {
|
|
76
139
|
this.cancel(id);
|
|
77
140
|
}
|
|
78
141
|
this.ids.clear();
|
|
79
142
|
}
|
|
80
|
-
/** Number of timers currently tracked (pending). */
|
|
81
143
|
get size() {
|
|
82
144
|
return this.ids.size;
|
|
83
145
|
}
|
|
84
146
|
};
|
|
85
147
|
var SafeInterval = class extends TimerRegistry {
|
|
86
|
-
/** Schedules a repeating `callback` every `delay` ms and returns the timer id. */
|
|
87
148
|
set(callback, delay) {
|
|
88
149
|
const id = this.schedule(callback, delay);
|
|
89
150
|
this.ids.add(id);
|
|
@@ -97,9 +158,13 @@ var SafeInterval = class extends TimerRegistry {
|
|
|
97
158
|
}
|
|
98
159
|
};
|
|
99
160
|
|
|
100
|
-
// src/controllers/countdown_controller.ts
|
|
101
161
|
var SECOND_MS = 1e3;
|
|
102
|
-
var
|
|
162
|
+
var OWNED_STATUS = "owns-status";
|
|
163
|
+
var CountdownController = class _CountdownController extends Controller {
|
|
164
|
+
#numbers = new NumberValueReader();
|
|
165
|
+
get #ownedStatus() {
|
|
166
|
+
return `data-${this.identifier}-${OWNED_STATUS}`;
|
|
167
|
+
}
|
|
103
168
|
static targets = ["days", "hours", "minutes", "seconds", "status"];
|
|
104
169
|
static values = {
|
|
105
170
|
deadline: { type: String, default: "" },
|
|
@@ -109,72 +174,122 @@ var CountdownController = class extends Controller {
|
|
|
109
174
|
completeLabel: { type: String, default: "" },
|
|
110
175
|
announceText: { type: String, default: "" }
|
|
111
176
|
};
|
|
177
|
+
static valueConstraints = {
|
|
178
|
+
interval: NUMBER_BOUNDS.positiveTimer
|
|
179
|
+
};
|
|
112
180
|
static actions = ["pause", "reset", "resume", "start"];
|
|
113
181
|
static events = ["complete", "tick"];
|
|
114
182
|
#intervals = new SafeInterval();
|
|
115
183
|
#intervalId = null;
|
|
116
|
-
|
|
117
|
-
#resync = new
|
|
118
|
-
|
|
184
|
+
#armedPeriod = 0;
|
|
185
|
+
#resync = new MorphRenderWatcher(() => this.#resyncToValues());
|
|
186
|
+
#connected = false;
|
|
119
187
|
#reference = 0;
|
|
120
|
-
/** Amount (ms) captured at pause, so resume can restore the same display. */
|
|
121
188
|
#pausedAmount = 0;
|
|
122
|
-
/**
|
|
123
|
-
* The amount the slots are currently showing, floored to the second they render.
|
|
124
|
-
* It lags {@link #currentAmount} by up to one tick, and it — not the live reading —
|
|
125
|
-
* is what a pause has to preserve: storing the fraction behind the display instead
|
|
126
|
-
* makes the first tick after a resume step by two units.
|
|
127
|
-
*/
|
|
128
189
|
#renderedAmount = 0;
|
|
190
|
+
#phase = "paused";
|
|
191
|
+
#valuesDirty = false;
|
|
192
|
+
#statusWrites = /* @__PURE__ */ new WeakMap();
|
|
129
193
|
connect() {
|
|
130
|
-
this.#
|
|
194
|
+
this.#connected = true;
|
|
195
|
+
this.#resync.observe(this.element);
|
|
196
|
+
this.#valuesDirty = false;
|
|
131
197
|
this.#initReference();
|
|
132
198
|
const amount = this.#currentAmount();
|
|
133
199
|
this.#render(amount);
|
|
134
200
|
this.#pausedAmount = this.#renderedAmount;
|
|
135
201
|
const authored = this.element.getAttribute("data-state");
|
|
202
|
+
this.#phase = authored ?? "paused";
|
|
203
|
+
const settled = authored === "complete" && this.#isSettled(amount);
|
|
136
204
|
if (authored === null) {
|
|
137
|
-
if (this.autostartValue && this.#isValidDeadline)
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
return;
|
|
205
|
+
if (this.autostartValue && this.#isValidDeadline) this.start();
|
|
206
|
+
else this.#setPhase("paused");
|
|
207
|
+
} else if (!settled) {
|
|
208
|
+
this.#setPhase("paused");
|
|
209
|
+
if (authored === "running") this.start();
|
|
143
210
|
}
|
|
144
|
-
|
|
145
|
-
return;
|
|
146
|
-
}
|
|
147
|
-
const wasRunning = authored === "running";
|
|
148
|
-
this.element.setAttribute("data-state", "paused");
|
|
149
|
-
if (wasRunning) this.start();
|
|
211
|
+
this.#syncStatus();
|
|
150
212
|
}
|
|
151
213
|
disconnect() {
|
|
152
|
-
this.#
|
|
214
|
+
this.#connected = false;
|
|
215
|
+
this.#resync.disconnect();
|
|
153
216
|
this.#intervals.clearAll();
|
|
154
217
|
this.#intervalId = null;
|
|
155
218
|
}
|
|
156
|
-
|
|
219
|
+
daysTargetConnected() {
|
|
220
|
+
this.#resync.schedule();
|
|
221
|
+
}
|
|
222
|
+
daysTargetDisconnected() {
|
|
223
|
+
this.#resync.schedule();
|
|
224
|
+
}
|
|
225
|
+
hoursTargetConnected() {
|
|
226
|
+
this.#resync.schedule();
|
|
227
|
+
}
|
|
228
|
+
hoursTargetDisconnected() {
|
|
229
|
+
this.#resync.schedule();
|
|
230
|
+
}
|
|
231
|
+
minutesTargetConnected() {
|
|
232
|
+
this.#resync.schedule();
|
|
233
|
+
}
|
|
234
|
+
minutesTargetDisconnected() {
|
|
235
|
+
this.#resync.schedule();
|
|
236
|
+
}
|
|
237
|
+
secondsTargetConnected() {
|
|
238
|
+
this.#resync.schedule();
|
|
239
|
+
}
|
|
240
|
+
secondsTargetDisconnected() {
|
|
241
|
+
this.#resync.schedule();
|
|
242
|
+
}
|
|
243
|
+
statusTargetConnected() {
|
|
244
|
+
this.#resync.schedule();
|
|
245
|
+
}
|
|
246
|
+
statusTargetDisconnected(status) {
|
|
247
|
+
if (!this.statusTargets.includes(status) && this.#ownsStatus(status)) {
|
|
248
|
+
status.removeAttribute(this.#ownedStatus);
|
|
249
|
+
this.#statusWrites.delete(status);
|
|
250
|
+
}
|
|
251
|
+
this.#resync.schedule();
|
|
252
|
+
}
|
|
157
253
|
deadlineValueChanged() {
|
|
254
|
+
this.#valuesDirty = true;
|
|
158
255
|
this.#resync.schedule();
|
|
159
256
|
}
|
|
160
|
-
/** Re-derives the display when a morph flips the counting direction in place. */
|
|
161
257
|
directionValueChanged() {
|
|
258
|
+
this.#valuesDirty = true;
|
|
162
259
|
this.#resync.schedule();
|
|
163
260
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
261
|
+
completeLabelValueChanged() {
|
|
262
|
+
if (this.#connected) this.#syncStatus();
|
|
263
|
+
}
|
|
264
|
+
intervalValueChanged() {
|
|
265
|
+
if (this.#intervalId === null || this.#armedPeriod === this.#safeInterval) return;
|
|
266
|
+
this.#teardownInterval();
|
|
267
|
+
this.#armTick();
|
|
268
|
+
}
|
|
269
|
+
#syncStatus() {
|
|
270
|
+
if (!this.hasStatusTarget || !this.#ownsStatus(this.statusTarget)) return;
|
|
271
|
+
if (this.#state === "complete") this.#writeStatus(this.statusTarget, this.completeLabelValue);
|
|
272
|
+
else this.#releaseStatus(this.statusTarget);
|
|
273
|
+
}
|
|
172
274
|
#resyncToValues() {
|
|
275
|
+
this.#setPhase(this.#state);
|
|
276
|
+
if (!this.#valuesDirty) {
|
|
277
|
+
this.#render(this.#renderedAmount);
|
|
278
|
+
this.#syncStatus();
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
this.#valuesDirty = false;
|
|
173
282
|
this.#initReference();
|
|
174
|
-
this.#
|
|
283
|
+
const amount = this.#currentAmount();
|
|
284
|
+
this.#render(amount);
|
|
285
|
+
if (this.#state === "running" && !this.#isValidDeadline) {
|
|
286
|
+
this.#teardownInterval();
|
|
287
|
+
this.#setPhase("paused");
|
|
288
|
+
}
|
|
289
|
+
if (this.#state === "complete" && !this.#isSettled(amount)) this.#setPhase("paused");
|
|
175
290
|
if (this.#state !== "running") this.#pausedAmount = this.#renderedAmount;
|
|
291
|
+
this.#syncStatus();
|
|
176
292
|
}
|
|
177
|
-
/** Starts (or restarts after pause) ticking toward the deadline. */
|
|
178
293
|
start() {
|
|
179
294
|
if (this.#state === "running" || !this.#isValidDeadline) return;
|
|
180
295
|
if (this.#isDown && this.#currentAmount() <= 0) {
|
|
@@ -183,39 +298,26 @@ var CountdownController = class extends Controller {
|
|
|
183
298
|
}
|
|
184
299
|
this.#runInterval();
|
|
185
300
|
}
|
|
186
|
-
/** Pauses ticking, preserving the currently displayed amount. */
|
|
187
301
|
pause() {
|
|
188
302
|
if (this.#state !== "running") return;
|
|
189
303
|
this.#pausedAmount = this.#renderedAmount;
|
|
190
304
|
this.#teardownInterval();
|
|
191
|
-
this
|
|
305
|
+
this.#setPhase("paused");
|
|
192
306
|
}
|
|
193
|
-
/** Resumes from a pause, continuing from the preserved amount. */
|
|
194
307
|
resume() {
|
|
195
308
|
if (this.#state !== "paused" || !this.#isValidDeadline) return;
|
|
196
309
|
const now = Date.now();
|
|
197
310
|
this.#reference = this.#isDown ? now + this.#pausedAmount : now - this.#pausedAmount;
|
|
198
311
|
this.start();
|
|
199
312
|
}
|
|
200
|
-
/**
|
|
201
|
-
* Re-syncs to the deadline and clears any pause offset, **preserving the current
|
|
202
|
-
* run state**: a running timer keeps counting down from the reset amount, while a
|
|
203
|
-
* paused (or completed) one resets the displayed amount but stays paused until the
|
|
204
|
-
* user resumes — it never silently restarts. The run state is read from the DOM,
|
|
205
|
-
* not re-derived from the declarative `autostart` Value (which governs only markup
|
|
206
|
-
* that states no run state at all); re-deriving it would override a user's pause —
|
|
207
|
-
* the DOM, not a re-run of declarative config, is the source of truth.
|
|
208
|
-
*/
|
|
209
313
|
reset() {
|
|
210
314
|
const wasRunning = this.#state === "running";
|
|
211
315
|
this.#teardownInterval();
|
|
212
316
|
this.#initReference();
|
|
213
317
|
const amount = this.#currentAmount();
|
|
214
318
|
this.#render(amount);
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
this.element.setAttribute("data-state", "paused");
|
|
319
|
+
this.#setPhase("paused");
|
|
320
|
+
this.#syncStatus();
|
|
219
321
|
if (wasRunning && this.#isValidDeadline) {
|
|
220
322
|
this.#pausedAmount = 0;
|
|
221
323
|
this.start();
|
|
@@ -223,19 +325,21 @@ var CountdownController = class extends Controller {
|
|
|
223
325
|
this.#pausedAmount = this.#renderedAmount;
|
|
224
326
|
}
|
|
225
327
|
}
|
|
226
|
-
/** Schedules the repeating tick and marks the timer running. */
|
|
227
328
|
#runInterval() {
|
|
228
|
-
this
|
|
229
|
-
this.#
|
|
329
|
+
this.#setPhase("running");
|
|
330
|
+
this.#syncStatus();
|
|
331
|
+
this.#armTick();
|
|
332
|
+
}
|
|
333
|
+
#armTick() {
|
|
334
|
+
this.#armedPeriod = this.#safeInterval;
|
|
335
|
+
this.#intervalId = this.#intervals.set(() => this.#tick(), this.#armedPeriod);
|
|
230
336
|
}
|
|
231
|
-
/** Cancels the repeating tick, if any. */
|
|
232
337
|
#teardownInterval() {
|
|
233
338
|
if (this.#intervalId !== null) {
|
|
234
339
|
this.#intervals.clear(this.#intervalId);
|
|
235
340
|
this.#intervalId = null;
|
|
236
341
|
}
|
|
237
342
|
}
|
|
238
|
-
/** Recomputes, renders, emits `tick`, and completes when a countdown hits 0. */
|
|
239
343
|
#tick() {
|
|
240
344
|
const amount = this.#currentAmount();
|
|
241
345
|
this.#render(amount);
|
|
@@ -246,33 +350,57 @@ var CountdownController = class extends Controller {
|
|
|
246
350
|
this.#complete();
|
|
247
351
|
}
|
|
248
352
|
}
|
|
249
|
-
/** Stops at zero, marks completion, announces it, and emits `complete`. */
|
|
250
353
|
#complete() {
|
|
251
354
|
this.#teardownInterval();
|
|
252
355
|
this.#render(0);
|
|
253
|
-
this
|
|
254
|
-
|
|
255
|
-
this.statusTarget.textContent = this.completeLabelValue;
|
|
256
|
-
}
|
|
356
|
+
this.#setPhase("complete");
|
|
357
|
+
this.#claimStatus();
|
|
257
358
|
this.dispatch("complete", { detail: {} });
|
|
359
|
+
this.#announceCompletion();
|
|
360
|
+
}
|
|
361
|
+
#claimStatus() {
|
|
362
|
+
if (!this.hasStatusTarget) return;
|
|
363
|
+
const status = this.statusTarget;
|
|
364
|
+
const label = this.completeLabelValue;
|
|
365
|
+
if (label === "" && !this.#isEmpty(status) && !this.#ownsStatus(status)) return;
|
|
366
|
+
this.#writeStatus(status, label);
|
|
367
|
+
}
|
|
368
|
+
#ownsStatus(status) {
|
|
369
|
+
const held = this.#statusWrites.get(status);
|
|
370
|
+
if (!status.hasAttribute(this.#ownedStatus) && held && status.firstElementChild === null && (status.textContent === held.text || status.textContent === held.original))
|
|
371
|
+
return true;
|
|
372
|
+
return status.getAttribute(this.#ownedStatus) === status.textContent && status.firstElementChild === null;
|
|
373
|
+
}
|
|
374
|
+
#isEmpty(status) {
|
|
375
|
+
return status.textContent === "" && status.firstElementChild === null;
|
|
376
|
+
}
|
|
377
|
+
#writeStatus(status, text) {
|
|
378
|
+
const original = this.#statusWrites.get(status)?.original ?? status.textContent ?? "";
|
|
379
|
+
this.#statusWrites.set(status, { original, text });
|
|
380
|
+
if (status.textContent !== text) status.textContent = text;
|
|
381
|
+
if (status.getAttribute(this.#ownedStatus) !== text)
|
|
382
|
+
status.setAttribute(this.#ownedStatus, text);
|
|
383
|
+
}
|
|
384
|
+
#releaseStatus(status) {
|
|
385
|
+
status.textContent = "";
|
|
386
|
+
status.removeAttribute(this.#ownedStatus);
|
|
387
|
+
this.#statusWrites.delete(status);
|
|
388
|
+
}
|
|
389
|
+
#announceCompletion() {
|
|
258
390
|
announce(fillTemplate(this.announceTextValue, {}));
|
|
259
391
|
}
|
|
260
|
-
/** Sets the time anchor from the `deadline` value. */
|
|
261
392
|
#initReference() {
|
|
262
393
|
this.#reference = Date.parse(this.deadlineValue);
|
|
263
394
|
}
|
|
264
|
-
|
|
395
|
+
#isSettled(amount) {
|
|
396
|
+
return this.#isDown && amount <= 0;
|
|
397
|
+
}
|
|
265
398
|
#currentAmount() {
|
|
266
399
|
if (!this.#isValidDeadline) return 0;
|
|
267
400
|
const now = Date.now();
|
|
268
401
|
const raw = this.#isDown ? this.#reference - now : now - this.#reference;
|
|
269
402
|
return Math.max(0, raw);
|
|
270
403
|
}
|
|
271
|
-
/**
|
|
272
|
-
* Writes the amount into the day/hour/minute/second slots.
|
|
273
|
-
*
|
|
274
|
-
* @stimeoRenderRoot
|
|
275
|
-
*/
|
|
276
404
|
#render(amount) {
|
|
277
405
|
const totalSeconds = Math.floor(amount / SECOND_MS);
|
|
278
406
|
this.#renderedAmount = totalSeconds * SECOND_MS;
|
|
@@ -285,7 +413,6 @@ var CountdownController = class extends Controller {
|
|
|
285
413
|
if (this.hasMinutesTarget) this.minutesTarget.textContent = this.#pad(minutes);
|
|
286
414
|
if (this.hasSecondsTarget) this.secondsTarget.textContent = this.#pad(seconds);
|
|
287
415
|
}
|
|
288
|
-
/** Zero-pads a unit to two digits. */
|
|
289
416
|
#pad(unit) {
|
|
290
417
|
return String(unit).padStart(2, "0");
|
|
291
418
|
}
|
|
@@ -295,12 +422,23 @@ var CountdownController = class extends Controller {
|
|
|
295
422
|
get #isValidDeadline() {
|
|
296
423
|
return !Number.isNaN(this.#reference);
|
|
297
424
|
}
|
|
298
|
-
|
|
425
|
+
#setPhase(phase) {
|
|
426
|
+
this.#phase = phase;
|
|
427
|
+
this.element.setAttribute("data-state", phase);
|
|
428
|
+
}
|
|
299
429
|
get #state() {
|
|
300
|
-
return this.element.getAttribute("data-state") ??
|
|
430
|
+
return this.element.getAttribute("data-state") ?? this.#phase;
|
|
431
|
+
}
|
|
432
|
+
get #safeInterval() {
|
|
433
|
+
return this.#numbers.read(
|
|
434
|
+
this,
|
|
435
|
+
"interval",
|
|
436
|
+
this.intervalValue,
|
|
437
|
+
_CountdownController.values.interval.default,
|
|
438
|
+
_CountdownController.valueConstraints.interval
|
|
439
|
+
);
|
|
301
440
|
}
|
|
302
441
|
};
|
|
303
442
|
|
|
304
443
|
export { CountdownController };
|
|
305
|
-
//# sourceMappingURL=countdown_controller.js.map
|
|
306
444
|
//# sourceMappingURL=countdown_controller.js.map
|