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
|
@@ -44,12 +44,23 @@ import { Controller } from '@hotwired/stimulus';
|
|
|
44
44
|
* - Opt-in **dismiss on scroll** (`closeOnScroll`): while open, scrolling a tracked
|
|
45
45
|
* scroll-parent ancestor (or the window) closes the panel, the usual convention for
|
|
46
46
|
* anchored popups. Closes without restoring focus (like the modeless `focusout` path)
|
|
47
|
-
* so the close never fights the user's scroll. Off by default.
|
|
47
|
+
* so the close never fights the user's scroll. Off by default. Flipping it while the
|
|
48
|
+
* panel is open wires or releases the dismissal in place.
|
|
49
|
+
* - The open panel holds its Escape layer and scroll dismissal only while it is in the
|
|
50
|
+
* DOM: once it leaves (a removal, or a morph that swaps in another panel) both are
|
|
51
|
+
* released and the trigger reads `aria-expanded="false"`. When the page hides the
|
|
52
|
+
* panel itself, the next outside click, focus leaving, Escape, dismissing scroll or
|
|
53
|
+
* `close` releases them the same way; the panel already reads closed, so nothing is
|
|
54
|
+
* reported.
|
|
55
|
+
* - A trigger that takes over — in one task, or after an earlier one leaves in a later
|
|
56
|
+
* task — reads the open state, and one that stops resolving as the trigger gets back
|
|
57
|
+
* the `aria-expanded` it carried before this controller wrote on it.
|
|
48
58
|
* - Each move of the open state is reported: `stimeo--popover:open` and
|
|
49
59
|
* `stimeo--popover:close` dispatch `{ reason: StateReason }`, after the state
|
|
50
60
|
* attributes are written. Both are informational, so neither is cancelable. A
|
|
51
61
|
* call that leaves the state where it already was, the normalization in
|
|
52
|
-
* {@link connect},
|
|
62
|
+
* {@link connect}, the open panel leaving the DOM, a trigger that takes over, and
|
|
63
|
+
* {@link disconnect} are all silent.
|
|
53
64
|
*/
|
|
54
65
|
declare class PopoverController extends Controller<HTMLElement> {
|
|
55
66
|
#private;
|
|
@@ -63,7 +74,9 @@ declare class PopoverController extends Controller<HTMLElement> {
|
|
|
63
74
|
static actions: readonly ["close", "open", "toggle"];
|
|
64
75
|
static events: readonly ["close", "open"];
|
|
65
76
|
readonly triggerTarget: HTMLButtonElement;
|
|
77
|
+
readonly triggerTargets: HTMLButtonElement[];
|
|
66
78
|
readonly panelTarget: HTMLElement;
|
|
79
|
+
readonly panelTargets: HTMLElement[];
|
|
67
80
|
readonly hasTriggerTarget: boolean;
|
|
68
81
|
readonly hasPanelTarget: boolean;
|
|
69
82
|
readonly closeOnScrollValue: boolean;
|
|
@@ -71,11 +84,34 @@ declare class PopoverController extends Controller<HTMLElement> {
|
|
|
71
84
|
connect(): void;
|
|
72
85
|
/**
|
|
73
86
|
* Removes every standing listener registered in {@link connect} plus any active
|
|
74
|
-
* dismiss-on-scroll observers.
|
|
75
|
-
*
|
|
76
|
-
*
|
|
87
|
+
* dismiss-on-scroll observers. Releasing the set is a no-op for what it does not
|
|
88
|
+
* hold, so this is safe in the closed state too — no listener outlives the
|
|
89
|
+
* element after a Turbo navigation.
|
|
77
90
|
*/
|
|
78
91
|
disconnect(): void;
|
|
92
|
+
/**
|
|
93
|
+
* Follows a runtime flip of `closeOnScroll` while the panel is open, wiring or releasing
|
|
94
|
+
* the scroll dismissal in place. A closed panel holds nothing, so its next opening reads
|
|
95
|
+
* the declaration as it is then; the delivery Stimulus makes ahead of `connect()` finds
|
|
96
|
+
* nothing held either.
|
|
97
|
+
*/
|
|
98
|
+
closeOnScrollValueChanged(): void;
|
|
99
|
+
/**
|
|
100
|
+
* Releases what the open panel holds once it leaves the DOM — a removal, or a morph that
|
|
101
|
+
* swaps in another panel — and writes the closed state onto it and onto the trigger and
|
|
102
|
+
* any panel that remains. Focus is left where the removal put it. Nothing is dispatched:
|
|
103
|
+
* target churn is not a state move anyone made. After {@link disconnect}, which already
|
|
104
|
+
* released everything, this leaves the DOM alone.
|
|
105
|
+
*/
|
|
106
|
+
panelTargetDisconnected(panel: HTMLElement): void;
|
|
107
|
+
/** Brings a trigger that arrives after connect to the open state. */
|
|
108
|
+
triggerTargetConnected(): void;
|
|
109
|
+
/**
|
|
110
|
+
* Gives a trigger that no longer resolves as one its own `aria-expanded` back — after
|
|
111
|
+
* `disconnect()` too, since dropping the identifier leaves the element on the page — and
|
|
112
|
+
* brings the trigger that stays to the open state.
|
|
113
|
+
*/
|
|
114
|
+
triggerTargetDisconnected(trigger: HTMLButtonElement): void;
|
|
79
115
|
/** Toggles the popover. Bound via `data-action` (click on the trigger). */
|
|
80
116
|
toggle(event?: Event): void;
|
|
81
117
|
/** Opens the panel, reflects state, and moves focus inside it. */
|
|
@@ -1,8 +1,158 @@
|
|
|
1
1
|
import { Controller } from '@hotwired/stimulus';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
function setAttributeIfChanged(element, name, value, beforeWrite) {
|
|
4
|
+
if (element.getAttribute(name) === value) return false;
|
|
5
|
+
if (value === null) element.removeAttribute(name);
|
|
6
|
+
else element.setAttribute(name, value);
|
|
7
|
+
return true;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function sharedRegistry(key, create) {
|
|
11
|
+
const symbol = Symbol.for(key);
|
|
12
|
+
const scope = globalThis;
|
|
13
|
+
const existing = scope[symbol];
|
|
14
|
+
if (existing !== void 0) return existing;
|
|
15
|
+
const registry2 = create();
|
|
16
|
+
Object.defineProperty(globalThis, symbol, { value: registry2 });
|
|
17
|
+
return registry2;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
var registry = sharedRegistry(
|
|
21
|
+
"stimeo-ui.attribute-lease.registry.v1",
|
|
22
|
+
() => ({ stacks: /* @__PURE__ */ new WeakMap(), names: /* @__PURE__ */ new Map() })
|
|
23
|
+
);
|
|
24
|
+
function isAttributeValue(value) {
|
|
25
|
+
return value === null || typeof value === "string";
|
|
26
|
+
}
|
|
27
|
+
function readLeaseRecord(element, record) {
|
|
28
|
+
try {
|
|
29
|
+
const parsed = JSON.parse(element.getAttribute(record) ?? "null");
|
|
30
|
+
if (!Array.isArray(parsed)) return void 0;
|
|
31
|
+
const [original, written, ...rest] = parsed;
|
|
32
|
+
const linked = rest[0] !== false;
|
|
33
|
+
const beneath = linked ? rest : rest.slice(1);
|
|
34
|
+
if (!beneath.every((under) => typeof under === "string")) return void 0;
|
|
35
|
+
return isAttributeValue(original) && isAttributeValue(written) ? { original, written, linked, beneath } : void 0;
|
|
36
|
+
} catch {
|
|
37
|
+
return void 0;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function attributeStack(element, attribute) {
|
|
41
|
+
const byAttribute = registry.stacks.get(element) ?? /* @__PURE__ */ new Map();
|
|
42
|
+
registry.stacks.set(element, byAttribute);
|
|
43
|
+
const known = byAttribute.get(attribute);
|
|
44
|
+
if (known) return known;
|
|
45
|
+
const found = [];
|
|
46
|
+
for (const record of registry.names.get(attribute) ?? []) {
|
|
47
|
+
const read = readLeaseRecord(element, record);
|
|
48
|
+
if (read) found.push({ ...read, record });
|
|
49
|
+
}
|
|
50
|
+
const depth = ({ beneath }) => beneath.filter((name) => found.some((other) => other.record === name)).length;
|
|
51
|
+
const stack = found.sort((one, other) => depth(one) - depth(other)).map(({ record, written, original, linked }, index) => ({
|
|
52
|
+
lease: null,
|
|
53
|
+
record,
|
|
54
|
+
written,
|
|
55
|
+
original,
|
|
56
|
+
linked: linked && index > 0
|
|
57
|
+
}));
|
|
58
|
+
byAttribute.set(attribute, stack);
|
|
59
|
+
return stack;
|
|
60
|
+
}
|
|
61
|
+
function findHold(stack, lease, record) {
|
|
62
|
+
return stack.find((held) => held.lease === lease) ?? stack.find((held) => held.lease === null && held.record === record);
|
|
63
|
+
}
|
|
64
|
+
var AttributeLease = class {
|
|
65
|
+
#attribute;
|
|
66
|
+
#record;
|
|
67
|
+
#base;
|
|
68
|
+
#preserveAuthor;
|
|
69
|
+
#held = /* @__PURE__ */ new Set();
|
|
70
|
+
constructor(attribute, owner, options = {}) {
|
|
71
|
+
this.#attribute = attribute;
|
|
72
|
+
this.#record = `data-${owner}-${attribute}-lease`;
|
|
73
|
+
this.#base = options.base === true;
|
|
74
|
+
this.#preserveAuthor = options.preserveAuthor === true;
|
|
75
|
+
const names = registry.names;
|
|
76
|
+
names.set(attribute, (names.get(attribute) ?? /* @__PURE__ */ new Set()).add(this.#record));
|
|
77
|
+
}
|
|
78
|
+
write(element, value) {
|
|
79
|
+
const stack = attributeStack(element, this.#attribute);
|
|
80
|
+
const hold = this.#take(stack) ?? this.#acquire(element, stack);
|
|
81
|
+
this.#held.add(element);
|
|
82
|
+
const shows = !this.#covered(element, stack, hold);
|
|
83
|
+
hold.written = value;
|
|
84
|
+
this.#mark(element, stack);
|
|
85
|
+
if (shows) this.#reflect(element, value);
|
|
86
|
+
}
|
|
87
|
+
return(element) {
|
|
88
|
+
const held = this.#held.delete(element);
|
|
89
|
+
const known = registry.stacks.get(element)?.has(this.#attribute);
|
|
90
|
+
const stack = held || known || element.hasAttribute(this.#record) ? attributeStack(element, this.#attribute) : [];
|
|
91
|
+
const hold = this.#take(stack);
|
|
92
|
+
if (!hold) return false;
|
|
93
|
+
const carries = element.getAttribute(this.#attribute) === hold.written;
|
|
94
|
+
const owns = carries && !this.#covered(element, stack, hold);
|
|
95
|
+
const index = stack.indexOf(hold);
|
|
96
|
+
stack.splice(index, 1);
|
|
97
|
+
const above = stack[index];
|
|
98
|
+
if (above) above.linked &&= hold.linked;
|
|
99
|
+
this.#mark(element, stack);
|
|
100
|
+
if (!owns) return true;
|
|
101
|
+
const below = hold.linked ? stack[index - 1] : void 0;
|
|
102
|
+
this.#reflect(element, below ? below.written : hold.original);
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
returnAll() {
|
|
106
|
+
for (const element of Array.from(this.#held)) this.return(element);
|
|
107
|
+
}
|
|
108
|
+
#take(stack) {
|
|
109
|
+
const hold = findHold(stack, this, this.#record);
|
|
110
|
+
if (hold) hold.lease = this;
|
|
111
|
+
return hold;
|
|
112
|
+
}
|
|
113
|
+
#acquire(element, stack) {
|
|
114
|
+
const current = element.getAttribute(this.#attribute);
|
|
115
|
+
const top = stack.at(-1);
|
|
116
|
+
const bottom = stack[0];
|
|
117
|
+
const over = top?.written === current ? top : void 0;
|
|
118
|
+
const from = this.#base ? this.#preserveAuthor && !stack.some((held) => held.written === current) ? void 0 : bottom : over;
|
|
119
|
+
const hold = {
|
|
120
|
+
lease: this,
|
|
121
|
+
record: this.#record,
|
|
122
|
+
written: current,
|
|
123
|
+
original: from ? from.original : current,
|
|
124
|
+
linked: !this.#base && over !== void 0
|
|
125
|
+
};
|
|
126
|
+
if (this.#base && bottom) {
|
|
127
|
+
bottom.linked = true;
|
|
128
|
+
stack.unshift(hold);
|
|
129
|
+
} else stack.push(hold);
|
|
130
|
+
return hold;
|
|
131
|
+
}
|
|
132
|
+
#covered(element, stack, hold) {
|
|
133
|
+
const current = element.getAttribute(this.#attribute);
|
|
134
|
+
return stack.slice(stack.indexOf(hold) + 1).some((above) => above.written === current);
|
|
135
|
+
}
|
|
136
|
+
#mark(element, stack) {
|
|
137
|
+
const records = /* @__PURE__ */ new Map([[this.#record, null]]);
|
|
138
|
+
stack.forEach((hold, index) => {
|
|
139
|
+
const names = stack.slice(0, index).map((under) => under.record);
|
|
140
|
+
const beneath = [...new Set(names.reverse())].filter((name) => name !== hold.record);
|
|
141
|
+
const marker = hold.linked || beneath.length === 0 ? [] : [false];
|
|
142
|
+
records.set(
|
|
143
|
+
hold.record,
|
|
144
|
+
hold.written === hold.original && beneath.length === 0 && index === stack.length - 1 ? null : JSON.stringify([hold.original, hold.written, ...marker, ...beneath])
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
for (const [name, recorded] of records) {
|
|
148
|
+
setAttributeIfChanged(element, name, recorded);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
#reflect(element, value) {
|
|
152
|
+
setAttributeIfChanged(element, this.#attribute, value);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
4
155
|
|
|
5
|
-
// src/utils/escape_layer.ts
|
|
6
156
|
function claimsWhileFocusWithin(element) {
|
|
7
157
|
return () => {
|
|
8
158
|
const active = element.ownerDocument.activeElement;
|
|
@@ -10,89 +160,68 @@ function claimsWhileFocusWithin(element) {
|
|
|
10
160
|
};
|
|
11
161
|
}
|
|
12
162
|
var EscapeLayer = class _EscapeLayer {
|
|
13
|
-
static #registries =
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
#claims = null;
|
|
19
|
-
/**
|
|
20
|
-
* Activates this layer at the top of its document's Escape stack, installing
|
|
21
|
-
* the document's shared resolver listener if this is its first layer.
|
|
22
|
-
* Re-activating an already-active layer moves it to the top.
|
|
23
|
-
*/
|
|
163
|
+
static #registries = sharedRegistry(
|
|
164
|
+
"stimeo-ui.escape-layer.registry.v1",
|
|
165
|
+
() => /* @__PURE__ */ new WeakMap()
|
|
166
|
+
);
|
|
167
|
+
#active = null;
|
|
24
168
|
activate(ownerDocument = document, options) {
|
|
25
169
|
this.deactivate();
|
|
26
|
-
let
|
|
27
|
-
if (!
|
|
28
|
-
|
|
29
|
-
_EscapeLayer.#registries.set(ownerDocument,
|
|
30
|
-
ownerDocument.addEventListener("keydown",
|
|
170
|
+
let registry2 = _EscapeLayer.#registries.get(ownerDocument);
|
|
171
|
+
if (!registry2) {
|
|
172
|
+
registry2 = _EscapeLayer.#createRegistry();
|
|
173
|
+
_EscapeLayer.#registries.set(ownerDocument, registry2);
|
|
174
|
+
ownerDocument.addEventListener("keydown", registry2.onKeydown);
|
|
31
175
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
this.#
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Removes this layer from its document's Escape stack, uninstalling the
|
|
39
|
-
* shared listener when the stack empties. Safe to call when inactive.
|
|
40
|
-
*/
|
|
176
|
+
const entry = { onDismiss: options.onDismiss, claims: options.claims ?? null };
|
|
177
|
+
registry2.stack.push(entry);
|
|
178
|
+
this.#active = { document: ownerDocument, entry };
|
|
179
|
+
}
|
|
41
180
|
deactivate() {
|
|
42
|
-
const
|
|
43
|
-
if (!
|
|
44
|
-
const
|
|
45
|
-
if (
|
|
46
|
-
const index =
|
|
47
|
-
if (index >= 0)
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
_EscapeLayer.#registries.delete(
|
|
181
|
+
const active = this.#active;
|
|
182
|
+
if (!active) return;
|
|
183
|
+
const registry2 = _EscapeLayer.#registries.get(active.document);
|
|
184
|
+
if (registry2) {
|
|
185
|
+
const index = registry2.stack.lastIndexOf(active.entry);
|
|
186
|
+
if (index >= 0) registry2.stack.splice(index, 1);
|
|
187
|
+
if (registry2.stack.length === 0) {
|
|
188
|
+
active.document.removeEventListener("keydown", registry2.onKeydown);
|
|
189
|
+
_EscapeLayer.#registries.delete(active.document);
|
|
51
190
|
}
|
|
52
191
|
}
|
|
53
|
-
this.#
|
|
54
|
-
|
|
55
|
-
this.#claims = null;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Whether this active layer would own a press right now: it is the topmost
|
|
59
|
-
* layer whose {@link EscapeLayerOptions.claims} passes. Exposed for tests
|
|
60
|
-
* and diagnostics — production dismissal goes through the shared listener.
|
|
61
|
-
*/
|
|
192
|
+
this.#active = null;
|
|
193
|
+
}
|
|
62
194
|
get ownsEscape() {
|
|
63
|
-
const
|
|
64
|
-
if (!
|
|
65
|
-
const
|
|
66
|
-
if (!
|
|
67
|
-
return _EscapeLayer.#resolveOwner(
|
|
195
|
+
const active = this.#active;
|
|
196
|
+
if (!active) return false;
|
|
197
|
+
const registry2 = _EscapeLayer.#registries.get(active.document);
|
|
198
|
+
if (!registry2) return false;
|
|
199
|
+
return _EscapeLayer.#resolveOwner(registry2.stack) === active.entry;
|
|
68
200
|
}
|
|
69
|
-
/** Builds a document's registry with its shared resolver listener. */
|
|
70
201
|
static #createRegistry() {
|
|
71
|
-
const
|
|
202
|
+
const registry2 = {
|
|
72
203
|
stack: [],
|
|
73
204
|
onKeydown: (event) => {
|
|
74
205
|
if (event.key !== "Escape" || event.defaultPrevented || event.isComposing) return;
|
|
75
|
-
const owner = _EscapeLayer.#resolveOwner(
|
|
206
|
+
const owner = _EscapeLayer.#resolveOwner(registry2.stack);
|
|
76
207
|
if (!owner) return;
|
|
77
208
|
event.preventDefault();
|
|
78
|
-
owner
|
|
209
|
+
owner.onDismiss();
|
|
79
210
|
}
|
|
80
211
|
};
|
|
81
|
-
return
|
|
212
|
+
return registry2;
|
|
82
213
|
}
|
|
83
|
-
/** The topmost stack layer whose claims predicate passes, or `null`. */
|
|
84
214
|
static #resolveOwner(stack) {
|
|
85
215
|
for (let index = stack.length - 1; index >= 0; index--) {
|
|
86
216
|
const layer = stack[index];
|
|
87
217
|
if (!layer) continue;
|
|
88
|
-
if (layer
|
|
218
|
+
if (layer.claims && !layer.claims()) continue;
|
|
89
219
|
return layer;
|
|
90
220
|
}
|
|
91
221
|
return null;
|
|
92
222
|
}
|
|
93
223
|
};
|
|
94
224
|
|
|
95
|
-
// src/utils/focus_candidate.ts
|
|
96
225
|
function inheritsFieldsetDisabled(control) {
|
|
97
226
|
let fieldset = control.closest("fieldset[disabled]");
|
|
98
227
|
while (fieldset) {
|
|
@@ -102,8 +231,19 @@ function inheritsFieldsetDisabled(control) {
|
|
|
102
231
|
}
|
|
103
232
|
return false;
|
|
104
233
|
}
|
|
234
|
+
function unslotted(element) {
|
|
235
|
+
return element.assignedSlot === null && element.parentElement?.shadowRoot != null;
|
|
236
|
+
}
|
|
237
|
+
function flatTreeParent(element) {
|
|
238
|
+
if (unslotted(element)) return null;
|
|
239
|
+
const parent = element.assignedSlot ?? element.parentNode;
|
|
240
|
+
if (parent instanceof ShadowRoot) return parent.host;
|
|
241
|
+
return parent instanceof Element ? parent : null;
|
|
242
|
+
}
|
|
105
243
|
function canTakeFocus(element) {
|
|
106
|
-
|
|
244
|
+
for (let node = element; node; node = flatTreeParent(node)) {
|
|
245
|
+
if (unslotted(node) || node.matches("[hidden], [inert]")) return false;
|
|
246
|
+
}
|
|
107
247
|
if (element instanceof HTMLInputElement && element.type === "hidden") return false;
|
|
108
248
|
if (!("disabled" in element)) return true;
|
|
109
249
|
if (element.disabled) return false;
|
|
@@ -167,7 +307,17 @@ function firstTabStop(root) {
|
|
|
167
307
|
return null;
|
|
168
308
|
}
|
|
169
309
|
|
|
170
|
-
|
|
310
|
+
var ListenerSet = class {
|
|
311
|
+
#abort = new AbortController();
|
|
312
|
+
add(target, type, handler, options) {
|
|
313
|
+
target.addEventListener(type, handler, { ...options, signal: this.#abort.signal });
|
|
314
|
+
}
|
|
315
|
+
dispose() {
|
|
316
|
+
this.#abort.abort();
|
|
317
|
+
this.#abort = new AbortController();
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
|
|
171
321
|
function observeScrollDismiss(element, onScroll) {
|
|
172
322
|
const targets = [...scrollParents(element), window];
|
|
173
323
|
const handler = () => onScroll();
|
|
@@ -192,7 +342,6 @@ function isScrollable(element) {
|
|
|
192
342
|
return /auto|scroll|overlay/.test(style.overflow + style.overflowX + style.overflowY);
|
|
193
343
|
}
|
|
194
344
|
|
|
195
|
-
// src/utils/state_reason.ts
|
|
196
345
|
var FOCUS_EVENTS = /* @__PURE__ */ new Set(["blur", "focus", "focusin", "focusout"]);
|
|
197
346
|
var POINTER_EVENTS = /* @__PURE__ */ new Set(["mouseenter", "mouseleave", "pointerenter", "pointerleave"]);
|
|
198
347
|
function stateReasonFor(event) {
|
|
@@ -202,7 +351,6 @@ function stateReasonFor(event) {
|
|
|
202
351
|
return "user";
|
|
203
352
|
}
|
|
204
353
|
|
|
205
|
-
// src/controllers/popover_controller.ts
|
|
206
354
|
var PopoverController = class extends Controller {
|
|
207
355
|
static targets = ["trigger", "panel"];
|
|
208
356
|
static values = {
|
|
@@ -210,34 +358,43 @@ var PopoverController = class extends Controller {
|
|
|
210
358
|
};
|
|
211
359
|
static actions = ["close", "open", "toggle"];
|
|
212
360
|
static events = ["close", "open"];
|
|
213
|
-
/** Cleanup for the dismiss-on-scroll listeners while open, or `null`. */
|
|
214
361
|
#stopScrollDismiss = null;
|
|
215
|
-
/** Escape-stack membership while open; the shared resolver dismisses via it. */
|
|
216
362
|
#escapeLayer = new EscapeLayer();
|
|
217
|
-
|
|
363
|
+
#expanded = new AttributeLease("aria-expanded", this.identifier);
|
|
364
|
+
#shownPanel = null;
|
|
365
|
+
#connected = false;
|
|
218
366
|
#reporting = false;
|
|
219
|
-
|
|
367
|
+
#listeners = new ListenerSet();
|
|
220
368
|
connect() {
|
|
221
369
|
this.#close("api");
|
|
222
|
-
|
|
223
|
-
this.element
|
|
370
|
+
this.#listeners.add(document, "click", this.#onOutsideClick, { capture: true });
|
|
371
|
+
this.#listeners.add(this.element, "focusout", this.#onFocusOut);
|
|
372
|
+
this.#connected = true;
|
|
224
373
|
this.#reporting = true;
|
|
225
374
|
}
|
|
226
|
-
/**
|
|
227
|
-
* Removes every standing listener registered in {@link connect} plus any active
|
|
228
|
-
* dismiss-on-scroll observers. `removeEventListener` is a no-op when it was
|
|
229
|
-
* never added, so this is safe in the closed state too — no listener outlives
|
|
230
|
-
* the element after a Turbo navigation.
|
|
231
|
-
*/
|
|
232
375
|
disconnect() {
|
|
376
|
+
this.#connected = false;
|
|
233
377
|
this.#reporting = false;
|
|
234
|
-
this.#
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
this.#
|
|
378
|
+
this.#release();
|
|
379
|
+
this.#listeners.dispose();
|
|
380
|
+
}
|
|
381
|
+
closeOnScrollValueChanged() {
|
|
382
|
+
if (this.#shownPanel) this.#syncScrollDismiss();
|
|
383
|
+
}
|
|
384
|
+
panelTargetDisconnected(panel) {
|
|
385
|
+
if (panel !== this.#shownPanel) return;
|
|
386
|
+
if (this.panelTargets.includes(panel)) return;
|
|
387
|
+
this.#release();
|
|
388
|
+
panel.hidden = true;
|
|
389
|
+
this.#reflectClosed();
|
|
390
|
+
}
|
|
391
|
+
triggerTargetConnected() {
|
|
392
|
+
if (this.#connected) this.#reflectTrigger();
|
|
393
|
+
}
|
|
394
|
+
triggerTargetDisconnected(trigger) {
|
|
395
|
+
if (!this.triggerTargets.includes(trigger)) this.#expanded.return(trigger);
|
|
396
|
+
if (this.#connected) this.#reflectTrigger();
|
|
239
397
|
}
|
|
240
|
-
/** Toggles the popover. Bound via `data-action` (click on the trigger). */
|
|
241
398
|
toggle(event) {
|
|
242
399
|
if (this.#isOpen) {
|
|
243
400
|
this.close(event);
|
|
@@ -245,46 +402,54 @@ var PopoverController = class extends Controller {
|
|
|
245
402
|
this.open(event);
|
|
246
403
|
}
|
|
247
404
|
}
|
|
248
|
-
/** Opens the panel, reflects state, and moves focus inside it. */
|
|
249
405
|
open(event) {
|
|
250
406
|
this.#open(stateReasonFor(event));
|
|
251
407
|
}
|
|
252
|
-
/** Closes the panel and reflects the collapsed state. Bound via `data-action`. */
|
|
253
408
|
close(event) {
|
|
254
409
|
this.#close(stateReasonFor(event));
|
|
255
410
|
}
|
|
256
|
-
/**
|
|
257
|
-
* Opens the panel, reflects state, reports a move, and moves focus inside it.
|
|
258
|
-
*
|
|
259
|
-
* @stimeoRuntimeOnly `closeOnScroll` decides whether this opening wires the scroll dismissal;
|
|
260
|
-
* what is shown does not depend on it.
|
|
261
|
-
*/
|
|
262
411
|
#open(reason) {
|
|
263
412
|
if (!this.hasPanelTarget || this.#isOpen) return;
|
|
264
|
-
this.panelTarget
|
|
265
|
-
|
|
413
|
+
const panel = this.panelTarget;
|
|
414
|
+
panel.hidden = false;
|
|
415
|
+
if (this.hasTriggerTarget) this.#expanded.write(this.triggerTarget, "true");
|
|
416
|
+
this.#shownPanel = panel;
|
|
266
417
|
if (this.#reporting) this.dispatch("open", { detail: { reason }, cancelable: false });
|
|
267
|
-
if (!this.#isOpen) return;
|
|
418
|
+
if (this.#shownPanel !== panel || !this.#isOpen) return;
|
|
268
419
|
this.#escapeLayer.activate(document, {
|
|
269
420
|
onDismiss: () => this.#closeAndRestore(),
|
|
270
421
|
claims: claimsWhileFocusWithin(this.element)
|
|
271
422
|
});
|
|
272
|
-
|
|
273
|
-
this.#stopScrollDismiss = observeScrollDismiss(this.element, () => this.#close("scroll"));
|
|
274
|
-
}
|
|
423
|
+
this.#syncScrollDismiss();
|
|
275
424
|
this.#focusFirst();
|
|
276
425
|
}
|
|
277
|
-
/** Closes the panel, reflects the collapsed state, and reports a move. */
|
|
278
426
|
#close(reason) {
|
|
279
427
|
const was = this.#isOpen;
|
|
428
|
+
this.#release();
|
|
429
|
+
this.#reflectClosed();
|
|
430
|
+
if (was && this.#reporting) this.dispatch("close", { detail: { reason }, cancelable: false });
|
|
431
|
+
}
|
|
432
|
+
#reflectClosed() {
|
|
433
|
+
if (this.hasPanelTarget) this.panelTarget.hidden = true;
|
|
434
|
+
if (this.hasTriggerTarget) this.#expanded.write(this.triggerTarget, "false");
|
|
435
|
+
}
|
|
436
|
+
#reflectTrigger() {
|
|
437
|
+
if (this.hasTriggerTarget) this.#expanded.write(this.triggerTarget, String(this.#isOpen));
|
|
438
|
+
}
|
|
439
|
+
#release() {
|
|
440
|
+
this.#shownPanel = null;
|
|
280
441
|
this.#escapeLayer.deactivate();
|
|
281
442
|
this.#stopScrollDismiss?.();
|
|
282
443
|
this.#stopScrollDismiss = null;
|
|
283
|
-
if (this.hasPanelTarget) this.panelTarget.hidden = true;
|
|
284
|
-
if (this.hasTriggerTarget) this.triggerTarget.setAttribute("aria-expanded", "false");
|
|
285
|
-
if (was && this.#reporting) this.dispatch("close", { detail: { reason }, cancelable: false });
|
|
286
444
|
}
|
|
287
|
-
|
|
445
|
+
#syncScrollDismiss() {
|
|
446
|
+
if (this.closeOnScrollValue) {
|
|
447
|
+
this.#stopScrollDismiss ??= observeScrollDismiss(this.element, () => this.#close("scroll"));
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
this.#stopScrollDismiss?.();
|
|
451
|
+
this.#stopScrollDismiss = null;
|
|
452
|
+
}
|
|
288
453
|
#focusFirst() {
|
|
289
454
|
const first = firstTabStop(this.panelTarget);
|
|
290
455
|
if (first) {
|
|
@@ -294,38 +459,29 @@ var PopoverController = class extends Controller {
|
|
|
294
459
|
if (!this.panelTarget.hasAttribute("tabindex")) this.panelTarget.tabIndex = -1;
|
|
295
460
|
this.panelTarget.focus();
|
|
296
461
|
}
|
|
297
|
-
/** Closes and restores focus to the trigger for explicit keyboard dismissal. */
|
|
298
462
|
#closeAndRestore() {
|
|
299
463
|
this.#close("escape");
|
|
300
464
|
if (this.hasTriggerTarget) this.triggerTarget.focus();
|
|
301
465
|
}
|
|
302
|
-
/** Closes without moving focus when a click lands outside the controller element. */
|
|
303
466
|
#onOutsideClick = (event) => {
|
|
304
467
|
const target = event.target;
|
|
305
|
-
if (this.#
|
|
468
|
+
if (this.#closable && target instanceof Node && !this.element.contains(target)) {
|
|
306
469
|
this.#close("outside");
|
|
307
470
|
}
|
|
308
471
|
};
|
|
309
|
-
/**
|
|
310
|
-
* Closes when focus leaves the controller for a known external destination
|
|
311
|
-
* (e.g. forward Tab past the panel or reverse Tab past the trigger). Focus is
|
|
312
|
-
* not restored — the natural destination is kept, which is the modeless
|
|
313
|
-
* contract. A null/non-Node destination is indeterminate: browsers use it for
|
|
314
|
-
* clicks on non-focusable content and window deactivation, so the later outside
|
|
315
|
-
* click handler decides pointer dismissal instead.
|
|
316
|
-
*/
|
|
317
472
|
#onFocusOut = (event) => {
|
|
318
|
-
if (!this.#
|
|
473
|
+
if (!this.#closable) return;
|
|
319
474
|
const next = event.relatedTarget;
|
|
320
475
|
if (!(next instanceof Node) || this.element.contains(next)) return;
|
|
321
476
|
this.#close("focus");
|
|
322
477
|
};
|
|
323
|
-
/** Whether the panel is currently visible. */
|
|
324
478
|
get #isOpen() {
|
|
325
479
|
return this.hasPanelTarget && !this.panelTarget.hidden;
|
|
326
480
|
}
|
|
481
|
+
get #closable() {
|
|
482
|
+
return this.#isOpen || this.#shownPanel !== null;
|
|
483
|
+
}
|
|
327
484
|
};
|
|
328
485
|
|
|
329
486
|
export { PopoverController };
|
|
330
|
-
//# sourceMappingURL=popover_controller.js.map
|
|
331
487
|
//# sourceMappingURL=popover_controller.js.map
|