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,69 +1,50 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
// src/controllers/pointer_drag_controller.ts
|
|
4
|
-
|
|
5
|
-
// src/utils/arrow_step.ts
|
|
6
3
|
function isReservedArrowChord(event, allow = []) {
|
|
7
4
|
if (!event.key.startsWith("Arrow")) return false;
|
|
8
5
|
return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
|
|
9
6
|
}
|
|
7
|
+
function hasModifierChord(event) {
|
|
8
|
+
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
9
|
+
}
|
|
10
10
|
|
|
11
|
-
// src/utils/detach_gate.ts
|
|
12
11
|
var DetachGate = class _DetachGate {
|
|
13
|
-
/** Set while a probe is queued, waiting for a reconnect to cancel it. */
|
|
14
12
|
#pending = false;
|
|
15
|
-
/**
|
|
16
|
-
* True while a probe is queued — the last disconnect was ambiguous and no
|
|
17
|
-
* reconnect has cancelled it yet. Read it from `connect()` to tell the
|
|
18
|
-
* reconnect half of an in-page move from a first connect: a controller whose
|
|
19
|
-
* initialisation restarts a measurement (a min-duration floor, an elapsed
|
|
20
|
-
* counter) must skip it for the move, where nothing actually restarted.
|
|
21
|
-
*/
|
|
22
13
|
get pending() {
|
|
23
14
|
return this.#pending;
|
|
24
15
|
}
|
|
25
|
-
/**
|
|
26
|
-
* True when the disconnect is definitely a real detach — the element left
|
|
27
|
-
* the document, or `data-controller` no longer lists the identifier. False
|
|
28
|
-
* means ambiguous (in-page move or observed-root exit), NOT "alive".
|
|
29
|
-
*/
|
|
30
16
|
static isDetached(host) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return !tokens.includes(host.identifier);
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Call from `disconnect()`: runs `teardown` synchronously on a definite
|
|
37
|
-
* detach (fast path), otherwise defers it one microtask — a reconnect
|
|
38
|
-
* ({@link cancel} from `connect()`) keeps the state, no reconnect runs it.
|
|
39
|
-
* One microtask is the whole probe window: Stimulus reconnects a moved
|
|
40
|
-
* element within the same mutation batch, before the checkpoint drains.
|
|
41
|
-
*/
|
|
17
|
+
return !host.element.isConnected || !_DetachGate.#listed(host);
|
|
18
|
+
}
|
|
42
19
|
disconnected(host, teardown) {
|
|
43
|
-
|
|
20
|
+
const carried = _DetachGate.#carried(host);
|
|
21
|
+
if (!carried && _DetachGate.isDetached(host)) {
|
|
44
22
|
this.#pending = false;
|
|
45
23
|
teardown();
|
|
46
24
|
return;
|
|
47
25
|
}
|
|
48
26
|
this.#pending = true;
|
|
49
|
-
|
|
27
|
+
const probe = () => {
|
|
50
28
|
if (!this.#pending) return;
|
|
51
29
|
this.#pending = false;
|
|
52
30
|
teardown();
|
|
53
|
-
}
|
|
31
|
+
};
|
|
32
|
+
if (carried) setTimeout(probe, 0);
|
|
33
|
+
else queueMicrotask(probe);
|
|
34
|
+
}
|
|
35
|
+
static #carried(host) {
|
|
36
|
+
const element = host.element;
|
|
37
|
+
return !element.isConnected && element.closest("[data-turbo-permanent]") !== null && _DetachGate.#listed(host);
|
|
38
|
+
}
|
|
39
|
+
static #listed(host) {
|
|
40
|
+
const tokens = (host.element.getAttribute("data-controller") ?? "").split(/\s+/);
|
|
41
|
+
return tokens.includes(host.identifier);
|
|
54
42
|
}
|
|
55
|
-
/**
|
|
56
|
-
* Disarms a pending probe. Call from `connect()` (the reconnect that proves
|
|
57
|
-
* an in-page move) and from the head of any teardown path not routed through
|
|
58
|
-
* {@link disconnected} (disabled-toggle, Escape), so an orphaned probe can
|
|
59
|
-
* never run the teardown a second time.
|
|
60
|
-
*/
|
|
61
43
|
cancel() {
|
|
62
44
|
this.#pending = false;
|
|
63
45
|
}
|
|
64
46
|
};
|
|
65
47
|
|
|
66
|
-
// src/utils/event_owner.ts
|
|
67
48
|
function ownerIndex(candidates, node) {
|
|
68
49
|
if (!(node instanceof Node)) return -1;
|
|
69
50
|
return candidates.findIndex((candidate) => candidate.contains(node));
|
|
@@ -72,7 +53,148 @@ function ownerOf(candidates, node) {
|
|
|
72
53
|
return candidates[ownerIndex(candidates, node)] ?? null;
|
|
73
54
|
}
|
|
74
55
|
|
|
75
|
-
|
|
56
|
+
function unslotted(element) {
|
|
57
|
+
return element.assignedSlot === null && element.parentElement?.shadowRoot != null;
|
|
58
|
+
}
|
|
59
|
+
function flatTreeParent(element) {
|
|
60
|
+
if (unslotted(element)) return null;
|
|
61
|
+
const parent = element.assignedSlot ?? element.parentNode;
|
|
62
|
+
if (parent instanceof ShadowRoot) return parent.host;
|
|
63
|
+
return parent instanceof Element ? parent : null;
|
|
64
|
+
}
|
|
65
|
+
function flatTreeContains(ancestor, element) {
|
|
66
|
+
for (let node = element; node; node = flatTreeParent(node)) {
|
|
67
|
+
if (node === ancestor) return true;
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
function closestInFlatTree(element, selector) {
|
|
72
|
+
for (let node = element; node; node = flatTreeParent(node)) {
|
|
73
|
+
if (node.matches(selector)) return node;
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
function deepActiveElement(ownerDocument) {
|
|
78
|
+
let active = ownerDocument.activeElement;
|
|
79
|
+
while (active?.shadowRoot?.activeElement) active = active.shadowRoot.activeElement;
|
|
80
|
+
return active;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
var ListenerSet = class {
|
|
84
|
+
#abort = new AbortController();
|
|
85
|
+
add(target, type, handler, options) {
|
|
86
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
87
|
+
}
|
|
88
|
+
dispose() {
|
|
89
|
+
this.#abort.abort();
|
|
90
|
+
this.#abort = new AbortController();
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
var MicrotaskCoalescer = class {
|
|
95
|
+
#run;
|
|
96
|
+
#queued = false;
|
|
97
|
+
#active = false;
|
|
98
|
+
#generation = 0;
|
|
99
|
+
constructor(run) {
|
|
100
|
+
this.#run = run;
|
|
101
|
+
}
|
|
102
|
+
activate() {
|
|
103
|
+
this.#active = true;
|
|
104
|
+
}
|
|
105
|
+
cancel() {
|
|
106
|
+
this.#active = false;
|
|
107
|
+
this.#queued = false;
|
|
108
|
+
this.#generation += 1;
|
|
109
|
+
}
|
|
110
|
+
get pending() {
|
|
111
|
+
return this.#queued;
|
|
112
|
+
}
|
|
113
|
+
schedule() {
|
|
114
|
+
if (!this.#active || this.#queued) return;
|
|
115
|
+
this.#queued = true;
|
|
116
|
+
const generation = this.#generation;
|
|
117
|
+
queueMicrotask(() => {
|
|
118
|
+
if (generation !== this.#generation || !this.#queued || !this.#active) return;
|
|
119
|
+
this.#queued = false;
|
|
120
|
+
this.#run();
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
var MorphRenderWatcher = class {
|
|
126
|
+
#listeners = new ListenerSet();
|
|
127
|
+
#pass;
|
|
128
|
+
#element = null;
|
|
129
|
+
#onMorph = () => this.#pass.schedule();
|
|
130
|
+
constructor(run) {
|
|
131
|
+
this.#pass = new MicrotaskCoalescer(run);
|
|
132
|
+
}
|
|
133
|
+
observe(element) {
|
|
134
|
+
if (this.#element === element) return;
|
|
135
|
+
this.disconnect();
|
|
136
|
+
this.#element = element;
|
|
137
|
+
this.#pass.activate();
|
|
138
|
+
this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
|
|
139
|
+
}
|
|
140
|
+
schedule() {
|
|
141
|
+
this.#pass.schedule();
|
|
142
|
+
}
|
|
143
|
+
get pending() {
|
|
144
|
+
return this.#pass.pending;
|
|
145
|
+
}
|
|
146
|
+
disconnect() {
|
|
147
|
+
this.#listeners.dispose();
|
|
148
|
+
this.#pass.cancel();
|
|
149
|
+
this.#element = null;
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
var NUMBER_BOUNDS = {
|
|
154
|
+
nonNegative: { finite: true, min: 0 },
|
|
155
|
+
positive: { finite: true, exclusiveMin: 0 }};
|
|
156
|
+
function matchesNumberBounds(value, bounds) {
|
|
157
|
+
if (!Number.isFinite(value)) {
|
|
158
|
+
const direction = value === Infinity ? "positive" : value === -Infinity ? "negative" : null;
|
|
159
|
+
if (direction === null) return false;
|
|
160
|
+
if (bounds.allowInfinity !== "both" && bounds.allowInfinity !== direction) return false;
|
|
161
|
+
}
|
|
162
|
+
if (bounds.min !== void 0 && value < bounds.min) return false;
|
|
163
|
+
if (bounds.max !== void 0 && value > bounds.max) return false;
|
|
164
|
+
if (bounds.exclusiveMin !== void 0 && value <= bounds.exclusiveMin) return false;
|
|
165
|
+
if (bounds.integer && !Number.isInteger(value)) return false;
|
|
166
|
+
if (bounds.allowedValues !== void 0 && !bounds.allowedValues.includes(value)) return false;
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function readNumber(raw, fallback, bounds) {
|
|
171
|
+
return matchesNumberBounds(raw, bounds) ? raw : fallback;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
var NumberValueReader = class {
|
|
175
|
+
#lastRejected = /* @__PURE__ */ new Map();
|
|
176
|
+
read(owner, name, raw, fallback, bounds) {
|
|
177
|
+
const resolved = readNumber(raw, fallback, bounds);
|
|
178
|
+
if (matchesNumberBounds(raw, bounds)) {
|
|
179
|
+
this.#lastRejected.delete(name);
|
|
180
|
+
return resolved;
|
|
181
|
+
}
|
|
182
|
+
const attribute = `data-${owner.identifier}-${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}-value`;
|
|
183
|
+
const literal = owner.element.getAttribute(attribute);
|
|
184
|
+
if (literal === null) {
|
|
185
|
+
this.#lastRejected.delete(name);
|
|
186
|
+
return resolved;
|
|
187
|
+
}
|
|
188
|
+
if (this.#lastRejected.get(name) !== literal) {
|
|
189
|
+
this.#lastRejected.set(name, literal);
|
|
190
|
+
console.warn(
|
|
191
|
+
`Stimeo UI: "${owner.identifier}" has an invalid number Value "${name}" declaration ${JSON.stringify(literal)}; using ${fallback}.`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
return resolved;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
|
|
76
198
|
var OwnedPointerSession = class {
|
|
77
199
|
#pointerId;
|
|
78
200
|
#owner;
|
|
@@ -92,7 +214,6 @@ var OwnedPointerSession = class {
|
|
|
92
214
|
} catch {
|
|
93
215
|
}
|
|
94
216
|
}
|
|
95
|
-
/** Releases capture and listeners, then reports the end exactly once. */
|
|
96
217
|
end() {
|
|
97
218
|
this.#finish("teardown");
|
|
98
219
|
}
|
|
@@ -117,23 +238,158 @@ var OwnedPointerSession = class {
|
|
|
117
238
|
};
|
|
118
239
|
};
|
|
119
240
|
|
|
120
|
-
|
|
241
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
242
|
+
if (element.getAttribute(name) === value) return false;
|
|
243
|
+
if (value === null) element.removeAttribute(name);
|
|
244
|
+
else element.setAttribute(name, value);
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function queryOpenDescendants(root, selector) {
|
|
249
|
+
const matches = [];
|
|
250
|
+
const roots = [root];
|
|
251
|
+
for (const scope of roots) {
|
|
252
|
+
matches.push(...scope.querySelectorAll(selector));
|
|
253
|
+
if (scope.nodeType === Node.ELEMENT_NODE) {
|
|
254
|
+
const shadow = scope.shadowRoot;
|
|
255
|
+
if (shadow) roots.push(shadow);
|
|
256
|
+
}
|
|
257
|
+
for (const element of scope.querySelectorAll("*")) {
|
|
258
|
+
if (element.shadowRoot) roots.push(element.shadowRoot);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
return matches;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function sharedRegistry(key, create) {
|
|
265
|
+
const symbol = Symbol.for(key);
|
|
266
|
+
const scope = globalThis;
|
|
267
|
+
const existing = scope[symbol];
|
|
268
|
+
if (existing !== void 0) return existing;
|
|
269
|
+
const registry = create();
|
|
270
|
+
Object.defineProperty(globalThis, symbol, { value: registry });
|
|
271
|
+
return registry;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function holdsFocus(element) {
|
|
275
|
+
return element.matches(":focus") || deepActiveElement(element.ownerDocument) === element;
|
|
276
|
+
}
|
|
277
|
+
var TabindexLoan = class _TabindexLoan {
|
|
278
|
+
static #registry = sharedRegistry(
|
|
279
|
+
"stimeo-ui.tabindex-loan.registry.v1",
|
|
280
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Set() })
|
|
281
|
+
);
|
|
282
|
+
#value;
|
|
283
|
+
#record;
|
|
284
|
+
#preserveFocus;
|
|
285
|
+
#lent = /* @__PURE__ */ new Set();
|
|
286
|
+
constructor(value, owner, options = {}) {
|
|
287
|
+
this.#value = value;
|
|
288
|
+
this.#record = `data-${owner}-tabindex-loan`;
|
|
289
|
+
this.#preserveFocus = options.preserveFocus === true;
|
|
290
|
+
_TabindexLoan.#registry.names.add(this.#record);
|
|
291
|
+
}
|
|
292
|
+
lend(element, options = {}) {
|
|
293
|
+
const stack = this.#stack(element);
|
|
294
|
+
const current = element.getAttribute("tabindex");
|
|
295
|
+
const held = stack.find((hold) => hold.loan === this) ?? stack.find(
|
|
296
|
+
(hold) => hold.loan === null && hold.record === this.#record && hold.value === this.#value
|
|
297
|
+
);
|
|
298
|
+
const linked = stack.at(-1)?.value === current;
|
|
299
|
+
if (!held && options.onlyIfUnfocusable && (current !== null || element.tabIndex >= 0)) return;
|
|
300
|
+
if (!held && current !== null && !linked) return;
|
|
301
|
+
this.#lent.add(element);
|
|
302
|
+
if (held) held.loan = this;
|
|
303
|
+
else stack.push({ loan: this, record: this.#record, value: this.#value, linked });
|
|
304
|
+
this.#mark(element, stack);
|
|
305
|
+
if (current === null || !held && current !== this.#value) {
|
|
306
|
+
element.setAttribute("tabindex", this.#value);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
return(element) {
|
|
310
|
+
const stack = this.#stack(element);
|
|
311
|
+
const hold = stack.find((held) => held.loan === this) ?? stack.find(
|
|
312
|
+
(held) => held.loan === null && held.record === this.#record && held.value === this.#value
|
|
313
|
+
);
|
|
314
|
+
if (!hold) return false;
|
|
315
|
+
if (!this.#release(element, stack, hold, this.#preserveFocus)) {
|
|
316
|
+
hold.loan = this;
|
|
317
|
+
this.#lent.add(element);
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
this.#lent.delete(element);
|
|
321
|
+
return true;
|
|
322
|
+
}
|
|
323
|
+
returnAll() {
|
|
324
|
+
for (const element of Array.from(this.#lent)) this.return(element);
|
|
325
|
+
}
|
|
326
|
+
reclaim(element) {
|
|
327
|
+
if (element.getAttribute(this.#record) !== this.#value) return;
|
|
328
|
+
const stack = this.#stack(element);
|
|
329
|
+
const hold = stack.find((held) => held.loan === null && held.record === this.#record);
|
|
330
|
+
if (hold && !holdsFocus(element)) this.#release(element, stack, hold);
|
|
331
|
+
}
|
|
332
|
+
reclaimWithin(root) {
|
|
333
|
+
for (const element of queryOpenDescendants(root, `[${this.#record}]`)) {
|
|
334
|
+
this.reclaim(element);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
#stack(element) {
|
|
338
|
+
const stacks = _TabindexLoan.#registry.stacks;
|
|
339
|
+
const stack = stacks.get(element) ?? this.#seed(element);
|
|
340
|
+
stacks.set(element, stack);
|
|
341
|
+
return stack;
|
|
342
|
+
}
|
|
343
|
+
#seed(element) {
|
|
344
|
+
const current = element.getAttribute("tabindex");
|
|
345
|
+
const holds = [];
|
|
346
|
+
for (const record of _TabindexLoan.#registry.names) {
|
|
347
|
+
const value = element.getAttribute(record);
|
|
348
|
+
if (value !== null) holds.push({ loan: null, record, value, linked: true });
|
|
349
|
+
}
|
|
350
|
+
holds.sort((one, other) => Number(one.value === current) - Number(other.value === current));
|
|
351
|
+
for (const [index, hold] of holds.entries()) hold.linked = index > 0;
|
|
352
|
+
return holds;
|
|
353
|
+
}
|
|
354
|
+
#release(element, stack, hold, preserveFocus = false) {
|
|
355
|
+
const current = element.getAttribute("tabindex");
|
|
356
|
+
const index = stack.indexOf(hold);
|
|
357
|
+
const owns = current === hold.value && !stack.slice(index + 1).some((above2) => above2.value === current);
|
|
358
|
+
if (owns && preserveFocus && holdsFocus(element)) return false;
|
|
359
|
+
stack.splice(index, 1);
|
|
360
|
+
const above = stack[index];
|
|
361
|
+
if (above) above.linked &&= hold.linked;
|
|
362
|
+
this.#mark(element, stack);
|
|
363
|
+
if (!owns) return true;
|
|
364
|
+
const below = hold.linked ? stack[index - 1] : void 0;
|
|
365
|
+
if (!below) element.removeAttribute("tabindex");
|
|
366
|
+
else if (below.value !== current) element.setAttribute("tabindex", below.value);
|
|
367
|
+
return true;
|
|
368
|
+
}
|
|
369
|
+
#mark(element, stack) {
|
|
370
|
+
const records = /* @__PURE__ */ new Map([[this.#record, null]]);
|
|
371
|
+
for (const hold of stack) records.set(hold.record, hold.value);
|
|
372
|
+
for (const [name, recorded] of records) {
|
|
373
|
+
setAttributeIfChanged(element, name, recorded);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
|
|
121
378
|
var TransientHooks = class {
|
|
122
379
|
#attributes;
|
|
123
380
|
constructor(options) {
|
|
124
381
|
this.#attributes = options.attributes;
|
|
125
382
|
}
|
|
126
|
-
/** Drops the declared hooks from `element`; what it carries besides stays. */
|
|
127
383
|
reset(element) {
|
|
128
384
|
for (const attribute of this.#attributes) element.removeAttribute(attribute);
|
|
129
385
|
}
|
|
130
386
|
};
|
|
131
387
|
|
|
132
|
-
// src/controllers/pointer_drag_controller.ts
|
|
133
388
|
var TRANSIENT_DRAG = new TransientHooks({ attributes: ["data-dragging"] });
|
|
134
389
|
var TRANSIENT_GRAB = new TransientHooks({ attributes: ["data-grabbed"] });
|
|
135
390
|
var NATIVE_KEY_OWNERS = "input, textarea, select, button, a[href], summary, [contenteditable]";
|
|
136
391
|
var PointerDragController = class _PointerDragController extends Controller {
|
|
392
|
+
#numbers = new NumberValueReader();
|
|
137
393
|
static targets = ["handle"];
|
|
138
394
|
static values = {
|
|
139
395
|
axis: { type: String, default: "both" },
|
|
@@ -142,52 +398,63 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
142
398
|
disabled: { type: Boolean, default: false },
|
|
143
399
|
follow: { type: Boolean, default: false }
|
|
144
400
|
};
|
|
401
|
+
static valueConstraints = {
|
|
402
|
+
threshold: NUMBER_BOUNDS.nonNegative,
|
|
403
|
+
keyboardStep: NUMBER_BOUNDS.positive
|
|
404
|
+
};
|
|
145
405
|
static actions = ["reset"];
|
|
146
406
|
static events = ["start", "move", "end", "cancel"];
|
|
147
|
-
/** Marker attribute recording that this controller set the touch-action. */
|
|
148
407
|
static #TOUCH_ACTION_MARKER = "data-pointer-drag-touch-action";
|
|
149
|
-
|
|
150
|
-
static #TABINDEX_MARKER = "data-pointer-drag-tabindex";
|
|
408
|
+
#tabindex = new TabindexLoan("0", this.identifier, { preserveFocus: true });
|
|
151
409
|
#pointer = null;
|
|
152
410
|
#keyboard = null;
|
|
153
|
-
|
|
411
|
+
#keyboardFocusSession = null;
|
|
412
|
+
#listeners = new ListenerSet();
|
|
413
|
+
#shadowFocus = new ListenerSet();
|
|
414
|
+
#keyboardFocus = new MicrotaskCoalescer(() => this.#settleKeyboardFocus());
|
|
154
415
|
#followBase = { x: 0, y: 0 };
|
|
155
|
-
|
|
416
|
+
#gestureFollows = false;
|
|
417
|
+
#followOutput = null;
|
|
156
418
|
#gate = new DetachGate();
|
|
419
|
+
#morphRender = new MorphRenderWatcher(() => {
|
|
420
|
+
for (const handle of this.#handles()) this.#prepareHandle(handle);
|
|
421
|
+
this.#reflectSession();
|
|
422
|
+
});
|
|
157
423
|
connect() {
|
|
424
|
+
this.#morphRender.observe(this.element);
|
|
425
|
+
if (!this.#pointer && !this.#keyboard) this.#followOutput = null;
|
|
158
426
|
this.#gate.cancel();
|
|
159
427
|
if (!this.#pointer) TRANSIENT_DRAG.reset(this.element);
|
|
160
428
|
if (!this.#keyboard) TRANSIENT_GRAB.reset(this.element);
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
this.element
|
|
165
|
-
this.
|
|
429
|
+
this.#listeners.add(this.element, "pointerdown", this.#onPointerDown);
|
|
430
|
+
this.#listeners.add(this.element, "keydown", this.#onKeydown);
|
|
431
|
+
this.#listeners.add(this.element, "focusout", this.#onFocusout);
|
|
432
|
+
this.#listeners.add(this.element, "focusin", this.#onFocusin);
|
|
433
|
+
this.#keyboardFocus.activate();
|
|
166
434
|
if (!this.hasHandleTarget) this.#prepareHandle(this.element);
|
|
435
|
+
if (this.#keyboard) {
|
|
436
|
+
this.#watchShadowFocus(this.#keyboard.handle);
|
|
437
|
+
this.#checkKeyboardFocus(this.#keyboard);
|
|
438
|
+
}
|
|
167
439
|
}
|
|
168
440
|
disconnect() {
|
|
169
|
-
this.
|
|
170
|
-
this.
|
|
441
|
+
this.#morphRender.disconnect();
|
|
442
|
+
this.#listeners.dispose();
|
|
443
|
+
this.#shadowFocus.dispose();
|
|
444
|
+
this.#keyboardFocus.cancel();
|
|
445
|
+
this.#keyboardFocusSession = null;
|
|
171
446
|
if (this.#pointer || this.#keyboard) {
|
|
172
447
|
this.#gate.disconnected(this, () => this.#teardown());
|
|
173
448
|
return;
|
|
174
449
|
}
|
|
175
450
|
this.#teardown();
|
|
176
451
|
}
|
|
177
|
-
/**
|
|
178
|
-
* Returns the element to its origin: drops the committed follow offset and the
|
|
179
|
-
* inline `translate` that carries it.
|
|
180
|
-
*
|
|
181
|
-
* In follow mode the inline `translate` belongs to this controller, and the
|
|
182
|
-
* committed offset lives in a field the DOM cannot reach — so a consumer that
|
|
183
|
-
* wants the element back at the start, or that has written a position of its
|
|
184
|
-
* own, needs this to make the two agree again. An in-flight drag is cancelled
|
|
185
|
-
* first, or its deltas would land on top of the offset just cleared.
|
|
186
|
-
*/
|
|
187
452
|
reset() {
|
|
453
|
+
const follows = this.#pointer || this.#keyboard ? this.#gestureFollows : this.followValue;
|
|
188
454
|
const live = this.#pointer?.started ? this.#pointer.pointerType : this.#keyboard ? "keyboard" : null;
|
|
189
455
|
if (this.#pointer || this.#keyboard) this.#teardownSessions();
|
|
190
456
|
if (live) this.#dispatchCancel(live);
|
|
457
|
+
if (!follows) return;
|
|
191
458
|
this.#followBase = { x: 0, y: 0 };
|
|
192
459
|
this.#applyFollow(0, 0);
|
|
193
460
|
}
|
|
@@ -204,13 +471,6 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
204
471
|
if (!this.hasHandleTarget) this.#prepareHandle(this.element);
|
|
205
472
|
if (interrupted) this.#dispatchCancel(interrupted);
|
|
206
473
|
}
|
|
207
|
-
/**
|
|
208
|
-
* Re-derives the handles' touch-action when the axis changes.
|
|
209
|
-
*
|
|
210
|
-
* Two layers, like the `tabindex` loan: the marker says the value was once
|
|
211
|
-
* ours, and the current inline value says it still is. A consumer that wrote
|
|
212
|
-
* its own `touch-action` after connect keeps it.
|
|
213
|
-
*/
|
|
214
474
|
axisValueChanged(_value, previousValue) {
|
|
215
475
|
const lent = this.#touchActionFor(previousValue ?? this.axisValue);
|
|
216
476
|
for (const handle of this.#handles()) {
|
|
@@ -219,7 +479,6 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
219
479
|
handle.style.touchAction = this.#touchActionForAxis();
|
|
220
480
|
}
|
|
221
481
|
}
|
|
222
|
-
/** Cancels any in-flight session when the controller is disabled mid-drag. */
|
|
223
482
|
disabledValueChanged() {
|
|
224
483
|
if (!this.disabledValue) return;
|
|
225
484
|
if (this.#pointer?.started || this.#keyboard) {
|
|
@@ -227,17 +486,14 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
227
486
|
}
|
|
228
487
|
this.#teardownSessions();
|
|
229
488
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
*
|
|
233
|
-
* @stimeoRuntimeOnly `disabled` decides whether this one pointer press starts a gesture.
|
|
234
|
-
*/
|
|
235
|
-
#onPointerDown = (event) => {
|
|
489
|
+
#onPointerDown = (rawEvent) => {
|
|
490
|
+
const event = rawEvent;
|
|
236
491
|
if (this.disabledValue || this.#pointer || this.#keyboard || event.button !== 0) return;
|
|
237
492
|
const handle = this.#handleFor(event.target);
|
|
238
493
|
if (!handle) return;
|
|
239
494
|
event.preventDefault();
|
|
240
495
|
handle.focus();
|
|
496
|
+
this.#beginGesture();
|
|
241
497
|
const session = {
|
|
242
498
|
pointer: null,
|
|
243
499
|
handle,
|
|
@@ -254,18 +510,13 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
254
510
|
});
|
|
255
511
|
this.#pointer = session;
|
|
256
512
|
};
|
|
257
|
-
/**
|
|
258
|
-
* Applies one tracked move: threshold, hooks, follow offset, events.
|
|
259
|
-
*
|
|
260
|
-
* @stimeoRuntimeOnly `threshold` decides when this one pointer move starts the drag.
|
|
261
|
-
*/
|
|
262
513
|
#trackMove(session, event) {
|
|
263
514
|
const [dx, dy] = this.#filterAxis(
|
|
264
515
|
event.clientX - session.originX,
|
|
265
516
|
event.clientY - session.originY
|
|
266
517
|
);
|
|
267
518
|
if (!session.started) {
|
|
268
|
-
if (Math.hypot(dx, dy) < this
|
|
519
|
+
if (Math.hypot(dx, dy) < this.#safeThreshold) return;
|
|
269
520
|
session.started = true;
|
|
270
521
|
this.element.setAttribute("data-dragging", "true");
|
|
271
522
|
this.dispatch("start", {
|
|
@@ -279,13 +530,6 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
279
530
|
detail: { dx, dy, x: event.clientX, y: event.clientY, pointerType: session.pointerType }
|
|
280
531
|
});
|
|
281
532
|
}
|
|
282
|
-
/**
|
|
283
|
-
* Closes the session and reports only the outcome the caller does not own.
|
|
284
|
-
*
|
|
285
|
-
* A teardown (detach, Escape, mid-drag disable, `reset`) is announced by the
|
|
286
|
-
* path that asked for it, so this one stays silent; `pointerup` below the
|
|
287
|
-
* threshold was a plain click, and `pointercancel` is an OS gesture takeover.
|
|
288
|
-
*/
|
|
289
533
|
#finishPointer(session, kind) {
|
|
290
534
|
const { started, dx, dy, pointerType } = session;
|
|
291
535
|
this.#pointer = null;
|
|
@@ -298,19 +542,14 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
298
542
|
}
|
|
299
543
|
this.#dispatchCancel(pointerType);
|
|
300
544
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
*
|
|
304
|
-
* @stimeoRuntimeOnly `disabled` decides whether this one key is taken and `keyboardStep` is the
|
|
305
|
-
* distance of one keyboard move.
|
|
306
|
-
*/
|
|
307
|
-
#onKeydown = (event) => {
|
|
545
|
+
#onKeydown = (rawEvent) => {
|
|
546
|
+
const event = rawEvent;
|
|
308
547
|
if (this.disabledValue) return;
|
|
309
548
|
const handle = this.#handleFor(event.target);
|
|
310
549
|
if (!handle) return;
|
|
311
550
|
if (event.defaultPrevented) return;
|
|
312
551
|
if (event.isComposing) return;
|
|
313
|
-
if (this.#ownsNativeKeys(event.target, handle)) return;
|
|
552
|
+
if (this.#ownsNativeKeys(event.composedPath()[0] ?? event.target, handle)) return;
|
|
314
553
|
if (isReservedArrowChord(event)) return;
|
|
315
554
|
if (event.key === "Escape") {
|
|
316
555
|
if (this.#pointer?.started) {
|
|
@@ -334,6 +573,7 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
334
573
|
}
|
|
335
574
|
if (!this.#keyboard) return;
|
|
336
575
|
if (event.key === "Home" || event.key === "End") {
|
|
576
|
+
if (hasModifierChord(event)) return;
|
|
337
577
|
event.preventDefault();
|
|
338
578
|
return;
|
|
339
579
|
}
|
|
@@ -355,9 +595,50 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
355
595
|
}
|
|
356
596
|
});
|
|
357
597
|
};
|
|
358
|
-
|
|
598
|
+
#onFocusin = () => {
|
|
599
|
+
const session = this.#keyboard;
|
|
600
|
+
if (session) {
|
|
601
|
+
this.#watchShadowFocus(session.handle);
|
|
602
|
+
this.#checkKeyboardFocus(session);
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
#watchShadowFocus(handle) {
|
|
606
|
+
const tree = handle.getRootNode();
|
|
607
|
+
let active = tree.activeElement;
|
|
608
|
+
while (active?.shadowRoot) {
|
|
609
|
+
const shadow = active.shadowRoot;
|
|
610
|
+
this.#shadowFocus.add(shadow, "focusin", this.#onFocusin);
|
|
611
|
+
active = shadow.activeElement;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
#onFocusout = (rawEvent) => {
|
|
615
|
+
const destination = rawEvent.relatedTarget;
|
|
616
|
+
const session = this.#keyboard;
|
|
617
|
+
if (session && this.#handleFor(destination) === session.handle && !this.#ownsNativeKeys(destination, session.handle)) {
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
this.#checkKeyboardFocus(this.#keyboard);
|
|
621
|
+
};
|
|
622
|
+
#checkKeyboardFocus(session) {
|
|
623
|
+
this.#keyboardFocusSession = session;
|
|
624
|
+
this.#keyboardFocus.schedule();
|
|
625
|
+
}
|
|
626
|
+
#settleKeyboardFocus() {
|
|
627
|
+
const session = this.#keyboardFocusSession;
|
|
628
|
+
this.#keyboardFocusSession = null;
|
|
629
|
+
if (!session || this.#keyboard !== session || !this.element.isConnected) return;
|
|
630
|
+
const tree = session.handle.getRootNode();
|
|
631
|
+
const active = tree.activeElement ?? null;
|
|
632
|
+
if (this.#handleFor(active) === session.handle && !this.#ownsNativeKeys(active, session.handle)) {
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
this.#clearKeyboardSession();
|
|
636
|
+
this.#dispatchCancel("keyboard");
|
|
637
|
+
}
|
|
359
638
|
#grabKeyboard(handle) {
|
|
639
|
+
this.#beginGesture();
|
|
360
640
|
this.#keyboard = { handle, dx: 0, dy: 0 };
|
|
641
|
+
this.#watchShadowFocus(handle);
|
|
361
642
|
this.element.setAttribute("data-grabbed", "true");
|
|
362
643
|
handle.setAttribute("data-grabbed", "true");
|
|
363
644
|
this.dispatch("start", { detail: { x: 0, y: 0, pointerType: "keyboard" } });
|
|
@@ -369,9 +650,8 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
369
650
|
this.#followCommit(session.dx, session.dy);
|
|
370
651
|
this.dispatch("end", { detail: { dx: session.dx, dy: session.dy, pointerType: "keyboard" } });
|
|
371
652
|
}
|
|
372
|
-
/** Maps an arrow key to a raw (unfiltered) `keyboardStep` delta. */
|
|
373
653
|
#keyboardDelta(key) {
|
|
374
|
-
const step = this
|
|
654
|
+
const step = this.#safeKeyboardStep;
|
|
375
655
|
switch (key) {
|
|
376
656
|
case "ArrowRight":
|
|
377
657
|
return [step, 0];
|
|
@@ -385,47 +665,29 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
385
665
|
return null;
|
|
386
666
|
}
|
|
387
667
|
}
|
|
388
|
-
/**
|
|
389
|
-
* Zeroes the delta on the locked axis (`axis` = x | y | both).
|
|
390
|
-
*
|
|
391
|
-
* @stimeoRuntimeOnly `axis` filters the offset of one move to the allowed direction.
|
|
392
|
-
*/
|
|
393
668
|
#filterAxis(dx, dy) {
|
|
394
669
|
if (this.axisValue === "x") return [dx, 0];
|
|
395
670
|
if (this.axisValue === "y") return [0, dy];
|
|
396
671
|
return [dx, dy];
|
|
397
672
|
}
|
|
398
|
-
/** Silently closes a live pointer session; the caller announces the outcome. */
|
|
399
673
|
#endPointerSession() {
|
|
400
674
|
this.#pointer?.pointer?.end();
|
|
401
675
|
}
|
|
402
676
|
#clearKeyboardSession() {
|
|
677
|
+
this.#shadowFocus.dispose();
|
|
403
678
|
this.#keyboard?.handle.removeAttribute("data-grabbed");
|
|
404
679
|
this.#keyboard = null;
|
|
680
|
+
this.#keyboardFocusSession = null;
|
|
405
681
|
this.element.removeAttribute("data-grabbed");
|
|
406
682
|
}
|
|
407
|
-
/**
|
|
408
|
-
* Full teardown for a controller whose element is going away or lost its
|
|
409
|
-
* controller. Into a dead (detached) tree it is silent — consumers restore
|
|
410
|
-
* from their own `connect()`, not from a cancel event. But a detach that
|
|
411
|
-
* KEEPS the element (Turbo morph, `data-controller` removed) leaves the
|
|
412
|
-
* consumers alive and listening: an in-flight session must end in `cancel`
|
|
413
|
-
* there, or a composer like sortable strands its one-at-a-time session
|
|
414
|
-
* bookkeeping forever.
|
|
415
|
-
*/
|
|
416
683
|
#teardown() {
|
|
417
|
-
this.#gate.cancel();
|
|
418
684
|
const interrupted = this.#pointer?.started ? this.#pointer.pointerType : this.#keyboard ? "keyboard" : null;
|
|
419
685
|
this.#teardownSessions();
|
|
420
686
|
for (const handle of this.#handles()) this.#restoreHandle(handle);
|
|
421
|
-
this.#
|
|
687
|
+
this.#tabindex.returnAll();
|
|
688
|
+
if (interrupted) this.#followReset();
|
|
422
689
|
if (interrupted && this.element.isConnected) this.#dispatchCancel(interrupted);
|
|
423
690
|
}
|
|
424
|
-
/**
|
|
425
|
-
* Silently tears down whatever session is live (disconnect / disabled /
|
|
426
|
-
* Escape). Composed from the two single-session teardowns so pointer and
|
|
427
|
-
* keyboard cleanup cannot diverge as either path evolves.
|
|
428
|
-
*/
|
|
429
691
|
#teardownSessions() {
|
|
430
692
|
this.#endPointerSession();
|
|
431
693
|
this.#clearKeyboardSession();
|
|
@@ -434,63 +696,52 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
434
696
|
this.#followReset();
|
|
435
697
|
this.dispatch("cancel", { detail: { pointerType } });
|
|
436
698
|
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
* offset itself comes from the gesture.
|
|
442
|
-
*/
|
|
699
|
+
#beginGesture() {
|
|
700
|
+
this.#gestureFollows = this.followValue;
|
|
701
|
+
if (this.#gestureFollows) this.#followBase = this.#parseFollowBase();
|
|
702
|
+
}
|
|
443
703
|
#followMove(dx, dy) {
|
|
444
|
-
if (!this
|
|
704
|
+
if (!this.#gestureFollows) return;
|
|
445
705
|
this.#applyFollow(this.#followBase.x + dx, this.#followBase.y + dy);
|
|
446
706
|
}
|
|
447
|
-
/**
|
|
448
|
-
* Folds a drop's deltas into the committed base offset (follow only).
|
|
449
|
-
*
|
|
450
|
-
* @stimeoRuntimeOnly `follow` decides whether the end of this one gesture keeps the offset as a
|
|
451
|
-
* translate.
|
|
452
|
-
*/
|
|
453
707
|
#followCommit(dx, dy) {
|
|
454
|
-
if (!this
|
|
708
|
+
if (!this.#gestureFollows) return;
|
|
455
709
|
this.#followBase = { x: this.#followBase.x + dx, y: this.#followBase.y + dy };
|
|
456
710
|
this.#applyFollow(this.#followBase.x, this.#followBase.y);
|
|
457
711
|
}
|
|
458
|
-
/**
|
|
459
|
-
* Snaps back to the committed position (follow only) — the cancel contract.
|
|
460
|
-
*
|
|
461
|
-
* @stimeoRuntimeOnly `follow` decides whether cancelling this one gesture clears the translate it
|
|
462
|
-
* wrote.
|
|
463
|
-
*/
|
|
464
712
|
#followReset() {
|
|
465
|
-
if (!this
|
|
713
|
+
if (!this.#gestureFollows) return;
|
|
466
714
|
this.#applyFollow(this.#followBase.x, this.#followBase.y);
|
|
467
715
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
716
|
+
#reflectSession() {
|
|
717
|
+
if (this.#pointer?.started) this.element.setAttribute("data-dragging", "true");
|
|
718
|
+
else this.element.removeAttribute("data-dragging");
|
|
719
|
+
if (this.#keyboard) {
|
|
720
|
+
this.element.setAttribute("data-grabbed", "true");
|
|
721
|
+
this.#keyboard.handle.setAttribute("data-grabbed", "true");
|
|
722
|
+
} else {
|
|
723
|
+
this.element.removeAttribute("data-grabbed");
|
|
724
|
+
for (const handle of this.#handles()) handle.removeAttribute("data-grabbed");
|
|
725
|
+
}
|
|
726
|
+
const follows = this.#pointer || this.#keyboard ? this.#gestureFollows : this.followValue;
|
|
727
|
+
if (follows && this.#followOutput) {
|
|
728
|
+
this.#applyFollow(this.#followOutput.x, this.#followOutput.y);
|
|
729
|
+
}
|
|
730
|
+
}
|
|
473
731
|
#applyFollow(x, y) {
|
|
732
|
+
this.#followOutput = { x, y };
|
|
474
733
|
if (x === 0 && y === 0) this.element.style.removeProperty("translate");
|
|
475
734
|
else this.element.style.setProperty("translate", `${x}px ${y}px`);
|
|
476
735
|
}
|
|
477
|
-
/**
|
|
478
|
-
* Reads a committed follow offset back from the inline `translate`. Only the
|
|
479
|
-
* controller's own `<x>px <y>px` shape is recognized; anything else (an
|
|
480
|
-
* authored percentage, `none`, an empty string) starts the base at 0 — follow
|
|
481
|
-
* mode owns this property, per the class contract.
|
|
482
|
-
*/
|
|
483
736
|
#parseFollowBase() {
|
|
484
737
|
const raw = this.element.style.getPropertyValue("translate").trim();
|
|
485
738
|
const match = /^(-?\d+(?:\.\d+)?)px(?:\s+(-?\d+(?:\.\d+)?)px)?$/.exec(raw);
|
|
486
739
|
if (!match) return { x: 0, y: 0 };
|
|
487
740
|
return { x: Number(match[1]), y: Number(match[2] ?? "0") };
|
|
488
741
|
}
|
|
489
|
-
/** The active handles: the `handle` targets, else the element itself. */
|
|
490
742
|
#handles() {
|
|
491
743
|
return this.hasHandleTarget ? this.handleTargets : [this.element];
|
|
492
744
|
}
|
|
493
|
-
/** Resolves the handle owning an event target (the handle or a descendant). */
|
|
494
745
|
#handleFor(target) {
|
|
495
746
|
return ownerOf(this.#handles(), target);
|
|
496
747
|
}
|
|
@@ -499,25 +750,14 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
499
750
|
if (type === "touch" || type === "pen") return type;
|
|
500
751
|
return "mouse";
|
|
501
752
|
}
|
|
502
|
-
/** `touch-action` that lets the page keep panning on the locked axis only. */
|
|
503
753
|
#touchActionForAxis() {
|
|
504
754
|
return this.#touchActionFor(this.axisValue);
|
|
505
755
|
}
|
|
506
|
-
/** The `touch-action` an `axis` declaration lends, for any axis value. */
|
|
507
756
|
#touchActionFor(axis) {
|
|
508
757
|
if (axis === "x") return "pan-y";
|
|
509
758
|
if (axis === "y") return "pan-x";
|
|
510
759
|
return "none";
|
|
511
760
|
}
|
|
512
|
-
/**
|
|
513
|
-
* Establishes the handle contract: a `touch-action` derived from `axis`
|
|
514
|
-
* (marker-guarded so an authored inline value wins and reconnects stay
|
|
515
|
-
* idempotent) and focusability for the keyboard path (`tabindex="0"` only when
|
|
516
|
-
* the author supplied none — prefer a real `<button>` handle). Both additions
|
|
517
|
-
* are marker-owned so `#restoreHandle` reverts them symmetrically on teardown.
|
|
518
|
-
*
|
|
519
|
-
* @stimeoRenderRoot
|
|
520
|
-
*/
|
|
521
761
|
#prepareHandle(handle) {
|
|
522
762
|
const lent = this.#touchActionForAxis();
|
|
523
763
|
const marked = handle.hasAttribute(_PointerDragController.#TOUCH_ACTION_MARKER);
|
|
@@ -525,17 +765,14 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
525
765
|
handle.style.touchAction = lent;
|
|
526
766
|
handle.setAttribute(_PointerDragController.#TOUCH_ACTION_MARKER, "true");
|
|
527
767
|
}
|
|
528
|
-
|
|
529
|
-
handle.setAttribute("tabindex", "0");
|
|
530
|
-
handle.setAttribute(_PointerDragController.#TABINDEX_MARKER, "true");
|
|
531
|
-
}
|
|
768
|
+
this.#tabindex.lend(handle, { onlyIfUnfocusable: true });
|
|
532
769
|
}
|
|
533
|
-
/** Whether the key belongs to a native control or editing surface in the handle. */
|
|
534
770
|
#ownsNativeKeys(target, handle) {
|
|
535
|
-
|
|
536
|
-
|
|
771
|
+
let element = target;
|
|
772
|
+
while (element.shadowRoot?.activeElement) element = element.shadowRoot.activeElement;
|
|
773
|
+
const owner = closestInFlatTree(element, NATIVE_KEY_OWNERS);
|
|
774
|
+
return owner !== null && owner !== handle && flatTreeContains(handle, owner);
|
|
537
775
|
}
|
|
538
|
-
/** Reverts the marker-owned touch-action + tabindex (authored values untouched). */
|
|
539
776
|
#restoreHandle(handle) {
|
|
540
777
|
if (handle.hasAttribute(_PointerDragController.#TOUCH_ACTION_MARKER)) {
|
|
541
778
|
if (handle.style.touchAction === this.#touchActionForAxis()) {
|
|
@@ -543,18 +780,27 @@ var PointerDragController = class _PointerDragController extends Controller {
|
|
|
543
780
|
}
|
|
544
781
|
handle.removeAttribute(_PointerDragController.#TOUCH_ACTION_MARKER);
|
|
545
782
|
}
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
783
|
+
this.#tabindex.return(handle);
|
|
784
|
+
}
|
|
785
|
+
get #safeThreshold() {
|
|
786
|
+
return this.#numbers.read(
|
|
787
|
+
this,
|
|
788
|
+
"threshold",
|
|
789
|
+
this.thresholdValue,
|
|
790
|
+
_PointerDragController.values.threshold.default,
|
|
791
|
+
_PointerDragController.valueConstraints.threshold
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
get #safeKeyboardStep() {
|
|
795
|
+
return this.#numbers.read(
|
|
796
|
+
this,
|
|
797
|
+
"keyboardStep",
|
|
798
|
+
this.keyboardStepValue,
|
|
799
|
+
_PointerDragController.values.keyboardStep.default,
|
|
800
|
+
_PointerDragController.valueConstraints.keyboardStep
|
|
801
|
+
);
|
|
555
802
|
}
|
|
556
803
|
};
|
|
557
804
|
|
|
558
805
|
export { PointerDragController };
|
|
559
|
-
//# sourceMappingURL=pointer_drag_controller.js.map
|
|
560
806
|
//# sourceMappingURL=pointer_drag_controller.js.map
|