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,13 +1,31 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
var FOCUS_EVENTS = /* @__PURE__ */ new Set(["blur", "focus", "focusin", "focusout"]);
|
|
4
|
+
var POINTER_EVENTS = /* @__PURE__ */ new Set(["mouseenter", "mouseleave", "pointerenter", "pointerleave"]);
|
|
5
|
+
function stateReasonFor(event) {
|
|
6
|
+
if (!event) return "api";
|
|
7
|
+
if (FOCUS_EVENTS.has(event.type)) return "focus";
|
|
8
|
+
if (POINTER_EVENTS.has(event.type)) return "pointer";
|
|
9
|
+
return "user";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function actionSource(source) {
|
|
13
|
+
if (source instanceof HTMLElement) {
|
|
14
|
+
return { event: null, host: source, origin: source, reason: "api" };
|
|
15
|
+
}
|
|
16
|
+
const event = source ?? null;
|
|
17
|
+
return {
|
|
18
|
+
event,
|
|
19
|
+
host: event?.currentTarget instanceof Element ? event.currentTarget : null,
|
|
20
|
+
origin: event?.target instanceof Element ? event.target : null,
|
|
21
|
+
reason: stateReasonFor(event)
|
|
22
|
+
};
|
|
23
|
+
}
|
|
4
24
|
|
|
5
|
-
// src/utils/logical_scroll.ts
|
|
6
25
|
function isRtl(element) {
|
|
7
26
|
return window.getComputedStyle(element).direction === "rtl";
|
|
8
27
|
}
|
|
9
28
|
|
|
10
|
-
// src/utils/arrow_step.ts
|
|
11
29
|
function logicalArrowStep(key, element) {
|
|
12
30
|
if (key === "ArrowDown") return 1;
|
|
13
31
|
if (key === "ArrowUp") return -1;
|
|
@@ -19,8 +37,108 @@ function isReservedArrowChord(event, allow = []) {
|
|
|
19
37
|
if (!event.key.startsWith("Arrow")) return false;
|
|
20
38
|
return event.altKey && !allow.includes("alt") || event.ctrlKey && !allow.includes("ctrl") || event.metaKey && !allow.includes("meta") || event.shiftKey && !allow.includes("shift");
|
|
21
39
|
}
|
|
40
|
+
function hasModifierChord(event) {
|
|
41
|
+
return event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
45
|
+
if (element.getAttribute(name) === value) return false;
|
|
46
|
+
beforeWrite?.();
|
|
47
|
+
if (value === null) element.removeAttribute(name);
|
|
48
|
+
else element.setAttribute(name, value);
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
var AuthoredMutationWatcher = class {
|
|
53
|
+
#onAuthored;
|
|
54
|
+
#claims = null;
|
|
55
|
+
#observer = null;
|
|
56
|
+
constructor(onAuthored) {
|
|
57
|
+
this.#onAuthored = onAuthored;
|
|
58
|
+
}
|
|
59
|
+
observe(root, options) {
|
|
60
|
+
this.disconnect();
|
|
61
|
+
const observer = new MutationObserver((records) => {
|
|
62
|
+
if (this.#observer !== observer) return;
|
|
63
|
+
const authored = this.#filter(records);
|
|
64
|
+
if (authored.length > 0) this.#onAuthored(authored);
|
|
65
|
+
});
|
|
66
|
+
this.#observer = observer;
|
|
67
|
+
this.#claims = { attributes: /* @__PURE__ */ new Map(), children: /* @__PURE__ */ new Map() };
|
|
68
|
+
observer.observe(root, {
|
|
69
|
+
attributes: true,
|
|
70
|
+
attributeFilter: [...options.attributes],
|
|
71
|
+
subtree: options.subtree ?? false,
|
|
72
|
+
childList: options.childList ?? false
|
|
73
|
+
});
|
|
74
|
+
if (options.ancestorAttributes) {
|
|
75
|
+
let ancestor = root.parentElement;
|
|
76
|
+
while (ancestor) {
|
|
77
|
+
observer.observe(ancestor, {
|
|
78
|
+
attributes: true,
|
|
79
|
+
attributeFilter: [...options.ancestorAttributes]
|
|
80
|
+
});
|
|
81
|
+
ancestor = ancestor.parentElement;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
claim(target, name, value) {
|
|
86
|
+
const claims = this.#claims?.attributes;
|
|
87
|
+
let attributes = claims?.get(target);
|
|
88
|
+
if (!attributes) {
|
|
89
|
+
attributes = /* @__PURE__ */ new Map();
|
|
90
|
+
claims?.set(target, attributes);
|
|
91
|
+
}
|
|
92
|
+
const pending = attributes.get(name);
|
|
93
|
+
attributes.set(name, { value, count: (pending?.count ?? 0) + 1 });
|
|
94
|
+
}
|
|
95
|
+
claimCurrent(target, name) {
|
|
96
|
+
this.claim(target, name, target.getAttribute(name));
|
|
97
|
+
}
|
|
98
|
+
claimChildList(target, added, removed) {
|
|
99
|
+
const claims = this.#claims?.children;
|
|
100
|
+
const pending = claims?.get(target) ?? { added: /* @__PURE__ */ new Map(), removed: /* @__PURE__ */ new Map() };
|
|
101
|
+
for (const node of added) pending.added.set(node, (pending.added.get(node) ?? 0) + 1);
|
|
102
|
+
for (const node of removed) pending.removed.set(node, (pending.removed.get(node) ?? 0) + 1);
|
|
103
|
+
claims?.set(target, pending);
|
|
104
|
+
}
|
|
105
|
+
take() {
|
|
106
|
+
return this.#filter(this.#observer?.takeRecords() ?? []);
|
|
107
|
+
}
|
|
108
|
+
disconnect() {
|
|
109
|
+
this.#observer?.disconnect();
|
|
110
|
+
this.#observer = null;
|
|
111
|
+
this.#claims = null;
|
|
112
|
+
}
|
|
113
|
+
#filter(records) {
|
|
114
|
+
const authored = records.filter((record) => !this.#consume(record));
|
|
115
|
+
this.#claims?.attributes.clear();
|
|
116
|
+
this.#claims?.children.clear();
|
|
117
|
+
return authored;
|
|
118
|
+
}
|
|
119
|
+
#consume(record) {
|
|
120
|
+
if (record.type === "attributes") {
|
|
121
|
+
const target = record.target;
|
|
122
|
+
const pending2 = this.#claims?.attributes.get(target)?.get(record.attributeName);
|
|
123
|
+
if (!pending2 || pending2.count === 0 || target.getAttribute(record.attributeName) !== pending2.value) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
pending2.count -= 1;
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
const pending = this.#claims?.children.get(record.target);
|
|
130
|
+
if (!pending) return false;
|
|
131
|
+
const added = [...record.addedNodes];
|
|
132
|
+
const removed = [...record.removedNodes];
|
|
133
|
+
if (added.some((node) => !pending.added.get(node)) || removed.some((node) => !pending.removed.get(node))) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
for (const node of added) pending.added.set(node, (pending.added.get(node) ?? 0) - 1);
|
|
137
|
+
for (const node of removed) pending.removed.set(node, (pending.removed.get(node) ?? 0) - 1);
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
22
141
|
|
|
23
|
-
// src/utils/event_owner.ts
|
|
24
142
|
function ownerIndex(candidates, node) {
|
|
25
143
|
if (!(node instanceof Node)) return -1;
|
|
26
144
|
return candidates.findIndex((candidate) => candidate.contains(node));
|
|
@@ -29,7 +147,6 @@ function ownerOf(candidates, node) {
|
|
|
29
147
|
return candidates[ownerIndex(candidates, node)] ?? null;
|
|
30
148
|
}
|
|
31
149
|
|
|
32
|
-
// src/utils/field_mirror.ts
|
|
33
150
|
function writeFields(container, values, { name, form = "" }) {
|
|
34
151
|
const current = [...container.children];
|
|
35
152
|
const submits = current.length === values.length && current.every(
|
|
@@ -52,7 +169,6 @@ function commitField(target) {
|
|
|
52
169
|
target.dispatchEvent(new Event("change", { bubbles: true }));
|
|
53
170
|
}
|
|
54
171
|
|
|
55
|
-
// src/utils/focus_candidate.ts
|
|
56
172
|
function inheritsFieldsetDisabled(control) {
|
|
57
173
|
let fieldset = control.closest("fieldset[disabled]");
|
|
58
174
|
while (fieldset) {
|
|
@@ -63,7 +179,6 @@ function inheritsFieldsetDisabled(control) {
|
|
|
63
179
|
return false;
|
|
64
180
|
}
|
|
65
181
|
|
|
66
|
-
// src/utils/interactive_host.ts
|
|
67
182
|
var INTERACTIVE_HOST_SELECTOR = "button, input, select, textarea, label, a[href], area[href], summary, details, audio[controls], video[controls], iframe, object, embed";
|
|
68
183
|
function isInteractiveHost(element) {
|
|
69
184
|
if (element.matches(INTERACTIVE_HOST_SELECTOR)) return true;
|
|
@@ -80,27 +195,36 @@ function isInteractiveHost(element) {
|
|
|
80
195
|
return false;
|
|
81
196
|
}
|
|
82
197
|
|
|
83
|
-
|
|
198
|
+
var ListenerSet = class {
|
|
199
|
+
#abort = new AbortController();
|
|
200
|
+
add(target, type, handler, options) {
|
|
201
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
202
|
+
}
|
|
203
|
+
dispose() {
|
|
204
|
+
this.#abort.abort();
|
|
205
|
+
this.#abort = new AbortController();
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
84
209
|
var MicrotaskCoalescer = class {
|
|
85
210
|
#run;
|
|
86
211
|
#queued = false;
|
|
87
212
|
#active = false;
|
|
88
213
|
#generation = 0;
|
|
89
|
-
/** @param run - the single reconciliation pass, invoked at most once per batch. */
|
|
90
214
|
constructor(run) {
|
|
91
215
|
this.#run = run;
|
|
92
216
|
}
|
|
93
|
-
/** Opens the window in which {@link schedule} is honoured; call from `connect()`. */
|
|
94
217
|
activate() {
|
|
95
218
|
this.#active = true;
|
|
96
219
|
}
|
|
97
|
-
/** Closes the window and drops any pending pass; call from `disconnect()`. */
|
|
98
220
|
cancel() {
|
|
99
221
|
this.#active = false;
|
|
100
222
|
this.#queued = false;
|
|
101
223
|
this.#generation += 1;
|
|
102
224
|
}
|
|
103
|
-
|
|
225
|
+
get pending() {
|
|
226
|
+
return this.#queued;
|
|
227
|
+
}
|
|
104
228
|
schedule() {
|
|
105
229
|
if (!this.#active || this.#queued) return;
|
|
106
230
|
this.#queued = true;
|
|
@@ -113,31 +237,53 @@ var MicrotaskCoalescer = class {
|
|
|
113
237
|
}
|
|
114
238
|
};
|
|
115
239
|
|
|
116
|
-
|
|
240
|
+
var MorphRenderWatcher = class {
|
|
241
|
+
#listeners = new ListenerSet();
|
|
242
|
+
#pass;
|
|
243
|
+
#element = null;
|
|
244
|
+
#onMorph = () => this.#pass.schedule();
|
|
245
|
+
constructor(run) {
|
|
246
|
+
this.#pass = new MicrotaskCoalescer(run);
|
|
247
|
+
}
|
|
248
|
+
observe(element) {
|
|
249
|
+
if (this.#element === element) return;
|
|
250
|
+
this.disconnect();
|
|
251
|
+
this.#element = element;
|
|
252
|
+
this.#pass.activate();
|
|
253
|
+
this.#listeners.add(element, "turbo:morph-element", this.#onMorph);
|
|
254
|
+
}
|
|
255
|
+
schedule() {
|
|
256
|
+
this.#pass.schedule();
|
|
257
|
+
}
|
|
258
|
+
get pending() {
|
|
259
|
+
return this.#pass.pending;
|
|
260
|
+
}
|
|
261
|
+
disconnect() {
|
|
262
|
+
this.#listeners.dispose();
|
|
263
|
+
this.#pass.cancel();
|
|
264
|
+
this.#element = null;
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
var MoveCounter = class {
|
|
269
|
+
#sequence = 0;
|
|
270
|
+
record() {
|
|
271
|
+
this.#sequence += 1;
|
|
272
|
+
return this.#sequence;
|
|
273
|
+
}
|
|
274
|
+
isLatest(token) {
|
|
275
|
+
return token === this.#sequence;
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
|
|
117
279
|
var RovingTabindex = class {
|
|
118
|
-
/** Returns the current ordered item elements; called on every operation. */
|
|
119
280
|
#getItems;
|
|
120
|
-
/**
|
|
121
|
-
* @param getItems - Returns the current ordered item elements. Called on every
|
|
122
|
-
* operation so the live target list is always used.
|
|
123
|
-
*/
|
|
124
281
|
constructor(getItems) {
|
|
125
282
|
this.#getItems = getItems;
|
|
126
283
|
}
|
|
127
|
-
/** Index of the currently tabbable item (`tabindex="0"`), or `-1` if none. */
|
|
128
284
|
get activeIndex() {
|
|
129
285
|
return this.#getItems().findIndex((item) => item.tabIndex === 0);
|
|
130
286
|
}
|
|
131
|
-
/**
|
|
132
|
-
* Makes exactly the item at `index` tabbable (`tabindex="0"`) and removes every
|
|
133
|
-
* other item from the Tab sequence (`tabindex="-1"`). An out-of-range `index`
|
|
134
|
-
* (e.g. `-1`) leaves all items at `-1`, which a controller can use to express
|
|
135
|
-
* "nothing is currently tabbable".
|
|
136
|
-
*
|
|
137
|
-
* @param index - Position of the item to make tabbable.
|
|
138
|
-
* @param options - Pass `{ focus: true }` to also move DOM focus to that item,
|
|
139
|
-
* and `items` to reuse an event-scoped collection snapshot.
|
|
140
|
-
*/
|
|
141
287
|
setActive(index, options = {}) {
|
|
142
288
|
const { focus = false } = options;
|
|
143
289
|
const items = options.items ?? this.#getItems();
|
|
@@ -153,7 +299,10 @@ function rovingMove(current, length, delta, wrap) {
|
|
|
153
299
|
return (next + length) % length;
|
|
154
300
|
}
|
|
155
301
|
|
|
156
|
-
|
|
302
|
+
function targetSelector(identifier, name) {
|
|
303
|
+
return `[data-${identifier}-target~="${name}"]`;
|
|
304
|
+
}
|
|
305
|
+
|
|
157
306
|
var ITEM_ATTRIBUTES = [
|
|
158
307
|
"aria-pressed",
|
|
159
308
|
"data-value",
|
|
@@ -164,8 +313,9 @@ var ITEM_ATTRIBUTES = [
|
|
|
164
313
|
"contenteditable",
|
|
165
314
|
"controls"
|
|
166
315
|
];
|
|
167
|
-
var hasModifier = (event) => event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
|
|
168
316
|
var ToggleGroupController = class extends Controller {
|
|
317
|
+
#moves = new MoveCounter();
|
|
318
|
+
#connectionGeneration = 0;
|
|
169
319
|
static targets = ["item", "fields"];
|
|
170
320
|
static values = {
|
|
171
321
|
mode: { type: String, default: "multiple" },
|
|
@@ -177,28 +327,18 @@ var ToggleGroupController = class extends Controller {
|
|
|
177
327
|
#roving = new RovingTabindex(() => this.#managedTargets);
|
|
178
328
|
#handledEvents = /* @__PURE__ */ new WeakSet();
|
|
179
329
|
#managedItems = /* @__PURE__ */ new Set();
|
|
180
|
-
#originalTabindex = /* @__PURE__ */ new
|
|
181
|
-
#ownedPressed = /* @__PURE__ */ new
|
|
182
|
-
#
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
330
|
+
#originalTabindex = /* @__PURE__ */ new WeakMap();
|
|
331
|
+
#ownedPressed = /* @__PURE__ */ new Map();
|
|
332
|
+
#pass = new MorphRenderWatcher(() => this.#reconcileDom());
|
|
333
|
+
#observer = new AuthoredMutationWatcher((records) => {
|
|
334
|
+
this.#releaseAuthoredPressed(records);
|
|
335
|
+
this.#pass.schedule();
|
|
336
|
+
});
|
|
186
337
|
#connected = false;
|
|
187
|
-
/** The pressed set last published: read on connect, then committed or reported. */
|
|
188
338
|
#committedValues = [];
|
|
189
|
-
|
|
190
|
-
* How many presses the user has committed, so a press whose reports are still
|
|
191
|
-
* going out can tell that a listener has committed a newer one meanwhile.
|
|
192
|
-
*/
|
|
193
|
-
#presses = 0;
|
|
194
|
-
/**
|
|
195
|
-
* Normalizes state and establishes one roving entry point. A single authored
|
|
196
|
-
* `tabindex="0"` survives reconnect; otherwise the first pressed, navigable
|
|
197
|
-
* item wins, falling back to the first navigable item. The pressed set it
|
|
198
|
-
* settles on is the one a later move is measured from; connecting reports
|
|
199
|
-
* nothing.
|
|
200
|
-
*/
|
|
339
|
+
#listeners = new ListenerSet();
|
|
201
340
|
connect() {
|
|
341
|
+
this.#releaseDefaultsRewrittenWhileAway();
|
|
202
342
|
const currentItems = new Set(this.itemTargets);
|
|
203
343
|
for (const item of this.#managedItems) {
|
|
204
344
|
if (!currentItems.has(item)) this.#releaseItem(item);
|
|
@@ -212,84 +352,62 @@ var ToggleGroupController = class extends Controller {
|
|
|
212
352
|
this.#ensureTabStop(preferred);
|
|
213
353
|
this.#mirrorFields(false);
|
|
214
354
|
this.#committedValues = this.#pressedValues();
|
|
215
|
-
this.element
|
|
216
|
-
this.element
|
|
217
|
-
this.element
|
|
218
|
-
this.element
|
|
219
|
-
this.element
|
|
355
|
+
this.#listeners.add(this.element, "click", this.#onClickCapture, { capture: true });
|
|
356
|
+
this.#listeners.add(this.element, "keydown", this.#onKeydownCapture, { capture: true });
|
|
357
|
+
this.#listeners.add(this.element, "click", this.#onClick);
|
|
358
|
+
this.#listeners.add(this.element, "keydown", this.#onKeydown);
|
|
359
|
+
this.#listeners.add(this.element, "focusin", this.#onFocusin);
|
|
220
360
|
this.#connected = true;
|
|
221
|
-
this.#
|
|
222
|
-
this.#pass.activate();
|
|
361
|
+
this.#pass.observe(this.element);
|
|
223
362
|
this.#observeMutations();
|
|
224
363
|
}
|
|
225
|
-
/**
|
|
226
|
-
* Releases every listener, the observer, and a pass still queued, while
|
|
227
|
-
* retaining DOM state for Turbo cache/reconnect.
|
|
228
|
-
*/
|
|
229
364
|
disconnect() {
|
|
365
|
+
this.#connectionGeneration += 1;
|
|
230
366
|
this.#connected = false;
|
|
231
|
-
this.#pass.
|
|
232
|
-
this.
|
|
233
|
-
this.
|
|
234
|
-
this.element.removeEventListener("click", this.#onClick);
|
|
235
|
-
this.element.removeEventListener("keydown", this.#onKeydown);
|
|
236
|
-
this.element.removeEventListener("focusin", this.#onFocusin);
|
|
237
|
-
this.#observer?.disconnect();
|
|
238
|
-
this.#observer = null;
|
|
239
|
-
this.#internalPressedValues.clear();
|
|
367
|
+
this.#pass.disconnect();
|
|
368
|
+
this.#listeners.dispose();
|
|
369
|
+
this.#observer.disconnect();
|
|
240
370
|
}
|
|
241
|
-
/** Drops a newly connected item from the Tab sequence before the batch is reconciled. */
|
|
242
371
|
itemTargetConnected(item) {
|
|
243
372
|
if (!this.#connected) return;
|
|
244
373
|
this.#reconcileHost(item, true);
|
|
245
374
|
this.#pass.schedule();
|
|
246
375
|
}
|
|
247
|
-
/** Restores attributes owned only while an element is an item, then reconciles the batch. */
|
|
248
376
|
itemTargetDisconnected(item) {
|
|
249
377
|
if (!this.#connected) return;
|
|
250
378
|
this.#releaseItem(item);
|
|
251
379
|
this.#pass.schedule();
|
|
252
380
|
}
|
|
253
|
-
/** Reconciles the single-selection invariant when the Stimulus Value changes. */
|
|
254
381
|
modeValueChanged() {
|
|
255
382
|
this.#pass.schedule();
|
|
256
383
|
}
|
|
257
|
-
/** Rebuilds the submitted fields when the public name changes at runtime. */
|
|
258
384
|
nameValueChanged() {
|
|
259
385
|
this.#pass.schedule();
|
|
260
386
|
}
|
|
261
|
-
/** Repoints the submitted fields when the owning form changes at runtime. */
|
|
262
387
|
formValueChanged() {
|
|
263
388
|
this.#pass.schedule();
|
|
264
389
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
*/
|
|
269
|
-
toggle(event) {
|
|
270
|
-
if (event.defaultPrevented) return;
|
|
271
|
-
const item = event.currentTarget;
|
|
390
|
+
toggle(source) {
|
|
391
|
+
const { event, host, origin, reason } = actionSource(source);
|
|
392
|
+
const item = host?.closest(targetSelector(this.identifier, "item"));
|
|
272
393
|
if (!item || !this.itemTargets.includes(item)) return;
|
|
273
|
-
this
|
|
274
|
-
|
|
394
|
+
if (origin && origin.closest(`[data-controller~="${this.identifier}"]`) !== this.element)
|
|
395
|
+
return;
|
|
396
|
+
if (event?.defaultPrevented) return;
|
|
397
|
+
if (event) this.#handledEvents.add(event);
|
|
398
|
+
this.#toggleItem(item, reason);
|
|
275
399
|
}
|
|
276
|
-
/**
|
|
277
|
-
* Moves focus or activates the action's item. Per-item action wiring is
|
|
278
|
-
* optional because keydown is also delegated from the group.
|
|
279
|
-
*/
|
|
280
400
|
onKeydown(event) {
|
|
281
401
|
const item = event.currentTarget;
|
|
282
402
|
if (!item || !this.itemTargets.includes(item)) return;
|
|
283
403
|
this.#handleKeydown(event, item);
|
|
284
404
|
}
|
|
285
|
-
/** Blocks disabled activation before per-item or consumer event handlers run. */
|
|
286
405
|
#onClickCapture = (event) => {
|
|
287
406
|
const item = this.#itemForEventTarget(event.target);
|
|
288
407
|
if (!item || !this.#isSupportedHost(item) || !this.#isActivationDisabled(item)) return;
|
|
289
408
|
event.preventDefault();
|
|
290
409
|
event.stopImmediatePropagation();
|
|
291
410
|
};
|
|
292
|
-
/** Blocks disabled keyboard activation while leaving navigation keys available. */
|
|
293
411
|
#onKeydownCapture = (event) => {
|
|
294
412
|
if (event.key !== " " && event.key !== "Enter") return;
|
|
295
413
|
const item = this.#itemForEventTarget(event.target);
|
|
@@ -297,29 +415,25 @@ var ToggleGroupController = class extends Controller {
|
|
|
297
415
|
event.preventDefault();
|
|
298
416
|
event.stopImmediatePropagation();
|
|
299
417
|
};
|
|
300
|
-
/** Delegated click path for static and runtime-added items without actions. */
|
|
301
418
|
#onClick = (event) => {
|
|
302
419
|
if (this.#handledEvents.delete(event) || event.defaultPrevented) return;
|
|
303
420
|
const item = this.#itemForEventTarget(event.target);
|
|
304
421
|
if (item) this.#toggleItem(item);
|
|
305
422
|
};
|
|
306
|
-
/** Delegated keydown path for static and runtime-added items without actions. */
|
|
307
423
|
#onKeydown = (event) => {
|
|
308
424
|
const item = this.#itemForEventTarget(event.target);
|
|
309
425
|
if (item) this.#handleKeydown(event, item);
|
|
310
426
|
};
|
|
311
|
-
/** Keeps programmatic and pointer focus as the group's next Tab entry point. */
|
|
312
427
|
#onFocusin = (event) => {
|
|
313
428
|
const item = this.#itemForEventTarget(event.target);
|
|
314
429
|
if (!item || !this.#isNavigable(item)) return;
|
|
315
430
|
this.#setActive(item);
|
|
316
431
|
};
|
|
317
|
-
/** Applies the APG navigation and activation key map to one supported item. */
|
|
318
432
|
#handleKeydown(event, item) {
|
|
319
433
|
if (event.defaultPrevented || !this.#isSupportedHost(item)) return;
|
|
320
434
|
if (event.isComposing) return;
|
|
321
435
|
if (isReservedArrowChord(event)) return;
|
|
322
|
-
if ((event.key === "Home" || event.key === "End") &&
|
|
436
|
+
if ((event.key === "Home" || event.key === "End") && hasModifierChord(event)) return;
|
|
323
437
|
if (!this.#managedItems.has(item)) this.#reconcileHost(item, true);
|
|
324
438
|
this.#ensureTabStop();
|
|
325
439
|
const items = this.#managedTargets;
|
|
@@ -353,19 +467,9 @@ var ToggleGroupController = class extends Controller {
|
|
|
353
467
|
event.preventDefault();
|
|
354
468
|
if (destination) this.#setActive(destination, true);
|
|
355
469
|
}
|
|
356
|
-
|
|
357
|
-
* Applies one user toggle and dispatches the documented change detail. The set
|
|
358
|
-
* it leaves is taken as published before either report goes out, so a
|
|
359
|
-
* listener that presses again or writes `aria-pressed` is measured from it. A
|
|
360
|
-
* listener of the native `change` that presses again has had that newer press
|
|
361
|
-
* reported, so this press's `change` would describe a set that is gone and is
|
|
362
|
-
* not dispatched.
|
|
363
|
-
*
|
|
364
|
-
* @stimeoRuntimeOnly `mode` is the rule this one press follows; the lasting single-press
|
|
365
|
-
* normalisation is a render root of its own.
|
|
366
|
-
*/
|
|
367
|
-
#toggleItem(item) {
|
|
470
|
+
#toggleItem(item, reason = "user") {
|
|
368
471
|
if (!this.#isSupportedHost(item) || this.#isActivationDisabled(item)) return;
|
|
472
|
+
const generation = this.#connectionGeneration;
|
|
369
473
|
if (!this.#managedItems.has(item)) this.#reconcileHost(item, true);
|
|
370
474
|
const willPress = !this.#isPressed(item);
|
|
371
475
|
if (this.modeValue === "single") {
|
|
@@ -376,49 +480,40 @@ var ToggleGroupController = class extends Controller {
|
|
|
376
480
|
}
|
|
377
481
|
this.#setActive(item);
|
|
378
482
|
const values = this.#pressedValues();
|
|
483
|
+
const previous = this.#committedValues;
|
|
484
|
+
const changed = values.length !== previous.length || values.some((value, index) => value !== previous[index]);
|
|
379
485
|
this.#committedValues = values;
|
|
380
|
-
|
|
381
|
-
|
|
486
|
+
if (!changed) {
|
|
487
|
+
this.#mirrorFields(false);
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
const token = this.#moves.record();
|
|
382
491
|
this.#mirrorFields(true);
|
|
383
|
-
if (
|
|
492
|
+
if (generation !== this.#connectionGeneration || !this.#moves.isLatest(token)) return;
|
|
384
493
|
this.dispatch("change", {
|
|
385
|
-
detail: { value: this.#itemValue(item), pressed: willPress, values: [...values] }
|
|
494
|
+
detail: { value: this.#itemValue(item), pressed: willPress, values: [...values], reason }
|
|
386
495
|
});
|
|
387
496
|
}
|
|
388
|
-
/**
|
|
389
|
-
* Mirrors the pressed values into the optional fields container.
|
|
390
|
-
*
|
|
391
|
-
* @stimeoRenderRoot
|
|
392
|
-
*/
|
|
393
497
|
#mirrorFields(notify) {
|
|
394
498
|
if (!this.hasFieldsTarget) return;
|
|
395
499
|
const options = { name: this.nameValue, form: this.formValue };
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
500
|
+
const removed = [...this.fieldsTarget.childNodes];
|
|
501
|
+
const changed = writeFields(this.fieldsTarget, this.#pressedValues(), options);
|
|
502
|
+
if (changed)
|
|
503
|
+
this.#observer.claimChildList(this.fieldsTarget, [...this.fieldsTarget.childNodes], removed);
|
|
504
|
+
if (changed && notify) commitField(this.fieldsTarget);
|
|
399
505
|
}
|
|
400
|
-
/**
|
|
401
|
-
* Reconciles supported hosts, pressed state, the roving invariant, and the
|
|
402
|
-
* fields after the page changed the group, then reports a pressed set that
|
|
403
|
-
* moved. Records still queued are read first, so an author's write is not lost
|
|
404
|
-
* when observation is suspended for this pass's own writes; observation resumes
|
|
405
|
-
* before the report, so an edit a listener makes is seen by the next pass.
|
|
406
|
-
*/
|
|
407
506
|
#reconcileDom() {
|
|
408
|
-
|
|
409
|
-
if (observer) {
|
|
410
|
-
this.#releaseAuthoredPressed(observer.takeRecords());
|
|
411
|
-
observer.disconnect();
|
|
412
|
-
}
|
|
507
|
+
this.#releaseAuthoredPressed(this.#observer.take());
|
|
413
508
|
for (const item of this.itemTargets) this.#reconcileHost(item, true);
|
|
414
509
|
this.#normalizeSelection();
|
|
415
510
|
this.#ensureTabStop();
|
|
416
511
|
this.#mirrorFields(false);
|
|
417
|
-
this.#
|
|
418
|
-
|
|
512
|
+
const authored = this.#observer.take();
|
|
513
|
+
this.#releaseAuthoredPressed(authored);
|
|
514
|
+
if (authored.length > 0) this.#pass.schedule();
|
|
419
515
|
this.#reportMove();
|
|
420
516
|
}
|
|
421
|
-
/** Reports a pressed set that moved since the one this group last published. */
|
|
422
517
|
#reportMove() {
|
|
423
518
|
const values = this.#pressedValues();
|
|
424
519
|
const previous = this.#committedValues;
|
|
@@ -428,7 +523,6 @@ var ToggleGroupController = class extends Controller {
|
|
|
428
523
|
this.#committedValues = values;
|
|
429
524
|
this.dispatch("reconcile", { detail: { values: [...values] } });
|
|
430
525
|
}
|
|
431
|
-
/** Begins or ends ownership according to the item's current host semantics. */
|
|
432
526
|
#reconcileHost(item, dropFromTabSequence) {
|
|
433
527
|
if (!this.#isSupportedHost(item)) {
|
|
434
528
|
this.#releaseItem(item);
|
|
@@ -441,34 +535,23 @@ var ToggleGroupController = class extends Controller {
|
|
|
441
535
|
}
|
|
442
536
|
this.#normalizePressed(item);
|
|
443
537
|
}
|
|
444
|
-
/** Restores only defaults owned because an element belonged to this group. */
|
|
445
538
|
#releaseItem(item) {
|
|
446
539
|
if (!this.#managedItems.delete(item)) return;
|
|
447
540
|
const original = this.#originalTabindex.get(item);
|
|
448
541
|
if (original === null) item.removeAttribute("tabindex");
|
|
449
542
|
else if (original !== void 0) item.setAttribute("tabindex", original);
|
|
450
|
-
this.#
|
|
451
|
-
if (this.#ownedPressed.delete(item)) item.removeAttribute("aria-pressed");
|
|
452
|
-
this.#internalPressedValues.delete(item);
|
|
543
|
+
if (this.#ownedPressed.delete(item)) this.#writePressed(item, null);
|
|
453
544
|
}
|
|
454
|
-
/** Supplies a missing pressed state and normalizes invalid ARIA tokens. */
|
|
455
545
|
#normalizePressed(item) {
|
|
456
546
|
const value = item.getAttribute("aria-pressed");
|
|
457
547
|
if (value === null) {
|
|
458
|
-
this.#ownedPressed.
|
|
459
|
-
this.#
|
|
460
|
-
item.setAttribute("aria-pressed", "false");
|
|
548
|
+
this.#ownedPressed.set(item, "false");
|
|
549
|
+
this.#writePressed(item, "false");
|
|
461
550
|
} else if (value !== "true" && value !== "false") {
|
|
462
|
-
item
|
|
551
|
+
this.#writePressed(item, "false");
|
|
463
552
|
}
|
|
464
553
|
}
|
|
465
|
-
/**
|
|
466
|
-
* Makes the first DOM-ordered pressed item the sole pressed item in single mode.
|
|
467
|
-
*
|
|
468
|
-
* @stimeoRenderRoot
|
|
469
|
-
*/
|
|
470
554
|
#normalizeSelection() {
|
|
471
|
-
for (const item of this.#managedTargets) this.#normalizePressed(item);
|
|
472
555
|
if (this.modeValue !== "single") return;
|
|
473
556
|
let found = false;
|
|
474
557
|
for (const item of this.#managedTargets) {
|
|
@@ -477,7 +560,6 @@ var ToggleGroupController = class extends Controller {
|
|
|
477
560
|
else this.#setPressed(item, false);
|
|
478
561
|
}
|
|
479
562
|
}
|
|
480
|
-
/** Keeps one navigable Tab stop, preferring current DOM state after initial connect. */
|
|
481
563
|
#ensureTabStop(initialPreference) {
|
|
482
564
|
const navigable = this.#navigableItems;
|
|
483
565
|
let active;
|
|
@@ -493,7 +575,6 @@ var ToggleGroupController = class extends Controller {
|
|
|
493
575
|
active ??= navigable[0];
|
|
494
576
|
this.#setActive(active ?? null);
|
|
495
577
|
}
|
|
496
|
-
/** Moves through the full item order until a navigable destination is found. */
|
|
497
578
|
#nextNavigable(fromIndex, delta) {
|
|
498
579
|
const items = this.#managedTargets;
|
|
499
580
|
let index = fromIndex;
|
|
@@ -504,31 +585,25 @@ var ToggleGroupController = class extends Controller {
|
|
|
504
585
|
}
|
|
505
586
|
return void 0;
|
|
506
587
|
}
|
|
507
|
-
/** Assigns the single roving Tab stop and optionally moves DOM focus. */
|
|
508
588
|
#setActive(item, focus = false) {
|
|
509
589
|
this.#roving.setActive(this.#managedTargets.indexOf(item), { focus });
|
|
510
590
|
}
|
|
511
|
-
/** Finds this group's item containing an event target, excluding nested groups. */
|
|
512
591
|
#itemForEventTarget(target) {
|
|
513
592
|
if (!this.#ownsEventTarget(target)) return null;
|
|
514
593
|
return ownerOf(this.itemTargets, target);
|
|
515
594
|
}
|
|
516
|
-
/** Whether the closest Toggle Group scope around a target is this instance. */
|
|
517
595
|
#ownsEventTarget(target) {
|
|
518
596
|
return target instanceof Element && target.closest(`[data-controller~="${this.identifier}"]`) === this.element;
|
|
519
597
|
}
|
|
520
|
-
/** Hosts whose activation model can be owned without conflicting native behavior. */
|
|
521
598
|
#isSupportedHost(item) {
|
|
522
599
|
if (item instanceof HTMLButtonElement) return item.type === "button";
|
|
523
600
|
return !isInteractiveHost(item);
|
|
524
601
|
}
|
|
525
|
-
/** Items eligible for roving focus (ARIA-disabled deliberately remains eligible). */
|
|
526
602
|
#isNavigable(item) {
|
|
527
603
|
if (!this.#isSupportedHost(item) || this.#isHidden(item)) return false;
|
|
528
604
|
if (!(item instanceof HTMLButtonElement)) return true;
|
|
529
605
|
return !item.disabled && !inheritsFieldsetDisabled(item);
|
|
530
606
|
}
|
|
531
|
-
/** Whether hidden applies on the path from an item up to the group root. */
|
|
532
607
|
#isHidden(item) {
|
|
533
608
|
let current = item;
|
|
534
609
|
while (current && current !== this.element) {
|
|
@@ -537,7 +612,6 @@ var ToggleGroupController = class extends Controller {
|
|
|
537
612
|
}
|
|
538
613
|
return false;
|
|
539
614
|
}
|
|
540
|
-
/** Whether ARIA, visibility, or native HTML semantics suppress activation. */
|
|
541
615
|
#isActivationDisabled(item) {
|
|
542
616
|
if (!this.#isNavigable(item)) return true;
|
|
543
617
|
let current = item;
|
|
@@ -547,72 +621,59 @@ var ToggleGroupController = class extends Controller {
|
|
|
547
621
|
}
|
|
548
622
|
return false;
|
|
549
623
|
}
|
|
550
|
-
/** Releases default ownership when a Turbo morph authors `aria-pressed`. */
|
|
551
624
|
#releaseAuthoredPressed(records) {
|
|
552
625
|
for (const record of records) {
|
|
553
626
|
if (record.attributeName !== "aria-pressed") continue;
|
|
554
627
|
const item = record.target;
|
|
555
628
|
const value = item.getAttribute("aria-pressed");
|
|
556
|
-
if (value !== null
|
|
629
|
+
if (value !== null) {
|
|
557
630
|
this.#ownedPressed.delete(item);
|
|
558
631
|
}
|
|
559
632
|
}
|
|
560
|
-
this.#internalPressedValues.clear();
|
|
561
633
|
}
|
|
562
|
-
/** Watches target membership, retained item hosts/state, and inherited host/fieldset state. */
|
|
563
634
|
#observeMutations() {
|
|
564
|
-
|
|
565
|
-
this.#releaseAuthoredPressed(records);
|
|
566
|
-
this.#pass.schedule();
|
|
567
|
-
});
|
|
568
|
-
this.#observer = observer;
|
|
569
|
-
this.#observeWith(observer);
|
|
570
|
-
}
|
|
571
|
-
/** Registers every root and ancestor observation on one observer instance. */
|
|
572
|
-
#observeWith(observer) {
|
|
573
|
-
observer.observe(this.element, {
|
|
635
|
+
this.#observer.observe(this.element, {
|
|
574
636
|
subtree: true,
|
|
575
637
|
childList: true,
|
|
576
|
-
attributes:
|
|
577
|
-
|
|
638
|
+
attributes: ITEM_ATTRIBUTES,
|
|
639
|
+
ancestorAttributes: ["contenteditable", "disabled"]
|
|
578
640
|
});
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
});
|
|
585
|
-
ancestor = ancestor.parentElement;
|
|
641
|
+
}
|
|
642
|
+
#releaseDefaultsRewrittenWhileAway() {
|
|
643
|
+
for (const [item, written] of this.#ownedPressed) {
|
|
644
|
+
const current = item.getAttribute("aria-pressed");
|
|
645
|
+
if (current !== null && current !== written) this.#ownedPressed.delete(item);
|
|
586
646
|
}
|
|
587
647
|
}
|
|
588
|
-
/** Supported targets currently managed by the roving primitive. */
|
|
589
648
|
get #managedTargets() {
|
|
590
649
|
return this.itemTargets.filter((item) => this.#managedItems.has(item));
|
|
591
650
|
}
|
|
592
|
-
/** Managed items eligible for the roving Tab stop. */
|
|
593
651
|
get #navigableItems() {
|
|
594
652
|
return this.#managedTargets.filter((item) => this.#isNavigable(item));
|
|
595
653
|
}
|
|
596
|
-
/** Whether an item is currently pressed. */
|
|
597
654
|
#isPressed(item) {
|
|
598
655
|
return item.getAttribute("aria-pressed") === "true";
|
|
599
656
|
}
|
|
600
|
-
/** Reflects pressed state while distinguishing controller writes from authored morphs. */
|
|
601
657
|
#setPressed(item, pressed) {
|
|
602
658
|
const value = pressed ? "true" : "false";
|
|
603
|
-
this.#
|
|
604
|
-
item
|
|
659
|
+
if (this.#ownedPressed.has(item)) this.#ownedPressed.set(item, value);
|
|
660
|
+
this.#writePressed(item, value);
|
|
605
661
|
}
|
|
606
|
-
/** The DOM-ordered values of every currently pressed managed item. */
|
|
607
662
|
#pressedValues() {
|
|
608
663
|
return this.#managedTargets.filter((item) => this.#isPressed(item)).map((item) => this.#itemValue(item));
|
|
609
664
|
}
|
|
610
|
-
/** An item's value (`data-value`, defaulting to empty). */
|
|
611
665
|
#itemValue(item) {
|
|
612
666
|
return item.getAttribute("data-value") ?? "";
|
|
613
667
|
}
|
|
668
|
+
#writePressed(item, value) {
|
|
669
|
+
setAttributeIfChanged(
|
|
670
|
+
item,
|
|
671
|
+
"aria-pressed",
|
|
672
|
+
value,
|
|
673
|
+
() => this.#observer.claim(item, "aria-pressed", value)
|
|
674
|
+
);
|
|
675
|
+
}
|
|
614
676
|
};
|
|
615
677
|
|
|
616
678
|
export { ToggleGroupController };
|
|
617
|
-
//# sourceMappingURL=toggle_group_controller.js.map
|
|
618
679
|
//# sourceMappingURL=toggle_group_controller.js.map
|