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,19 +1,14 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
// src/controllers/stick_to_bottom_controller.ts
|
|
4
|
-
|
|
5
|
-
// src/utils/layout_observer.ts
|
|
6
3
|
var LayoutObserver = class {
|
|
7
4
|
#callback;
|
|
8
5
|
#resizeObserverFactory;
|
|
9
6
|
#resizeObserver = null;
|
|
10
7
|
#observingViewport = false;
|
|
11
8
|
#loadContainer = null;
|
|
12
|
-
/** Stable bound handler so add/removeEventListener target the same reference. */
|
|
13
9
|
#handleViewportResize = () => {
|
|
14
10
|
this.#callback();
|
|
15
11
|
};
|
|
16
|
-
/** Stable bound handler for the capture-phase `load`; see {@link observeDescendantLoads}. */
|
|
17
12
|
#handleDescendantLoad = () => {
|
|
18
13
|
this.#callback();
|
|
19
14
|
};
|
|
@@ -21,11 +16,6 @@ var LayoutObserver = class {
|
|
|
21
16
|
this.#callback = callback;
|
|
22
17
|
this.#resizeObserverFactory = options.resizeObserverFactory ?? (typeof ResizeObserver === "undefined" ? null : (cb) => new ResizeObserver(cb));
|
|
23
18
|
}
|
|
24
|
-
/**
|
|
25
|
-
* Starts observing an element's size. Repeated calls observe additional
|
|
26
|
-
* elements through the same shared observer. No-ops when no
|
|
27
|
-
* `ResizeObserver` implementation is available.
|
|
28
|
-
*/
|
|
29
19
|
observe(element) {
|
|
30
20
|
if (!this.#resizeObserverFactory) return;
|
|
31
21
|
if (!this.#resizeObserver) {
|
|
@@ -35,47 +25,28 @@ var LayoutObserver = class {
|
|
|
35
25
|
}
|
|
36
26
|
this.#resizeObserver.observe(element);
|
|
37
27
|
}
|
|
38
|
-
/** Stops observing a single element while leaving any others in place. */
|
|
39
28
|
unobserve(element) {
|
|
40
29
|
this.#resizeObserver?.unobserve(element);
|
|
41
30
|
}
|
|
42
|
-
/** Starts observing viewport resizes. Idempotent: the listener is added once. */
|
|
43
31
|
observeViewport() {
|
|
44
32
|
if (this.#observingViewport) return;
|
|
45
33
|
this.#observingViewport = true;
|
|
46
34
|
window.addEventListener("resize", this.#handleViewportResize);
|
|
47
35
|
}
|
|
48
|
-
/** Stops observing viewport resizes without affecting element observation. */
|
|
49
36
|
unobserveViewport() {
|
|
50
37
|
if (!this.#observingViewport) return;
|
|
51
38
|
this.#observingViewport = false;
|
|
52
39
|
window.removeEventListener("resize", this.#handleViewportResize);
|
|
53
40
|
}
|
|
54
|
-
/**
|
|
55
|
-
* Starts reporting a `load` from anywhere inside `container` — an image or a
|
|
56
|
-
* frame settling changes the box it sits in, and it measures as zero high until
|
|
57
|
-
* then. `load` does not bubble, so the subscription is a capture-phase listener
|
|
58
|
-
* on the container itself and nothing the caller spells.
|
|
59
|
-
*
|
|
60
|
-
* **One container at a time.** A further call moves the observation, so a widget
|
|
61
|
-
* whose content element is swapped at runtime releases the element it let go by
|
|
62
|
-
* naming the new one — there is no second place for the release to drift from.
|
|
63
|
-
*/
|
|
64
41
|
observeDescendantLoads(container) {
|
|
65
42
|
this.unobserveDescendantLoads();
|
|
66
43
|
this.#loadContainer = container;
|
|
67
44
|
container.addEventListener("load", this.#handleDescendantLoad, true);
|
|
68
45
|
}
|
|
69
|
-
/** Stops reporting descendant loads without affecting element or viewport observation. */
|
|
70
46
|
unobserveDescendantLoads() {
|
|
71
47
|
this.#loadContainer?.removeEventListener("load", this.#handleDescendantLoad, true);
|
|
72
48
|
this.#loadContainer = null;
|
|
73
49
|
}
|
|
74
|
-
/**
|
|
75
|
-
* Releases every observation: disconnects the {@link ResizeObserver} and removes
|
|
76
|
-
* the viewport and descendant-load listeners. Safe to call multiple times. Call
|
|
77
|
-
* this from a controller's `disconnect()`.
|
|
78
|
-
*/
|
|
79
50
|
disconnect() {
|
|
80
51
|
this.#resizeObserver?.disconnect();
|
|
81
52
|
this.#resizeObserver = null;
|
|
@@ -84,21 +55,155 @@ var LayoutObserver = class {
|
|
|
84
55
|
}
|
|
85
56
|
};
|
|
86
57
|
|
|
87
|
-
|
|
58
|
+
var ListenerSet = class {
|
|
59
|
+
#abort = new AbortController();
|
|
60
|
+
add(target, type, handler, options) {
|
|
61
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
62
|
+
}
|
|
63
|
+
dispose() {
|
|
64
|
+
this.#abort.abort();
|
|
65
|
+
this.#abort = new AbortController();
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
var MicrotaskCoalescer = class {
|
|
70
|
+
#run;
|
|
71
|
+
#queued = false;
|
|
72
|
+
#active = false;
|
|
73
|
+
#generation = 0;
|
|
74
|
+
constructor(run) {
|
|
75
|
+
this.#run = run;
|
|
76
|
+
}
|
|
77
|
+
activate() {
|
|
78
|
+
this.#active = true;
|
|
79
|
+
}
|
|
80
|
+
cancel() {
|
|
81
|
+
this.#active = false;
|
|
82
|
+
this.#queued = false;
|
|
83
|
+
this.#generation += 1;
|
|
84
|
+
}
|
|
85
|
+
get pending() {
|
|
86
|
+
return this.#queued;
|
|
87
|
+
}
|
|
88
|
+
schedule() {
|
|
89
|
+
if (!this.#active || this.#queued) return;
|
|
90
|
+
this.#queued = true;
|
|
91
|
+
const generation = this.#generation;
|
|
92
|
+
queueMicrotask(() => {
|
|
93
|
+
if (generation !== this.#generation || !this.#queued || !this.#active) return;
|
|
94
|
+
this.#queued = false;
|
|
95
|
+
this.#run();
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
var MorphRenderWatcher = class {
|
|
101
|
+
#listeners = new ListenerSet();
|
|
102
|
+
#pass;
|
|
103
|
+
#element = null;
|
|
104
|
+
#onMorph = () => this.#pass.schedule();
|
|
105
|
+
constructor(run) {
|
|
106
|
+
this.#pass = new MicrotaskCoalescer(run);
|
|
107
|
+
}
|
|
108
|
+
observe(element) {
|
|
109
|
+
if (this.#element === element) return;
|
|
110
|
+
this.disconnect();
|
|
111
|
+
this.#element = element;
|
|
112
|
+
this.#pass.activate();
|
|
113
|
+
this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
|
|
114
|
+
}
|
|
115
|
+
schedule() {
|
|
116
|
+
this.#pass.schedule();
|
|
117
|
+
}
|
|
118
|
+
get pending() {
|
|
119
|
+
return this.#pass.pending;
|
|
120
|
+
}
|
|
121
|
+
disconnect() {
|
|
122
|
+
this.#listeners.dispose();
|
|
123
|
+
this.#pass.cancel();
|
|
124
|
+
this.#element = null;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
var NUMBER_BOUNDS = {
|
|
129
|
+
nonNegative: { finite: true, min: 0 }};
|
|
130
|
+
function matchesNumberBounds(value, bounds) {
|
|
131
|
+
if (!Number.isFinite(value)) {
|
|
132
|
+
const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
|
|
133
|
+
if (direction === null) return false;
|
|
134
|
+
if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
|
|
135
|
+
}
|
|
136
|
+
if (bounds.min !== void 0 && value < bounds.min) return false;
|
|
137
|
+
if (bounds.max !== void 0 && value > bounds.max) return false;
|
|
138
|
+
if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
|
|
139
|
+
if (bounds.integer && !Number.isInteger(value)) return false;
|
|
140
|
+
if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function readNumber(raw, fallback, bounds) {
|
|
145
|
+
return matchesNumberBounds(raw, bounds) ? raw : fallback;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
var NumberValueReader = class {
|
|
149
|
+
#lastRejected = /* @__PURE__ */ new Map();
|
|
150
|
+
read(owner, name, raw, fallback, bounds) {
|
|
151
|
+
const resolved = readNumber(raw, fallback, bounds);
|
|
152
|
+
if (matchesNumberBounds(raw, bounds)) {
|
|
153
|
+
this.#lastRejected.delete(name);
|
|
154
|
+
return resolved;
|
|
155
|
+
}
|
|
156
|
+
const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
|
|
157
|
+
const literal = owner.element.getAttribute(attribute);
|
|
158
|
+
if (literal === null) {
|
|
159
|
+
this.#lastRejected.delete(name);
|
|
160
|
+
return resolved;
|
|
161
|
+
}
|
|
162
|
+
if (this.#lastRejected.get(name) !== literal) {
|
|
163
|
+
this.#lastRejected.set(name, literal);
|
|
164
|
+
console.warn(
|
|
165
|
+
`Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
return resolved;
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
88
172
|
function prefersReducedMotion() {
|
|
89
173
|
return typeof window.matchMedia === "function" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
90
174
|
}
|
|
91
175
|
|
|
92
|
-
|
|
93
|
-
|
|
176
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
177
|
+
if (element.getAttribute(name) === value) return false;
|
|
178
|
+
if (value === null) element.removeAttribute(name);
|
|
179
|
+
else element.setAttribute(name, value);
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function sharedRegistry(key, create) {
|
|
184
|
+
const symbol = Symbol.for(key);
|
|
185
|
+
const scope = globalThis;
|
|
186
|
+
const existing = scope[symbol];
|
|
187
|
+
if (existing !== void 0) return existing;
|
|
188
|
+
const registry = create();
|
|
189
|
+
Object.defineProperty(globalThis, symbol, { value: registry });
|
|
190
|
+
return registry;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
var StateRegions = class _StateRegions {
|
|
194
|
+
static #registry = sharedRegistry(
|
|
195
|
+
"stimeo-ui.state-regions.registry.v1",
|
|
196
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Set() })
|
|
197
|
+
);
|
|
94
198
|
#whenTrue;
|
|
95
199
|
#whenFalse;
|
|
96
|
-
#
|
|
97
|
-
constructor(options) {
|
|
200
|
+
#record;
|
|
201
|
+
constructor(options, owner) {
|
|
98
202
|
this.#whenTrue = options.whenTrue;
|
|
99
203
|
this.#whenFalse = options.whenFalse ?? null;
|
|
204
|
+
this.#record = `data-${owner}-hidden-region`;
|
|
205
|
+
_StateRegions.#registry.names.add(this.#record);
|
|
100
206
|
}
|
|
101
|
-
/** Shows the regions inside `host` that belong to `isTrue` and hides the others. */
|
|
102
207
|
reflect(host, isTrue) {
|
|
103
208
|
const shown = this.#inside(host, this.#whenTrue());
|
|
104
209
|
if (!this.#whenFalse) {
|
|
@@ -114,112 +219,192 @@ var StateRegions = class {
|
|
|
114
219
|
for (const region of shown) this.#write(region, !isTrue);
|
|
115
220
|
for (const region of hiddenSide) this.#write(region, isTrue);
|
|
116
221
|
}
|
|
117
|
-
|
|
222
|
+
release(host) {
|
|
223
|
+
for (const region of [host, ...host.querySelectorAll("*")]) {
|
|
224
|
+
if (!(region instanceof HTMLElement)) continue;
|
|
225
|
+
const stack = this.#held(region);
|
|
226
|
+
const hold = stack && this.#take(stack);
|
|
227
|
+
if (!stack || !hold) continue;
|
|
228
|
+
const owns = region.hidden === hold.written && !this.#covered(region, stack, hold);
|
|
229
|
+
const index = stack.indexOf(hold);
|
|
230
|
+
stack.splice(index, 1);
|
|
231
|
+
const above = stack[index];
|
|
232
|
+
if (above) above.linked &&= hold.linked;
|
|
233
|
+
if (owns) {
|
|
234
|
+
const below = hold.linked ? stack[index - 1] : void 0;
|
|
235
|
+
if (below) {
|
|
236
|
+
if (region.hidden !== below.written) region.hidden = below.written;
|
|
237
|
+
} else {
|
|
238
|
+
setAttributeIfChanged(region, "hidden", hold.authored);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
this.#mark(region, stack);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
118
244
|
#write(region, hidden) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
245
|
+
const stack = this.#stack(region);
|
|
246
|
+
const hold = this.#take(stack) ?? this.#acquire(region, stack);
|
|
247
|
+
const shows = !this.#covered(region, stack, hold);
|
|
248
|
+
hold.written = hidden;
|
|
249
|
+
if (shows && region.hidden !== hidden) region.hidden = hidden;
|
|
250
|
+
this.#mark(region, stack);
|
|
122
251
|
}
|
|
123
|
-
/** Returns a region this instance hid; one it never hid keeps what it carries. */
|
|
124
252
|
#give(region) {
|
|
125
|
-
|
|
253
|
+
const stack = this.#held(region);
|
|
254
|
+
if (stack && this.#take(stack)?.written) this.#write(region, false);
|
|
255
|
+
}
|
|
256
|
+
#held(region) {
|
|
257
|
+
return _StateRegions.#registry.stacks.has(region) || region.hasAttribute(this.#record) ? this.#stack(region) : void 0;
|
|
258
|
+
}
|
|
259
|
+
#stack(region) {
|
|
260
|
+
const stacks = _StateRegions.#registry.stacks;
|
|
261
|
+
const stack = stacks.get(region) ?? this.#seed(region);
|
|
262
|
+
stacks.set(region, stack);
|
|
263
|
+
return stack;
|
|
264
|
+
}
|
|
265
|
+
#seed(region) {
|
|
266
|
+
const found = [];
|
|
267
|
+
for (const record of _StateRegions.#registry.names) {
|
|
268
|
+
const read = this.#recorded(region, record);
|
|
269
|
+
if (read) found.push({ ...read, record });
|
|
270
|
+
}
|
|
271
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
272
|
+
return found.sort((one, other) => depth(one) - depth(other)).map(({ record, authored, written, linked }, index) => ({
|
|
273
|
+
instance: null,
|
|
274
|
+
record,
|
|
275
|
+
authored,
|
|
276
|
+
written,
|
|
277
|
+
linked: linked && index > 0
|
|
278
|
+
}));
|
|
279
|
+
}
|
|
280
|
+
#take(stack) {
|
|
281
|
+
const hold = stack.find((held) => held.instance === this) ?? stack.find((held) => held.instance === null && held.record === this.#record);
|
|
282
|
+
if (hold) hold.instance = this;
|
|
283
|
+
return hold;
|
|
284
|
+
}
|
|
285
|
+
#covered(region, stack, hold) {
|
|
286
|
+
return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === region.hidden);
|
|
287
|
+
}
|
|
288
|
+
#acquire(region, stack) {
|
|
289
|
+
const top = stack.at(-1);
|
|
290
|
+
const over = top && region.hidden === top.written ? top : void 0;
|
|
291
|
+
const hold = {
|
|
292
|
+
instance: this,
|
|
293
|
+
record: this.#record,
|
|
294
|
+
authored: over ? over.authored : region.getAttribute("hidden"),
|
|
295
|
+
written: false,
|
|
296
|
+
linked: over !== void 0
|
|
297
|
+
};
|
|
298
|
+
stack.push(hold);
|
|
299
|
+
return hold;
|
|
300
|
+
}
|
|
301
|
+
#mark(region, stack) {
|
|
302
|
+
const records = /* @__PURE__ */ new Map([[this.#record, null]]);
|
|
303
|
+
stack.forEach((hold, index) => {
|
|
304
|
+
const names = stack.slice(0, index).map((under) => under.record);
|
|
305
|
+
const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
|
|
306
|
+
const marker = hold.linked || beneath.length === 0 ? [] : [false];
|
|
307
|
+
records.set(
|
|
308
|
+
hold.record,
|
|
309
|
+
region.getAttribute("hidden") === hold.authored && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([hold.authored, hold.written, ...marker, ...beneath])
|
|
310
|
+
);
|
|
311
|
+
});
|
|
312
|
+
for (const [name, recorded] of records) {
|
|
313
|
+
setAttributeIfChanged(region, name, recorded);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
#recorded(region, name) {
|
|
317
|
+
try {
|
|
318
|
+
const parsed = JSON.parse(region.getAttribute(name) ?? "null");
|
|
319
|
+
if (!Array.isArray(parsed)) return null;
|
|
320
|
+
const [authored, written, ...rest] = parsed;
|
|
321
|
+
if (authored !== null && typeof authored !== "string") return null;
|
|
322
|
+
const linked = rest[0] !== false;
|
|
323
|
+
const beneath = linked ? rest : rest.slice(1);
|
|
324
|
+
if (!beneath.every((under) => typeof under === "string")) return null;
|
|
325
|
+
return typeof written === "boolean" ? { authored, written, linked, beneath } : null;
|
|
326
|
+
} catch {
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
126
329
|
}
|
|
127
|
-
/** The declared regions that sit within `host`, which may be the host itself. */
|
|
128
330
|
#inside(host, regions) {
|
|
129
331
|
return regions.filter((region) => host.contains(region));
|
|
130
332
|
}
|
|
131
333
|
};
|
|
132
334
|
|
|
133
|
-
// src/controllers/stick_to_bottom_controller.ts
|
|
134
335
|
var DEFAULT_THRESHOLD = 80;
|
|
135
336
|
var countElements = (nodes) => {
|
|
136
337
|
let n = 0;
|
|
137
338
|
for (const node of nodes) if (node.nodeType === Node.ELEMENT_NODE) n += 1;
|
|
138
339
|
return n;
|
|
139
340
|
};
|
|
140
|
-
var StickToBottomController = class extends Controller {
|
|
341
|
+
var StickToBottomController = class _StickToBottomController extends Controller {
|
|
342
|
+
#numbers = new NumberValueReader();
|
|
141
343
|
static targets = ["content", "hasNew"];
|
|
142
344
|
static values = {
|
|
143
345
|
threshold: { type: Number, default: DEFAULT_THRESHOLD },
|
|
144
346
|
behavior: { type: String, default: "auto" },
|
|
145
347
|
pinOnConnect: { type: Boolean, default: false }
|
|
146
348
|
};
|
|
349
|
+
static valueConstraints = {
|
|
350
|
+
threshold: NUMBER_BOUNDS.nonNegative
|
|
351
|
+
};
|
|
147
352
|
static actions = ["scrollToBottom"];
|
|
148
353
|
static events = ["pin", "new"];
|
|
149
354
|
#observer = null;
|
|
150
|
-
/** The element the append observer currently holds, so a swap can be detected. */
|
|
151
355
|
#watched = null;
|
|
152
|
-
/** Watches for the box a container connected without one is still waiting on. */
|
|
153
356
|
#layout = new LayoutObserver(() => this.#onLaidOut());
|
|
154
357
|
#awaitingLayout = false;
|
|
155
358
|
#connected = false;
|
|
156
359
|
#pinned = false;
|
|
157
360
|
#hasNew = false;
|
|
158
|
-
|
|
159
|
-
|
|
361
|
+
#hasNewRegion = new StateRegions(
|
|
362
|
+
{ whenTrue: () => this.hasNewTargets },
|
|
363
|
+
this.identifier
|
|
364
|
+
);
|
|
160
365
|
#onScroll = () => this.#updatePinned();
|
|
366
|
+
#morphRender = new MorphRenderWatcher(() => {
|
|
367
|
+
this.#updatePinned();
|
|
368
|
+
this.#setHasNew(this.#hasNew);
|
|
369
|
+
});
|
|
370
|
+
#listeners = new ListenerSet();
|
|
161
371
|
connect() {
|
|
372
|
+
this.#morphRender.observe(this.element);
|
|
162
373
|
this.#connected = true;
|
|
163
374
|
if (this.pinOnConnectValue && this.#measurable()) this.#scrollToBottom("instant");
|
|
164
375
|
this.#setHasNew(false);
|
|
165
376
|
this.#pinned = this.#isPinned();
|
|
166
377
|
this.#reflectPinned();
|
|
167
|
-
this.element
|
|
378
|
+
this.#listeners.add(this.element, "scroll", this.#onScroll, { passive: true });
|
|
168
379
|
this.#syncWatched();
|
|
169
380
|
if (!this.#measurable()) this.#waitForLayout();
|
|
170
381
|
}
|
|
171
382
|
disconnect() {
|
|
383
|
+
this.#morphRender.disconnect();
|
|
172
384
|
this.#connected = false;
|
|
173
|
-
this.
|
|
385
|
+
this.#listeners.dispose();
|
|
174
386
|
this.#stopWatching();
|
|
175
387
|
this.#stopWaitingForLayout();
|
|
176
388
|
}
|
|
177
|
-
/** Moves the append watch onto a `content` target that arrived at runtime. */
|
|
178
389
|
contentTargetConnected() {
|
|
179
390
|
this.#syncWatched();
|
|
180
391
|
}
|
|
181
|
-
/** Moves the append watch off a `content` target that left, back onto the container. */
|
|
182
392
|
contentTargetDisconnected() {
|
|
183
393
|
this.#syncWatched();
|
|
184
394
|
}
|
|
185
|
-
/**
|
|
186
|
-
* Settles a has-new region that arrived at runtime on the side the flag is currently
|
|
187
|
-
* on, the way a region present at connect is settled by the connect-time normalization.
|
|
188
|
-
*
|
|
189
|
-
* Stimulus attaches targets before `connect()`, and a container that leaves the document
|
|
190
|
-
* and comes back keeps its controller, so in that window the flag still reads the
|
|
191
|
-
* arrival of the connection that ended. A region attached there is left to the
|
|
192
|
-
* connect-time normalization, which drops the flag and settles the region in one write.
|
|
193
|
-
*/
|
|
194
395
|
hasNewTargetConnected() {
|
|
195
396
|
if (!this.#connected) return;
|
|
196
397
|
this.#hasNewRegion.reflect(this.element, this.#hasNew);
|
|
197
398
|
}
|
|
198
|
-
/**
|
|
199
|
-
* Re-derives pinned when the distance that counts as the bottom is changed at runtime
|
|
200
|
-
* (a morph that swaps the attribute on a retained element).
|
|
201
|
-
*/
|
|
202
399
|
thresholdValueChanged() {
|
|
203
400
|
if (!this.#connected) return;
|
|
204
401
|
this.#updatePinned();
|
|
205
402
|
}
|
|
206
|
-
/**
|
|
207
|
-
* Jumps to the bottom and re-pins (wired to a "new messages" button).
|
|
208
|
-
*
|
|
209
|
-
* The has-new flag clears on request — the user has acknowledged the arrival — while
|
|
210
|
-
* pinned is read back from where the scroll landed: a jump that arrives by the time
|
|
211
|
-
* this returns pins immediately, an animated one settles from its own scroll events,
|
|
212
|
-
* and a jump the engine cannot honor leaves the container unpinned, so the next append
|
|
213
|
-
* flags it again instead of being swallowed by a pinned state that does not hold.
|
|
214
|
-
*
|
|
215
|
-
* Which of those happens is not this method's to decide — see {@link behaviorValue}.
|
|
216
|
-
*/
|
|
217
403
|
scrollToBottom() {
|
|
218
404
|
this.#scrollToBottom();
|
|
219
405
|
this.#setHasNew(false);
|
|
220
406
|
this.#updatePinned();
|
|
221
407
|
}
|
|
222
|
-
/** Follows appended children while pinned; otherwise flags new content. */
|
|
223
408
|
#onMutations(mutations) {
|
|
224
409
|
let added = 0;
|
|
225
410
|
for (const mutation of mutations) added += countElements(mutation.addedNodes);
|
|
@@ -231,19 +416,13 @@ var StickToBottomController = class extends Controller {
|
|
|
231
416
|
this.dispatch("new", { detail: { count: added } });
|
|
232
417
|
}
|
|
233
418
|
}
|
|
234
|
-
/**
|
|
235
|
-
* Recomputes pinned from the scroll position and reflects it on a transition.
|
|
236
|
-
*
|
|
237
|
-
* @stimeoRenderRoot
|
|
238
|
-
*/
|
|
239
419
|
#updatePinned() {
|
|
240
420
|
const pinned = this.#isPinned();
|
|
241
|
-
|
|
421
|
+
const changed = pinned !== this.#pinned;
|
|
242
422
|
this.#pinned = pinned;
|
|
243
423
|
this.#reflectPinned();
|
|
244
|
-
this.dispatch("pin", { detail: { pinned } });
|
|
424
|
+
if (changed) this.dispatch("pin", { detail: { pinned } });
|
|
245
425
|
}
|
|
246
|
-
/** Mirrors the current `#pinned` onto the state hooks (clearing has-new once pinned). */
|
|
247
426
|
#reflectPinned() {
|
|
248
427
|
if (this.#pinned) {
|
|
249
428
|
this.element.setAttribute("data-pinned", "true");
|
|
@@ -252,10 +431,6 @@ var StickToBottomController = class extends Controller {
|
|
|
252
431
|
this.element.removeAttribute("data-pinned");
|
|
253
432
|
}
|
|
254
433
|
}
|
|
255
|
-
/**
|
|
256
|
-
* Mirrors whether content has arrived that the container did not follow onto the state
|
|
257
|
-
* hook and onto the regions declared for that state.
|
|
258
|
-
*/
|
|
259
434
|
#setHasNew(hasNew) {
|
|
260
435
|
this.#hasNew = hasNew;
|
|
261
436
|
if (hasNew) {
|
|
@@ -265,61 +440,31 @@ var StickToBottomController = class extends Controller {
|
|
|
265
440
|
}
|
|
266
441
|
this.#hasNewRegion.reflect(this.element, hasNew);
|
|
267
442
|
}
|
|
268
|
-
/** Whether the container currently sits within `threshold` of its bottom. */
|
|
269
443
|
#isPinned() {
|
|
270
444
|
if (!this.#measurable()) return false;
|
|
271
445
|
const el = this.element;
|
|
272
446
|
return el.scrollHeight - el.clientHeight - el.scrollTop <= this.#threshold;
|
|
273
447
|
}
|
|
274
|
-
/**
|
|
275
|
-
* The distance from the bottom that counts as pinned: a finite, non-negative number of
|
|
276
|
-
* pixels. Anything else names no distance the container can be at, and settles the
|
|
277
|
-
* comparison the same way at every scroll position, so it falls back to the default.
|
|
278
|
-
* `Number` reads `"abc"` as `NaN` and every comparison against it is false; a negative
|
|
279
|
-
* distance sits below the closest the container ever gets; `Infinity` is never
|
|
280
|
-
* exceeded. The first two stop following and flag every append as new, and the last
|
|
281
|
-
* never stops following — it takes the reading position the flag exists to protect.
|
|
282
|
-
* Zero is a real declaration: it pins at the exact bottom only.
|
|
283
|
-
*/
|
|
284
448
|
get #threshold() {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Whether the container has a box to scroll and to measure. One that is not rendered
|
|
290
|
-
* (inside a closed panel) reports every metric as 0, which reads as "already at the
|
|
291
|
-
* bottom" — a position describing no layout the user will ever see.
|
|
292
|
-
*/
|
|
449
|
+
return this.#safeThreshold;
|
|
450
|
+
}
|
|
293
451
|
#measurable() {
|
|
294
452
|
return this.element.clientHeight > 0;
|
|
295
453
|
}
|
|
296
|
-
/**
|
|
297
|
-
* Holds the pinned decision until the container is laid out — otherwise the panel opens
|
|
298
|
-
* at the top while the state claims the bottom, and the appends that arrived meanwhile
|
|
299
|
-
* were followed into a box that could not move rather than flagged.
|
|
300
|
-
*/
|
|
301
454
|
#waitForLayout() {
|
|
302
455
|
this.#awaitingLayout = true;
|
|
303
456
|
this.#layout.observe(this.element);
|
|
304
457
|
}
|
|
305
|
-
/** Runs the held decision once the container has the box it was waiting for. */
|
|
306
458
|
#onLaidOut() {
|
|
307
459
|
if (!this.#awaitingLayout || !this.#measurable()) return;
|
|
308
460
|
this.#stopWaitingForLayout();
|
|
309
461
|
if (this.pinOnConnectValue) this.#scrollToBottom("instant");
|
|
310
462
|
this.#updatePinned();
|
|
311
463
|
}
|
|
312
|
-
/** Releases the layout watch, whether or not the held decision ever ran. */
|
|
313
464
|
#stopWaitingForLayout() {
|
|
314
465
|
this.#awaitingLayout = false;
|
|
315
466
|
this.#layout.disconnect();
|
|
316
467
|
}
|
|
317
|
-
/**
|
|
318
|
-
* Scrolls to the bottom, clamped by the engine to the maximum scroll offset — which is
|
|
319
|
-
* 0 for a container tall enough to hold its whole content, so the jump moves nothing
|
|
320
|
-
* there. `behavior` defaults to the configured follow behavior; pass `"instant"` for a
|
|
321
|
-
* jump that must not animate.
|
|
322
|
-
*/
|
|
323
468
|
#scrollToBottom(behavior = this.#behavior()) {
|
|
324
469
|
const top = this.element.scrollHeight;
|
|
325
470
|
if (typeof this.element.scrollTo === "function") {
|
|
@@ -328,17 +473,6 @@ var StickToBottomController = class extends Controller {
|
|
|
328
473
|
this.element.scrollTop = top;
|
|
329
474
|
}
|
|
330
475
|
}
|
|
331
|
-
/**
|
|
332
|
-
* Points the append watch at the current `content` target, or at the container when
|
|
333
|
-
* there is none. Re-resolved whenever that target changes, so a swap does not leave the
|
|
334
|
-
* observer holding a detached node whose appends nobody sees.
|
|
335
|
-
*
|
|
336
|
-
* Stimulus runs the target callbacks outside the connected window too — before
|
|
337
|
-
* `connect()` for a target already in the DOM, and after `disconnect()` while the
|
|
338
|
-
* element is torn down — where this would arm an observer nothing releases. Re-syncing
|
|
339
|
-
* to the target already held is left alone, so an arrival still in flight is not
|
|
340
|
-
* dropped with the observer that was about to deliver it.
|
|
341
|
-
*/
|
|
342
476
|
#syncWatched() {
|
|
343
477
|
if (!this.#connected) return;
|
|
344
478
|
const next = this.hasContentTarget ? this.contentTarget : this.element;
|
|
@@ -349,24 +483,25 @@ var StickToBottomController = class extends Controller {
|
|
|
349
483
|
this.#observer = new MutationObserver((mutations) => this.#onMutations(mutations));
|
|
350
484
|
this.#observer.observe(next, { childList: true });
|
|
351
485
|
}
|
|
352
|
-
/** Releases the append watch and the element it held. */
|
|
353
486
|
#stopWatching() {
|
|
354
487
|
this.#observer?.disconnect();
|
|
355
488
|
this.#observer = null;
|
|
356
489
|
this.#watched = null;
|
|
357
490
|
}
|
|
358
|
-
/**
|
|
359
|
-
* The behavior a follow-scroll runs with. `"auto"` is **not** a request to arrive at
|
|
360
|
-
* once: it hands the decision to the element's computed `scroll-behavior`, so a
|
|
361
|
-
* consumer stylesheet saying `smooth` animates these scrolls too. Only `"instant"`
|
|
362
|
-
* overrides that CSS, which is why reduced motion and the `pinOnConnect` jump name it.
|
|
363
|
-
*/
|
|
364
491
|
#behavior() {
|
|
365
492
|
if (prefersReducedMotion()) return "instant";
|
|
366
493
|
return this.behaviorValue === "smooth" ? "smooth" : "auto";
|
|
367
494
|
}
|
|
495
|
+
get #safeThreshold() {
|
|
496
|
+
return this.#numbers.read(
|
|
497
|
+
this,
|
|
498
|
+
"threshold",
|
|
499
|
+
this.thresholdValue,
|
|
500
|
+
_StickToBottomController.values.threshold.default,
|
|
501
|
+
_StickToBottomController.valueConstraints.threshold
|
|
502
|
+
);
|
|
503
|
+
}
|
|
368
504
|
};
|
|
369
505
|
|
|
370
506
|
export { StickToBottomController };
|
|
371
|
-
//# sourceMappingURL=stick_to_bottom_controller.js.map
|
|
372
507
|
//# sourceMappingURL=stick_to_bottom_controller.js.map
|