stimeo-ui 0.1.0-alpha.1
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/LICENSE +21 -0
- package/README.md +72 -0
- package/dist/controllers/accordion_controller.d.ts +59 -0
- package/dist/controllers/accordion_controller.js +76 -0
- package/dist/controllers/accordion_controller.js.map +1 -0
- package/dist/controllers/announcer_controller.d.ts +78 -0
- package/dist/controllers/announcer_controller.js +184 -0
- package/dist/controllers/announcer_controller.js.map +1 -0
- package/dist/controllers/aspect_ratio_controller.d.ts +39 -0
- package/dist/controllers/aspect_ratio_controller.js +36 -0
- package/dist/controllers/aspect_ratio_controller.js.map +1 -0
- package/dist/controllers/auto_submit_controller.d.ts +74 -0
- package/dist/controllers/auto_submit_controller.js +147 -0
- package/dist/controllers/auto_submit_controller.js.map +1 -0
- package/dist/controllers/avatar_controller.d.ts +50 -0
- package/dist/controllers/avatar_controller.js +66 -0
- package/dist/controllers/avatar_controller.js.map +1 -0
- package/dist/controllers/breadcrumb_controller.d.ts +60 -0
- package/dist/controllers/breadcrumb_controller.js +123 -0
- package/dist/controllers/breadcrumb_controller.js.map +1 -0
- package/dist/controllers/bulk_select_controller.d.ts +67 -0
- package/dist/controllers/bulk_select_controller.js +104 -0
- package/dist/controllers/bulk_select_controller.js.map +1 -0
- package/dist/controllers/calendar_controller.d.ts +100 -0
- package/dist/controllers/calendar_controller.js +394 -0
- package/dist/controllers/calendar_controller.js.map +1 -0
- package/dist/controllers/character_counter_controller.d.ts +63 -0
- package/dist/controllers/character_counter_controller.js +179 -0
- package/dist/controllers/character_counter_controller.js.map +1 -0
- package/dist/controllers/checkbox_controller.d.ts +52 -0
- package/dist/controllers/checkbox_controller.js +73 -0
- package/dist/controllers/checkbox_controller.js.map +1 -0
- package/dist/controllers/combobox_controller.d.ts +76 -0
- package/dist/controllers/combobox_controller.js +186 -0
- package/dist/controllers/combobox_controller.js.map +1 -0
- package/dist/controllers/command_palette_controller.d.ts +103 -0
- package/dist/controllers/command_palette_controller.js +381 -0
- package/dist/controllers/command_palette_controller.js.map +1 -0
- package/dist/controllers/conditional_fields_controller.d.ts +56 -0
- package/dist/controllers/conditional_fields_controller.js +112 -0
- package/dist/controllers/conditional_fields_controller.js.map +1 -0
- package/dist/controllers/confirm_controller.d.ts +83 -0
- package/dist/controllers/confirm_controller.js +276 -0
- package/dist/controllers/confirm_controller.js.map +1 -0
- package/dist/controllers/context_menu_controller.d.ts +81 -0
- package/dist/controllers/context_menu_controller.js +112 -0
- package/dist/controllers/context_menu_controller.js.map +1 -0
- package/dist/controllers/countdown_controller.d.ts +93 -0
- package/dist/controllers/countdown_controller.js +202 -0
- package/dist/controllers/countdown_controller.js.map +1 -0
- package/dist/controllers/dialog_controller.d.ts +57 -0
- package/dist/controllers/dialog_controller.js +207 -0
- package/dist/controllers/dialog_controller.js.map +1 -0
- package/dist/controllers/direct_upload_controller.d.ts +77 -0
- package/dist/controllers/direct_upload_controller.js +212 -0
- package/dist/controllers/direct_upload_controller.js.map +1 -0
- package/dist/controllers/dirty_form_controller.d.ts +52 -0
- package/dist/controllers/dirty_form_controller.js +128 -0
- package/dist/controllers/dirty_form_controller.js.map +1 -0
- package/dist/controllers/dropdown_controller.d.ts +49 -0
- package/dist/controllers/dropdown_controller.js +66 -0
- package/dist/controllers/dropdown_controller.js.map +1 -0
- package/dist/controllers/empty_state_controller.d.ts +60 -0
- package/dist/controllers/empty_state_controller.js +67 -0
- package/dist/controllers/empty_state_controller.js.map +1 -0
- package/dist/controllers/flash_controller.d.ts +63 -0
- package/dist/controllers/flash_controller.js +221 -0
- package/dist/controllers/flash_controller.js.map +1 -0
- package/dist/controllers/focus_controller.d.ts +69 -0
- package/dist/controllers/focus_controller.js +216 -0
- package/dist/controllers/focus_controller.js.map +1 -0
- package/dist/controllers/form_field_controller.d.ts +79 -0
- package/dist/controllers/form_field_controller.js +154 -0
- package/dist/controllers/form_field_controller.js.map +1 -0
- package/dist/controllers/form_validation_controller.d.ts +114 -0
- package/dist/controllers/form_validation_controller.js +202 -0
- package/dist/controllers/form_validation_controller.js.map +1 -0
- package/dist/controllers/frame_loading_controller.d.ts +58 -0
- package/dist/controllers/frame_loading_controller.js +177 -0
- package/dist/controllers/frame_loading_controller.js.map +1 -0
- package/dist/controllers/highlight_controller.d.ts +50 -0
- package/dist/controllers/highlight_controller.js +107 -0
- package/dist/controllers/highlight_controller.js.map +1 -0
- package/dist/controllers/hover_card_controller.d.ts +79 -0
- package/dist/controllers/hover_card_controller.js +165 -0
- package/dist/controllers/hover_card_controller.js.map +1 -0
- package/dist/controllers/idle_controller.d.ts +51 -0
- package/dist/controllers/idle_controller.js +141 -0
- package/dist/controllers/idle_controller.js.map +1 -0
- package/dist/controllers/input_mask_controller.d.ts +74 -0
- package/dist/controllers/input_mask_controller.js +166 -0
- package/dist/controllers/input_mask_controller.js.map +1 -0
- package/dist/controllers/lazy_frame_controller.d.ts +53 -0
- package/dist/controllers/lazy_frame_controller.js +68 -0
- package/dist/controllers/lazy_frame_controller.js.map +1 -0
- package/dist/controllers/listbox_controller.d.ts +88 -0
- package/dist/controllers/listbox_controller.js +256 -0
- package/dist/controllers/listbox_controller.js.map +1 -0
- package/dist/controllers/local_time_controller.d.ts +60 -0
- package/dist/controllers/local_time_controller.js +81 -0
- package/dist/controllers/local_time_controller.js.map +1 -0
- package/dist/controllers/menu_controller.d.ts +81 -0
- package/dist/controllers/menu_controller.js +134 -0
- package/dist/controllers/menu_controller.js.map +1 -0
- package/dist/controllers/meter_controller.d.ts +93 -0
- package/dist/controllers/meter_controller.js +96 -0
- package/dist/controllers/meter_controller.js.map +1 -0
- package/dist/controllers/nested_form_controller.d.ts +85 -0
- package/dist/controllers/nested_form_controller.js +131 -0
- package/dist/controllers/nested_form_controller.js.map +1 -0
- package/dist/controllers/network_status_controller.d.ts +49 -0
- package/dist/controllers/network_status_controller.js +126 -0
- package/dist/controllers/network_status_controller.js.map +1 -0
- package/dist/controllers/number_input_controller.d.ts +93 -0
- package/dist/controllers/number_input_controller.js +306 -0
- package/dist/controllers/number_input_controller.js.map +1 -0
- package/dist/controllers/otp_controller.d.ts +68 -0
- package/dist/controllers/otp_controller.js +201 -0
- package/dist/controllers/otp_controller.js.map +1 -0
- package/dist/controllers/overflow_indicator_controller.d.ts +62 -0
- package/dist/controllers/overflow_indicator_controller.js +169 -0
- package/dist/controllers/overflow_indicator_controller.js.map +1 -0
- package/dist/controllers/overflow_menu_controller.d.ts +64 -0
- package/dist/controllers/overflow_menu_controller.js +274 -0
- package/dist/controllers/overflow_menu_controller.js.map +1 -0
- package/dist/controllers/pagination_controller.d.ts +69 -0
- package/dist/controllers/pagination_controller.js +89 -0
- package/dist/controllers/pagination_controller.js.map +1 -0
- package/dist/controllers/password_strength_controller.d.ts +67 -0
- package/dist/controllers/password_strength_controller.js +175 -0
- package/dist/controllers/password_strength_controller.js.map +1 -0
- package/dist/controllers/persist_controller.d.ts +63 -0
- package/dist/controllers/persist_controller.js +259 -0
- package/dist/controllers/persist_controller.js.map +1 -0
- package/dist/controllers/popover_controller.d.ts +63 -0
- package/dist/controllers/popover_controller.js +94 -0
- package/dist/controllers/popover_controller.js.map +1 -0
- package/dist/controllers/portal_controller.d.ts +58 -0
- package/dist/controllers/portal_controller.js +63 -0
- package/dist/controllers/portal_controller.js.map +1 -0
- package/dist/controllers/preview_guard_controller.d.ts +47 -0
- package/dist/controllers/preview_guard_controller.js +69 -0
- package/dist/controllers/preview_guard_controller.js.map +1 -0
- package/dist/controllers/progress_controller.d.ts +85 -0
- package/dist/controllers/progress_controller.js +93 -0
- package/dist/controllers/progress_controller.js.map +1 -0
- package/dist/controllers/radio_group_controller.d.ts +49 -0
- package/dist/controllers/radio_group_controller.js +128 -0
- package/dist/controllers/radio_group_controller.js.map +1 -0
- package/dist/controllers/rating_controller.d.ts +82 -0
- package/dist/controllers/rating_controller.js +179 -0
- package/dist/controllers/rating_controller.js.map +1 -0
- package/dist/controllers/relative_time_controller.d.ts +48 -0
- package/dist/controllers/relative_time_controller.js +129 -0
- package/dist/controllers/relative_time_controller.js.map +1 -0
- package/dist/controllers/reset_before_cache_controller.d.ts +54 -0
- package/dist/controllers/reset_before_cache_controller.js +62 -0
- package/dist/controllers/reset_before_cache_controller.js.map +1 -0
- package/dist/controllers/resizable_controller.d.ts +81 -0
- package/dist/controllers/resizable_controller.js +163 -0
- package/dist/controllers/resizable_controller.js.map +1 -0
- package/dist/controllers/roving_controller.d.ts +63 -0
- package/dist/controllers/roving_controller.js +116 -0
- package/dist/controllers/roving_controller.js.map +1 -0
- package/dist/controllers/scroll_area_controller.d.ts +45 -0
- package/dist/controllers/scroll_area_controller.js +183 -0
- package/dist/controllers/scroll_area_controller.js.map +1 -0
- package/dist/controllers/scroll_visibility_controller.d.ts +72 -0
- package/dist/controllers/scroll_visibility_controller.js +103 -0
- package/dist/controllers/scroll_visibility_controller.js.map +1 -0
- package/dist/controllers/scrollspy_controller.d.ts +65 -0
- package/dist/controllers/scrollspy_controller.js +171 -0
- package/dist/controllers/scrollspy_controller.js.map +1 -0
- package/dist/controllers/skeleton_controller.d.ts +50 -0
- package/dist/controllers/skeleton_controller.js +125 -0
- package/dist/controllers/skeleton_controller.js.map +1 -0
- package/dist/controllers/slider_controller.d.ts +76 -0
- package/dist/controllers/slider_controller.js +109 -0
- package/dist/controllers/slider_controller.js.map +1 -0
- package/dist/controllers/spinner_controller.d.ts +62 -0
- package/dist/controllers/spinner_controller.js +164 -0
- package/dist/controllers/spinner_controller.js.map +1 -0
- package/dist/controllers/step_indicator_controller.d.ts +55 -0
- package/dist/controllers/step_indicator_controller.js +55 -0
- package/dist/controllers/step_indicator_controller.js.map +1 -0
- package/dist/controllers/stepper_controller.d.ts +66 -0
- package/dist/controllers/stepper_controller.js +78 -0
- package/dist/controllers/stepper_controller.js.map +1 -0
- package/dist/controllers/stick_to_bottom_controller.d.ts +61 -0
- package/dist/controllers/stick_to_bottom_controller.js +100 -0
- package/dist/controllers/stick_to_bottom_controller.js.map +1 -0
- package/dist/controllers/sticky_observer_controller.d.ts +54 -0
- package/dist/controllers/sticky_observer_controller.js +53 -0
- package/dist/controllers/sticky_observer_controller.js.map +1 -0
- package/dist/controllers/submit_once_controller.d.ts +66 -0
- package/dist/controllers/submit_once_controller.js +206 -0
- package/dist/controllers/submit_once_controller.js.map +1 -0
- package/dist/controllers/switch_controller.d.ts +43 -0
- package/dist/controllers/switch_controller.js +50 -0
- package/dist/controllers/switch_controller.js.map +1 -0
- package/dist/controllers/tabs_controller.d.ts +48 -0
- package/dist/controllers/tabs_controller.js +63 -0
- package/dist/controllers/tabs_controller.js.map +1 -0
- package/dist/controllers/textarea_autosize_controller.d.ts +47 -0
- package/dist/controllers/textarea_autosize_controller.js +72 -0
- package/dist/controllers/textarea_autosize_controller.js.map +1 -0
- package/dist/controllers/theme_controller.d.ts +70 -0
- package/dist/controllers/theme_controller.js +154 -0
- package/dist/controllers/theme_controller.js.map +1 -0
- package/dist/controllers/toast_controller.d.ts +123 -0
- package/dist/controllers/toast_controller.js +310 -0
- package/dist/controllers/toast_controller.js.map +1 -0
- package/dist/controllers/toggle_group_controller.d.ts +56 -0
- package/dist/controllers/toggle_group_controller.js +130 -0
- package/dist/controllers/toggle_group_controller.js.map +1 -0
- package/dist/controllers/toolbar_controller.d.ts +59 -0
- package/dist/controllers/toolbar_controller.js +113 -0
- package/dist/controllers/toolbar_controller.js.map +1 -0
- package/dist/controllers/tooltip_controller.d.ts +74 -0
- package/dist/controllers/tooltip_controller.js +165 -0
- package/dist/controllers/tooltip_controller.js.map +1 -0
- package/dist/controllers/transition_controller.d.ts +86 -0
- package/dist/controllers/transition_controller.js +203 -0
- package/dist/controllers/transition_controller.js.map +1 -0
- package/dist/index.d.ts +1931 -0
- package/dist/index.js +12241 -0
- package/dist/index.js.map +1 -0
- package/dist/inspector/cli.d.ts +149 -0
- package/dist/inspector/cli.js +663 -0
- package/dist/inspector/cli.js.map +1 -0
- package/dist/inspector/cli_bin.d.ts +2 -0
- package/dist/inspector/cli_bin.js +665 -0
- package/dist/inspector/cli_bin.js.map +1 -0
- package/dist/inspector/manifest.json +2235 -0
- package/dist/positioning/index.d.ts +226 -0
- package/dist/positioning/index.js +145 -0
- package/dist/positioning/index.js.map +1 -0
- package/package.json +93 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1931 @@
|
|
|
1
|
+
import { Controller, Application } from '@hotwired/stimulus';
|
|
2
|
+
import { AccordionController } from './controllers/accordion_controller.js';
|
|
3
|
+
import { AnnouncerController } from './controllers/announcer_controller.js';
|
|
4
|
+
import { AspectRatioController } from './controllers/aspect_ratio_controller.js';
|
|
5
|
+
import { AutoSubmitController } from './controllers/auto_submit_controller.js';
|
|
6
|
+
import { AvatarController } from './controllers/avatar_controller.js';
|
|
7
|
+
import { BreadcrumbController } from './controllers/breadcrumb_controller.js';
|
|
8
|
+
import { BulkSelectController } from './controllers/bulk_select_controller.js';
|
|
9
|
+
import { CalendarController } from './controllers/calendar_controller.js';
|
|
10
|
+
import { CharacterCounterController } from './controllers/character_counter_controller.js';
|
|
11
|
+
import { CheckboxController } from './controllers/checkbox_controller.js';
|
|
12
|
+
import { ComboboxController } from './controllers/combobox_controller.js';
|
|
13
|
+
import { CommandPaletteController } from './controllers/command_palette_controller.js';
|
|
14
|
+
import { ConditionalFieldsController } from './controllers/conditional_fields_controller.js';
|
|
15
|
+
import { ConfirmController } from './controllers/confirm_controller.js';
|
|
16
|
+
import { ContextMenuController } from './controllers/context_menu_controller.js';
|
|
17
|
+
import { CountdownController } from './controllers/countdown_controller.js';
|
|
18
|
+
import { DialogController } from './controllers/dialog_controller.js';
|
|
19
|
+
import { DirectUploadController } from './controllers/direct_upload_controller.js';
|
|
20
|
+
import { DirtyFormController } from './controllers/dirty_form_controller.js';
|
|
21
|
+
import { DropdownController } from './controllers/dropdown_controller.js';
|
|
22
|
+
import { EmptyStateController } from './controllers/empty_state_controller.js';
|
|
23
|
+
import { FlashController } from './controllers/flash_controller.js';
|
|
24
|
+
import { FocusController } from './controllers/focus_controller.js';
|
|
25
|
+
import { FormFieldController } from './controllers/form_field_controller.js';
|
|
26
|
+
import { FormValidationController } from './controllers/form_validation_controller.js';
|
|
27
|
+
import { FrameLoadingController } from './controllers/frame_loading_controller.js';
|
|
28
|
+
import { HighlightController } from './controllers/highlight_controller.js';
|
|
29
|
+
import { HoverCardController } from './controllers/hover_card_controller.js';
|
|
30
|
+
import { IdleController } from './controllers/idle_controller.js';
|
|
31
|
+
import { InputMaskController } from './controllers/input_mask_controller.js';
|
|
32
|
+
import { LazyFrameController } from './controllers/lazy_frame_controller.js';
|
|
33
|
+
import { ListboxController } from './controllers/listbox_controller.js';
|
|
34
|
+
import { LocalTimeController } from './controllers/local_time_controller.js';
|
|
35
|
+
import { MenuController } from './controllers/menu_controller.js';
|
|
36
|
+
import { MeterController } from './controllers/meter_controller.js';
|
|
37
|
+
import { NestedFormController } from './controllers/nested_form_controller.js';
|
|
38
|
+
import { NetworkStatusController } from './controllers/network_status_controller.js';
|
|
39
|
+
import { NumberInputController } from './controllers/number_input_controller.js';
|
|
40
|
+
import { OtpController } from './controllers/otp_controller.js';
|
|
41
|
+
import { OverflowIndicatorController } from './controllers/overflow_indicator_controller.js';
|
|
42
|
+
import { OverflowMenuController } from './controllers/overflow_menu_controller.js';
|
|
43
|
+
import { PaginationController } from './controllers/pagination_controller.js';
|
|
44
|
+
import { PasswordStrengthController } from './controllers/password_strength_controller.js';
|
|
45
|
+
import { PersistController } from './controllers/persist_controller.js';
|
|
46
|
+
import { PopoverController } from './controllers/popover_controller.js';
|
|
47
|
+
import { PortalController } from './controllers/portal_controller.js';
|
|
48
|
+
import { PreviewGuardController } from './controllers/preview_guard_controller.js';
|
|
49
|
+
import { ProgressController } from './controllers/progress_controller.js';
|
|
50
|
+
import { RadioGroupController } from './controllers/radio_group_controller.js';
|
|
51
|
+
import { RatingController } from './controllers/rating_controller.js';
|
|
52
|
+
import { RelativeTimeController } from './controllers/relative_time_controller.js';
|
|
53
|
+
import { ResetBeforeCacheController } from './controllers/reset_before_cache_controller.js';
|
|
54
|
+
import { ResizableController } from './controllers/resizable_controller.js';
|
|
55
|
+
import { RovingController } from './controllers/roving_controller.js';
|
|
56
|
+
import { ScrollAreaController } from './controllers/scroll_area_controller.js';
|
|
57
|
+
import { ScrollVisibilityController } from './controllers/scroll_visibility_controller.js';
|
|
58
|
+
import { ScrollspyController } from './controllers/scrollspy_controller.js';
|
|
59
|
+
import { SkeletonController } from './controllers/skeleton_controller.js';
|
|
60
|
+
import { SliderController } from './controllers/slider_controller.js';
|
|
61
|
+
import { SpinnerController } from './controllers/spinner_controller.js';
|
|
62
|
+
import { StepIndicatorController } from './controllers/step_indicator_controller.js';
|
|
63
|
+
import { StepperController } from './controllers/stepper_controller.js';
|
|
64
|
+
import { StickToBottomController } from './controllers/stick_to_bottom_controller.js';
|
|
65
|
+
import { StickyObserverController } from './controllers/sticky_observer_controller.js';
|
|
66
|
+
import { SubmitOnceController } from './controllers/submit_once_controller.js';
|
|
67
|
+
import { SwitchController } from './controllers/switch_controller.js';
|
|
68
|
+
import { TabsController } from './controllers/tabs_controller.js';
|
|
69
|
+
import { TextareaAutosizeController } from './controllers/textarea_autosize_controller.js';
|
|
70
|
+
import { ThemeController } from './controllers/theme_controller.js';
|
|
71
|
+
import { ToastController } from './controllers/toast_controller.js';
|
|
72
|
+
import { ToggleGroupController } from './controllers/toggle_group_controller.js';
|
|
73
|
+
import { ToolbarController } from './controllers/toolbar_controller.js';
|
|
74
|
+
import { TooltipController } from './controllers/tooltip_controller.js';
|
|
75
|
+
import { TransitionController } from './controllers/transition_controller.js';
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Headless, accessible **alert dialog** behavior.
|
|
79
|
+
*
|
|
80
|
+
* Markup contract (identifier: `stimeo--alert-dialog`):
|
|
81
|
+
* <div data-controller="stimeo--alert-dialog">
|
|
82
|
+
* <button data-stimeo--alert-dialog-target="trigger"
|
|
83
|
+
* data-action="click->stimeo--alert-dialog#open">Delete…</button>
|
|
84
|
+
* <div data-stimeo--alert-dialog-target="dialog" role="alertdialog"
|
|
85
|
+
* aria-modal="true" aria-labelledby="t" aria-describedby="d" hidden>
|
|
86
|
+
* <h2 id="t">…</h2><p id="d">…</p>
|
|
87
|
+
* <button data-stimeo--alert-dialog-target="initialFocus"
|
|
88
|
+
* data-action="click->stimeo--alert-dialog#cancel">Cancel</button>
|
|
89
|
+
* <button data-action="click->stimeo--alert-dialog#confirm">Delete</button>
|
|
90
|
+
* </div>
|
|
91
|
+
* </div>
|
|
92
|
+
*
|
|
93
|
+
* Implements the WAI-ARIA APG **Alert Dialog** pattern. It is the same modal as
|
|
94
|
+
* `stimeo--dialog` with two deliberate differences that suit an *interrupting
|
|
95
|
+
* confirmation*: it never closes on a backdrop click (an accidental dismissal
|
|
96
|
+
* would be dangerous), and it exposes explicit {@link confirm}/{@link cancel}
|
|
97
|
+
* actions that emit events so the consumer only writes the message and "what to
|
|
98
|
+
* do on confirm".
|
|
99
|
+
*
|
|
100
|
+
* @remarks
|
|
101
|
+
* Behavior only. The modal lifecycle (focus trap, scroll lock, background
|
|
102
|
+
* `inert`, focus restore, teardown reversal) is delegated to the shared
|
|
103
|
+
* {@link FocusTrap}. The only closing affordances are the confirm/cancel actions
|
|
104
|
+
* and `Escape` (which cancels) — there is intentionally no backdrop close.
|
|
105
|
+
*
|
|
106
|
+
* Behavior provided:
|
|
107
|
+
* - {@link open} shows the dialog and moves focus to the `initialFocus` target
|
|
108
|
+
* (the least destructive action, by convention), else the first focusable
|
|
109
|
+
* element.
|
|
110
|
+
* - `Tab`/`Shift+Tab` cycle focus within the dialog (focus trap).
|
|
111
|
+
* - {@link confirm} closes and dispatches `stimeo--alert-dialog:confirm`.
|
|
112
|
+
* - {@link cancel} and `Escape` close and dispatch `stimeo--alert-dialog:cancel`
|
|
113
|
+
* with a `reason` of `"user"` / `"escape"`. Focus returns to the opener.
|
|
114
|
+
*/
|
|
115
|
+
declare class AlertDialogController extends Controller<HTMLElement> {
|
|
116
|
+
#private;
|
|
117
|
+
static targets: string[];
|
|
118
|
+
static actions: readonly ["cancel", "confirm", "open"];
|
|
119
|
+
static events: readonly ["cancel", "confirm"];
|
|
120
|
+
readonly triggerTarget: HTMLElement;
|
|
121
|
+
readonly dialogTarget: HTMLElement;
|
|
122
|
+
readonly initialFocusTarget: HTMLElement;
|
|
123
|
+
readonly hasTriggerTarget: boolean;
|
|
124
|
+
readonly hasDialogTarget: boolean;
|
|
125
|
+
readonly hasInitialFocusTarget: boolean;
|
|
126
|
+
/** Starts closed (idempotently reflects the closed state on the markup). */
|
|
127
|
+
connect(): void;
|
|
128
|
+
/** Reverts the modal side effects if torn down while open (Turbo navigation). */
|
|
129
|
+
disconnect(): void;
|
|
130
|
+
/** Opens the dialog, traps focus, and locks background scroll. */
|
|
131
|
+
open(): void;
|
|
132
|
+
/** Confirms: closes and dispatches `confirm`. Bound via `data-action`. */
|
|
133
|
+
confirm(): void;
|
|
134
|
+
/** Cancels (user action): closes and dispatches `cancel` with `reason: "user"`. */
|
|
135
|
+
cancel(): void;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Headless, accessible **Carousel** (slideshow) behavior.
|
|
140
|
+
*
|
|
141
|
+
* Markup contract (identifier: `stimeo--carousel`):
|
|
142
|
+
* <section data-controller="stimeo--carousel" aria-roledescription="carousel"
|
|
143
|
+
* aria-label="Featured"
|
|
144
|
+
* data-stimeo--carousel-autoplay-value="false"
|
|
145
|
+
* data-stimeo--carousel-interval-value="5000"
|
|
146
|
+
* data-stimeo--carousel-loop-value="true"
|
|
147
|
+
* data-action="mouseenter->stimeo--carousel#pause
|
|
148
|
+
* mouseleave->stimeo--carousel#resume
|
|
149
|
+
* focusin->stimeo--carousel#pause
|
|
150
|
+
* focusout->stimeo--carousel#resume">
|
|
151
|
+
* <button data-stimeo--carousel-target="playToggle"
|
|
152
|
+
* data-action="stimeo--carousel#togglePlay">…</button>
|
|
153
|
+
* <div data-stimeo--carousel-target="viewport">
|
|
154
|
+
* <div role="tabpanel" data-stimeo--carousel-target="slide">…</div>
|
|
155
|
+
* <div role="tabpanel" data-stimeo--carousel-target="slide" hidden>…</div>
|
|
156
|
+
* </div>
|
|
157
|
+
* <button data-stimeo--carousel-target="prev" data-action="stimeo--carousel#prev">‹</button>
|
|
158
|
+
* <button data-stimeo--carousel-target="next" data-action="stimeo--carousel#next">›</button>
|
|
159
|
+
* <div role="tablist">
|
|
160
|
+
* <button role="tab" data-stimeo--carousel-target="picker"
|
|
161
|
+
* data-action="stimeo--carousel#goto
|
|
162
|
+
* keydown->stimeo--carousel#onPickerKeydown"></button>
|
|
163
|
+
* </div>
|
|
164
|
+
* </section>
|
|
165
|
+
*
|
|
166
|
+
* Implements the WAI-ARIA APG **Carousel** (tabbed) pattern. The current slide is
|
|
167
|
+
* exposed through `data-state` (`active`/`inactive`) and the `hidden` attribute on
|
|
168
|
+
* inactive slides (removing them from focus order); the matching picker carries
|
|
169
|
+
* `aria-selected` and the single roving `tabindex`. The play/pause toggle's
|
|
170
|
+
* `aria-pressed` mirrors the autoplay state.
|
|
171
|
+
*
|
|
172
|
+
* @remarks
|
|
173
|
+
* Behavior only — transitions, layout, and visuals are the consumer's CSS.
|
|
174
|
+
* Autoplay honors WCAG 2.2.2: it suspends while the pointer is over the carousel
|
|
175
|
+
* and **hard-stops** when keyboard focus enters (it does not silently resume on
|
|
176
|
+
* focus out — the user must press play), so motion never surprises a keyboard
|
|
177
|
+
* user. The interval is cleared on `disconnect()` (Turbo navigation included).
|
|
178
|
+
* Picker arrow keys move focus only (manual activation); slide changes never steal
|
|
179
|
+
* focus from the control the user operated.
|
|
180
|
+
*/
|
|
181
|
+
declare class CarouselController extends Controller<HTMLElement> {
|
|
182
|
+
#private;
|
|
183
|
+
static targets: string[];
|
|
184
|
+
static values: {
|
|
185
|
+
autoplay: {
|
|
186
|
+
type: BooleanConstructor;
|
|
187
|
+
default: boolean;
|
|
188
|
+
};
|
|
189
|
+
interval: {
|
|
190
|
+
type: NumberConstructor;
|
|
191
|
+
default: number;
|
|
192
|
+
};
|
|
193
|
+
loop: {
|
|
194
|
+
type: BooleanConstructor;
|
|
195
|
+
default: boolean;
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
static actions: readonly ["goto", "next", "onPickerKeydown", "pause", "prev", "resume", "togglePlay"];
|
|
199
|
+
static events: readonly ["change", "pause", "play"];
|
|
200
|
+
readonly slideTargets: HTMLElement[];
|
|
201
|
+
readonly pickerTargets: HTMLElement[];
|
|
202
|
+
readonly playToggleTarget: HTMLElement;
|
|
203
|
+
readonly hasPlayToggleTarget: boolean;
|
|
204
|
+
autoplayValue: boolean;
|
|
205
|
+
intervalValue: number;
|
|
206
|
+
loopValue: boolean;
|
|
207
|
+
/** Renders the initial slide and starts autoplay when requested. */
|
|
208
|
+
connect(): void;
|
|
209
|
+
/** Clears the autoplay interval so it never fires after teardown. */
|
|
210
|
+
disconnect(): void;
|
|
211
|
+
/** Advances to the next slide. Bound via `data-action`. */
|
|
212
|
+
next(): void;
|
|
213
|
+
/** Returns to the previous slide. Bound via `data-action`. */
|
|
214
|
+
prev(): void;
|
|
215
|
+
/** Jumps to the slide whose picker was activated (click / Enter / Space). */
|
|
216
|
+
goto(event: Event): void;
|
|
217
|
+
/** Toggles autoplay on the user's explicit request and syncs the timer. */
|
|
218
|
+
togglePlay(): void;
|
|
219
|
+
/**
|
|
220
|
+
* Suspends autoplay. Hover (`mouseenter`) is a temporary suspension that resumes
|
|
221
|
+
* on leave; keyboard focus (`focusin`) is a hard stop that turns autoplay off so
|
|
222
|
+
* it cannot resume without an explicit play (WCAG 2.2.2).
|
|
223
|
+
*/
|
|
224
|
+
pause(event?: Event): void;
|
|
225
|
+
/**
|
|
226
|
+
* Lifts a hover suspension (`mouseleave`) and resumes autoplay if it is still
|
|
227
|
+
* on. A `focusout` does nothing here: the focus pause was a hard stop, so the
|
|
228
|
+
* user must press play to restart.
|
|
229
|
+
*/
|
|
230
|
+
resume(event?: Event): void;
|
|
231
|
+
/** Picker roving: arrows move focus only; Home/End activate first/last slide. */
|
|
232
|
+
onPickerKeydown(event: KeyboardEvent): void;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Headless copy-to-clipboard behavior with a live-region completion notice.
|
|
237
|
+
*
|
|
238
|
+
* Markup contract (identifier: `stimeo--clipboard`):
|
|
239
|
+
* <div data-controller="stimeo--clipboard"
|
|
240
|
+
* data-stimeo--clipboard-feedback-duration-value="2000">
|
|
241
|
+
* <input type="text" value="https://example.com" readonly
|
|
242
|
+
* data-stimeo--clipboard-target="source">
|
|
243
|
+
* <button type="button" data-stimeo--clipboard-target="button"
|
|
244
|
+
* data-action="stimeo--clipboard#copy">Copy</button>
|
|
245
|
+
* <span role="status" aria-live="polite"
|
|
246
|
+
* data-stimeo--clipboard-target="feedback"></span>
|
|
247
|
+
* </div>
|
|
248
|
+
*
|
|
249
|
+
* No dedicated APG pattern; this follows the Button + live-region practice. The
|
|
250
|
+
* copy uses the standard `navigator.clipboard` API (no extra dependency); when
|
|
251
|
+
* it is unavailable or rejects, the failure is surfaced rather than silently
|
|
252
|
+
* swallowed, and never communicated by icon alone — the `role="status"` region
|
|
253
|
+
* carries text so screen readers announce the outcome.
|
|
254
|
+
*
|
|
255
|
+
* @remarks
|
|
256
|
+
* Behavior only — icon swaps and styling are the consumer's, keyed off
|
|
257
|
+
* `data-state` (`idle` / `copied` / `error`). The completion notice clears
|
|
258
|
+
* itself after `feedbackDuration`; that timer is torn down on disconnect (Turbo)
|
|
259
|
+
* via {@link SafeTimeout}.
|
|
260
|
+
*/
|
|
261
|
+
declare class ClipboardController extends Controller<HTMLElement> {
|
|
262
|
+
#private;
|
|
263
|
+
static targets: string[];
|
|
264
|
+
static values: {
|
|
265
|
+
text: {
|
|
266
|
+
type: StringConstructor;
|
|
267
|
+
default: string;
|
|
268
|
+
};
|
|
269
|
+
feedbackDuration: {
|
|
270
|
+
type: NumberConstructor;
|
|
271
|
+
default: number;
|
|
272
|
+
};
|
|
273
|
+
copiedLabel: {
|
|
274
|
+
type: StringConstructor;
|
|
275
|
+
default: string;
|
|
276
|
+
};
|
|
277
|
+
errorLabel: {
|
|
278
|
+
type: StringConstructor;
|
|
279
|
+
default: string;
|
|
280
|
+
};
|
|
281
|
+
};
|
|
282
|
+
static actions: readonly ["copy"];
|
|
283
|
+
static events: readonly ["copy"];
|
|
284
|
+
readonly sourceTarget: HTMLElement;
|
|
285
|
+
readonly buttonTarget: HTMLElement;
|
|
286
|
+
readonly feedbackTarget: HTMLElement;
|
|
287
|
+
readonly hasSourceTarget: boolean;
|
|
288
|
+
readonly hasButtonTarget: boolean;
|
|
289
|
+
readonly hasFeedbackTarget: boolean;
|
|
290
|
+
textValue: string;
|
|
291
|
+
feedbackDurationValue: number;
|
|
292
|
+
copiedLabelValue: string;
|
|
293
|
+
errorLabelValue: string;
|
|
294
|
+
connect(): void;
|
|
295
|
+
disconnect(): void;
|
|
296
|
+
/**
|
|
297
|
+
* Copies the resolved text and reports the outcome. Bound via `data-action`
|
|
298
|
+
* (click). Always dispatches `stimeo--clipboard:copy` with `{ success, text }`
|
|
299
|
+
* — including on failure — so consumers can react either way.
|
|
300
|
+
*/
|
|
301
|
+
copy(): Promise<void>;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Headless, accessible single-disclosure (collapsible) behavior.
|
|
306
|
+
*
|
|
307
|
+
* Markup contract (identifier: `stimeo--collapsible`):
|
|
308
|
+
* <div data-controller="stimeo--collapsible">
|
|
309
|
+
* <button data-stimeo--collapsible-target="trigger"
|
|
310
|
+
* data-action="stimeo--collapsible#toggle"
|
|
311
|
+
* aria-expanded="false" aria-controls="more">Show details</button>
|
|
312
|
+
* <div id="more" data-stimeo--collapsible-target="content"
|
|
313
|
+
* data-state="closed" hidden>…</div>
|
|
314
|
+
* </div>
|
|
315
|
+
*
|
|
316
|
+
* Implements the WAI-ARIA APG **Disclosure** pattern for a single inline region.
|
|
317
|
+
* Unlike {@link AccordionController} it manages exactly one trigger/content pair
|
|
318
|
+
* with no sibling coordination, and unlike a dropdown the content expands in
|
|
319
|
+
* flow and never closes on an outside click.
|
|
320
|
+
*
|
|
321
|
+
* @remarks
|
|
322
|
+
* Behavior only — the consumer owns the height transition and all decoration.
|
|
323
|
+
* The controller keeps the open lifecycle ordered so `hidden` (effectively
|
|
324
|
+
* `display:none`) never blocks measurement or the transition:
|
|
325
|
+
* - **Open**: drop `hidden` → measure the natural height into
|
|
326
|
+
* `--stimeo-collapsible-content-height` → set `data-state="open"`.
|
|
327
|
+
* - **Close**: set `data-state="closed"` (CSS shrinks the height) → re-apply
|
|
328
|
+
* `hidden` after `transitionend`. With no transition (or reduced motion, which
|
|
329
|
+
* the consumer's CSS expresses as a zero duration) it is applied immediately.
|
|
330
|
+
*/
|
|
331
|
+
declare class CollapsibleController extends Controller<HTMLElement> {
|
|
332
|
+
#private;
|
|
333
|
+
static targets: string[];
|
|
334
|
+
static values: {
|
|
335
|
+
open: {
|
|
336
|
+
type: BooleanConstructor;
|
|
337
|
+
default: boolean;
|
|
338
|
+
};
|
|
339
|
+
};
|
|
340
|
+
static actions: readonly ["toggle"];
|
|
341
|
+
readonly triggerTarget: HTMLElement;
|
|
342
|
+
readonly contentTarget: HTMLElement;
|
|
343
|
+
readonly hasTriggerTarget: boolean;
|
|
344
|
+
readonly hasContentTarget: boolean;
|
|
345
|
+
openValue: boolean;
|
|
346
|
+
/**
|
|
347
|
+
* Establishes the initial open/closed state without animating.
|
|
348
|
+
*
|
|
349
|
+
* The DOM is the source of truth on reconnect (Turbo cache restore / morph): an
|
|
350
|
+
* **explicit** state attribute — `aria-expanded="true"`/`"false"` (or, with no
|
|
351
|
+
* trigger, `data-state="open"`/`"closed"`) — is honored verbatim so a region the
|
|
352
|
+
* user opened *or* closed survives a back-navigation, even when the declarative
|
|
353
|
+
* `open` Value disagrees. The Value only seeds a genuinely fresh render where no
|
|
354
|
+
* state attribute is present yet. Mirrors `sidebar`'s `#restoreCollapsed`.
|
|
355
|
+
*/
|
|
356
|
+
connect(): void;
|
|
357
|
+
disconnect(): void;
|
|
358
|
+
/** Toggles the region open/closed. Bound via `data-action` (click). */
|
|
359
|
+
toggle(): void;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Headless, accessible **Color Picker** behavior.
|
|
364
|
+
*
|
|
365
|
+
* Markup contract (identifier: `stimeo--color-picker`):
|
|
366
|
+
* <div data-controller="stimeo--color-picker"
|
|
367
|
+
* data-stimeo--color-picker-value-value="#3366cc">
|
|
368
|
+
* <div role="slider" aria-label="Hue" data-channel="hue" tabindex="0"
|
|
369
|
+
* aria-valuemin="0" aria-valuemax="360" aria-valuenow="210"
|
|
370
|
+
* data-stimeo--color-picker-target="slider"
|
|
371
|
+
* data-action="keydown->stimeo--color-picker#onKeydown
|
|
372
|
+
* pointerdown->stimeo--color-picker#onPointerDown"></div>
|
|
373
|
+
* <!-- saturation / lightness / alpha sliders share the same contract -->
|
|
374
|
+
* <input type="text" aria-label="Hex color"
|
|
375
|
+
* data-stimeo--color-picker-target="hex"
|
|
376
|
+
* data-action="change->stimeo--color-picker#onHexInput" />
|
|
377
|
+
* <div data-stimeo--color-picker-target="preview" aria-hidden="true"></div>
|
|
378
|
+
* <input type="hidden" data-stimeo--color-picker-target="field" />
|
|
379
|
+
* </div>
|
|
380
|
+
*
|
|
381
|
+
* Decomposes color selection into independent APG **Slider** channels (hue,
|
|
382
|
+
* saturation, lightness, optional alpha) instead of a 2-D palette, so every
|
|
383
|
+
* adjustment is keyboard- and screen-reader-operable. Each slider exposes
|
|
384
|
+
* `aria-valuenow` and a human-readable `aria-valuetext` (e.g. "Hue 210 degrees");
|
|
385
|
+
* the hex input stays two-way synced; the current color is published on the
|
|
386
|
+
* preview and root as the `--stimeo-color` custom property and mirrored into a
|
|
387
|
+
* hidden form field.
|
|
388
|
+
*
|
|
389
|
+
* @remarks
|
|
390
|
+
* Behavior only — the swatch/gradient visuals are the consumer's CSS/canvas, fed
|
|
391
|
+
* by `--stimeo-color`. Pointer-drag listeners on `document` are bound to an
|
|
392
|
+
* {@link AbortController} and released on drag end and on `disconnect()` (Turbo
|
|
393
|
+
* navigation included). Color is fully reconstructable from the `value` (hex), so
|
|
394
|
+
* there is no transient state to restore after a Turbo cache/morph.
|
|
395
|
+
*
|
|
396
|
+
* The internal model is integer HSL(A), so a hex → HSL → hex round-trip is not
|
|
397
|
+
* exactly bijective: a typed hex can normalize to a near (not identical) value
|
|
398
|
+
* once the HSL sliders are touched. This keeps the model small and zero-dep; use a
|
|
399
|
+
* dedicated color library on the consumer side if exact hex preservation matters.
|
|
400
|
+
*/
|
|
401
|
+
declare class ColorPickerController extends Controller<HTMLElement> {
|
|
402
|
+
#private;
|
|
403
|
+
static targets: string[];
|
|
404
|
+
static values: {
|
|
405
|
+
value: {
|
|
406
|
+
type: StringConstructor;
|
|
407
|
+
default: string;
|
|
408
|
+
};
|
|
409
|
+
alpha: {
|
|
410
|
+
type: BooleanConstructor;
|
|
411
|
+
default: boolean;
|
|
412
|
+
};
|
|
413
|
+
};
|
|
414
|
+
static actions: readonly ["onHexInput", "onKeydown", "onPointerDown"];
|
|
415
|
+
static events: readonly ["change"];
|
|
416
|
+
readonly sliderTargets: HTMLElement[];
|
|
417
|
+
readonly hexTarget: HTMLInputElement;
|
|
418
|
+
readonly hasHexTarget: boolean;
|
|
419
|
+
readonly previewTargets: HTMLElement[];
|
|
420
|
+
readonly fieldTargets: HTMLInputElement[];
|
|
421
|
+
valueValue: string;
|
|
422
|
+
alphaValue: boolean;
|
|
423
|
+
/** Seeds the model from the initial hex value and renders every surface. */
|
|
424
|
+
connect(): void;
|
|
425
|
+
/** Cancels any active pointer drag so document listeners never leak. */
|
|
426
|
+
disconnect(): void;
|
|
427
|
+
/** Keyboard stepping on the focused channel slider (APG Slider model). */
|
|
428
|
+
onKeydown(event: KeyboardEvent): void;
|
|
429
|
+
/** Begins a pointer drag on a channel slider and tracks movement. */
|
|
430
|
+
onPointerDown(event: PointerEvent): void;
|
|
431
|
+
/** Parses the hex input on confirm and syncs every channel + surface. */
|
|
432
|
+
onHexInput(): void;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Headless currency / amount input behavior: groups digits for display while
|
|
437
|
+
* keeping a machine-readable number in a hidden field, and mirrors the
|
|
438
|
+
* normalized value to a visually-hidden span so assistive tech reads the real
|
|
439
|
+
* amount rather than the grouped display string.
|
|
440
|
+
*
|
|
441
|
+
* Markup contract (identifier: `stimeo--currency-input`):
|
|
442
|
+
* <div data-controller="stimeo--currency-input"
|
|
443
|
+
* data-stimeo--currency-input-locale-value="en-US"
|
|
444
|
+
* data-stimeo--currency-input-currency-value="USD"
|
|
445
|
+
* data-stimeo--currency-input-precision-value="2">
|
|
446
|
+
* <input type="text" inputmode="decimal"
|
|
447
|
+
* aria-describedby="amt-sr"
|
|
448
|
+
* data-stimeo--currency-input-target="display"
|
|
449
|
+
* data-action="input->stimeo--currency-input#onInput
|
|
450
|
+
* blur->stimeo--currency-input#format" />
|
|
451
|
+
* <span id="amt-sr" class="visually-hidden"
|
|
452
|
+
* data-stimeo--currency-input-target="srValue"></span>
|
|
453
|
+
* <input type="hidden" data-stimeo--currency-input-target="field" />
|
|
454
|
+
* </div>
|
|
455
|
+
*
|
|
456
|
+
* @remarks
|
|
457
|
+
* Behavior only — no styling, no validation (range/required belong to the
|
|
458
|
+
* consumer or Form Field). The display field is the sole Tab stop and keeps its
|
|
459
|
+
* native text-editing behavior; this controller never steals focus. Grouping is
|
|
460
|
+
* applied on every input while preserving the caret (counted by digits to its
|
|
461
|
+
* left), and the fixed-precision rounding is applied on `blur`.
|
|
462
|
+
*
|
|
463
|
+
* Honest a11y note: a hidden `<input>` is not exposed to assistive tech, so the
|
|
464
|
+
* normalized value is *also* published as text in the `srValue` span referenced
|
|
465
|
+
* by the display's `aria-describedby` — that, not the hidden field, is what a
|
|
466
|
+
* screen reader announces.
|
|
467
|
+
*/
|
|
468
|
+
declare class CurrencyInputController extends Controller<HTMLElement> {
|
|
469
|
+
#private;
|
|
470
|
+
static targets: string[];
|
|
471
|
+
static values: {
|
|
472
|
+
locale: {
|
|
473
|
+
type: StringConstructor;
|
|
474
|
+
default: string;
|
|
475
|
+
};
|
|
476
|
+
currency: {
|
|
477
|
+
type: StringConstructor;
|
|
478
|
+
default: string;
|
|
479
|
+
};
|
|
480
|
+
precision: {
|
|
481
|
+
type: NumberConstructor;
|
|
482
|
+
default: number;
|
|
483
|
+
};
|
|
484
|
+
};
|
|
485
|
+
static actions: readonly ["format", "onInput"];
|
|
486
|
+
static events: readonly ["change"];
|
|
487
|
+
readonly displayTarget: HTMLInputElement;
|
|
488
|
+
readonly fieldTarget: HTMLInputElement;
|
|
489
|
+
readonly srValueTarget: HTMLElement;
|
|
490
|
+
readonly hasDisplayTarget: boolean;
|
|
491
|
+
readonly hasFieldTarget: boolean;
|
|
492
|
+
readonly hasSrValueTarget: boolean;
|
|
493
|
+
localeValue: string;
|
|
494
|
+
currencyValue: string;
|
|
495
|
+
precisionValue: number;
|
|
496
|
+
/** Normalizes any pre-filled display value to its fixed-precision form. */
|
|
497
|
+
connect(): void;
|
|
498
|
+
/** Re-groups digits as the user types, preserving the caret position. */
|
|
499
|
+
onInput(): void;
|
|
500
|
+
/** Applies the fixed-precision rounding on blur. */
|
|
501
|
+
format(): void;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Headless, accessible **Data Grid** behavior: column sorting, row selection, and
|
|
506
|
+
* roving keyboard navigation over an interactive table.
|
|
507
|
+
*
|
|
508
|
+
* Markup contract (identifier: `stimeo--data-grid`):
|
|
509
|
+
* <table data-controller="stimeo--data-grid" role="grid" aria-label="Users"
|
|
510
|
+
* data-stimeo--data-grid-selection-value="single">
|
|
511
|
+
* <thead><tr role="row">
|
|
512
|
+
* <th role="columnheader" aria-sort="none" tabindex="-1"
|
|
513
|
+
* data-stimeo--data-grid-target="columnHeader"
|
|
514
|
+
* data-action="click->stimeo--data-grid#sort
|
|
515
|
+
* keydown->stimeo--data-grid#onKeydown">Name</th>
|
|
516
|
+
* </tr></thead>
|
|
517
|
+
* <tbody><tr role="row" aria-selected="false"
|
|
518
|
+
* data-stimeo--data-grid-target="row">
|
|
519
|
+
* <td role="gridcell" tabindex="0" data-stimeo--data-grid-target="cell"
|
|
520
|
+
* data-action="keydown->stimeo--data-grid#onKeydown">Jane</td>
|
|
521
|
+
* </tr></tbody>
|
|
522
|
+
* </table>
|
|
523
|
+
*
|
|
524
|
+
* Implements the WAI-ARIA APG **Grid** pattern plus `aria-sort`. The whole grid is
|
|
525
|
+
* a single Tab stop (roving `tabindex`: exactly one cell/header is `0`, the rest
|
|
526
|
+
* `-1`); arrow keys move both DOM focus and that tabbable position. Sort state is
|
|
527
|
+
* exposed via `aria-sort` on headers, selection via `aria-selected` on rows.
|
|
528
|
+
*
|
|
529
|
+
* @remarks
|
|
530
|
+
* Behavior only — the consumer performs the actual data sort/render in response to
|
|
531
|
+
* the `sort` event and owns all styling. No timers or observers are held, so there
|
|
532
|
+
* is nothing to leak across Turbo navigations; `connect()` rebuilds the single tab
|
|
533
|
+
* stop idempotently from the DOM.
|
|
534
|
+
*
|
|
535
|
+
* Behavior provided:
|
|
536
|
+
* - `Arrow*` move between cells (clamped at edges); `Home`/`End` to the row's
|
|
537
|
+
* first/last cell; `Ctrl+Home`/`Ctrl+End` to the grid's first/last cell.
|
|
538
|
+
* - `Enter`/`Space` cycles a header's sort (`none→ascending→descending`) or toggles
|
|
539
|
+
* the focused row's selection when selection is enabled.
|
|
540
|
+
*/
|
|
541
|
+
declare class DataGridController extends Controller<HTMLElement> {
|
|
542
|
+
#private;
|
|
543
|
+
static targets: string[];
|
|
544
|
+
static values: {
|
|
545
|
+
selection: {
|
|
546
|
+
type: StringConstructor;
|
|
547
|
+
default: string;
|
|
548
|
+
};
|
|
549
|
+
};
|
|
550
|
+
static actions: readonly ["onKeydown", "sort", "toggleSelect"];
|
|
551
|
+
static events: readonly ["selectionchange", "sort"];
|
|
552
|
+
readonly columnHeaderTargets: HTMLElement[];
|
|
553
|
+
readonly rowTargets: HTMLElement[];
|
|
554
|
+
readonly cellTargets: HTMLElement[];
|
|
555
|
+
selectionValue: string;
|
|
556
|
+
/** Establishes a single tab stop across all navigable cells/headers. */
|
|
557
|
+
connect(): void;
|
|
558
|
+
/**
|
|
559
|
+
* Keeps `aria-multiselectable` in step with the `selection` Value. Fires on connect
|
|
560
|
+
* (so it self-heals after a Turbo morph) and on any runtime change, so the ARIA
|
|
561
|
+
* never drifts from the selection logic, which reads `selectionValue` live.
|
|
562
|
+
*/
|
|
563
|
+
selectionValueChanged(): void;
|
|
564
|
+
/** Cycles the activated column header's sort and emits `sort`. */
|
|
565
|
+
sort(event: Event): void;
|
|
566
|
+
/** Toggles selection of the row owning the event target. Bound optionally. */
|
|
567
|
+
toggleSelect(event: Event): void;
|
|
568
|
+
/** Grid navigation + sort/select activation. Bound to cells and headers. */
|
|
569
|
+
onKeydown(event: KeyboardEvent): void;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Headless, accessible **date range picker** behavior. A derivative of
|
|
574
|
+
* {@link CalendarController}: it reuses the month-grid navigation model and adds
|
|
575
|
+
* two-point range selection, in-progress range preview, and presets.
|
|
576
|
+
*
|
|
577
|
+
* Markup contract (identifier: `stimeo--date-range-picker`):
|
|
578
|
+
* <div data-controller="stimeo--date-range-picker"
|
|
579
|
+
* data-stimeo--date-range-picker-min-value="2026-01-01"
|
|
580
|
+
* data-stimeo--date-range-picker-max-value="2026-12-31">
|
|
581
|
+
* <button data-action="stimeo--date-range-picker#prev">Prev</button>
|
|
582
|
+
* <span data-stimeo--date-range-picker-target="monthLabel" aria-live="polite"></span>
|
|
583
|
+
* <button data-action="stimeo--date-range-picker#next">Next</button>
|
|
584
|
+
* <div role="grid" data-stimeo--date-range-picker-target="grid">
|
|
585
|
+
* <!-- exactly 42 cell targets (7 days × 6 rows) -->
|
|
586
|
+
* <button role="gridcell" tabindex="-1"
|
|
587
|
+
* data-stimeo--date-range-picker-target="cell"
|
|
588
|
+
* data-action="click->stimeo--date-range-picker#selectDate
|
|
589
|
+
* mouseenter->stimeo--date-range-picker#previewTo
|
|
590
|
+
* focus->stimeo--date-range-picker#previewTo
|
|
591
|
+
* keydown->stimeo--date-range-picker#onKeydown"></button>
|
|
592
|
+
* </div>
|
|
593
|
+
* <button data-range="last7" data-action="stimeo--date-range-picker#applyPreset">…</button>
|
|
594
|
+
* <span role="status" aria-live="polite" data-stimeo--date-range-picker-target="status"></span>
|
|
595
|
+
* <input type="hidden" data-stimeo--date-range-picker-target="startField" />
|
|
596
|
+
* <input type="hidden" data-stimeo--date-range-picker-target="endField" />
|
|
597
|
+
* </div>
|
|
598
|
+
*
|
|
599
|
+
* @remarks
|
|
600
|
+
* Behavior only — the consumer styles the grid and renders the range using the
|
|
601
|
+
* `data-range-start` / `data-in-range` / `data-range-end` hooks. Assistive tech
|
|
602
|
+
* is told the two confirmed endpoints via `aria-selected`; inner cells use
|
|
603
|
+
* `data-in-range` (visual only) so the announcement stays to the two ends. The
|
|
604
|
+
* confirmed range is also mirrored to the live `status` region.
|
|
605
|
+
*
|
|
606
|
+
* Selection model: the first click/Enter sets a *pending* start and enters
|
|
607
|
+
* "selecting" mode (preview follows the pointer/focus); the second confirms the
|
|
608
|
+
* end (auto-swapped if earlier than the start) and dispatches `change`. Escape
|
|
609
|
+
* abandons an in-progress selection, restoring the last confirmed range.
|
|
610
|
+
*/
|
|
611
|
+
declare class DateRangePickerController extends Controller<HTMLElement> {
|
|
612
|
+
#private;
|
|
613
|
+
static targets: string[];
|
|
614
|
+
static values: {
|
|
615
|
+
min: {
|
|
616
|
+
type: StringConstructor;
|
|
617
|
+
default: string;
|
|
618
|
+
};
|
|
619
|
+
max: {
|
|
620
|
+
type: StringConstructor;
|
|
621
|
+
default: string;
|
|
622
|
+
};
|
|
623
|
+
};
|
|
624
|
+
static actions: readonly ["applyPreset", "next", "onKeydown", "prev", "previewTo", "selectDate"];
|
|
625
|
+
static events: readonly ["change"];
|
|
626
|
+
readonly gridTarget: HTMLElement;
|
|
627
|
+
readonly monthLabelTarget: HTMLElement;
|
|
628
|
+
readonly cellTargets: HTMLElement[];
|
|
629
|
+
readonly statusTarget: HTMLElement;
|
|
630
|
+
readonly startFieldTarget: HTMLInputElement;
|
|
631
|
+
readonly endFieldTarget: HTMLInputElement;
|
|
632
|
+
readonly hasMonthLabelTarget: boolean;
|
|
633
|
+
readonly hasStatusTarget: boolean;
|
|
634
|
+
readonly hasStartFieldTarget: boolean;
|
|
635
|
+
readonly hasEndFieldTarget: boolean;
|
|
636
|
+
minValue: string;
|
|
637
|
+
maxValue: string;
|
|
638
|
+
/** Seeds the range from any pre-filled hidden fields and renders the grid. */
|
|
639
|
+
connect(): void;
|
|
640
|
+
/** Cancels any pending deferred focus so it never fires on a detached element. */
|
|
641
|
+
disconnect(): void;
|
|
642
|
+
/** Navigates to the previous month. */
|
|
643
|
+
prev(event?: Event): void;
|
|
644
|
+
/** Navigates to the next month. */
|
|
645
|
+
next(event?: Event): void;
|
|
646
|
+
/** Confirms a range endpoint from a clicked cell. */
|
|
647
|
+
selectDate(event: Event): void;
|
|
648
|
+
/** Previews the range up to a hovered/focused cell while selecting. */
|
|
649
|
+
previewTo(event: Event): void;
|
|
650
|
+
/** Applies a named preset (`today` / `last7` / `last30` / `thisMonth`). */
|
|
651
|
+
applyPreset(event: Event): void;
|
|
652
|
+
/** Grid keyboard navigation, selection (Enter/Space), and Escape-to-cancel. */
|
|
653
|
+
onKeydown(event: KeyboardEvent): void;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Headless "dismissible" behavior for banners, notices, and inline alerts.
|
|
658
|
+
*
|
|
659
|
+
* Markup contract (identifier: `stimeo--dismissible`):
|
|
660
|
+
* <div data-controller="stimeo--dismissible"
|
|
661
|
+
* data-stimeo--dismissible-mode-value="remove">
|
|
662
|
+
* <div data-stimeo--dismissible-target="root" role="status">
|
|
663
|
+
* <p>Saved.</p>
|
|
664
|
+
* <button type="button" aria-label="Close"
|
|
665
|
+
* data-action="stimeo--dismissible#dismiss">×</button>
|
|
666
|
+
* </div>
|
|
667
|
+
* </div>
|
|
668
|
+
*
|
|
669
|
+
* A general utility with no dedicated APG pattern. Its accessibility job is to
|
|
670
|
+
* keep focus from being orphaned: if focus is inside the element being removed,
|
|
671
|
+
* it is moved to a safe place first so the close button vanishing never strands
|
|
672
|
+
* the user (WCAG 2.4.3).
|
|
673
|
+
*
|
|
674
|
+
* @remarks
|
|
675
|
+
* Behavior only — the consumer owns any exit transition (use `hide` mode, which
|
|
676
|
+
* adds `hidden`, and animate off `data-state`) and any semantics like
|
|
677
|
+
* `role="alert"`. Focus retreats to, in order: the `fallback` target → the next
|
|
678
|
+
* focusable element after the root → the previous one → `document.body` as a
|
|
679
|
+
* last resort (weak focus; prefer providing a `fallback`).
|
|
680
|
+
*/
|
|
681
|
+
declare class DismissibleController extends Controller<HTMLElement> {
|
|
682
|
+
#private;
|
|
683
|
+
static targets: string[];
|
|
684
|
+
static values: {
|
|
685
|
+
mode: {
|
|
686
|
+
type: StringConstructor;
|
|
687
|
+
default: string;
|
|
688
|
+
};
|
|
689
|
+
closeOnEscape: {
|
|
690
|
+
type: BooleanConstructor;
|
|
691
|
+
default: boolean;
|
|
692
|
+
};
|
|
693
|
+
};
|
|
694
|
+
static actions: readonly ["dismiss"];
|
|
695
|
+
static events: readonly ["dismiss"];
|
|
696
|
+
readonly rootTarget: HTMLElement;
|
|
697
|
+
readonly fallbackTarget: HTMLElement;
|
|
698
|
+
readonly hasRootTarget: boolean;
|
|
699
|
+
readonly hasFallbackTarget: boolean;
|
|
700
|
+
modeValue: string;
|
|
701
|
+
closeOnEscapeValue: boolean;
|
|
702
|
+
connect(): void;
|
|
703
|
+
disconnect(): void;
|
|
704
|
+
/** Dismisses the element. Bound via `data-action` (click on the close button). */
|
|
705
|
+
dismiss(): void;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* Headless, accessible **drawer / slide-over** behavior.
|
|
710
|
+
*
|
|
711
|
+
* Markup contract (identifier: `stimeo--drawer`):
|
|
712
|
+
* <div data-controller="stimeo--drawer" data-stimeo--drawer-placement-value="right">
|
|
713
|
+
* <button data-stimeo--drawer-target="trigger"
|
|
714
|
+
* data-action="click->stimeo--drawer#open">Open panel</button>
|
|
715
|
+
* <div data-stimeo--drawer-target="overlay"
|
|
716
|
+
* data-action="click->stimeo--drawer#closeOnBackdrop">
|
|
717
|
+
* <aside data-stimeo--drawer-target="panel" role="dialog" aria-modal="true"
|
|
718
|
+
* aria-labelledby="t" data-state="closed" hidden>
|
|
719
|
+
* <h2 id="t">…</h2>
|
|
720
|
+
* <button data-action="click->stimeo--drawer#close">Close</button>
|
|
721
|
+
* </aside>
|
|
722
|
+
* </div>
|
|
723
|
+
* </div>
|
|
724
|
+
*
|
|
725
|
+
* Implements the WAI-ARIA APG **Dialog (Modal)** pattern. It is the same modal as
|
|
726
|
+
* `stimeo--dialog`; what it adds is the state plumbing an enter/exit *slide*
|
|
727
|
+
* needs: `data-state` (`open`/`closed`) is synced on the panel and overlay so CSS
|
|
728
|
+
* can animate, and `hidden` is applied only *after* the close transition finishes
|
|
729
|
+
* (so the exit animation can play). `placement` is reflected as `data-placement`
|
|
730
|
+
* for the CSS to read — the controller never computes coordinates.
|
|
731
|
+
*
|
|
732
|
+
* @remarks
|
|
733
|
+
* Behavior only. The modal lifecycle (focus trap, scroll lock, background
|
|
734
|
+
* `inert`, focus restore, teardown reversal) is delegated to the shared
|
|
735
|
+
* {@link FocusTrap}. Placement, slide direction, distance, and easing are all the
|
|
736
|
+
* consumer's CSS — `data-placement` is merely a flag.
|
|
737
|
+
*
|
|
738
|
+
* Behavior provided:
|
|
739
|
+
* - {@link open}/{@link close} toggle `data-state` and (deferred) `hidden`.
|
|
740
|
+
* - On open, focus moves to the first focusable element in the panel.
|
|
741
|
+
* - `Tab`/`Shift+Tab` cycle focus within the panel; `Escape` closes.
|
|
742
|
+
* - {@link closeOnBackdrop} closes only when the overlay *itself* is clicked.
|
|
743
|
+
*/
|
|
744
|
+
declare class DrawerController extends Controller<HTMLElement> {
|
|
745
|
+
#private;
|
|
746
|
+
static targets: string[];
|
|
747
|
+
static values: {
|
|
748
|
+
placement: {
|
|
749
|
+
type: StringConstructor;
|
|
750
|
+
default: string;
|
|
751
|
+
};
|
|
752
|
+
open: {
|
|
753
|
+
type: BooleanConstructor;
|
|
754
|
+
default: boolean;
|
|
755
|
+
};
|
|
756
|
+
};
|
|
757
|
+
static actions: readonly ["close", "closeOnBackdrop", "open"];
|
|
758
|
+
readonly triggerTarget: HTMLElement;
|
|
759
|
+
readonly overlayTarget: HTMLElement;
|
|
760
|
+
readonly panelTarget: HTMLElement;
|
|
761
|
+
readonly hasTriggerTarget: boolean;
|
|
762
|
+
readonly hasOverlayTarget: boolean;
|
|
763
|
+
readonly hasPanelTarget: boolean;
|
|
764
|
+
placementValue: string;
|
|
765
|
+
openValue: boolean;
|
|
766
|
+
/**
|
|
767
|
+
* Reflects placement and establishes the initial open/closed state.
|
|
768
|
+
*
|
|
769
|
+
* The DOM is the source of truth on reconnect (Turbo cache restore / morph): a
|
|
770
|
+
* restored snapshot whose panel is already `data-state="open"` stays open
|
|
771
|
+
* rather than being re-derived from the declarative `open` Value (which would
|
|
772
|
+
* close a user-opened drawer). The `open` Value only seeds a genuinely fresh
|
|
773
|
+
* render. We normalize to a clean closed baseline first so {@link open} runs its
|
|
774
|
+
* full reveal + trap activation — the {@link FocusTrap} is a fresh instance
|
|
775
|
+
* after a reconnect and must be re-activated.
|
|
776
|
+
*/
|
|
777
|
+
connect(): void;
|
|
778
|
+
/** Reverts the modal side effects and pending hide if torn down while open. */
|
|
779
|
+
disconnect(): void;
|
|
780
|
+
/** Keeps `data-placement` in sync if the value changes at runtime. */
|
|
781
|
+
placementValueChanged(): void;
|
|
782
|
+
/** Opens the drawer: reveals it, syncs `data-state`, traps focus. */
|
|
783
|
+
open(): void;
|
|
784
|
+
/**
|
|
785
|
+
* Closes the drawer: syncs `data-state` to start the exit transition, then
|
|
786
|
+
* defers both `hidden` *and* the modal teardown (scroll lock / background
|
|
787
|
+
* `inert` / focus restore) until the transition finishes — see
|
|
788
|
+
* `#applyHidden`. This keeps the background inert and focus trapped while
|
|
789
|
+
* the drawer is still visually on screen, preserving the modal contract during
|
|
790
|
+
* the exit animation.
|
|
791
|
+
*/
|
|
792
|
+
close(): void;
|
|
793
|
+
/** Closes only when the overlay itself (not its contents) is clicked. */
|
|
794
|
+
closeOnBackdrop(event: MouseEvent): void;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* Headless, accessible inline-editing behavior.
|
|
799
|
+
*
|
|
800
|
+
* Markup contract (identifier: `stimeo--editable`):
|
|
801
|
+
* <div data-controller="stimeo--editable"
|
|
802
|
+
* data-stimeo--editable-submit-on-blur-value="true">
|
|
803
|
+
* <button type="button" aria-label="Edit title"
|
|
804
|
+
* data-stimeo--editable-target="display"
|
|
805
|
+
* data-action="click->stimeo--editable#edit
|
|
806
|
+
* keydown->stimeo--editable#onDisplayKeydown">Current title</button>
|
|
807
|
+
* <input type="text" aria-label="Title" hidden
|
|
808
|
+
* data-stimeo--editable-target="input"
|
|
809
|
+
* data-action="keydown->stimeo--editable#onKeydown
|
|
810
|
+
* blur->stimeo--editable#onBlur" />
|
|
811
|
+
* </div>
|
|
812
|
+
*
|
|
813
|
+
* There is no dedicated APG pattern; this implements a display ⇄ edit toggle with
|
|
814
|
+
* focus management and keyboard commit/cancel, leaning on native form-control
|
|
815
|
+
* labeling (WCAG 1.3.1 / 4.1.2). The look is the consumer's CSS, keyed off
|
|
816
|
+
* `data-mode`.
|
|
817
|
+
*
|
|
818
|
+
* Behavior provided:
|
|
819
|
+
* - Activating the display element (`Enter`/`Space` via the `<button>`, or `F2`)
|
|
820
|
+
* enters edit mode, focuses the input, and selects its text.
|
|
821
|
+
* - `Enter` (single-line) or `Ctrl+Enter` / `Cmd+Enter` (multiline `<textarea>`)
|
|
822
|
+
* saves; `Escape` cancels. Both return focus to the display element.
|
|
823
|
+
* - Losing focus while editing saves when `submitOnBlur` is true (the default),
|
|
824
|
+
* honoring wherever focus moved; when false, editing is kept.
|
|
825
|
+
* - Saving dispatches `stimeo--editable:change` with `{ value, previous }` only
|
|
826
|
+
* when the value actually changed; cancelling dispatches
|
|
827
|
+
* `stimeo--editable:cancel`.
|
|
828
|
+
*/
|
|
829
|
+
declare class EditableController extends Controller<HTMLElement> {
|
|
830
|
+
#private;
|
|
831
|
+
static targets: string[];
|
|
832
|
+
static values: {
|
|
833
|
+
submitOnBlur: {
|
|
834
|
+
type: BooleanConstructor;
|
|
835
|
+
default: boolean;
|
|
836
|
+
};
|
|
837
|
+
};
|
|
838
|
+
static actions: readonly ["edit", "onBlur", "onDisplayKeydown", "onKeydown"];
|
|
839
|
+
static events: readonly ["cancel", "change"];
|
|
840
|
+
readonly displayTarget: HTMLElement;
|
|
841
|
+
readonly inputTarget: HTMLInputElement | HTMLTextAreaElement;
|
|
842
|
+
readonly hasDisplayTarget: boolean;
|
|
843
|
+
readonly hasInputTarget: boolean;
|
|
844
|
+
submitOnBlurValue: boolean;
|
|
845
|
+
/** Establishes the initial display mode (display shown, input hidden). */
|
|
846
|
+
connect(): void;
|
|
847
|
+
/** Enters edit mode: seeds the input from the display text, focuses, selects. */
|
|
848
|
+
edit(): void;
|
|
849
|
+
/** Adds `F2` as an editing entry point alongside the button's native activation. */
|
|
850
|
+
onDisplayKeydown(event: KeyboardEvent): void;
|
|
851
|
+
/** Commits on `Enter` (or `Ctrl+Enter` when multiline) and cancels on `Escape`. */
|
|
852
|
+
onKeydown(event: KeyboardEvent): void;
|
|
853
|
+
/** Saves on blur when `submitOnBlur` is set; otherwise keeps editing. */
|
|
854
|
+
onBlur(): void;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* Headless, accessible file drag-and-drop / upload field.
|
|
859
|
+
*
|
|
860
|
+
* Markup contract (identifier: `stimeo--file-dropzone`):
|
|
861
|
+
* <div data-controller="stimeo--file-dropzone"
|
|
862
|
+
* data-stimeo--file-dropzone-max-size-value="5242880">
|
|
863
|
+
* <div data-stimeo--file-dropzone-target="zone"
|
|
864
|
+
* data-action="dragover->stimeo--file-dropzone#onDragOver
|
|
865
|
+
* dragleave->stimeo--file-dropzone#onDragLeave
|
|
866
|
+
* drop->stimeo--file-dropzone#onDrop">
|
|
867
|
+
* <button type="button" data-stimeo--file-dropzone-target="trigger"
|
|
868
|
+
* data-action="click->stimeo--file-dropzone#openDialog">Choose…</button>
|
|
869
|
+
* <input type="file" accept="image/*" multiple class="visually-hidden"
|
|
870
|
+
* data-stimeo--file-dropzone-target="input"
|
|
871
|
+
* data-action="change->stimeo--file-dropzone#onChange" />
|
|
872
|
+
* </div>
|
|
873
|
+
* <ul data-stimeo--file-dropzone-target="list" aria-label="Selected files"></ul>
|
|
874
|
+
* <span role="status" aria-live="polite" class="visually-hidden"
|
|
875
|
+
* data-stimeo--file-dropzone-target="status"></span>
|
|
876
|
+
* <template data-stimeo--file-dropzone-target="itemTemplate">…</template>
|
|
877
|
+
* </div>
|
|
878
|
+
*
|
|
879
|
+
* There is no single APG pattern; the native `<input type="file">` stays the
|
|
880
|
+
* primary, keyboard-operable path and the drop zone is an enhancement, mapping to
|
|
881
|
+
* WCAG 2.1.1, 2.4.7, 4.1.2, 4.1.3, and 1.4.1 (drag state is conveyed in words,
|
|
882
|
+
* not color alone).
|
|
883
|
+
*
|
|
884
|
+
* Behavior provided:
|
|
885
|
+
* - Click / keyboard via the `trigger` opens the native file dialog; drag-and-drop
|
|
886
|
+
* over the `zone` adds files (with a `data-dragover` flag and a spoken hint).
|
|
887
|
+
* - Each file is validated against `accept`, `maxSize`, and the file count
|
|
888
|
+
* (`maxFiles`, or 1 when the input is not `multiple`); rejects fire
|
|
889
|
+
* `stimeo--file-dropzone:reject` and set `data-…-invalid`.
|
|
890
|
+
* - Accepted files render from `itemTemplate` with a `Remove {name}` button and an
|
|
891
|
+
* image thumbnail (`objectURL`); every change dispatches
|
|
892
|
+
* `stimeo--file-dropzone:change` with the current `File[]`.
|
|
893
|
+
* - Removing a file revokes its `objectURL` and moves focus to the next (else
|
|
894
|
+
* previous) remove button, falling back to the trigger; `disconnect()` revokes
|
|
895
|
+
* every outstanding `objectURL`.
|
|
896
|
+
*/
|
|
897
|
+
declare class FileDropzoneController extends Controller<HTMLElement> {
|
|
898
|
+
#private;
|
|
899
|
+
static targets: string[];
|
|
900
|
+
static values: {
|
|
901
|
+
maxSize: {
|
|
902
|
+
type: NumberConstructor;
|
|
903
|
+
default: number;
|
|
904
|
+
};
|
|
905
|
+
maxFiles: {
|
|
906
|
+
type: NumberConstructor;
|
|
907
|
+
default: number;
|
|
908
|
+
};
|
|
909
|
+
dragLabel: {
|
|
910
|
+
type: StringConstructor;
|
|
911
|
+
default: string;
|
|
912
|
+
};
|
|
913
|
+
};
|
|
914
|
+
static actions: readonly ["onChange", "onDragLeave", "onDragOver", "onDrop", "openDialog"];
|
|
915
|
+
static events: readonly ["change", "reject"];
|
|
916
|
+
readonly inputTarget: HTMLInputElement;
|
|
917
|
+
readonly listTarget: HTMLElement;
|
|
918
|
+
readonly triggerTarget: HTMLElement;
|
|
919
|
+
readonly itemTemplateTarget: HTMLTemplateElement;
|
|
920
|
+
readonly statusTarget: HTMLElement;
|
|
921
|
+
readonly hasListTarget: boolean;
|
|
922
|
+
readonly hasTriggerTarget: boolean;
|
|
923
|
+
readonly hasItemTemplateTarget: boolean;
|
|
924
|
+
readonly hasStatusTarget: boolean;
|
|
925
|
+
readonly hasZoneTarget: boolean;
|
|
926
|
+
readonly zoneTarget: HTMLElement;
|
|
927
|
+
maxSizeValue: number;
|
|
928
|
+
maxFilesValue: number;
|
|
929
|
+
dragLabelValue: string;
|
|
930
|
+
/** Wires file removal as a delegated listener on the list container. */
|
|
931
|
+
connect(): void;
|
|
932
|
+
/** Revokes any outstanding preview URLs so none leaks across navigations. */
|
|
933
|
+
disconnect(): void;
|
|
934
|
+
/** Opens the native file dialog. Bound via `data-action` (trigger click). */
|
|
935
|
+
openDialog(): void;
|
|
936
|
+
/** Adds the files chosen through the native dialog. */
|
|
937
|
+
onChange(): void;
|
|
938
|
+
/** Marks the zone as a drop target and announces the affordance in words. */
|
|
939
|
+
onDragOver(event: DragEvent): void;
|
|
940
|
+
/** Clears the drag-over flag when the pointer leaves the zone. */
|
|
941
|
+
onDragLeave(): void;
|
|
942
|
+
/** Accepts dropped files, clearing the drag-over state. */
|
|
943
|
+
onDrop(event: DragEvent): void;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
/** A control whose "on" state contributes its token to the active filter set. */
|
|
947
|
+
type FilterControl = HTMLElement;
|
|
948
|
+
/**
|
|
949
|
+
* Headless faceted-filter behavior: shows or hides a collection of items based on the
|
|
950
|
+
* set of currently-active facet tokens, decoupled from how those tokens are toggled
|
|
951
|
+
* (native checkboxes/radios, or button toggles such as `stimeo--toggle-group`).
|
|
952
|
+
*
|
|
953
|
+
* Markup contract (identifier: `stimeo--filter`):
|
|
954
|
+
* <div data-controller="stimeo--filter" data-stimeo--filter-match-value="all">
|
|
955
|
+
* <!-- controls: each contributes its token while "on" (aria-pressed / checked) -->
|
|
956
|
+
* <button type="button" aria-pressed="false" data-value="apg:dialog"
|
|
957
|
+
* data-stimeo--filter-target="control">Dialog</button>
|
|
958
|
+
* <!-- items: filtered in/out by their space-separated tokens -->
|
|
959
|
+
* <li data-stimeo--filter-target="item"
|
|
960
|
+
* data-stimeo--filter-tokens="apg:dialog overlay">…</li>
|
|
961
|
+
* <!-- optional: a container hidden once it holds no visible item -->
|
|
962
|
+
* <section data-stimeo--filter-target="group">…</section>
|
|
963
|
+
* <!-- optional: an element revealed when nothing matches -->
|
|
964
|
+
* <p data-stimeo--filter-target="empty" hidden>No matches</p>
|
|
965
|
+
* </div>
|
|
966
|
+
*
|
|
967
|
+
* `match` decides how multiple active tokens combine: `all` (default — an item must
|
|
968
|
+
* carry every active token) or `any` (at least one). With no active token every item
|
|
969
|
+
* is shown. Items are toggled via `hidden`; groups with zero visible items and the
|
|
970
|
+
* `empty` element are kept in sync, and `stimeo--filter:change` is dispatched.
|
|
971
|
+
*
|
|
972
|
+
* @remarks
|
|
973
|
+
* Behavior only — the consumer owns all styling and the controls' own accessible
|
|
974
|
+
* state (e.g. `aria-pressed`). Visibility is re-derived from the live DOM on
|
|
975
|
+
* `connect()` (Morph/Turbo-safe) and on every native `change` that bubbles to the
|
|
976
|
+
* root; button toggles that emit no native `change` wire their event to the `apply`
|
|
977
|
+
* action (e.g. `stimeo--toggle-group:change->stimeo--filter#apply`).
|
|
978
|
+
*/
|
|
979
|
+
declare class FilterController extends Controller<HTMLElement> {
|
|
980
|
+
#private;
|
|
981
|
+
static targets: string[];
|
|
982
|
+
static values: {
|
|
983
|
+
match: {
|
|
984
|
+
type: StringConstructor;
|
|
985
|
+
default: string;
|
|
986
|
+
};
|
|
987
|
+
};
|
|
988
|
+
static actions: readonly ["apply", "clear"];
|
|
989
|
+
static events: readonly ["change"];
|
|
990
|
+
readonly itemTargets: HTMLElement[];
|
|
991
|
+
readonly controlTargets: FilterControl[];
|
|
992
|
+
readonly groupTargets: HTMLElement[];
|
|
993
|
+
readonly emptyTargets: HTMLElement[];
|
|
994
|
+
matchValue: string;
|
|
995
|
+
connect(): void;
|
|
996
|
+
disconnect(): void;
|
|
997
|
+
/** Re-derives every item's visibility from the active tokens and syncs groups/empty. */
|
|
998
|
+
apply(): void;
|
|
999
|
+
/** Turns every control off (uncheck / aria-pressed="false") and re-applies. */
|
|
1000
|
+
clear(): void;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* Headless **Masonry** layout helper: assigns each item to the shortest column so
|
|
1005
|
+
* variable-height cards pack without vertical gaps. There is no APG widget — this
|
|
1006
|
+
* is a layout-only utility that emits state hooks, never visual structure.
|
|
1007
|
+
*
|
|
1008
|
+
* Markup contract (identifier: `stimeo--masonry`):
|
|
1009
|
+
* <div data-controller="stimeo--masonry"
|
|
1010
|
+
* data-stimeo--masonry-min-column-width-value="240"
|
|
1011
|
+
* data-stimeo--masonry-gap-value="16">
|
|
1012
|
+
* <div data-stimeo--masonry-target="item">…</div>
|
|
1013
|
+
* <div data-stimeo--masonry-target="item">…</div>
|
|
1014
|
+
* </div>
|
|
1015
|
+
*
|
|
1016
|
+
* The column count is derived responsively from the container width and
|
|
1017
|
+
* `minColumnWidth`; each item is then placed into whichever column is currently
|
|
1018
|
+
* shortest (measured from item heights). The count is published on the controller
|
|
1019
|
+
* element as the `--stimeo-masonry-columns` custom property and each item gets a
|
|
1020
|
+
* `data-column` index, so the consumer's CSS owns the actual placement.
|
|
1021
|
+
*
|
|
1022
|
+
* @remarks
|
|
1023
|
+
* Behavior only. **DOM order is never changed** — reading order and focus order
|
|
1024
|
+
* stay the source markup order (WCAG 1.3.2). The visual packing is purely the
|
|
1025
|
+
* column assignment a consumer reads from `data-column`; this controller writes no
|
|
1026
|
+
* positioning styles. Re-layout runs on connect, on resize ({@link LayoutObserver}),
|
|
1027
|
+
* and on item add/remove ({@link MutationObserver}); both observers are released on
|
|
1028
|
+
* `disconnect()` (Turbo navigation included). Use only for independent cards whose
|
|
1029
|
+
* visual order carries no meaning.
|
|
1030
|
+
*/
|
|
1031
|
+
declare class MasonryController extends Controller<HTMLElement> {
|
|
1032
|
+
#private;
|
|
1033
|
+
static targets: string[];
|
|
1034
|
+
static values: {
|
|
1035
|
+
minColumnWidth: {
|
|
1036
|
+
type: NumberConstructor;
|
|
1037
|
+
default: number;
|
|
1038
|
+
};
|
|
1039
|
+
gap: {
|
|
1040
|
+
type: NumberConstructor;
|
|
1041
|
+
default: number;
|
|
1042
|
+
};
|
|
1043
|
+
};
|
|
1044
|
+
static events: readonly ["layout"];
|
|
1045
|
+
readonly itemTargets: HTMLElement[];
|
|
1046
|
+
minColumnWidthValue: number;
|
|
1047
|
+
gapValue: number;
|
|
1048
|
+
/** Observes size/content changes and performs the first layout pass. */
|
|
1049
|
+
connect(): void;
|
|
1050
|
+
/** Releases both observers and the load listener so nothing fires after detach. */
|
|
1051
|
+
disconnect(): void;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
/**
|
|
1055
|
+
* Headless, accessible **menubar** behavior.
|
|
1056
|
+
*
|
|
1057
|
+
* Markup contract (identifier: `stimeo--menubar`):
|
|
1058
|
+
* <div data-controller="stimeo--menubar" role="menubar" aria-label="Main">
|
|
1059
|
+
* <button role="menuitem" aria-haspopup="menu" aria-expanded="false"
|
|
1060
|
+
* aria-controls="m-file" data-stimeo--menubar-target="top"
|
|
1061
|
+
* data-action="click->stimeo--menubar#toggle
|
|
1062
|
+
* keydown->stimeo--menubar#onTopKeydown">File</button>
|
|
1063
|
+
* <ul id="m-file" role="menu" data-stimeo--menubar-target="menu" hidden>
|
|
1064
|
+
* <li role="none">
|
|
1065
|
+
* <button role="menuitem" tabindex="-1" data-stimeo--menubar-target="item"
|
|
1066
|
+
* data-action="click->stimeo--menubar#activate
|
|
1067
|
+
* keydown->stimeo--menubar#onItemKeydown">New</button>
|
|
1068
|
+
* </li>
|
|
1069
|
+
* </ul>
|
|
1070
|
+
* <!-- more top items + menus -->
|
|
1071
|
+
* </div>
|
|
1072
|
+
*
|
|
1073
|
+
* Implements the WAI-ARIA APG **Menubar** pattern (single level): the top items
|
|
1074
|
+
* form one Tab stop via roving tabindex and the arrow keys move between them;
|
|
1075
|
+
* `ArrowDown`/`Enter`/`Space` open a menu (`ArrowUp` opens it at the last item),
|
|
1076
|
+
* the arrow keys then move within the menu, and pressing `ArrowLeft`/`ArrowRight`
|
|
1077
|
+
* while a menu is open jumps to the adjacent top menu. `Escape` closes and
|
|
1078
|
+
* returns focus to the owning top item; `Tab` and an outside click close.
|
|
1079
|
+
*
|
|
1080
|
+
* @remarks
|
|
1081
|
+
* Behavior only. Each top item↔menu pair is linked by `aria-controls`/`id` (not by
|
|
1082
|
+
* position), so the markup order is free. Menu placement and viewport-edge
|
|
1083
|
+
* collision are out of scope — static placement is the consumer's CSS, and dynamic
|
|
1084
|
+
* placement is delegated to the opt-in `stimeo-ui/positioning` module (never
|
|
1085
|
+
* imported here, keeping the core zero-dependency). Roving mechanics across the top
|
|
1086
|
+
* items are delegated to {@link RovingTabindex}.
|
|
1087
|
+
*/
|
|
1088
|
+
declare class MenubarController extends Controller<HTMLElement> {
|
|
1089
|
+
#private;
|
|
1090
|
+
static targets: string[];
|
|
1091
|
+
static actions: readonly ["activate", "onItemKeydown", "onTopKeydown", "toggle"];
|
|
1092
|
+
readonly topTargets: HTMLElement[];
|
|
1093
|
+
readonly menuTargets: HTMLElement[];
|
|
1094
|
+
readonly itemTargets: HTMLElement[];
|
|
1095
|
+
/** Establishes the single tab stop and the closed baseline. */
|
|
1096
|
+
connect(): void;
|
|
1097
|
+
/** Removes the document listener and any pending typeahead timer. */
|
|
1098
|
+
disconnect(): void;
|
|
1099
|
+
/** Toggles a top item's menu. Bound via `data-action` (click on the top item). */
|
|
1100
|
+
toggle(event: Event): void;
|
|
1101
|
+
/** Keyboard handling while focus is on a top item. */
|
|
1102
|
+
onTopKeydown(event: KeyboardEvent): void;
|
|
1103
|
+
/** Keyboard handling while focus is on a menu item. */
|
|
1104
|
+
onItemKeydown(event: KeyboardEvent): void;
|
|
1105
|
+
/** Closes the owning menu after an item is activated and refocuses its top. */
|
|
1106
|
+
activate(event: Event): void;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
/**
|
|
1110
|
+
* Headless, accessible multi-select combobox with chips.
|
|
1111
|
+
*
|
|
1112
|
+
* Markup contract (identifier: `stimeo--multi-select`):
|
|
1113
|
+
* <div data-controller="stimeo--multi-select">
|
|
1114
|
+
* <ul data-stimeo--multi-select-target="tags" aria-label="Selected"></ul>
|
|
1115
|
+
* <input type="text" role="combobox" aria-expanded="false"
|
|
1116
|
+
* aria-autocomplete="list" aria-controls="ms-list" aria-activedescendant=""
|
|
1117
|
+
* data-stimeo--multi-select-target="input"
|
|
1118
|
+
* data-action="input->stimeo--multi-select#filter
|
|
1119
|
+
* keydown->stimeo--multi-select#onKeydown
|
|
1120
|
+
* focus->stimeo--multi-select#open" />
|
|
1121
|
+
* <ul id="ms-list" role="listbox" aria-multiselectable="true" hidden
|
|
1122
|
+
* data-stimeo--multi-select-target="list">
|
|
1123
|
+
* <li id="ms-opt-1" role="option" aria-selected="false" data-value="apple"
|
|
1124
|
+
* data-stimeo--multi-select-target="option"
|
|
1125
|
+
* data-action="click->stimeo--multi-select#toggleOption">Apple</li>
|
|
1126
|
+
* </ul>
|
|
1127
|
+
* <span role="status" aria-live="polite" class="visually-hidden"
|
|
1128
|
+
* data-stimeo--multi-select-target="status"></span>
|
|
1129
|
+
* <template data-stimeo--multi-select-target="tagTemplate">…</template>
|
|
1130
|
+
* </div>
|
|
1131
|
+
*
|
|
1132
|
+
* Implements the WAI-ARIA APG **Combobox** pattern in its list-autocomplete,
|
|
1133
|
+
* multi-select form. Focus stays on the input; the active option is tracked with
|
|
1134
|
+
* `aria-activedescendant` and selection with `aria-selected`. Selected options are
|
|
1135
|
+
* mirrored as removable chips. For single selection use {@link ListboxController}
|
|
1136
|
+
* or Combobox; for free-text tags use {@link TagsInputController}.
|
|
1137
|
+
*
|
|
1138
|
+
* Behavior provided:
|
|
1139
|
+
* - Typing filters options by substring and opens the list; `ArrowDown`/`ArrowUp`
|
|
1140
|
+
* (wrapping), `Home`/`End` move the active option; `Enter` toggles it (the list
|
|
1141
|
+
* stays open); `Escape`/`Tab`/outside click close.
|
|
1142
|
+
* - Toggling syncs `aria-selected`, adds/removes a `Remove {label}` chip, mirrors
|
|
1143
|
+
* the live region, and dispatches `stimeo--multi-select:change` with `values`;
|
|
1144
|
+
* filtering dispatches `stimeo--multi-select:filter` for async candidates.
|
|
1145
|
+
* - The chips are one roving Tab stop: `ArrowLeft`/`ArrowRight` move between them,
|
|
1146
|
+
* `Delete`/`Backspace` remove the focused chip, and `Backspace` on an empty
|
|
1147
|
+
* input removes the last; removal re-homes focus to a neighbor or the input.
|
|
1148
|
+
* - `max` caps the selection (`0` = unlimited).
|
|
1149
|
+
*/
|
|
1150
|
+
declare class MultiSelectController extends Controller<HTMLElement> {
|
|
1151
|
+
#private;
|
|
1152
|
+
static targets: string[];
|
|
1153
|
+
static values: {
|
|
1154
|
+
max: {
|
|
1155
|
+
type: NumberConstructor;
|
|
1156
|
+
default: number;
|
|
1157
|
+
};
|
|
1158
|
+
};
|
|
1159
|
+
static actions: readonly ["close", "filter", "onKeydown", "open", "toggleOption"];
|
|
1160
|
+
static events: readonly ["change", "filter"];
|
|
1161
|
+
readonly inputTarget: HTMLInputElement;
|
|
1162
|
+
readonly listTarget: HTMLElement;
|
|
1163
|
+
readonly optionTargets: HTMLElement[];
|
|
1164
|
+
readonly tagsTarget: HTMLElement;
|
|
1165
|
+
readonly tagTargets: HTMLElement[];
|
|
1166
|
+
readonly tagTemplateTarget: HTMLTemplateElement;
|
|
1167
|
+
readonly statusTarget: HTMLElement;
|
|
1168
|
+
readonly hasListTarget: boolean;
|
|
1169
|
+
readonly hasTagsTarget: boolean;
|
|
1170
|
+
readonly hasTagTemplateTarget: boolean;
|
|
1171
|
+
readonly hasStatusTarget: boolean;
|
|
1172
|
+
maxValue: number;
|
|
1173
|
+
/** Starts closed, syncs chips for any pre-selected options, and listens out. */
|
|
1174
|
+
connect(): void;
|
|
1175
|
+
/** Tears down document and chip listeners on disconnect (Turbo included). */
|
|
1176
|
+
disconnect(): void;
|
|
1177
|
+
/** Filters options by the input substring, opens, and re-seeds the active one. */
|
|
1178
|
+
filter(): void;
|
|
1179
|
+
/** Opens the list and activates the first visible option when none is active. */
|
|
1180
|
+
open(): void;
|
|
1181
|
+
/** Closes the list and clears the active option. */
|
|
1182
|
+
close(): void;
|
|
1183
|
+
/** Routes input keyboard interaction per the multi-select combobox model. */
|
|
1184
|
+
onKeydown(event: KeyboardEvent): void;
|
|
1185
|
+
/** Toggles the clicked option's selection. Bound via `data-action`. */
|
|
1186
|
+
toggleOption(event: Event): void;
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
/**
|
|
1190
|
+
* Headless, accessible **navigation menu** behavior (disclosure navigation).
|
|
1191
|
+
*
|
|
1192
|
+
* Markup contract (identifier: `stimeo--navigation-menu`):
|
|
1193
|
+
* <nav data-controller="stimeo--navigation-menu" aria-label="Main">
|
|
1194
|
+
* <ul>
|
|
1195
|
+
* <li>
|
|
1196
|
+
* <button data-stimeo--navigation-menu-target="trigger"
|
|
1197
|
+
* aria-expanded="false" aria-controls="nav-products"
|
|
1198
|
+
* data-action="click->stimeo--navigation-menu#toggle
|
|
1199
|
+
* keydown->stimeo--navigation-menu#onTriggerKeydown">
|
|
1200
|
+
* Products
|
|
1201
|
+
* </button>
|
|
1202
|
+
* <div id="nav-products" data-stimeo--navigation-menu-target="panel" hidden>
|
|
1203
|
+
* <a href="/a">Product A</a><a href="/b">Product B</a>
|
|
1204
|
+
* </div>
|
|
1205
|
+
* </li>
|
|
1206
|
+
* </ul>
|
|
1207
|
+
* </nav>
|
|
1208
|
+
*
|
|
1209
|
+
* Implements the WAI-ARIA APG **Disclosure** navigation pattern: each top-level
|
|
1210
|
+
* button toggles its sub-panel (`aria-expanded` + `hidden` synced), only one panel
|
|
1211
|
+
* is open at a time, and the panel content is a plain set of links (not a
|
|
1212
|
+
* `role="menu"`). Focus is **not** trapped — `Tab` moves through the links
|
|
1213
|
+
* naturally. `Escape` closes the open panel and returns focus to its trigger; an
|
|
1214
|
+
* outside click or focus leaving the nav closes it. `ArrowLeft`/`ArrowRight` move
|
|
1215
|
+
* focus between triggers without rewriting `tabindex` (they keep their natural Tab
|
|
1216
|
+
* order). Hover open/close is opt-in via `openOnHover`.
|
|
1217
|
+
*
|
|
1218
|
+
* @remarks
|
|
1219
|
+
* Behavior only. Panel layout, mega-menu styling, and animation are the
|
|
1220
|
+
* consumer's CSS. Static placement is CSS; viewport-edge collision avoidance is
|
|
1221
|
+
* delegated to the opt-in `stimeo-ui/positioning` module (never imported here, so
|
|
1222
|
+
* the core stays zero-dependency). For an app command menu with arrow roving and
|
|
1223
|
+
* `role="menu"`, use `stimeo--menubar` instead.
|
|
1224
|
+
*/
|
|
1225
|
+
declare class NavigationMenuController extends Controller<HTMLElement> {
|
|
1226
|
+
#private;
|
|
1227
|
+
static targets: string[];
|
|
1228
|
+
static values: {
|
|
1229
|
+
openOnHover: {
|
|
1230
|
+
type: BooleanConstructor;
|
|
1231
|
+
default: boolean;
|
|
1232
|
+
};
|
|
1233
|
+
hoverDelay: {
|
|
1234
|
+
type: NumberConstructor;
|
|
1235
|
+
default: number;
|
|
1236
|
+
};
|
|
1237
|
+
};
|
|
1238
|
+
static actions: readonly ["onTriggerKeydown", "toggle"];
|
|
1239
|
+
readonly triggerTargets: HTMLElement[];
|
|
1240
|
+
readonly panelTargets: HTMLElement[];
|
|
1241
|
+
openOnHoverValue: boolean;
|
|
1242
|
+
hoverDelayValue: number;
|
|
1243
|
+
/** Establishes the closed baseline and the dismissal listeners. */
|
|
1244
|
+
connect(): void;
|
|
1245
|
+
/** Removes every listener and pending hover timer registered in {@link connect}. */
|
|
1246
|
+
disconnect(): void;
|
|
1247
|
+
/** Toggles a trigger's panel (single-open). Bound via `data-action` (click). */
|
|
1248
|
+
toggle(event: Event): void;
|
|
1249
|
+
/** `ArrowLeft`/`ArrowRight` move focus between triggers (keeping Tab order). */
|
|
1250
|
+
onTriggerKeydown(event: KeyboardEvent): void;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
/**
|
|
1254
|
+
* Headless password show/hide (unmask) toggle behavior.
|
|
1255
|
+
*
|
|
1256
|
+
* Markup contract (identifier: `stimeo--password-reveal`):
|
|
1257
|
+
* <div data-controller="stimeo--password-reveal">
|
|
1258
|
+
* <input type="password" aria-label="Password"
|
|
1259
|
+
* data-stimeo--password-reveal-target="input">
|
|
1260
|
+
* <button type="button" aria-pressed="false" aria-label="Show password"
|
|
1261
|
+
* data-stimeo--password-reveal-target="toggle"
|
|
1262
|
+
* data-action="stimeo--password-reveal#toggle"></button>
|
|
1263
|
+
* </div>
|
|
1264
|
+
*
|
|
1265
|
+
* No dedicated APG pattern; this follows the toggle **Button** practice. The
|
|
1266
|
+
* accessible name stays state-independent ("Show password") while the pressed
|
|
1267
|
+
* state is conveyed by `aria-pressed`.
|
|
1268
|
+
*
|
|
1269
|
+
* @remarks
|
|
1270
|
+
* Behavior only — icon rendering is the consumer's, keyed off `aria-pressed` /
|
|
1271
|
+
* `data-state` (`hidden` / `visible`). Flipping `input.type` can drop focus and
|
|
1272
|
+
* the caret, so when (and only when) the input was the focused element its focus
|
|
1273
|
+
* and selection are restored afterward; when the toggle button holds focus
|
|
1274
|
+
* (keyboard use) focus is left on the button. An optional `autoHide` re-masks
|
|
1275
|
+
* after a delay, and that timer is torn down on disconnect (Turbo).
|
|
1276
|
+
*/
|
|
1277
|
+
declare class PasswordRevealController extends Controller<HTMLElement> {
|
|
1278
|
+
#private;
|
|
1279
|
+
static targets: string[];
|
|
1280
|
+
static values: {
|
|
1281
|
+
autoHide: {
|
|
1282
|
+
type: NumberConstructor;
|
|
1283
|
+
default: number;
|
|
1284
|
+
};
|
|
1285
|
+
};
|
|
1286
|
+
static actions: readonly ["toggle"];
|
|
1287
|
+
static events: readonly ["toggle"];
|
|
1288
|
+
readonly inputTarget: HTMLInputElement;
|
|
1289
|
+
readonly toggleTarget: HTMLElement;
|
|
1290
|
+
readonly hasInputTarget: boolean;
|
|
1291
|
+
readonly hasToggleTarget: boolean;
|
|
1292
|
+
autoHideValue: number;
|
|
1293
|
+
connect(): void;
|
|
1294
|
+
disconnect(): void;
|
|
1295
|
+
/** Toggles the input between masked and revealed. Bound via `data-action`. */
|
|
1296
|
+
toggle(): void;
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
/**
|
|
1300
|
+
* Headless, accessible **two-thumb range slider** behavior (APG Slider —
|
|
1301
|
+
* Multi-Thumb). A derivative of {@link SliderController}: it manages two thumbs
|
|
1302
|
+
* (`start` ≤ `end`) that constrain each other.
|
|
1303
|
+
*
|
|
1304
|
+
* Markup contract (identifier: `stimeo--range-slider`):
|
|
1305
|
+
* <div data-controller="stimeo--range-slider"
|
|
1306
|
+
* data-stimeo--range-slider-min-value="0"
|
|
1307
|
+
* data-stimeo--range-slider-max-value="100"
|
|
1308
|
+
* data-stimeo--range-slider-step-value="1"
|
|
1309
|
+
* data-stimeo--range-slider-start-value="20"
|
|
1310
|
+
* data-stimeo--range-slider-end-value="80">
|
|
1311
|
+
* <div data-stimeo--range-slider-target="track"
|
|
1312
|
+
* data-action="pointerdown->stimeo--range-slider#onPointerDown">
|
|
1313
|
+
* <div role="slider" tabindex="0" aria-label="Minimum"
|
|
1314
|
+
* data-stimeo--range-slider-target="startThumb"
|
|
1315
|
+
* data-action="keydown->stimeo--range-slider#onKeydown"></div>
|
|
1316
|
+
* <div role="slider" tabindex="0" aria-label="Maximum"
|
|
1317
|
+
* data-stimeo--range-slider-target="endThumb"
|
|
1318
|
+
* data-action="keydown->stimeo--range-slider#onKeydown"></div>
|
|
1319
|
+
* </div>
|
|
1320
|
+
* </div>
|
|
1321
|
+
*
|
|
1322
|
+
* @remarks
|
|
1323
|
+
* Behavior only — the consumer owns all layout (positioning the thumbs and the
|
|
1324
|
+
* selected range from the fractions). Only the horizontal orientation is handled
|
|
1325
|
+
* in this MVP. Each thumb's movable range is bounded by the *other* thumb's
|
|
1326
|
+
* current value, reflected on its `aria-valuemin`/`aria-valuemax` so assistive
|
|
1327
|
+
* tech announces the live constraint.
|
|
1328
|
+
*
|
|
1329
|
+
* Behavior provided (per focused thumb):
|
|
1330
|
+
* - `ArrowRight`/`ArrowUp` increase and `ArrowLeft`/`ArrowDown` decrease by one
|
|
1331
|
+
* step; `Home`/`End` jump to that thumb's movable min/max; `PageUp`/`PageDown`
|
|
1332
|
+
* move by ten steps. A thumb never crosses the other.
|
|
1333
|
+
* - Pointer press/drag on the track moves the nearest thumb.
|
|
1334
|
+
*/
|
|
1335
|
+
declare class RangeSliderController extends Controller<HTMLElement> {
|
|
1336
|
+
#private;
|
|
1337
|
+
static targets: string[];
|
|
1338
|
+
static values: {
|
|
1339
|
+
min: {
|
|
1340
|
+
type: NumberConstructor;
|
|
1341
|
+
default: number;
|
|
1342
|
+
};
|
|
1343
|
+
max: {
|
|
1344
|
+
type: NumberConstructor;
|
|
1345
|
+
default: number;
|
|
1346
|
+
};
|
|
1347
|
+
step: {
|
|
1348
|
+
type: NumberConstructor;
|
|
1349
|
+
default: number;
|
|
1350
|
+
};
|
|
1351
|
+
start: {
|
|
1352
|
+
type: NumberConstructor;
|
|
1353
|
+
default: number;
|
|
1354
|
+
};
|
|
1355
|
+
end: {
|
|
1356
|
+
type: NumberConstructor;
|
|
1357
|
+
default: number;
|
|
1358
|
+
};
|
|
1359
|
+
};
|
|
1360
|
+
static actions: readonly ["onKeydown", "onPointerDown"];
|
|
1361
|
+
static events: readonly ["change"];
|
|
1362
|
+
readonly trackTarget: HTMLElement;
|
|
1363
|
+
readonly startThumbTarget: HTMLElement;
|
|
1364
|
+
readonly endThumbTarget: HTMLElement;
|
|
1365
|
+
readonly hasTrackTarget: boolean;
|
|
1366
|
+
readonly hasStartThumbTarget: boolean;
|
|
1367
|
+
readonly hasEndThumbTarget: boolean;
|
|
1368
|
+
minValue: number;
|
|
1369
|
+
maxValue: number;
|
|
1370
|
+
stepValue: number;
|
|
1371
|
+
startValue: number;
|
|
1372
|
+
endValue: number;
|
|
1373
|
+
/** Normalizes the initial pair (clamped, snapped, ordered) and renders. */
|
|
1374
|
+
connect(): void;
|
|
1375
|
+
/** Cancels any active pointer drag so document listeners never leak. */
|
|
1376
|
+
disconnect(): void;
|
|
1377
|
+
/** Keyboard stepping for whichever thumb is focused (the action's element). */
|
|
1378
|
+
onKeydown(event: KeyboardEvent): void;
|
|
1379
|
+
/** Begins a pointer drag on the track, moving the thumb nearest the press. */
|
|
1380
|
+
onPointerDown(event: PointerEvent): void;
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
/**
|
|
1384
|
+
* Headless "read more / truncate" behavior for visually clamped text.
|
|
1385
|
+
*
|
|
1386
|
+
* Markup contract (identifier: `stimeo--read-more`):
|
|
1387
|
+
* <div data-controller="stimeo--read-more">
|
|
1388
|
+
* <p id="bio" data-stimeo--read-more-target="content" data-state="collapsed">…</p>
|
|
1389
|
+
* <button data-stimeo--read-more-target="trigger"
|
|
1390
|
+
* data-action="stimeo--read-more#toggle"
|
|
1391
|
+
* aria-expanded="false" aria-controls="bio" hidden>Read more</button>
|
|
1392
|
+
* </div>
|
|
1393
|
+
*
|
|
1394
|
+
* There is no dedicated APG widget; the toggle borrows the **Disclosure**
|
|
1395
|
+
* convention (`aria-expanded`). The visual clamp itself (`-webkit-line-clamp`
|
|
1396
|
+
* etc.) is the consumer's CSS, keyed off `data-state`.
|
|
1397
|
+
*
|
|
1398
|
+
* @remarks
|
|
1399
|
+
* Behavior only. The full text always stays in the DOM — the clamp is purely
|
|
1400
|
+
* visual, so assistive technology reads everything regardless of state; here
|
|
1401
|
+
* `aria-expanded` therefore signals the *visual* expansion, not content hidden
|
|
1402
|
+
* from AT. The controller's extra job is **overflow detection**: when the
|
|
1403
|
+
* content is not actually clamped (it fits), the toggle is `hidden` so no
|
|
1404
|
+
* pointless "read more" is offered. This is re-evaluated on resize.
|
|
1405
|
+
*/
|
|
1406
|
+
declare class ReadMoreController extends Controller<HTMLElement> {
|
|
1407
|
+
#private;
|
|
1408
|
+
static targets: string[];
|
|
1409
|
+
static values: {
|
|
1410
|
+
collapsed: {
|
|
1411
|
+
type: BooleanConstructor;
|
|
1412
|
+
default: boolean;
|
|
1413
|
+
};
|
|
1414
|
+
};
|
|
1415
|
+
static actions: readonly ["toggle"];
|
|
1416
|
+
readonly contentTarget: HTMLElement;
|
|
1417
|
+
readonly triggerTarget: HTMLElement;
|
|
1418
|
+
readonly hasContentTarget: boolean;
|
|
1419
|
+
readonly hasTriggerTarget: boolean;
|
|
1420
|
+
collapsedValue: boolean;
|
|
1421
|
+
connect(): void;
|
|
1422
|
+
disconnect(): void;
|
|
1423
|
+
/** Toggles between the collapsed (clamped) and expanded states. */
|
|
1424
|
+
toggle(): void;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
/**
|
|
1428
|
+
* Headless **Scroll Restore** behavior: persists and restores the scroll
|
|
1429
|
+
* position of an inner scrolling region across Turbo Drive navigations (and full
|
|
1430
|
+
* reloads within the same tab session). No APG widget — a pure state-preservation
|
|
1431
|
+
* utility, like {@link import("./scroll_visibility_controller").ScrollVisibilityController}
|
|
1432
|
+
* and the Sticky State Observer.
|
|
1433
|
+
*
|
|
1434
|
+
* Markup contract (identifier: `stimeo--scroll-restore`):
|
|
1435
|
+
* <div data-controller="stimeo--scroll-restore"
|
|
1436
|
+
* data-stimeo--scroll-restore-key-value="sidebar"
|
|
1437
|
+
* style="overflow: auto">
|
|
1438
|
+
* …long content…
|
|
1439
|
+
* </div>
|
|
1440
|
+
*
|
|
1441
|
+
* Turbo swaps the whole `<body>` on navigation, so an inner scroll container is
|
|
1442
|
+
* rebuilt with `scrollTop` reset to 0. Rather than have every app hand-write a
|
|
1443
|
+
* controller for this (which contradicts a "ship the behavior" library), this
|
|
1444
|
+
* persists the offset under a stable key in `sessionStorage` and restores it on
|
|
1445
|
+
* `connect()`.
|
|
1446
|
+
*
|
|
1447
|
+
* @remarks
|
|
1448
|
+
* Behavior only — it sets no ARIA/`data-*`/CSS and never moves focus (restore is
|
|
1449
|
+
* a plain `scrollTop`/`scrollLeft` assignment). The `scroll` listener is internal
|
|
1450
|
+
* and `passive` (no consumer `data-action` needed): each event records the live
|
|
1451
|
+
* offset synchronously, and a `requestAnimationFrame` coalesces the writes to
|
|
1452
|
+
* `sessionStorage`. On `disconnect()` (Turbo navigation included) it flushes the
|
|
1453
|
+
* **last captured** offset rather than re-reading the element — by the time Turbo
|
|
1454
|
+
* fires `disconnect` it has already detached the node, whose `scrollTop` then
|
|
1455
|
+
* reads `0`, so a fresh read would clobber the saved position with `0`. Keying by
|
|
1456
|
+
* `key` (falling back to the element `id`) in `sessionStorage` makes it
|
|
1457
|
+
* multi-instance safe and survives full reloads — unlike a module-scope variable,
|
|
1458
|
+
* which only survives Turbo Drive and assumes a single instance.
|
|
1459
|
+
*/
|
|
1460
|
+
declare class ScrollRestoreController extends Controller<HTMLElement> {
|
|
1461
|
+
#private;
|
|
1462
|
+
static values: {
|
|
1463
|
+
key: {
|
|
1464
|
+
type: StringConstructor;
|
|
1465
|
+
default: string;
|
|
1466
|
+
};
|
|
1467
|
+
axis: {
|
|
1468
|
+
type: StringConstructor;
|
|
1469
|
+
default: string;
|
|
1470
|
+
};
|
|
1471
|
+
};
|
|
1472
|
+
keyValue: string;
|
|
1473
|
+
axisValue: string;
|
|
1474
|
+
connect(): void;
|
|
1475
|
+
disconnect(): void;
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
/**
|
|
1479
|
+
* Headless **Separator** behavior (APG Separator pattern).
|
|
1480
|
+
*
|
|
1481
|
+
* Markup contract (identifier: `stimeo--separator`):
|
|
1482
|
+
* <!-- decorative -->
|
|
1483
|
+
* <div data-controller="stimeo--separator" role="separator"
|
|
1484
|
+
* data-stimeo--separator-orientation-value="horizontal"></div>
|
|
1485
|
+
*
|
|
1486
|
+
* <!-- focusable, value-bearing -->
|
|
1487
|
+
* <div data-controller="stimeo--separator" role="separator" tabindex="0"
|
|
1488
|
+
* aria-label="Resize sidebar" aria-orientation="vertical"
|
|
1489
|
+
* aria-valuemin="0" aria-valuemax="100" aria-valuenow="50"
|
|
1490
|
+
* data-stimeo--separator-focusable-value="true"
|
|
1491
|
+
* data-action="keydown->stimeo--separator#onKeydown"></div>
|
|
1492
|
+
*
|
|
1493
|
+
* Most separators are static (`role="separator"` + `aria-orientation`); this
|
|
1494
|
+
* controller adds those semantics and, for the optional **focusable** variant,
|
|
1495
|
+
* keeps `aria-valuenow` in sync and emits arrow-key value changes. The actual
|
|
1496
|
+
* pane resize/drag is out of scope — that belongs to {@link ResizableController}.
|
|
1497
|
+
*
|
|
1498
|
+
* @remarks
|
|
1499
|
+
* Behavior only — line drawing is the consumer's CSS. Increment direction
|
|
1500
|
+
* follows the slider convention: ArrowUp/ArrowRight increase, ArrowDown/ArrowLeft
|
|
1501
|
+
* decrease, scoped to the relevant axis for the orientation.
|
|
1502
|
+
*/
|
|
1503
|
+
declare class SeparatorController extends Controller<HTMLElement> {
|
|
1504
|
+
#private;
|
|
1505
|
+
static values: {
|
|
1506
|
+
orientation: {
|
|
1507
|
+
type: StringConstructor;
|
|
1508
|
+
default: string;
|
|
1509
|
+
};
|
|
1510
|
+
focusable: {
|
|
1511
|
+
type: BooleanConstructor;
|
|
1512
|
+
default: boolean;
|
|
1513
|
+
};
|
|
1514
|
+
step: {
|
|
1515
|
+
type: NumberConstructor;
|
|
1516
|
+
default: number;
|
|
1517
|
+
};
|
|
1518
|
+
};
|
|
1519
|
+
static actions: readonly ["onKeydown"];
|
|
1520
|
+
static events: readonly ["change"];
|
|
1521
|
+
orientationValue: string;
|
|
1522
|
+
focusableValue: boolean;
|
|
1523
|
+
stepValue: number;
|
|
1524
|
+
connect(): void;
|
|
1525
|
+
/** Adjusts the value on arrow / Home / End keys (focusable variant only). */
|
|
1526
|
+
onKeydown(event: KeyboardEvent): void;
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
/**
|
|
1530
|
+
* Headless, accessible **responsive collapsible sidebar** behavior.
|
|
1531
|
+
*
|
|
1532
|
+
* Markup contract (identifier: `stimeo--sidebar`):
|
|
1533
|
+
* <div data-controller="stimeo--sidebar"
|
|
1534
|
+
* data-stimeo--sidebar-breakpoint-value="768"
|
|
1535
|
+
* data-stimeo--sidebar-key-value="main-nav">
|
|
1536
|
+
* <header>
|
|
1537
|
+
* <button data-stimeo--sidebar-target="trigger"
|
|
1538
|
+
* data-action="click->stimeo--sidebar#toggle"
|
|
1539
|
+
* aria-expanded="true" aria-controls="app-sidebar">Menu</button>
|
|
1540
|
+
* </header>
|
|
1541
|
+
* <div data-stimeo--sidebar-target="backdrop"
|
|
1542
|
+
* data-action="click->stimeo--sidebar#close" hidden></div>
|
|
1543
|
+
* <aside id="app-sidebar" data-stimeo--sidebar-target="panel"
|
|
1544
|
+
* aria-label="Main" data-mode="inline" data-state="expanded">
|
|
1545
|
+
* <nav aria-label="…">…</nav>
|
|
1546
|
+
* </aside>
|
|
1547
|
+
* </div>
|
|
1548
|
+
* <main>…</main> <!-- a body-level sibling so it can be made inert in overlay -->
|
|
1549
|
+
*
|
|
1550
|
+
* No dedicated APG pattern: the base is **Disclosure** (the trigger's
|
|
1551
|
+
* `aria-expanded` controls the panel's expanded state) and, *below* the
|
|
1552
|
+
* `breakpoint`, it borrows the **Dialog (Modal)** focus behavior via the shared
|
|
1553
|
+
* {@link FocusTrap} (the same trap used by dialog / alert-dialog / drawer).
|
|
1554
|
+
*
|
|
1555
|
+
* Above the breakpoint it is an **inline**, non-modal element that toggles
|
|
1556
|
+
* `expanded`↔`collapsed` (a rail), persisting that preference in `localStorage`.
|
|
1557
|
+
* Below it, it becomes an **overlay** off-canvas panel: opening activates the
|
|
1558
|
+
* trap (focus move, `Tab` cycle, `Escape`, body scroll lock, background `inert`,
|
|
1559
|
+
* focus restore); closing defers `hidden` and the trap teardown until the exit
|
|
1560
|
+
* transition ends (synchronously when there is none).
|
|
1561
|
+
*
|
|
1562
|
+
* @remarks
|
|
1563
|
+
* Behavior only — rail width, slide, and backdrop are the consumer's CSS, keyed
|
|
1564
|
+
* off `data-mode` (`inline`/`overlay`) and `data-state`. `aria-expanded` is an
|
|
1565
|
+
* abstract "is the panel expanded" flag, independent of the visual difference
|
|
1566
|
+
* between an inline collapsed rail (still in the DOM) and an overlay closed panel
|
|
1567
|
+
* (`hidden`/off-canvas). The `role="dialog"` semantics are intentionally **not**
|
|
1568
|
+
* applied — the sidebar stays an `<aside>`/`<nav>` landmark and only borrows the
|
|
1569
|
+
* modal *behavior* (cf. drawer's note on `<aside role="dialog">` conflicts).
|
|
1570
|
+
* The collapsed preference persists across Turbo navigations and full reloads;
|
|
1571
|
+
* the transient overlay-open state never persists, so "back/forward" never
|
|
1572
|
+
* restores a stuck-open menu.
|
|
1573
|
+
*/
|
|
1574
|
+
declare class SidebarController extends Controller<HTMLElement> {
|
|
1575
|
+
#private;
|
|
1576
|
+
static targets: string[];
|
|
1577
|
+
static values: {
|
|
1578
|
+
breakpoint: {
|
|
1579
|
+
type: NumberConstructor;
|
|
1580
|
+
default: number;
|
|
1581
|
+
};
|
|
1582
|
+
key: {
|
|
1583
|
+
type: StringConstructor;
|
|
1584
|
+
default: string;
|
|
1585
|
+
};
|
|
1586
|
+
collapsed: {
|
|
1587
|
+
type: BooleanConstructor;
|
|
1588
|
+
default: boolean;
|
|
1589
|
+
};
|
|
1590
|
+
};
|
|
1591
|
+
static actions: readonly ["close", "open", "toggle"];
|
|
1592
|
+
readonly triggerTarget: HTMLElement;
|
|
1593
|
+
readonly panelTarget: HTMLElement;
|
|
1594
|
+
readonly backdropTarget: HTMLElement;
|
|
1595
|
+
readonly hasTriggerTarget: boolean;
|
|
1596
|
+
readonly hasPanelTarget: boolean;
|
|
1597
|
+
readonly hasBackdropTarget: boolean;
|
|
1598
|
+
breakpointValue: number;
|
|
1599
|
+
keyValue: string;
|
|
1600
|
+
collapsedValue: boolean;
|
|
1601
|
+
connect(): void;
|
|
1602
|
+
disconnect(): void;
|
|
1603
|
+
/** Toggles the panel: inline flips collapsed/expanded, overlay flips open/closed. */
|
|
1604
|
+
toggle(): void;
|
|
1605
|
+
/** Shows the panel (inline: expand; overlay: open). */
|
|
1606
|
+
open(): void;
|
|
1607
|
+
/** Hides the panel (inline: collapse; overlay: close). */
|
|
1608
|
+
close(): void;
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
/**
|
|
1612
|
+
* Headless, accessible free-input tags / chips field.
|
|
1613
|
+
*
|
|
1614
|
+
* Markup contract (identifier: `stimeo--tags-input`):
|
|
1615
|
+
* <div data-controller="stimeo--tags-input"
|
|
1616
|
+
* data-stimeo--tags-input-delimiter-value=",">
|
|
1617
|
+
* <ul role="list" aria-label="Tags" data-stimeo--tags-input-target="tags"></ul>
|
|
1618
|
+
* <input type="text" aria-label="Add tag" aria-describedby="tags-help"
|
|
1619
|
+
* data-stimeo--tags-input-target="input"
|
|
1620
|
+
* data-action="keydown->stimeo--tags-input#onKeydown" />
|
|
1621
|
+
* <span role="status" aria-live="polite" class="visually-hidden"
|
|
1622
|
+
* data-stimeo--tags-input-target="status"></span>
|
|
1623
|
+
* <div data-stimeo--tags-input-target="fields"></div>
|
|
1624
|
+
* <template data-stimeo--tags-input-target="tagTemplate">
|
|
1625
|
+
* <li role="listitem" data-stimeo--tags-input-target="tag">
|
|
1626
|
+
* <span data-tags-input-slot="label"></span>
|
|
1627
|
+
* <!-- Removal is delegated on the tags container; no per-chip action needed. -->
|
|
1628
|
+
* <button type="button" tabindex="-1">×</button>
|
|
1629
|
+
* </li>
|
|
1630
|
+
* </template>
|
|
1631
|
+
* </div>
|
|
1632
|
+
*
|
|
1633
|
+
* There is no single established APG pattern; this composes a labeled text input
|
|
1634
|
+
* with a roving-tabindex list of removable chips, mapping to WCAG 2.1.1, 2.4.7,
|
|
1635
|
+
* 4.1.2, 4.1.3, and 1.3.1. Unlike {@link MultiSelectController} (pick from a
|
|
1636
|
+
* candidate list) the user types arbitrary strings.
|
|
1637
|
+
*
|
|
1638
|
+
* Behavior provided:
|
|
1639
|
+
* - `Enter` or the configured delimiter commits the trimmed input as a tag.
|
|
1640
|
+
* - Empty / duplicate / over-limit additions are rejected with
|
|
1641
|
+
* `stimeo--tags-input:reject`; duplicates are allowed when `allowDuplicates`.
|
|
1642
|
+
* - Tags render from the `tagTemplate`, each with a `Remove {label}` button; the
|
|
1643
|
+
* `fields` container mirrors the tag set as `name`d hidden inputs for form
|
|
1644
|
+
* submission, and every change dispatches `stimeo--tags-input:change`.
|
|
1645
|
+
* - The remove buttons form one roving Tab stop: `ArrowLeft`/`ArrowRight` move
|
|
1646
|
+
* between them (right past the end returns to the input), `Delete`/`Backspace`
|
|
1647
|
+
* delete the focused tag, and `Backspace` on an empty input deletes the last.
|
|
1648
|
+
* - Removing a tag moves focus to the neighboring tag, else back to the input.
|
|
1649
|
+
*/
|
|
1650
|
+
declare class TagsInputController extends Controller<HTMLElement> {
|
|
1651
|
+
#private;
|
|
1652
|
+
static targets: string[];
|
|
1653
|
+
static values: {
|
|
1654
|
+
delimiter: {
|
|
1655
|
+
type: StringConstructor;
|
|
1656
|
+
default: string;
|
|
1657
|
+
};
|
|
1658
|
+
max: {
|
|
1659
|
+
type: NumberConstructor;
|
|
1660
|
+
default: number;
|
|
1661
|
+
};
|
|
1662
|
+
allowDuplicates: {
|
|
1663
|
+
type: BooleanConstructor;
|
|
1664
|
+
default: boolean;
|
|
1665
|
+
};
|
|
1666
|
+
name: {
|
|
1667
|
+
type: StringConstructor;
|
|
1668
|
+
default: string;
|
|
1669
|
+
};
|
|
1670
|
+
};
|
|
1671
|
+
static actions: readonly ["onKeydown"];
|
|
1672
|
+
static events: readonly ["change", "reject"];
|
|
1673
|
+
readonly inputTarget: HTMLInputElement;
|
|
1674
|
+
readonly tagsTarget: HTMLElement;
|
|
1675
|
+
readonly tagTargets: HTMLElement[];
|
|
1676
|
+
readonly tagTemplateTarget: HTMLTemplateElement;
|
|
1677
|
+
readonly statusTarget: HTMLElement;
|
|
1678
|
+
readonly fieldsTarget: HTMLElement;
|
|
1679
|
+
readonly hasStatusTarget: boolean;
|
|
1680
|
+
readonly hasFieldsTarget: boolean;
|
|
1681
|
+
readonly hasTagTemplateTarget: boolean;
|
|
1682
|
+
delimiterValue: string;
|
|
1683
|
+
maxValue: number;
|
|
1684
|
+
allowDuplicatesValue: boolean;
|
|
1685
|
+
nameValue: string;
|
|
1686
|
+
/** Wires tag-list keyboard navigation and removal, and seeds the single Tab stop. */
|
|
1687
|
+
connect(): void;
|
|
1688
|
+
/** Releases the delegated listeners so no handler outlives the element. */
|
|
1689
|
+
disconnect(): void;
|
|
1690
|
+
/** Commits on `Enter`/delimiter and deletes the last tag on empty `Backspace`. */
|
|
1691
|
+
onKeydown(event: KeyboardEvent): void;
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
/**
|
|
1695
|
+
* Headless, accessible **time picker** behavior. Each segment (hour, minute,
|
|
1696
|
+
* optional second, optional AM/PM) is an APG **Spinbutton**; the controller
|
|
1697
|
+
* composes them into an `HH:MM[:SS]` value mirrored to a hidden field.
|
|
1698
|
+
*
|
|
1699
|
+
* Markup contract (identifier: `stimeo--time-picker`):
|
|
1700
|
+
* <div data-controller="stimeo--time-picker"
|
|
1701
|
+
* data-stimeo--time-picker-hour-cycle-value="24"
|
|
1702
|
+
* role="group" aria-label="Time">
|
|
1703
|
+
* <span role="spinbutton" aria-label="Hours" tabindex="0"
|
|
1704
|
+
* aria-valuenow="9" aria-valuemin="0" aria-valuemax="23" aria-valuetext="09"
|
|
1705
|
+
* data-segment="hour" data-stimeo--time-picker-target="segment"
|
|
1706
|
+
* data-action="keydown->stimeo--time-picker#onKeydown">09</span>
|
|
1707
|
+
* <span aria-hidden="true">:</span>
|
|
1708
|
+
* <span role="spinbutton" aria-label="Minutes" tabindex="0"
|
|
1709
|
+
* data-segment="minute" data-stimeo--time-picker-target="segment"
|
|
1710
|
+
* data-action="keydown->stimeo--time-picker#onKeydown">30</span>
|
|
1711
|
+
* <input type="hidden" data-stimeo--time-picker-target="field" />
|
|
1712
|
+
* </div>
|
|
1713
|
+
*
|
|
1714
|
+
* @remarks
|
|
1715
|
+
* Behavior only — no styling, no locale formatting. Every segment is its own Tab
|
|
1716
|
+
* stop (multi-tabstop, *not* roving); `ArrowLeft`/`ArrowRight` are an auxiliary
|
|
1717
|
+
* move between segments. `ArrowUp`/`ArrowDown` step the focused segment, wrapping
|
|
1718
|
+
* (and, when `wrap` is set, carrying minutes→hours and seconds→minutes). Typing
|
|
1719
|
+
* digits enters a value directly and advances after two digits. AM/PM is modeled
|
|
1720
|
+
* as a `meridiem` spinbutton that toggles; the hidden field is always 24-hour.
|
|
1721
|
+
*/
|
|
1722
|
+
declare class TimePickerController extends Controller<HTMLElement> {
|
|
1723
|
+
#private;
|
|
1724
|
+
static targets: string[];
|
|
1725
|
+
static values: {
|
|
1726
|
+
hourCycle: {
|
|
1727
|
+
type: NumberConstructor;
|
|
1728
|
+
default: number;
|
|
1729
|
+
};
|
|
1730
|
+
step: {
|
|
1731
|
+
type: NumberConstructor;
|
|
1732
|
+
default: number;
|
|
1733
|
+
};
|
|
1734
|
+
seconds: {
|
|
1735
|
+
type: BooleanConstructor;
|
|
1736
|
+
default: boolean;
|
|
1737
|
+
};
|
|
1738
|
+
wrap: {
|
|
1739
|
+
type: BooleanConstructor;
|
|
1740
|
+
default: boolean;
|
|
1741
|
+
};
|
|
1742
|
+
};
|
|
1743
|
+
static actions: readonly ["onKeydown"];
|
|
1744
|
+
static events: readonly ["change"];
|
|
1745
|
+
readonly segmentTargets: HTMLElement[];
|
|
1746
|
+
readonly fieldTarget: HTMLInputElement;
|
|
1747
|
+
readonly hasFieldTarget: boolean;
|
|
1748
|
+
hourCycleValue: number;
|
|
1749
|
+
stepValue: number;
|
|
1750
|
+
secondsValue: boolean;
|
|
1751
|
+
wrapValue: boolean;
|
|
1752
|
+
/** Seeds each segment from its initial `aria-valuenow` and syncs the field. */
|
|
1753
|
+
connect(): void;
|
|
1754
|
+
/** Handles stepping, inter-segment focus moves, jumps, and direct entry. */
|
|
1755
|
+
onKeydown(event: KeyboardEvent): void;
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
/**
|
|
1759
|
+
* Headless, accessible single-select tree view.
|
|
1760
|
+
*
|
|
1761
|
+
* Markup contract (identifier: `stimeo--tree-view`):
|
|
1762
|
+
* <ul data-controller="stimeo--tree-view" role="tree" aria-label="Files">
|
|
1763
|
+
* <li role="treeitem" aria-expanded="false" aria-selected="false" tabindex="0"
|
|
1764
|
+
* data-stimeo--tree-view-target="item"
|
|
1765
|
+
* data-action="keydown->stimeo--tree-view#onKeydown
|
|
1766
|
+
* click->stimeo--tree-view#onClick">
|
|
1767
|
+
* <span>src</span>
|
|
1768
|
+
* <ul role="group" data-stimeo--tree-view-target="group" hidden>
|
|
1769
|
+
* <li role="treeitem" aria-selected="false" tabindex="-1"
|
|
1770
|
+
* data-stimeo--tree-view-target="item" data-action="…">…</li>
|
|
1771
|
+
* </ul>
|
|
1772
|
+
* </li>
|
|
1773
|
+
* </ul>
|
|
1774
|
+
*
|
|
1775
|
+
* Implements the WAI-ARIA APG **Tree View** (single-select) pattern. Parent/child
|
|
1776
|
+
* structure is read from the DOM nesting (`treeitem` → child `group`). The whole
|
|
1777
|
+
* tree is one Tab stop (roving tabindex); arrows navigate visible items, expand /
|
|
1778
|
+
* collapse, and move between parent and child.
|
|
1779
|
+
*
|
|
1780
|
+
* Behavior provided:
|
|
1781
|
+
* - `ArrowDown`/`ArrowUp` move between visible items; `Home`/`End` jump to the
|
|
1782
|
+
* first / last visible item; printable characters typeahead by label prefix.
|
|
1783
|
+
* - `ArrowRight` expands a collapsed parent or steps into its first child;
|
|
1784
|
+
* `ArrowLeft` collapses an expanded parent or steps to the parent item.
|
|
1785
|
+
* - `Enter`/`Space`/click select the item (single selection via `aria-selected`).
|
|
1786
|
+
* - `aria-expanded` and each child `group`'s `hidden` stay in sync, dispatching
|
|
1787
|
+
* `stimeo--tree-view:toggle`; selection dispatches `stimeo--tree-view:select`.
|
|
1788
|
+
*/
|
|
1789
|
+
declare class TreeViewController extends Controller<HTMLElement> {
|
|
1790
|
+
#private;
|
|
1791
|
+
static targets: string[];
|
|
1792
|
+
static actions: readonly ["onClick", "onKeydown"];
|
|
1793
|
+
static events: readonly ["select", "toggle"];
|
|
1794
|
+
readonly itemTargets: HTMLElement[];
|
|
1795
|
+
/** Establishes the single tab stop (keeps an existing one, else the first). */
|
|
1796
|
+
connect(): void;
|
|
1797
|
+
/** Clears the pending typeahead-reset timer. */
|
|
1798
|
+
disconnect(): void;
|
|
1799
|
+
/**
|
|
1800
|
+
* Routes tree keyboard interaction. Because `treeitem`s nest, only the handler
|
|
1801
|
+
* on the nearest item to the event target acts; the same keydown bubbling to an
|
|
1802
|
+
* ancestor item's handler is ignored to avoid double moves / selections.
|
|
1803
|
+
*/
|
|
1804
|
+
onKeydown(event: KeyboardEvent): void;
|
|
1805
|
+
/** Selects the clicked item (nearest to the target only). */
|
|
1806
|
+
onClick(event: Event): void;
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
/**
|
|
1810
|
+
* Maps Stimeo controller identifiers to their controller classes.
|
|
1811
|
+
* Identifiers use the official `stimeo--` namespace.
|
|
1812
|
+
*/
|
|
1813
|
+
declare const stimeoControllers: {
|
|
1814
|
+
readonly "stimeo--accordion": typeof AccordionController;
|
|
1815
|
+
readonly "stimeo--alert-dialog": typeof AlertDialogController;
|
|
1816
|
+
readonly "stimeo--announcer": typeof AnnouncerController;
|
|
1817
|
+
readonly "stimeo--aspect-ratio": typeof AspectRatioController;
|
|
1818
|
+
readonly "stimeo--auto-submit": typeof AutoSubmitController;
|
|
1819
|
+
readonly "stimeo--avatar": typeof AvatarController;
|
|
1820
|
+
readonly "stimeo--breadcrumb": typeof BreadcrumbController;
|
|
1821
|
+
readonly "stimeo--bulk-select": typeof BulkSelectController;
|
|
1822
|
+
readonly "stimeo--calendar": typeof CalendarController;
|
|
1823
|
+
readonly "stimeo--carousel": typeof CarouselController;
|
|
1824
|
+
readonly "stimeo--character-counter": typeof CharacterCounterController;
|
|
1825
|
+
readonly "stimeo--checkbox": typeof CheckboxController;
|
|
1826
|
+
readonly "stimeo--clipboard": typeof ClipboardController;
|
|
1827
|
+
readonly "stimeo--collapsible": typeof CollapsibleController;
|
|
1828
|
+
readonly "stimeo--color-picker": typeof ColorPickerController;
|
|
1829
|
+
readonly "stimeo--combobox": typeof ComboboxController;
|
|
1830
|
+
readonly "stimeo--command-palette": typeof CommandPaletteController;
|
|
1831
|
+
readonly "stimeo--conditional-fields": typeof ConditionalFieldsController;
|
|
1832
|
+
readonly "stimeo--confirm": typeof ConfirmController;
|
|
1833
|
+
readonly "stimeo--context-menu": typeof ContextMenuController;
|
|
1834
|
+
readonly "stimeo--countdown": typeof CountdownController;
|
|
1835
|
+
readonly "stimeo--currency-input": typeof CurrencyInputController;
|
|
1836
|
+
readonly "stimeo--data-grid": typeof DataGridController;
|
|
1837
|
+
readonly "stimeo--date-range-picker": typeof DateRangePickerController;
|
|
1838
|
+
readonly "stimeo--dialog": typeof DialogController;
|
|
1839
|
+
readonly "stimeo--direct-upload": typeof DirectUploadController;
|
|
1840
|
+
readonly "stimeo--dirty-form": typeof DirtyFormController;
|
|
1841
|
+
readonly "stimeo--dismissible": typeof DismissibleController;
|
|
1842
|
+
readonly "stimeo--drawer": typeof DrawerController;
|
|
1843
|
+
readonly "stimeo--dropdown": typeof DropdownController;
|
|
1844
|
+
readonly "stimeo--editable": typeof EditableController;
|
|
1845
|
+
readonly "stimeo--empty-state": typeof EmptyStateController;
|
|
1846
|
+
readonly "stimeo--file-dropzone": typeof FileDropzoneController;
|
|
1847
|
+
readonly "stimeo--filter": typeof FilterController;
|
|
1848
|
+
readonly "stimeo--flash": typeof FlashController;
|
|
1849
|
+
readonly "stimeo--focus": typeof FocusController;
|
|
1850
|
+
readonly "stimeo--form-field": typeof FormFieldController;
|
|
1851
|
+
readonly "stimeo--form-validation": typeof FormValidationController;
|
|
1852
|
+
readonly "stimeo--frame-loading": typeof FrameLoadingController;
|
|
1853
|
+
readonly "stimeo--highlight": typeof HighlightController;
|
|
1854
|
+
readonly "stimeo--hover-card": typeof HoverCardController;
|
|
1855
|
+
readonly "stimeo--idle": typeof IdleController;
|
|
1856
|
+
readonly "stimeo--input-mask": typeof InputMaskController;
|
|
1857
|
+
readonly "stimeo--lazy-frame": typeof LazyFrameController;
|
|
1858
|
+
readonly "stimeo--listbox": typeof ListboxController;
|
|
1859
|
+
readonly "stimeo--local-time": typeof LocalTimeController;
|
|
1860
|
+
readonly "stimeo--masonry": typeof MasonryController;
|
|
1861
|
+
readonly "stimeo--menu": typeof MenuController;
|
|
1862
|
+
readonly "stimeo--menubar": typeof MenubarController;
|
|
1863
|
+
readonly "stimeo--meter": typeof MeterController;
|
|
1864
|
+
readonly "stimeo--multi-select": typeof MultiSelectController;
|
|
1865
|
+
readonly "stimeo--navigation-menu": typeof NavigationMenuController;
|
|
1866
|
+
readonly "stimeo--nested-form": typeof NestedFormController;
|
|
1867
|
+
readonly "stimeo--network-status": typeof NetworkStatusController;
|
|
1868
|
+
readonly "stimeo--number-input": typeof NumberInputController;
|
|
1869
|
+
readonly "stimeo--otp": typeof OtpController;
|
|
1870
|
+
readonly "stimeo--overflow-indicator": typeof OverflowIndicatorController;
|
|
1871
|
+
readonly "stimeo--overflow-menu": typeof OverflowMenuController;
|
|
1872
|
+
readonly "stimeo--pagination": typeof PaginationController;
|
|
1873
|
+
readonly "stimeo--password-reveal": typeof PasswordRevealController;
|
|
1874
|
+
readonly "stimeo--password-strength": typeof PasswordStrengthController;
|
|
1875
|
+
readonly "stimeo--persist": typeof PersistController;
|
|
1876
|
+
readonly "stimeo--popover": typeof PopoverController;
|
|
1877
|
+
readonly "stimeo--portal": typeof PortalController;
|
|
1878
|
+
readonly "stimeo--preview-guard": typeof PreviewGuardController;
|
|
1879
|
+
readonly "stimeo--progress": typeof ProgressController;
|
|
1880
|
+
readonly "stimeo--radio-group": typeof RadioGroupController;
|
|
1881
|
+
readonly "stimeo--range-slider": typeof RangeSliderController;
|
|
1882
|
+
readonly "stimeo--rating": typeof RatingController;
|
|
1883
|
+
readonly "stimeo--read-more": typeof ReadMoreController;
|
|
1884
|
+
readonly "stimeo--relative-time": typeof RelativeTimeController;
|
|
1885
|
+
readonly "stimeo--reset-before-cache": typeof ResetBeforeCacheController;
|
|
1886
|
+
readonly "stimeo--resizable": typeof ResizableController;
|
|
1887
|
+
readonly "stimeo--roving": typeof RovingController;
|
|
1888
|
+
readonly "stimeo--scroll-area": typeof ScrollAreaController;
|
|
1889
|
+
readonly "stimeo--scroll-restore": typeof ScrollRestoreController;
|
|
1890
|
+
readonly "stimeo--scroll-visibility": typeof ScrollVisibilityController;
|
|
1891
|
+
readonly "stimeo--scrollspy": typeof ScrollspyController;
|
|
1892
|
+
readonly "stimeo--separator": typeof SeparatorController;
|
|
1893
|
+
readonly "stimeo--sidebar": typeof SidebarController;
|
|
1894
|
+
readonly "stimeo--skeleton": typeof SkeletonController;
|
|
1895
|
+
readonly "stimeo--slider": typeof SliderController;
|
|
1896
|
+
readonly "stimeo--spinner": typeof SpinnerController;
|
|
1897
|
+
readonly "stimeo--step-indicator": typeof StepIndicatorController;
|
|
1898
|
+
readonly "stimeo--stepper": typeof StepperController;
|
|
1899
|
+
readonly "stimeo--stick-to-bottom": typeof StickToBottomController;
|
|
1900
|
+
readonly "stimeo--sticky-observer": typeof StickyObserverController;
|
|
1901
|
+
readonly "stimeo--submit-once": typeof SubmitOnceController;
|
|
1902
|
+
readonly "stimeo--switch": typeof SwitchController;
|
|
1903
|
+
readonly "stimeo--tabs": typeof TabsController;
|
|
1904
|
+
readonly "stimeo--tags-input": typeof TagsInputController;
|
|
1905
|
+
readonly "stimeo--textarea-autosize": typeof TextareaAutosizeController;
|
|
1906
|
+
readonly "stimeo--theme": typeof ThemeController;
|
|
1907
|
+
readonly "stimeo--time-picker": typeof TimePickerController;
|
|
1908
|
+
readonly "stimeo--toast": typeof ToastController;
|
|
1909
|
+
readonly "stimeo--toggle-group": typeof ToggleGroupController;
|
|
1910
|
+
readonly "stimeo--toolbar": typeof ToolbarController;
|
|
1911
|
+
readonly "stimeo--tooltip": typeof TooltipController;
|
|
1912
|
+
readonly "stimeo--transition": typeof TransitionController;
|
|
1913
|
+
readonly "stimeo--tree-view": typeof TreeViewController;
|
|
1914
|
+
};
|
|
1915
|
+
/**
|
|
1916
|
+
* Registers all official Stimeo controllers on a Stimulus Application.
|
|
1917
|
+
*
|
|
1918
|
+
* @param application - The Stimulus application to register controllers on.
|
|
1919
|
+
*
|
|
1920
|
+
* @example
|
|
1921
|
+
* ```ts
|
|
1922
|
+
* import { Application } from "@hotwired/stimulus";
|
|
1923
|
+
* import { registerStimeo } from "stimeo-ui";
|
|
1924
|
+
*
|
|
1925
|
+
* const application = Application.start();
|
|
1926
|
+
* registerStimeo(application);
|
|
1927
|
+
* ```
|
|
1928
|
+
*/
|
|
1929
|
+
declare function registerStimeo(application: Application): void;
|
|
1930
|
+
|
|
1931
|
+
export { AccordionController, AlertDialogController, AnnouncerController, AspectRatioController, AutoSubmitController, AvatarController, BreadcrumbController, BulkSelectController, CalendarController, CarouselController, CharacterCounterController, CheckboxController, ClipboardController, CollapsibleController, ColorPickerController, ComboboxController, CommandPaletteController, ConditionalFieldsController, ConfirmController, ContextMenuController, CountdownController, CurrencyInputController, DataGridController, DateRangePickerController, DialogController, DirectUploadController, DirtyFormController, DismissibleController, DrawerController, DropdownController, EditableController, EmptyStateController, FileDropzoneController, FilterController, FlashController, FocusController, FormFieldController, FormValidationController, FrameLoadingController, HighlightController, HoverCardController, IdleController, InputMaskController, LazyFrameController, ListboxController, LocalTimeController, MasonryController, MenuController, MenubarController, MeterController, MultiSelectController, NavigationMenuController, NestedFormController, NetworkStatusController, NumberInputController, OtpController, OverflowIndicatorController, OverflowMenuController, PaginationController, PasswordRevealController, PasswordStrengthController, PersistController, PopoverController, PortalController, PreviewGuardController, ProgressController, RadioGroupController, RangeSliderController, RatingController, ReadMoreController, RelativeTimeController, ResetBeforeCacheController, ResizableController, RovingController, ScrollAreaController, ScrollRestoreController, ScrollVisibilityController, ScrollspyController, SeparatorController, SidebarController, SkeletonController, SliderController, SpinnerController, StepIndicatorController, StepperController, StickToBottomController, StickyObserverController, SubmitOnceController, SwitchController, TabsController, TagsInputController, TextareaAutosizeController, ThemeController, TimePickerController, ToastController, ToggleGroupController, ToolbarController, TooltipController, TransitionController, TreeViewController, registerStimeo, stimeoControllers };
|