stimeo-ui 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +212 -0
- package/README.md +120 -0
- package/dist/cable/index.js +123 -29
- package/dist/cable/index.js.map +1 -1
- package/dist/controllers/accordion_controller.d.ts +30 -3
- package/dist/controllers/accordion_controller.js +98 -9
- package/dist/controllers/accordion_controller.js.map +1 -1
- package/dist/controllers/alert_dialog_controller.d.ts +8 -7
- package/dist/controllers/alert_dialog_controller.js.map +1 -1
- package/dist/controllers/announcer_controller.d.ts +3 -2
- package/dist/controllers/announcer_controller.js +96 -62
- package/dist/controllers/announcer_controller.js.map +1 -1
- package/dist/controllers/auto_submit_controller.js +83 -7
- package/dist/controllers/auto_submit_controller.js.map +1 -1
- package/dist/controllers/avatar_controller.js +1 -1
- package/dist/controllers/avatar_controller.js.map +1 -1
- package/dist/controllers/breadcrumb_controller.d.ts +10 -7
- package/dist/controllers/breadcrumb_controller.js +38 -11
- package/dist/controllers/breadcrumb_controller.js.map +1 -1
- package/dist/controllers/bulk_select_controller.d.ts +4 -4
- package/dist/controllers/bulk_select_controller.js +7 -6
- package/dist/controllers/bulk_select_controller.js.map +1 -1
- package/dist/controllers/calendar_controller.d.ts +101 -23
- package/dist/controllers/calendar_controller.js +340 -123
- package/dist/controllers/calendar_controller.js.map +1 -1
- package/dist/controllers/carousel_controller.d.ts +67 -22
- package/dist/controllers/carousel_controller.js +263 -38
- package/dist/controllers/carousel_controller.js.map +1 -1
- package/dist/controllers/character_counter_controller.d.ts +1 -1
- package/dist/controllers/character_counter_controller.js +40 -2
- package/dist/controllers/character_counter_controller.js.map +1 -1
- package/dist/controllers/checkbox_controller.js +81 -12
- package/dist/controllers/checkbox_controller.js.map +1 -1
- package/dist/controllers/clipboard_controller.d.ts +28 -2
- package/dist/controllers/clipboard_controller.js +63 -5
- package/dist/controllers/clipboard_controller.js.map +1 -1
- package/dist/controllers/collapsible_controller.d.ts +25 -1
- package/dist/controllers/collapsible_controller.js +99 -14
- package/dist/controllers/collapsible_controller.js.map +1 -1
- package/dist/controllers/color_picker_controller.d.ts +29 -8
- package/dist/controllers/color_picker_controller.js +80 -34
- package/dist/controllers/color_picker_controller.js.map +1 -1
- package/dist/controllers/combobox_controller.d.ts +10 -1
- package/dist/controllers/combobox_controller.js +106 -16
- package/dist/controllers/combobox_controller.js.map +1 -1
- package/dist/controllers/command_palette_controller.d.ts +3 -3
- package/dist/controllers/command_palette_controller.js +35 -3
- package/dist/controllers/command_palette_controller.js.map +1 -1
- package/dist/controllers/conditional_fields_controller.js +85 -17
- package/dist/controllers/conditional_fields_controller.js.map +1 -1
- package/dist/controllers/confirm_controller.js +3 -0
- package/dist/controllers/confirm_controller.js.map +1 -1
- package/dist/controllers/context_menu_controller.d.ts +6 -0
- package/dist/controllers/context_menu_controller.js +32 -12
- package/dist/controllers/context_menu_controller.js.map +1 -1
- package/dist/controllers/count_up_controller.js.map +1 -1
- package/dist/controllers/countdown_controller.d.ts +30 -1
- package/dist/controllers/countdown_controller.js +129 -26
- package/dist/controllers/countdown_controller.js.map +1 -1
- package/dist/controllers/currency_input_controller.d.ts +77 -16
- package/dist/controllers/currency_input_controller.js +221 -67
- package/dist/controllers/currency_input_controller.js.map +1 -1
- package/dist/controllers/data_grid_controller.d.ts +63 -18
- package/dist/controllers/data_grid_controller.js +195 -29
- package/dist/controllers/data_grid_controller.js.map +1 -1
- package/dist/controllers/date_range_picker_controller.d.ts +41 -6
- package/dist/controllers/date_range_picker_controller.js +151 -30
- package/dist/controllers/date_range_picker_controller.js.map +1 -1
- package/dist/controllers/dialog_controller.d.ts +10 -3
- package/dist/controllers/dialog_controller.js +35 -8
- package/dist/controllers/dialog_controller.js.map +1 -1
- package/dist/controllers/direct_upload_controller.js +22 -4
- package/dist/controllers/direct_upload_controller.js.map +1 -1
- package/dist/controllers/dirty_form_controller.d.ts +2 -2
- package/dist/controllers/dirty_form_controller.js +46 -13
- package/dist/controllers/dirty_form_controller.js.map +1 -1
- package/dist/controllers/dismissible_controller.js +1 -0
- package/dist/controllers/dismissible_controller.js.map +1 -1
- package/dist/controllers/drawer_controller.d.ts +18 -10
- package/dist/controllers/drawer_controller.js +54 -19
- package/dist/controllers/drawer_controller.js.map +1 -1
- package/dist/controllers/dropdown_controller.d.ts +9 -3
- package/dist/controllers/dropdown_controller.js +36 -9
- package/dist/controllers/dropdown_controller.js.map +1 -1
- package/dist/controllers/editable_controller.js +34 -0
- package/dist/controllers/editable_controller.js.map +1 -1
- package/dist/controllers/file_dropzone_controller.js +144 -51
- package/dist/controllers/file_dropzone_controller.js.map +1 -1
- package/dist/controllers/filter_controller.d.ts +10 -4
- package/dist/controllers/filter_controller.js +20 -6
- package/dist/controllers/filter_controller.js.map +1 -1
- package/dist/controllers/flash_controller.d.ts +26 -6
- package/dist/controllers/flash_controller.js +432 -71
- package/dist/controllers/flash_controller.js.map +1 -1
- package/dist/controllers/focus_controller.js +1 -0
- package/dist/controllers/focus_controller.js.map +1 -1
- package/dist/controllers/form_field_controller.js +7 -5
- package/dist/controllers/form_field_controller.js.map +1 -1
- package/dist/controllers/form_validation_controller.js +19 -13
- package/dist/controllers/form_validation_controller.js.map +1 -1
- package/dist/controllers/frame_loading_controller.js +45 -8
- package/dist/controllers/frame_loading_controller.js.map +1 -1
- package/dist/controllers/highlight_controller.js +82 -25
- package/dist/controllers/highlight_controller.js.map +1 -1
- package/dist/controllers/hover_card_controller.d.ts +10 -2
- package/dist/controllers/hover_card_controller.js +40 -14
- package/dist/controllers/hover_card_controller.js.map +1 -1
- package/dist/controllers/idle_controller.d.ts +16 -3
- package/dist/controllers/idle_controller.js +90 -5
- package/dist/controllers/idle_controller.js.map +1 -1
- package/dist/controllers/input_mask_controller.d.ts +5 -2
- package/dist/controllers/input_mask_controller.js +65 -9
- package/dist/controllers/input_mask_controller.js.map +1 -1
- package/dist/controllers/intersection_controller.js +3 -0
- package/dist/controllers/intersection_controller.js.map +1 -1
- package/dist/controllers/lazy_frame_controller.js +11 -2
- package/dist/controllers/lazy_frame_controller.js.map +1 -1
- package/dist/controllers/listbox_controller.d.ts +50 -8
- package/dist/controllers/listbox_controller.js +203 -45
- package/dist/controllers/listbox_controller.js.map +1 -1
- package/dist/controllers/local_time_controller.js +10 -5
- package/dist/controllers/local_time_controller.js.map +1 -1
- package/dist/controllers/masonry_controller.d.ts +3 -3
- package/dist/controllers/masonry_controller.js +31 -15
- package/dist/controllers/masonry_controller.js.map +1 -1
- package/dist/controllers/menu_controller.d.ts +9 -3
- package/dist/controllers/menu_controller.js +45 -16
- package/dist/controllers/menu_controller.js.map +1 -1
- package/dist/controllers/menubar_controller.d.ts +11 -0
- package/dist/controllers/menubar_controller.js +58 -24
- package/dist/controllers/menubar_controller.js.map +1 -1
- package/dist/controllers/meter_controller.js +9 -5
- package/dist/controllers/meter_controller.js.map +1 -1
- package/dist/controllers/multi_select_controller.d.ts +18 -3
- package/dist/controllers/multi_select_controller.js +278 -104
- package/dist/controllers/multi_select_controller.js.map +1 -1
- package/dist/controllers/navigation_menu_controller.d.ts +11 -0
- package/dist/controllers/navigation_menu_controller.js +48 -15
- package/dist/controllers/navigation_menu_controller.js.map +1 -1
- package/dist/controllers/nested_form_controller.js +37 -8
- package/dist/controllers/nested_form_controller.js.map +1 -1
- package/dist/controllers/network_status_controller.js +9 -1
- package/dist/controllers/network_status_controller.js.map +1 -1
- package/dist/controllers/number_input_controller.d.ts +36 -8
- package/dist/controllers/number_input_controller.js +124 -21
- package/dist/controllers/number_input_controller.js.map +1 -1
- package/dist/controllers/optimistic_controller.js +42 -5
- package/dist/controllers/optimistic_controller.js.map +1 -1
- package/dist/controllers/otp_controller.d.ts +22 -7
- package/dist/controllers/otp_controller.js +198 -55
- package/dist/controllers/otp_controller.js.map +1 -1
- package/dist/controllers/overflow_indicator_controller.d.ts +8 -12
- package/dist/controllers/overflow_indicator_controller.js +115 -21
- package/dist/controllers/overflow_indicator_controller.js.map +1 -1
- package/dist/controllers/overflow_menu_controller.d.ts +26 -6
- package/dist/controllers/overflow_menu_controller.js +141 -44
- package/dist/controllers/overflow_menu_controller.js.map +1 -1
- package/dist/controllers/pagination_controller.d.ts +19 -11
- package/dist/controllers/pagination_controller.js +74 -28
- package/dist/controllers/pagination_controller.js.map +1 -1
- package/dist/controllers/password_reveal_controller.d.ts +15 -1
- package/dist/controllers/password_reveal_controller.js +59 -2
- package/dist/controllers/password_reveal_controller.js.map +1 -1
- package/dist/controllers/persist_controller.js +30 -8
- package/dist/controllers/persist_controller.js.map +1 -1
- package/dist/controllers/pointer_drag_controller.js +131 -52
- package/dist/controllers/pointer_drag_controller.js.map +1 -1
- package/dist/controllers/popover_controller.d.ts +9 -3
- package/dist/controllers/popover_controller.js +45 -11
- package/dist/controllers/popover_controller.js.map +1 -1
- package/dist/controllers/portal_controller.d.ts +1 -1
- package/dist/controllers/portal_controller.js +6 -2
- package/dist/controllers/portal_controller.js.map +1 -1
- package/dist/controllers/preview_guard_controller.js +16 -1
- package/dist/controllers/preview_guard_controller.js.map +1 -1
- package/dist/controllers/progress_controller.js +8 -4
- package/dist/controllers/progress_controller.js.map +1 -1
- package/dist/controllers/radio_group_controller.d.ts +6 -4
- package/dist/controllers/radio_group_controller.js +42 -17
- package/dist/controllers/radio_group_controller.js.map +1 -1
- package/dist/controllers/range_slider_controller.d.ts +49 -1
- package/dist/controllers/range_slider_controller.js +88 -42
- package/dist/controllers/range_slider_controller.js.map +1 -1
- package/dist/controllers/rating_controller.d.ts +14 -3
- package/dist/controllers/rating_controller.js +39 -15
- package/dist/controllers/rating_controller.js.map +1 -1
- package/dist/controllers/read_more_controller.d.ts +24 -2
- package/dist/controllers/read_more_controller.js +100 -7
- package/dist/controllers/read_more_controller.js.map +1 -1
- package/dist/controllers/reading_progress_controller.js +65 -19
- package/dist/controllers/reading_progress_controller.js.map +1 -1
- package/dist/controllers/relative_time_controller.js +10 -5
- package/dist/controllers/relative_time_controller.js.map +1 -1
- package/dist/controllers/resizable_controller.d.ts +16 -2
- package/dist/controllers/resizable_controller.js +82 -22
- package/dist/controllers/resizable_controller.js.map +1 -1
- package/dist/controllers/scroll_area_controller.js +75 -27
- package/dist/controllers/scroll_area_controller.js.map +1 -1
- package/dist/controllers/scroll_restore_controller.js +37 -16
- package/dist/controllers/scroll_restore_controller.js.map +1 -1
- package/dist/controllers/scroll_visibility_controller.js +49 -30
- package/dist/controllers/scroll_visibility_controller.js.map +1 -1
- package/dist/controllers/scrollspy_controller.d.ts +3 -2
- package/dist/controllers/scrollspy_controller.js +71 -26
- package/dist/controllers/scrollspy_controller.js.map +1 -1
- package/dist/controllers/separator_controller.d.ts +41 -14
- package/dist/controllers/separator_controller.js +66 -37
- package/dist/controllers/separator_controller.js.map +1 -1
- package/dist/controllers/sidebar_controller.d.ts +20 -3
- package/dist/controllers/sidebar_controller.js +77 -18
- package/dist/controllers/sidebar_controller.js.map +1 -1
- package/dist/controllers/skeleton_controller.js +6 -1
- package/dist/controllers/skeleton_controller.js.map +1 -1
- package/dist/controllers/slider_controller.d.ts +45 -7
- package/dist/controllers/slider_controller.js +82 -47
- package/dist/controllers/slider_controller.js.map +1 -1
- package/dist/controllers/smart_sticky_header_controller.js +60 -26
- package/dist/controllers/smart_sticky_header_controller.js.map +1 -1
- package/dist/controllers/sortable_controller.js +17 -2
- package/dist/controllers/sortable_controller.js.map +1 -1
- package/dist/controllers/spinner_controller.js +10 -2
- package/dist/controllers/spinner_controller.js.map +1 -1
- package/dist/controllers/step_indicator_controller.d.ts +19 -17
- package/dist/controllers/step_indicator_controller.js +18 -17
- package/dist/controllers/step_indicator_controller.js.map +1 -1
- package/dist/controllers/stepper_controller.d.ts +34 -9
- package/dist/controllers/stepper_controller.js +101 -19
- package/dist/controllers/stepper_controller.js.map +1 -1
- package/dist/controllers/stick_to_bottom_controller.d.ts +19 -0
- package/dist/controllers/stick_to_bottom_controller.js +104 -8
- package/dist/controllers/stick_to_bottom_controller.js.map +1 -1
- package/dist/controllers/submit_once_controller.d.ts +3 -2
- package/dist/controllers/submit_once_controller.js +45 -9
- package/dist/controllers/submit_once_controller.js.map +1 -1
- package/dist/controllers/switch_controller.d.ts +29 -7
- package/dist/controllers/switch_controller.js +101 -10
- package/dist/controllers/switch_controller.js.map +1 -1
- package/dist/controllers/tabs_controller.d.ts +12 -0
- package/dist/controllers/tabs_controller.js +21 -2
- package/dist/controllers/tabs_controller.js.map +1 -1
- package/dist/controllers/tags_input_controller.d.ts +15 -3
- package/dist/controllers/tags_input_controller.js +209 -59
- package/dist/controllers/tags_input_controller.js.map +1 -1
- package/dist/controllers/textarea_autosize_controller.js +29 -3
- package/dist/controllers/textarea_autosize_controller.js.map +1 -1
- package/dist/controllers/theme_controller.d.ts +20 -3
- package/dist/controllers/theme_controller.js +64 -14
- package/dist/controllers/theme_controller.js.map +1 -1
- package/dist/controllers/time_picker_controller.js +23 -8
- package/dist/controllers/time_picker_controller.js.map +1 -1
- package/dist/controllers/toast_controller.d.ts +55 -15
- package/dist/controllers/toast_controller.js +451 -105
- package/dist/controllers/toast_controller.js.map +1 -1
- package/dist/controllers/toggle_group_controller.d.ts +49 -7
- package/dist/controllers/toggle_group_controller.js +159 -23
- package/dist/controllers/toggle_group_controller.js.map +1 -1
- package/dist/controllers/toolbar_controller.js +32 -0
- package/dist/controllers/toolbar_controller.js.map +1 -1
- package/dist/controllers/tooltip_controller.d.ts +8 -0
- package/dist/controllers/tooltip_controller.js +39 -13
- package/dist/controllers/tooltip_controller.js.map +1 -1
- package/dist/controllers/transition_controller.js +4 -0
- package/dist/controllers/transition_controller.js.map +1 -1
- package/dist/controllers/tree_view_controller.d.ts +39 -8
- package/dist/controllers/tree_view_controller.js +169 -16
- package/dist/controllers/tree_view_controller.js.map +1 -1
- package/dist/index.d.ts +28 -1
- package/dist/index.js +5002 -1911
- package/dist/index.js.map +1 -1
- package/dist/inspector/cli.d.ts +72 -6
- package/dist/inspector/cli.js +262 -51
- package/dist/inspector/cli.js.map +1 -1
- package/dist/inspector/cli_bin.js +309 -51
- package/dist/inspector/cli_bin.js.map +1 -1
- package/dist/inspector/examples.json +40 -40
- package/dist/inspector/manifest.json +529 -61
- package/dist/positioning/index.js +2 -0
- package/dist/positioning/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"examples": {
|
|
4
4
|
"stimeo--accordion": {
|
|
5
5
|
"file": "examples/accordion/_demo.html.erb",
|
|
6
|
-
"source": "<%# Markup for the accordion (APG Accordion) demo.\n stimeo--accordion manages each header's aria-expanded and each panel's hidden,\n and allows multiple panels open at once. Arrow keys move focus between headers.\n Headers and panels are linked via aria-controls (= the panel's id), and each\n panel (role=\"region\") references its header button's id via aria-labelledby. %>\n<div class=\"accordion\" data-controller=\"stimeo--accordion\">\n <h3 class=\"accordion__header\">\n <button type=\"button\" id=\"acc-shipping-trigger\" class=\"accordion__trigger\"\n aria-expanded=\"false\" aria-controls=\"acc-shipping\"\n data-stimeo--accordion-target=\"trigger\"\n data-action=\"click->stimeo--accordion#toggle\n keydown->stimeo--accordion#onKeydown\"
|
|
6
|
+
"source": "<%# Markup for the accordion (APG Accordion) demo.\n stimeo--accordion manages each header's aria-expanded and each panel's hidden,\n and allows multiple panels open at once. Arrow keys move focus between headers.\n Headers and panels are linked via aria-controls (= the panel's id), and each\n panel (role=\"region\") references its header button's id via aria-labelledby.\n Each header also carries a \"+\" / \"−\" pair, and the library hides the half that\n does not belong to its state. The glyphs are decorative, so they are aria-hidden\n and the accessible name stays the section title. %>\n<div class=\"accordion\" data-controller=\"stimeo--accordion\">\n <h3 class=\"accordion__header\">\n <button type=\"button\" id=\"acc-shipping-trigger\" class=\"accordion__trigger\"\n aria-expanded=\"false\" aria-controls=\"acc-shipping\"\n data-stimeo--accordion-target=\"trigger\"\n data-action=\"click->stimeo--accordion#toggle\n keydown->stimeo--accordion#onKeydown\">\n <%= t(\"components.accordion.demo.shipping_title\") %>\n <span class=\"accordion__marker\" aria-hidden=\"true\"\n data-stimeo--accordion-target=\"collapsedLabel\">+</span>\n <span class=\"accordion__marker\" aria-hidden=\"true\" hidden\n data-stimeo--accordion-target=\"expandedLabel\">−</span>\n </button>\n </h3>\n <div class=\"accordion__panel\" id=\"acc-shipping\" role=\"region\"\n aria-labelledby=\"acc-shipping-trigger\"\n data-stimeo--accordion-target=\"panel\" hidden>\n <p><%= t(\"components.accordion.demo.shipping_desc\") %></p>\n </div>\n\n <h3 class=\"accordion__header\">\n <button type=\"button\" id=\"acc-returns-trigger\" class=\"accordion__trigger\"\n aria-expanded=\"false\" aria-controls=\"acc-returns\"\n data-stimeo--accordion-target=\"trigger\"\n data-action=\"click->stimeo--accordion#toggle\n keydown->stimeo--accordion#onKeydown\">\n <%= t(\"components.accordion.demo.returns_title\") %>\n <span class=\"accordion__marker\" aria-hidden=\"true\"\n data-stimeo--accordion-target=\"collapsedLabel\">+</span>\n <span class=\"accordion__marker\" aria-hidden=\"true\" hidden\n data-stimeo--accordion-target=\"expandedLabel\">−</span>\n </button>\n </h3>\n <div class=\"accordion__panel\" id=\"acc-returns\" role=\"region\"\n aria-labelledby=\"acc-returns-trigger\"\n data-stimeo--accordion-target=\"panel\" hidden>\n <p><%= t(\"components.accordion.demo.returns_desc\") %></p>\n </div>\n\n <h3 class=\"accordion__header\">\n <button type=\"button\" id=\"acc-warranty-trigger\" class=\"accordion__trigger\"\n aria-expanded=\"false\" aria-controls=\"acc-warranty\"\n data-stimeo--accordion-target=\"trigger\"\n data-action=\"click->stimeo--accordion#toggle\n keydown->stimeo--accordion#onKeydown\">\n <%= t(\"components.accordion.demo.warranty_title\") %>\n <span class=\"accordion__marker\" aria-hidden=\"true\"\n data-stimeo--accordion-target=\"collapsedLabel\">+</span>\n <span class=\"accordion__marker\" aria-hidden=\"true\" hidden\n data-stimeo--accordion-target=\"expandedLabel\">−</span>\n </button>\n </h3>\n <div class=\"accordion__panel\" id=\"acc-warranty\" role=\"region\"\n aria-labelledby=\"acc-warranty-trigger\"\n data-stimeo--accordion-target=\"panel\" hidden>\n <p><%= t(\"components.accordion.demo.warranty_desc\") %></p>\n </div>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.events\") %></span>\n <span class=\"demo-readout__value\" data-readout>—</span>\n</p>\n"
|
|
7
7
|
},
|
|
8
8
|
"stimeo--alert-dialog": {
|
|
9
9
|
"file": "examples/alert_dialog/_demo.html.erb",
|
|
@@ -39,11 +39,11 @@
|
|
|
39
39
|
},
|
|
40
40
|
"stimeo--calendar": {
|
|
41
41
|
"file": "examples/calendar/_demo.html.erb",
|
|
42
|
-
"source": "<%# Markup for the calendar (APG Date Picker Dialog) demo.\n stimeo--calendar provides the displayed month label via Intl.DateTimeFormat,\n date navigation via roving focus, month transitions, 42-cell sync, and min/max\n boundary limits. %>\n<div\n class=\"calendar-demo demo-card\"\n data-controller=\"stimeo--calendar\"\n data-stimeo--calendar-month-value=\"<%= Time.current.strftime(\"%Y-%m\") %>\"\n data-stimeo--calendar-selected-value=\"<%= Time.current.strftime(\"%Y-%m-%d\") %>\"\n data-stimeo--calendar-min-value=\"<%= (Time.current - 1.month).beginning_of_month.strftime(\n \"%Y-%m-%d\"\n ) %>\"\n data-stimeo--calendar-max-value=\"<%= (Time.current + 2.months).end_of_month.strftime(\n \"%Y-%m-%d\"\n ) %>\"\n data-stimeo--calendar-week-start-value=\"0\"\n>\n \n <div class=\"calendar-demo__header\">\n <button\n class=\"calendar-demo__btn\"\n type=\"button\"\n data-action=\"click->stimeo--calendar#prev\"\n aria-label=\"<%= t(\"components.calendar.demo.prev_month\") %>\"\n >\n <svg\n class=\"calendar-demo__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <polyline points=\"15 18 9 12 15 6\"></polyline>\n </svg>\n </button>\n <span\n class=\"calendar-demo__label\"\n data-stimeo--calendar-target=\"label\"\n ></span>\n <button\n class=\"calendar-demo__btn\"\n type=\"button\"\n data-action=\"click->stimeo--calendar#next\"\n aria-label=\"<%= t(\"components.calendar.demo.next_month\") %>\"\n >\n <svg\n class=\"calendar-demo__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <polyline points=\"9 18 15 12 9 6\"></polyline>\n </svg>\n </button>\n </div>\n\n <table class=\"calendar-demo__table\" role=\"grid\">\n <thead>\n <tr role=\"row\">\n <th\n scope=\"col\"\n aria-label=\"<%= t(\"components.calendar.demo.sunday\") %>\"\n >\n <%= t(\"components.calendar.demo.sunday\")[0] %>\n </th>\n <th\n scope=\"col\"\n aria-label=\"<%= t(\"components.calendar.demo.monday\") %>\"\n >\n <%= t(\"components.calendar.demo.monday\")[0] %>\n </th>\n <th\n scope=\"col\"\n aria-label=\"<%= t(\"components.calendar.demo.tuesday\") %>\"\n >\n <%= t(\"components.calendar.demo.tuesday\")[0] %>\n </th>\n <th\n scope=\"col\"\n aria-label=\"<%= t(\"components.calendar.demo.wednesday\") %>\"\n >\n <%= t(\"components.calendar.demo.wednesday\")[0] %>\n </th>\n <th\n scope=\"col\"\n aria-label=\"<%= t(\"components.calendar.demo.thursday\") %>\"\n >\n <%= t(\"components.calendar.demo.thursday\")[0] %>\n </th>\n <th\n scope=\"col\"\n aria-label=\"<%= t(\"components.calendar.demo.friday\") %>\"\n >\n <%= t(\"components.calendar.demo.friday\")[0] %>\n </th>\n <th\n scope=\"col\"\n aria-label=\"<%= t(\"components.calendar.demo.saturday\") %>\"\n >\n <%= t(\"components.calendar.demo.saturday\")[0] %>\n </th>\n </tr>\n </thead>\n <tbody\n data-stimeo--calendar-target=\"grid\"\n data-action=\"\n keydown->stimeo--calendar#onKeydown\n click->stimeo--calendar#selectByClick\n \"\n >\n <% 6.times do %>\n <tr role=\"row\">\n <% 7.times do %>\n <td\n role=\"gridcell\"\n class=\"calendar-demo__cell\"\n data-stimeo--calendar-target=\"day\"\n tabindex=\"-1\"\n ></td>\n <% end %>\n </tr>\n <% end %>\n </tbody>\n </table>\n</div>\n"
|
|
42
|
+
"source": "<%# Markup for the calendar (APG Date Picker Dialog) demo.\n stimeo--calendar provides the displayed month label via Intl.DateTimeFormat,\n date navigation via roving focus, month transitions, 42-cell sync, and min/max\n boundary limits. %>\n<div\n class=\"calendar-demo demo-card\"\n data-controller=\"stimeo--calendar\"\n data-stimeo--calendar-month-value=\"<%= Time.current.strftime(\"%Y-%m\") %>\"\n data-stimeo--calendar-selected-value=\"<%= Time.current.strftime(\"%Y-%m-%d\") %>\"\n data-stimeo--calendar-min-value=\"<%= (Time.current - 1.month).beginning_of_month.strftime(\n \"%Y-%m-%d\"\n ) %>\"\n data-stimeo--calendar-max-value=\"<%= (Time.current + 2.months).end_of_month.strftime(\n \"%Y-%m-%d\"\n ) %>\"\n data-stimeo--calendar-week-start-value=\"0\"\n>\n <%# The hidden fields carry the selected day and the painted month into the\n form, so a server can serve the days it is showing. Both are optional. %>\n <input type=\"hidden\" name=\"on\" data-stimeo--calendar-target=\"field\" />\n <input type=\"hidden\" name=\"month\" data-stimeo--calendar-target=\"monthField\" />\n \n <div class=\"calendar-demo__header\">\n <button\n class=\"calendar-demo__btn\"\n type=\"button\"\n data-action=\"click->stimeo--calendar#prev\"\n aria-label=\"<%= t(\"components.calendar.demo.prev_month\") %>\"\n >\n <svg\n class=\"calendar-demo__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <polyline points=\"15 18 9 12 15 6\"></polyline>\n </svg>\n </button>\n <span\n class=\"calendar-demo__label\"\n data-stimeo--calendar-target=\"label\"\n ></span>\n <button\n class=\"calendar-demo__btn\"\n type=\"button\"\n data-action=\"click->stimeo--calendar#next\"\n aria-label=\"<%= t(\"components.calendar.demo.next_month\") %>\"\n >\n <svg\n class=\"calendar-demo__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n <polyline points=\"9 18 15 12 9 6\"></polyline>\n </svg>\n </button>\n </div>\n\n <table class=\"calendar-demo__table\" role=\"grid\">\n <thead>\n <tr role=\"row\">\n <th\n scope=\"col\"\n aria-label=\"<%= t(\"components.calendar.demo.sunday\") %>\"\n >\n <%= t(\"components.calendar.demo.sunday\")[0] %>\n </th>\n <th\n scope=\"col\"\n aria-label=\"<%= t(\"components.calendar.demo.monday\") %>\"\n >\n <%= t(\"components.calendar.demo.monday\")[0] %>\n </th>\n <th\n scope=\"col\"\n aria-label=\"<%= t(\"components.calendar.demo.tuesday\") %>\"\n >\n <%= t(\"components.calendar.demo.tuesday\")[0] %>\n </th>\n <th\n scope=\"col\"\n aria-label=\"<%= t(\"components.calendar.demo.wednesday\") %>\"\n >\n <%= t(\"components.calendar.demo.wednesday\")[0] %>\n </th>\n <th\n scope=\"col\"\n aria-label=\"<%= t(\"components.calendar.demo.thursday\") %>\"\n >\n <%= t(\"components.calendar.demo.thursday\")[0] %>\n </th>\n <th\n scope=\"col\"\n aria-label=\"<%= t(\"components.calendar.demo.friday\") %>\"\n >\n <%= t(\"components.calendar.demo.friday\")[0] %>\n </th>\n <th\n scope=\"col\"\n aria-label=\"<%= t(\"components.calendar.demo.saturday\") %>\"\n >\n <%= t(\"components.calendar.demo.saturday\")[0] %>\n </th>\n </tr>\n </thead>\n <tbody\n data-stimeo--calendar-target=\"grid\"\n data-action=\"\n keydown->stimeo--calendar#onKeydown\n click->stimeo--calendar#selectByClick\n \"\n >\n <% 6.times do %>\n <tr role=\"row\">\n <% 7.times do %>\n <td\n role=\"gridcell\"\n class=\"calendar-demo__cell\"\n data-stimeo--calendar-target=\"day\"\n tabindex=\"-1\"\n ></td>\n <% end %>\n </tr>\n <% end %>\n </tbody>\n </table>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.field\") %></span>\n <span class=\"demo-readout__value\" data-readout\n data-empty-text=\"<%= t(\"catalog.readout.empty\") %>\">—</span>\n</p>\n"
|
|
43
43
|
},
|
|
44
44
|
"stimeo--carousel": {
|
|
45
45
|
"file": "examples/carousel/_demo.html.erb",
|
|
46
|
-
"source": "<%# Markup for the carousel demo.\n The library handles slide advance, autoplay, syncing the current slide's\n data-state / hidden / inert, the pickers' (tabs) aria-selected and roving, the\n aria-disabled of controls that cannot be reached, and the viewport's aria-live.\n There is no data-action anywhere: the controller delegates clicks, picker keys,\n hover, and focus from its own element, so the markup only declares targets.\n Autoplay deliberately demonstrates WCAG 2.2.2: the play toggle is what stops it for\n good, while hovering, focusing, or backgrounding the tab only suspends it until that\n condition ends. This is spelled out in the on-screen note below the carousel.\n Transitions and layout are the consumer's CSS. %>\n<section\n class=\"carousel\"\n data-controller=\"stimeo--carousel\"\n aria-roledescription=\"carousel\"\n aria-label=\"<%= t(\"components.carousel.demo.label\") %>\"\n data-stimeo--carousel-autoplay-value=\"false\"\n data-stimeo--carousel-interval-value=\"2500\"\n data-stimeo--carousel-loop-value=\"true\">\n <div class=\"carousel__bar\">\n <button\n type=\"button\"\n class=\"carousel__play\"\n aria-label=\"<%= t(\"components.carousel.demo.autoplay\") %>\"\n data-stimeo--carousel-target=\"playToggle\">\n <%# The library owns aria-pressed (the autoplay Value is the
|
|
46
|
+
"source": "<%# Markup for the carousel demo.\n The library handles slide advance, autoplay, syncing the current slide's\n data-state / hidden / inert, the pickers' (tabs) aria-selected and roving, the\n aria-disabled of controls that cannot be reached, and the viewport's aria-live.\n There is no data-action anywhere: the controller delegates clicks, picker keys,\n hover, and focus from its own element, so the markup only declares targets.\n Autoplay deliberately demonstrates WCAG 2.2.2: the play toggle is what stops it for\n good, while hovering, focusing, or backgrounding the tab only suspends it until that\n condition ends. This is spelled out in the on-screen note below the carousel.\n Transitions and layout are the consumer's CSS. %>\n<section\n class=\"carousel\"\n data-controller=\"stimeo--carousel\"\n aria-roledescription=\"carousel\"\n aria-label=\"<%= t(\"components.carousel.demo.label\") %>\"\n data-stimeo--carousel-autoplay-value=\"false\"\n data-stimeo--carousel-interval-value=\"2500\"\n data-stimeo--carousel-loop-value=\"true\">\n <div class=\"carousel__bar\">\n <button\n type=\"button\"\n class=\"carousel__play\"\n aria-label=\"<%= t(\"components.carousel.demo.autoplay\") %>\"\n data-stimeo--carousel-target=\"playToggle\">\n <%# The library owns aria-pressed (derived from the autoplay Value, whether a slide\n is left to rotate to, and the reduced-motion preference) and the hidden of the\n two glyph halves: ❚❚ shows while autoplay runs, ▶ while it is stopped. The\n icons are decorative; the accessible name comes from the aria-label above and\n stays the same in both states. %>\n <span aria-hidden=\"true\" data-stimeo--carousel-target=\"offLabel\">▶</span>\n <span aria-hidden=\"true\" hidden data-stimeo--carousel-target=\"onLabel\">❚❚</span>\n </button>\n <%# A visual read-out only. The library makes the viewport the live region, so a\n second one here would make a screen reader announce the change twice. %>\n <p\n class=\"carousel__status\"\n data-carousel-status\n data-template=\"<%= t(\"components.carousel.demo.status_template\") %>\"\n data-playing-suffix=\"<%= t(\"components.carousel.demo.status_playing\") %>\"></p>\n </div>\n\n <div class=\"carousel__viewport\" data-stimeo--carousel-target=\"viewport\">\n <% t(\"components.carousel.demo.slides\").each_with_index do |slide, i| %>\n <div\n id=\"carousel-slide-<%= i + 1 %>\"\n class=\"carousel__slide\"\n role=\"tabpanel\"\n aria-roledescription=\"slide\"\n aria-label=\"<%= \"#{i + 1} of #{t('components.carousel.demo.slides').size}\" %>\"\n aria-labelledby=\"carousel-dot-<%= i + 1 %>\"\n data-stimeo--carousel-target=\"slide\"\n <%= \"hidden inert\" if i.positive? %>>\n <h3 class=\"carousel__title\"><%= slide[:title] %></h3>\n <p><%= slide[:body] %></p>\n </div>\n <% end %>\n </div>\n\n <div class=\"carousel__nav\">\n <button type=\"button\" class=\"carousel__arrow\"\n aria-label=\"<%= t(\"components.carousel.demo.prev\") %>\"\n data-stimeo--carousel-target=\"prev\">‹</button>\n <button type=\"button\" class=\"carousel__arrow\"\n aria-label=\"<%= t(\"components.carousel.demo.next\") %>\"\n data-stimeo--carousel-target=\"next\">›</button>\n </div>\n\n <div class=\"carousel__dots\" role=\"tablist\"\n aria-label=\"<%= t(\"components.carousel.demo.tablist\") %>\">\n <% t(\"components.carousel.demo.slides\").each_with_index do |slide, i| %>\n <button\n id=\"carousel-dot-<%= i + 1 %>\"\n class=\"carousel__dot\"\n role=\"tab\"\n aria-selected=\"<%= i.zero? %>\"\n aria-controls=\"carousel-slide-<%= i + 1 %>\"\n aria-label=\"<%= slide[:title] %>\"\n tabindex=\"<%= i.zero? ? 0 : -1 %>\"\n data-stimeo--carousel-target=\"picker\"></button>\n <% end %>\n </div>\n</section>\n\n<%# On-screen explanation of the deliberate autoplay accessibility behavior, so the\n pause-on-hover / hard-stop-on-focus is understood as intentional (WCAG 2.2.2), not a bug.\n Kept outside the <section> so reading it doesn't itself pause the carousel. %>\n<p class=\"carousel__hint\"><%= t(\"components.carousel.demo.hint\") %></p>\n"
|
|
47
47
|
},
|
|
48
48
|
"stimeo--character-counter": {
|
|
49
49
|
"file": "examples/character_counter/_demo.html.erb",
|
|
@@ -55,19 +55,19 @@
|
|
|
55
55
|
},
|
|
56
56
|
"stimeo--clipboard": {
|
|
57
57
|
"file": "examples/clipboard/_demo.html.erb",
|
|
58
|
-
"source": "<%# Markup for the clipboard (copy & completion feedback) demo.\n Copies via navigator.clipboard, shows the result in the visible feedback slot,\n and hands the announcement to the shared stimeo--announcer your app seats once,\n in its layout. Keep the feedback slot free of live-region semantics — the\n announcer already reads the result, so a role=\"status\" here would say it twice.\n For localization the visible labels come from the copied-label / error-label\n Values and the spoken ones from the announce-copied-text / announce-error-text\n Values. The look per data-state (idle / copied / error) lives in demo.css. %>\n<div\n class=\"clipboard\"\n data-controller=\"stimeo--clipboard\"\n data-stimeo--clipboard-feedback-duration-value=\"2000\"\n data-stimeo--clipboard-copied-label-value=\"<%= t('components.clipboard.demo.copied') %>\"\n data-stimeo--clipboard-error-label-value=\"<%= t('components.clipboard.demo.error') %>\"\n data-stimeo--clipboard-announce-copied-text-value=\"<%= t(\n 'components.clipboard.demo.announce_copied'\n ) %>\"\n data-stimeo--clipboard-announce-error-text-value=\"<%= t(\n 'components.clipboard.demo.announce_error'\n ) %>\">\n <input\n class=\"clipboard__source\"\n type=\"text\"\n readonly\n aria-label=\"<%= t('components.clipboard.demo.source_label') %>\"\n value=\"https://stimeo.example/share/abc123\"\n data-stimeo--clipboard-target=\"source\">\n <button\n class=\"clipboard__button\"\n type=\"button\"\n data-stimeo--clipboard-target=\"button\"\n data-action=\"click->stimeo--clipboard#copy\">\n <%= t(\"components.clipboard.demo.button\") %>\n </button>\n <span class=\"clipboard__feedback\" data-stimeo--clipboard-target=\"feedback\"></span>\n</div>\n"
|
|
58
|
+
"source": "<%# Markup for the clipboard (copy & completion feedback) demo.\n Copies via navigator.clipboard, shows the result in the visible feedback slot,\n and hands the announcement to the shared stimeo--announcer your app seats once,\n in its layout. Keep the feedback slot free of live-region semantics — the\n announcer already reads the result, so a role=\"status\" here would say it twice.\n For localization the visible labels come from the copied-label / error-label\n Values and the spoken ones from the announce-copied-text / announce-error-text\n Values. The look per data-state (idle / copied / error) lives in demo.css. %>\n<div\n class=\"clipboard\"\n data-controller=\"stimeo--clipboard\"\n data-stimeo--clipboard-feedback-duration-value=\"2000\"\n data-stimeo--clipboard-copied-label-value=\"<%= t('components.clipboard.demo.copied') %>\"\n data-stimeo--clipboard-error-label-value=\"<%= t('components.clipboard.demo.error') %>\"\n data-stimeo--clipboard-announce-copied-text-value=\"<%= t(\n 'components.clipboard.demo.announce_copied'\n ) %>\"\n data-stimeo--clipboard-announce-error-text-value=\"<%= t(\n 'components.clipboard.demo.announce_error'\n ) %>\">\n <input\n class=\"clipboard__source\"\n type=\"text\"\n readonly\n aria-label=\"<%= t('components.clipboard.demo.source_label') %>\"\n value=\"https://stimeo.example/share/abc123\"\n data-stimeo--clipboard-target=\"source\">\n <button\n class=\"clipboard__button\"\n type=\"button\"\n data-stimeo--clipboard-target=\"button\"\n data-action=\"click->stimeo--clipboard#copy\">\n <%= t(\"components.clipboard.demo.button\") %>\n </button>\n <span class=\"clipboard__feedback\" data-stimeo--clipboard-target=\"feedback\"></span>\n</div>\n\n<%# Second form: hand the result straight to a toast. The copy event carries the\n wording, so `stimeo--clipboard:copy->stimeo--toast#show` is the whole wire — no\n feedback slot and no consumer JS. The announce-* Values are left empty on\n purpose: the toast's message slot is a role=\"status\" live region, so wiring the\n shared announcer as well would read the same result twice. %>\n<h3 class=\"clipboard-toast__heading\"><%= t(\"components.clipboard.demo.toast_heading\") %></h3>\n\n<div\n class=\"clipboard-toast\"\n data-controller=\"stimeo--toast\"\n data-stimeo--toast-duration-value=\"4000\"\n data-action=\"stimeo--clipboard:copy->stimeo--toast#show\">\n <div\n class=\"clipboard\"\n data-controller=\"stimeo--clipboard\"\n data-stimeo--clipboard-copied-label-value=\"<%= t('components.clipboard.demo.copied') %>\"\n data-stimeo--clipboard-error-label-value=\"<%= t('components.clipboard.demo.error') %>\">\n <input\n class=\"clipboard__source\"\n type=\"text\"\n readonly\n aria-label=\"<%= t('components.clipboard.demo.source_label') %>\"\n value=\"https://stimeo.example/share/xyz789\"\n data-stimeo--clipboard-target=\"source\">\n <button\n class=\"clipboard__button\"\n type=\"button\"\n data-stimeo--clipboard-target=\"button\"\n data-action=\"click->stimeo--clipboard#copy\">\n <%= t(\"components.clipboard.demo.button\") %>\n </button>\n </div>\n\n <div\n role=\"region\"\n aria-label=\"<%= t(\"components.clipboard.demo.toast_region_label\") %>\"\n class=\"clipboard-toast__region\">\n <ol class=\"clipboard-toast__list\" data-stimeo--toast-target=\"list\"></ol>\n <template data-stimeo--toast-target=\"template\">\n <li class=\"clipboard-toast__item\" data-stimeo--toast-target=\"item\" tabindex=\"0\">\n <span role=\"status\" data-toast-slot=\"message\"></span>\n </li>\n </template>\n </div>\n</div>\n"
|
|
59
59
|
},
|
|
60
60
|
"stimeo--collapsible": {
|
|
61
61
|
"file": "examples/collapsible/_demo.html.erb",
|
|
62
|
-
"source": "<%# Markup for the collapsible (APG Disclosure) demo.\n The trigger opens/closes a single region inline. The library syncs aria-expanded /\n hidden / data-state and the content's measured-height variable; the look (the\n height transition) lives in demo.css. %>\n<div class=\"collapsible\" data-controller=\"stimeo--collapsible\">\n <button\n class=\"collapsible__trigger\"\n type=\"button\"\n aria-expanded=\"false\"\n aria-controls=\"collapsible-demo-content\"\n data-stimeo--collapsible-target=\"trigger\"\n data-action=\"click->stimeo--collapsible#toggle\">\n <span class=\"collapsible__chevron\" aria-hidden=\"true\"></span>\n <%= t(\"components.collapsible.demo.
|
|
62
|
+
"source": "<%# Markup for the collapsible (APG Disclosure) demo.\n The trigger opens/closes a single region inline. The library syncs aria-expanded /\n hidden / data-state and the content's measured-height variable; the look (the\n height transition) lives in demo.css.\n The trigger carries both of its wordings as a label pair, so the words live in the\n markup where they can be translated. The library shows the half that belongs to the\n current state and hides the other, so demo.css has nothing to do here. The chevron\n is decoration and is kept out of the accessible name. %>\n<div class=\"collapsible\" data-controller=\"stimeo--collapsible\">\n <button\n class=\"collapsible__trigger\"\n type=\"button\"\n aria-expanded=\"false\"\n aria-controls=\"collapsible-demo-content\"\n data-stimeo--collapsible-target=\"trigger\"\n data-action=\"click->stimeo--collapsible#toggle\">\n <span class=\"collapsible__chevron\" aria-hidden=\"true\"></span>\n <span data-stimeo--collapsible-target=\"collapsedLabel\">\n <%= t(\"components.collapsible.demo.show\") %>\n </span>\n <span data-stimeo--collapsible-target=\"expandedLabel\" hidden>\n <%= t(\"components.collapsible.demo.hide\") %>\n </span>\n </button>\n <div\n class=\"collapsible__content\"\n id=\"collapsible-demo-content\"\n data-state=\"closed\"\n hidden\n data-stimeo--collapsible-target=\"content\">\n <p class=\"collapsible__body\"><%= t(\"components.collapsible.demo.body\") %></p>\n </div>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.events\") %></span>\n <span class=\"demo-readout__value\" data-readout>—</span>\n</p>\n"
|
|
63
63
|
},
|
|
64
64
|
"stimeo--color-picker": {
|
|
65
65
|
"file": "examples/color_picker/_demo.html.erb",
|
|
66
|
-
"source": "<%# Markup for the color-picker demo.\n The library manages each channel's (hue / saturation / lightness) role=\"slider\"\n value, composes them into a color two-way-synced with the hex input, and updates\n --stimeo--color for the preview. The 2D palette is decomposed into independent 1D\n sliders for accessibility. Thumb position and look are the consumer's CSS.\n data-value-text carries the announced wording, so this catalog announces the\n channel in the reader's own language instead of the library's English. %>\n<div\n class=\"color-picker\"\n data-controller=\"stimeo--color-picker\"\n data-stimeo--color-picker-value-value=\"#3366cc\">\n <div\n class=\"color-picker__preview\"\n data-stimeo--color-picker-target=\"preview\"\n aria-hidden=\"true\"></div>\n\n <div class=\"color-picker__channels\">\n <% { hue: [t(\"components.color_picker.demo.hue\"), 360, 210],\n saturation: [t(\"components.color_picker.demo.saturation\"), 100, 60],\n lightness: [t(\"components.color_picker.demo.lightness\"), 100, 50] }\n .each do |channel, (label, max, now)| %>\n <div class=\"color-picker__channel\">\n <span class=\"color-picker__channel-label\"><%= label %></span>\n <div\n class=\"color-picker__track color-picker__track--<%= channel %>\"\n role=\"slider\"\n aria-label=\"<%= label %>\"\n data-channel=\"<%= channel %>\"\n data-value-text=\"<%= t(\"components.color_picker.demo.value_text.#{channel}\") %>\"\n tabindex=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"<%= max %>\"\n aria-valuenow=\"<%= now %>\"\n data-stimeo--color-picker-target=\"slider\"\n data-action=\"\n keydown->stimeo--color-picker#onKeydown\n pointerdown->stimeo--color-picker#onPointerDown\">\n <span class=\"color-picker__thumb\" aria-hidden=\"true\"></span>\n </div>\n </div>\n <% end %>\n </div>\n\n <label class=\"color-picker__hex\">\n <span><%= t(\"components.color_picker.demo.hex\") %></span>\n <input\n type=\"text\"\n inputmode=\"text\"\n aria-label=\"<%= t(\"components.color_picker.demo.hex\") %>\"\n value=\"#3366cc\"\n data-stimeo--color-picker-target=\"hex\"\n data-action=\"change->stimeo--color-picker#onHexInput\" />\n </label>\n\n <input type=\"hidden\" name=\"brand_color\" data-stimeo--color-picker-target=\"field\" />\n</div>\n"
|
|
66
|
+
"source": "<%# Markup for the color-picker demo.\n The library manages each channel's (hue / saturation / lightness) role=\"slider\"\n value, composes them into a color two-way-synced with the hex input, and updates\n --stimeo--color for the preview. The 2D palette is decomposed into independent 1D\n sliders for accessibility. Thumb position and look are the consumer's CSS.\n data-value-text carries the announced wording, so this catalog announces the\n channel in the reader's own language instead of the library's English. %>\n<div\n class=\"color-picker\"\n data-controller=\"stimeo--color-picker\"\n data-stimeo--color-picker-value-value=\"#3366cc\">\n <div\n class=\"color-picker__preview\"\n data-stimeo--color-picker-target=\"preview\"\n aria-hidden=\"true\"></div>\n\n <div class=\"color-picker__channels\">\n <% { hue: [t(\"components.color_picker.demo.hue\"), 360, 210],\n saturation: [t(\"components.color_picker.demo.saturation\"), 100, 60],\n lightness: [t(\"components.color_picker.demo.lightness\"), 100, 50] }\n .each do |channel, (label, max, now)| %>\n <div class=\"color-picker__channel\">\n <span class=\"color-picker__channel-label\"><%= label %></span>\n <div\n class=\"color-picker__track color-picker__track--<%= channel %>\"\n role=\"slider\"\n aria-label=\"<%= label %>\"\n data-channel=\"<%= channel %>\"\n data-value-text=\"<%= t(\"components.color_picker.demo.value_text.#{channel}\") %>\"\n tabindex=\"0\"\n aria-valuemin=\"0\"\n aria-valuemax=\"<%= max %>\"\n aria-valuenow=\"<%= now %>\"\n data-stimeo--color-picker-target=\"slider\"\n data-action=\"\n keydown->stimeo--color-picker#onKeydown\n pointerdown->stimeo--color-picker#onPointerDown\">\n <span class=\"color-picker__thumb\" aria-hidden=\"true\"></span>\n </div>\n </div>\n <% end %>\n </div>\n\n <label class=\"color-picker__hex\">\n <span><%= t(\"components.color_picker.demo.hex\") %></span>\n <input\n type=\"text\"\n inputmode=\"text\"\n aria-label=\"<%= t(\"components.color_picker.demo.hex\") %>\"\n value=\"#3366cc\"\n data-stimeo--color-picker-target=\"hex\"\n data-action=\"change->stimeo--color-picker#onHexInput\" />\n </label>\n\n <input type=\"hidden\" name=\"brand_color\" data-stimeo--color-picker-target=\"field\" />\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.field\") %></span>\n <span class=\"demo-readout__value\" data-readout\n data-empty-text=\"<%= t(\"catalog.readout.empty\") %>\">—</span>\n</p>\n"
|
|
67
67
|
},
|
|
68
68
|
"stimeo--combobox": {
|
|
69
69
|
"file": "examples/combobox/_demo.html.erb",
|
|
70
|
-
"source": "<%# Markup for the combobox (APG Combobox / list autocomplete) demo.\n stimeo--combobox provides list filtering on input, Arrow/Enter/Esc, and\n aria-activedescendant. Focus stays on the input and the active option is shown via\n aria-selected. On selection, data-value (or the text, if absent) is placed in the input. %>\n<div class=\"combobox\" data-controller=\"stimeo--combobox\">\n <label id=\"fruit-label\" class=\"combobox__label\" for=\"fruit-input\"><%= t(\n \"components.combobox.demo.label\"\n ) %></label>\n <input\n id=\"fruit-input\"\n type=\"text\"\n class=\"combobox__input\"\n role=\"combobox\"\n aria-expanded=\"false\"\n aria-autocomplete=\"list\"\n aria-controls=\"fruit-list\"\n autocomplete=\"off\"\n data-stimeo--combobox-target=\"input\"\n data-action=\"input->stimeo--combobox#filter\n keydown->stimeo--combobox#onKeydown\n focus->stimeo--combobox#open\n click->stimeo--combobox#open\">\n\n <ul\n id=\"fruit-list\"\n class=\"combobox__list\"\n role=\"listbox\"\n aria-labelledby=\"fruit-label\"\n data-stimeo--combobox-target=\"list\"\n hidden>\n <li role=\"option\" id=\"fruit-apple\" class=\"combobox__option\" data-value=\"Apple\"\n data-stimeo--combobox-target=\"option\"\n data-action=\"click->stimeo--combobox#selectByClick\">Apple</li>\n <li role=\"option\" id=\"fruit-apricot\" class=\"combobox__option\" data-value=\"Apricot\"\n data-stimeo--combobox-target=\"option\"\n data-action=\"click->stimeo--combobox#selectByClick\">Apricot</li>\n <li role=\"option\" id=\"fruit-banana\" class=\"combobox__option\" data-value=\"Banana\"\n data-stimeo--combobox-target=\"option\"\n data-action=\"click->stimeo--combobox#selectByClick\">Banana</li>\n <li role=\"option\" id=\"fruit-cherry\" class=\"combobox__option\" data-value=\"Cherry\"\n data-stimeo--combobox-target=\"option\"\n data-action=\"click->stimeo--combobox#selectByClick\">Cherry</li>\n </ul>\n\n <%#
|
|
70
|
+
"source": "<%# Markup for the combobox (APG Combobox / list autocomplete) demo.\n stimeo--combobox provides list filtering on input, Arrow/Enter/Esc, and\n aria-activedescendant. Focus stays on the input and the active option is shown via\n aria-selected. On selection, data-value (or the text, if absent) is placed in the input. %>\n<div class=\"combobox\" data-controller=\"stimeo--combobox\">\n <label id=\"fruit-label\" class=\"combobox__label\" for=\"fruit-input\"><%= t(\n \"components.combobox.demo.label\"\n ) %></label>\n <input\n id=\"fruit-input\"\n type=\"text\"\n class=\"combobox__input\"\n role=\"combobox\"\n aria-expanded=\"false\"\n aria-autocomplete=\"list\"\n aria-controls=\"fruit-list\"\n autocomplete=\"off\"\n data-stimeo--combobox-target=\"input\"\n data-action=\"input->stimeo--combobox#filter\n keydown->stimeo--combobox#onKeydown\n focus->stimeo--combobox#open\n click->stimeo--combobox#open\">\n\n <ul\n id=\"fruit-list\"\n class=\"combobox__list\"\n role=\"listbox\"\n aria-labelledby=\"fruit-label\"\n data-stimeo--combobox-target=\"list\"\n hidden>\n <li role=\"option\" id=\"fruit-apple\" class=\"combobox__option\" data-value=\"Apple\"\n data-stimeo--combobox-target=\"option\"\n data-action=\"click->stimeo--combobox#selectByClick\">Apple</li>\n <li role=\"option\" id=\"fruit-apricot\" class=\"combobox__option\" data-value=\"Apricot\"\n data-stimeo--combobox-target=\"option\"\n data-action=\"click->stimeo--combobox#selectByClick\">Apricot</li>\n <li role=\"option\" id=\"fruit-banana\" class=\"combobox__option\" data-value=\"Banana\"\n data-stimeo--combobox-target=\"option\"\n data-action=\"click->stimeo--combobox#selectByClick\">Banana</li>\n <li role=\"option\" id=\"fruit-cherry\" class=\"combobox__option\" data-value=\"Cherry\"\n data-stimeo--combobox-target=\"option\"\n data-action=\"click->stimeo--combobox#selectByClick\">Cherry</li>\n </ul>\n\n <%# The no-results message is a region of the empty state: the library shows it while the\n open listbox has no match and hides it otherwise, so it is authored hidden. Copy via\n i18n. %>\n <div\n class=\"combobox__empty\"\n data-stimeo--combobox-target=\"empty\"\n hidden><%= t(\"components.combobox.demo.empty\") %></div>\n</div>\n"
|
|
71
71
|
},
|
|
72
72
|
"stimeo--command-palette": {
|
|
73
73
|
"file": "examples/command_palette/_demo.html.erb",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
},
|
|
84
84
|
"stimeo--context-menu": {
|
|
85
85
|
"file": "examples/context_menu/_demo.html.erb",
|
|
86
|
-
"source": "<%# Markup for the context_menu demo.\n A right-click on the region (or the ContextMenu key / Shift+F10) opens a\n role=\"menu\" at the pointer position. The interaction model is the same as a Menu\n Button. The click coordinate is reflected on the menu as\n --stimeo--context-menu-x / -y, and the Playground CSS uses it for top/left\n placement (works even without the positioning module). %>\n<div class=\"context-menu\" data-controller=\"stimeo--context-menu\">\n <div\n class=\"context-menu__region\"\n data-stimeo--context-menu-target=\"region\"\n tabindex=\"0\"\n aria-haspopup=\"menu\"\n aria-controls=\"context-menu-list\"\n data-action=\"\n contextmenu->stimeo--context-menu#open\n keydown->stimeo--context-menu#onRegionKeydown\">\n <%= t(\"components.context_menu.demo.region\") %>\n </div>\n\n <ul\n class=\"context-menu__list\"\n id=\"context-menu-list\"\n role=\"menu\"\n aria-label=\"<%= t(\"components.context_menu.demo.label\") %>\"\n data-stimeo--context-menu-target=\"menu\"\n hidden>\n <li role=\"none\">\n <button type=\"button\" class=\"demo-menuitem\" role=\"menuitem\" tabindex=\"-1\"\n data-stimeo--context-menu-target=\"item\"\n data-action=\"\n click->stimeo--context-menu#activate\n keydown->stimeo--context-menu#onItemKeydown\">\n <%= t(\"components.context_menu.demo.copy\") %>\n </button>\n </li>\n <li role=\"none\">\n <button type=\"button\" class=\"demo-menuitem\" role=\"menuitem\" tabindex=\"-1\"\n data-stimeo--context-menu-target=\"item\"\n data-action=\"\n click->stimeo--context-menu#activate\n keydown->stimeo--context-menu#onItemKeydown\">\n <%= t(\"components.context_menu.demo.paste\") %>\n </button>\n </li>\n <li role=\"none\">\n <button type=\"button\" class=\"demo-menuitem\" role=\"menuitem\" tabindex=\"-1\"\n data-stimeo--context-menu-target=\"item\"\n data-action=\"\n click->stimeo--context-menu#activate\n keydown->stimeo--context-menu#onItemKeydown\">\n <%= t(\"components.context_menu.demo.delete\") %>\n </button>\n </li>\n </ul>\n</div>\n"
|
|
86
|
+
"source": "<%# Markup for the context_menu demo.\n A right-click on the region (or the ContextMenu key / Shift+F10) opens a\n role=\"menu\" at the pointer position. The interaction model is the same as a Menu\n Button. The click coordinate is reflected on the menu as\n --stimeo--context-menu-x / -y, and the Playground CSS uses it for top/left\n placement (works even without the positioning module). %>\n<div class=\"context-menu\" data-controller=\"stimeo--context-menu\">\n <div\n class=\"context-menu__region\"\n data-stimeo--context-menu-target=\"region\"\n tabindex=\"0\"\n aria-haspopup=\"menu\"\n aria-controls=\"context-menu-list\"\n data-action=\"\n contextmenu->stimeo--context-menu#open\n keydown->stimeo--context-menu#onRegionKeydown\">\n <%= t(\"components.context_menu.demo.region\") %>\n </div>\n\n <ul\n class=\"context-menu__list\"\n id=\"context-menu-list\"\n role=\"menu\"\n aria-label=\"<%= t(\"components.context_menu.demo.label\") %>\"\n data-stimeo--context-menu-target=\"menu\"\n hidden>\n <li role=\"none\">\n <button type=\"button\" class=\"demo-menuitem\" role=\"menuitem\" tabindex=\"-1\"\n data-stimeo--context-menu-target=\"item\"\n data-action=\"\n click->stimeo--context-menu#activate\n keydown->stimeo--context-menu#onItemKeydown\">\n <%= t(\"components.context_menu.demo.copy\") %>\n </button>\n </li>\n <li role=\"none\">\n <button type=\"button\" class=\"demo-menuitem\" role=\"menuitem\" tabindex=\"-1\"\n data-stimeo--context-menu-target=\"item\"\n data-action=\"\n click->stimeo--context-menu#activate\n keydown->stimeo--context-menu#onItemKeydown\">\n <%= t(\"components.context_menu.demo.paste\") %>\n </button>\n </li>\n <li role=\"none\">\n <button type=\"button\" class=\"demo-menuitem\" role=\"menuitem\" tabindex=\"-1\"\n data-stimeo--context-menu-target=\"item\"\n data-action=\"\n click->stimeo--context-menu#activate\n keydown->stimeo--context-menu#onItemKeydown\">\n <%= t(\"components.context_menu.demo.delete\") %>\n </button>\n </li>\n </ul>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.events\") %></span>\n <span class=\"demo-readout__value\" data-readout>—</span>\n</p>\n"
|
|
87
87
|
},
|
|
88
88
|
"stimeo--count-up": {
|
|
89
89
|
"file": "examples/count_up/_demo.html.erb",
|
|
@@ -99,15 +99,15 @@
|
|
|
99
99
|
},
|
|
100
100
|
"stimeo--data-grid": {
|
|
101
101
|
"file": "examples/data_grid/_demo.html.erb",
|
|
102
|
-
"source": "<%# Markup for the data-grid (basic data grid) demo.\n The library cycles column headers' aria-sort and fires sort events, syncs rows'\n aria-selected, and moves between cells with the arrow keys via roving. Actually\n sorting/rendering the data is the consumer's job (here demo.js), in response to\n stimeo--data-grid:sort. %>\n<table\n class=\"data-grid\"\n data-controller=\"stimeo--data-grid\"\n role=\"grid\"\n aria-label=\"<%= t(\"components.data_grid.demo.label\") %>\"\n data-stimeo--data-grid-selection-value=\"single\">\n <thead>\n <tr role=\"row\">\n <% t(\"components.data_grid.demo.columns\").each do |column| %>\n <th\n role=\"columnheader\"\n aria-sort=\"none\"\n tabindex=\"-1\"\n scope=\"col\"\n data-stimeo--data-grid-target=\"columnHeader\"\n data-action=\"click->stimeo--data-grid#sort keydown->stimeo--data-grid#onKeydown\">\n <%= column %>\n </th>\n <% end %>\n </tr>\n </thead>\n <tbody>\n <% t(\"components.data_grid.demo.rows\").
|
|
102
|
+
"source": "<%# Markup for the data-grid (basic data grid) demo.\n The library cycles column headers' aria-sort and fires sort events, syncs rows'\n aria-selected, and moves between cells with the arrow keys via roving. Actually\n sorting/rendering the data is the consumer's job (here demo.js), in response to\n stimeo--data-grid:sort. %>\n<table\n class=\"data-grid\"\n data-controller=\"stimeo--data-grid\"\n role=\"grid\"\n aria-label=\"<%= t(\"components.data_grid.demo.label\") %>\"\n data-stimeo--data-grid-selection-value=\"single\"\n data-stimeo--data-grid-name-value=\"user_id\">\n <%# The container the selected rows' data-value are generated into as hidden\n inputs; both the container and the values are optional. A caption keeps the\n container inside the table's content model. %>\n <caption class=\"visually-hidden\"><div data-stimeo--data-grid-target=\"fields\"></div></caption>\n <thead>\n <tr role=\"row\">\n <% t(\"components.data_grid.demo.columns\").each do |column| %>\n <th\n role=\"columnheader\"\n aria-sort=\"none\"\n tabindex=\"-1\"\n scope=\"col\"\n data-stimeo--data-grid-target=\"columnHeader\"\n data-action=\"click->stimeo--data-grid#sort keydown->stimeo--data-grid#onKeydown\">\n <%= column %>\n </th>\n <% end %>\n </tr>\n </thead>\n <tbody>\n <%# data-value is the record id the selection submits — a number, not copy, so\n it is derived from the row order rather than localized. A row without one\n submits nothing. %>\n <% t(\"components.data_grid.demo.rows\").each_with_index do |cells, row_index| %>\n <tr role=\"row\" aria-selected=\"false\" data-value=\"<%= row_index + 1 %>\"\n data-stimeo--data-grid-target=\"row\">\n <% cells.each_with_index do |cell, i| %>\n <td\n role=\"gridcell\"\n tabindex=\"<%= i.zero? ? 0 : -1 %>\"\n data-stimeo--data-grid-target=\"cell\"\n data-action=\"keydown->stimeo--data-grid#onKeydown\">\n <%= cell %>\n </td>\n <% end %>\n </tr>\n <% end %>\n </tbody>\n</table>\n<p\n class=\"data-grid__status\"\n data-data-grid-status\n data-selected-template=\"<%= t(\"components.data_grid.demo.selected_template\") %>\"\n data-empty-text=\"<%= t(\"components.data_grid.demo.selected_empty\") %>\"\n aria-live=\"polite\"></p>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.field\") %></span>\n <span class=\"demo-readout__value\" data-readout\n data-empty-text=\"<%= t(\"catalog.readout.empty\") %>\">—</span>\n</p>\n"
|
|
103
103
|
},
|
|
104
104
|
"stimeo--date-range-picker": {
|
|
105
105
|
"file": "examples/date_range_picker/_demo.html.erb",
|
|
106
|
-
"source": "<%# Markup for the date-range-picker (range-selection calendar) demo.\n stimeo--date-range-picker derives from calendar and handles two-point start/end\n selection, a provisional range preview mid-selection, marking in-range cells,\n auto-swapping when start > end, applying presets, and grid keyboard movement\n (roving). Range ends are shown with aria-selected and the inside with data-in-range;\n placement and styling live in demo.css.\n\n Two unavailable days are declared as data rather than written onto cells. The\n 42 cells are reused for a different date every month, so availability has to\n be keyed by the date; the controller derives each cell's aria-disabled from\n this array on every paint. A range may still span such a day — it just cannot\n end on one. %>\n<% blackout = [3.days.from_now, 4.days.from_now].map { |day| day.strftime(\"%Y-%m-%d\") } %>\n<div class=\"drp demo-card\" data-controller=\"stimeo--date-range-picker\"\n data-stimeo--date-range-picker-disabled-dates-value=\"<%= blackout.to_json %>\">\n <div class=\"drp__header\">\n <button class=\"drp__nav\" type=\"button\"\n data-action=\"click->stimeo--date-range-picker#prev\"\n aria-label=\"<%= t(\"components.date_range_picker.demo.prev_month\") %>\">‹</button>\n <span class=\"drp__label\" id=\"drp-month\" aria-live=\"polite\"\n data-stimeo--date-range-picker-target=\"monthLabel\"></span>\n <button class=\"drp__nav\" type=\"button\"\n data-action=\"click->stimeo--date-range-picker#next\"\n aria-label=\"<%= t(\"components.date_range_picker.demo.next_month\") %>\">›</button>\n </div>\n\n <div class=\"drp__weekdays\" aria-hidden=\"true\">\n <% t(\"components.date_range_picker.demo.weekdays\").each do |day| %>\n <span class=\"drp__weekday\"><%= day %></span>\n <% end %>\n </div>\n\n <div class=\"drp__grid\" role=\"grid\" aria-labelledby=\"drp-month\"\n data-stimeo--date-range-picker-target=\"grid\">\n <% 6.times do %>\n <div class=\"drp__row\" role=\"row\">\n <% 7.times do %>\n <button class=\"drp__cell\" type=\"button\" role=\"gridcell\" tabindex=\"-1\"\n data-stimeo--date-range-picker-target=\"cell\"\n data-action=\"click->stimeo--date-range-picker#selectDate\n mouseenter->stimeo--date-range-picker#previewTo\n focus->stimeo--date-range-picker#previewTo\n keydown->stimeo--date-range-picker#onKeydown\"></button>\n <% end %>\n </div>\n <% end %>\n </div>\n\n <div class=\"drp__presets\" role=\"group\"\n aria-label=\"<%= t(\"components.date_range_picker.demo.presets_label\") %>\">\n <button class=\"drp__preset\" type=\"button\" data-range=\"today\"\n data-action=\"click->stimeo--date-range-picker#applyPreset\">\n <%= t(\"components.date_range_picker.demo.preset_today\") %>\n </button>\n <button class=\"drp__preset\" type=\"button\" data-range=\"last7\"\n data-action=\"click->stimeo--date-range-picker#applyPreset\">\n <%= t(\"components.date_range_picker.demo.preset_last7\") %>\n </button>\n <button class=\"drp__preset\" type=\"button\" data-range=\"thisMonth\"\n data-action=\"click->stimeo--date-range-picker#applyPreset\">\n <%= t(\"components.date_range_picker.demo.preset_this_month\") %>\n </button>\n </div>\n\n <span class=\"drp__status\" role=\"status\" aria-live=\"polite\"\n data-stimeo--date-range-picker-target=\"status\"></span>\n\n <%# Says on screen why two days are struck out. The dates move with today, so\n without this the exclusion reads as a glitch rather than a demonstration. %>\n <p class=\"drp__note\"><%= t(\"components.date_range_picker.demo.blackout_note\") %></p>\n\n <input type=\"hidden\" name=\"start_date\" data-stimeo--date-range-picker-target=\"startField\" />\n <input type=\"hidden\" name=\"end_date\" data-stimeo--date-range-picker-target=\"endField\" />\n</div>\n"
|
|
106
|
+
"source": "<%# Markup for the date-range-picker (range-selection calendar) demo.\n stimeo--date-range-picker derives from calendar and handles two-point start/end\n selection, a provisional range preview mid-selection, marking in-range cells,\n auto-swapping when start > end, applying presets, and grid keyboard movement\n (roving). Range ends are shown with aria-selected and the inside with data-in-range;\n placement and styling live in demo.css.\n\n Two unavailable days are declared as data rather than written onto cells. The\n 42 cells are reused for a different date every month, so availability has to\n be keyed by the date; the controller derives each cell's aria-disabled from\n this array on every paint. A range may still span such a day — it just cannot\n end on one. %>\n<% blackout = [3.days.from_now, 4.days.from_now].map { |day| day.strftime(\"%Y-%m-%d\") } %>\n<div class=\"drp demo-card\" data-controller=\"stimeo--date-range-picker\"\n data-stimeo--date-range-picker-disabled-dates-value=\"<%= blackout.to_json %>\">\n <div class=\"drp__header\">\n <button class=\"drp__nav\" type=\"button\"\n data-action=\"click->stimeo--date-range-picker#prev\"\n aria-label=\"<%= t(\"components.date_range_picker.demo.prev_month\") %>\">‹</button>\n <span class=\"drp__label\" id=\"drp-month\" aria-live=\"polite\"\n data-stimeo--date-range-picker-target=\"monthLabel\"></span>\n <button class=\"drp__nav\" type=\"button\"\n data-action=\"click->stimeo--date-range-picker#next\"\n aria-label=\"<%= t(\"components.date_range_picker.demo.next_month\") %>\">›</button>\n </div>\n\n <div class=\"drp__weekdays\" aria-hidden=\"true\">\n <% t(\"components.date_range_picker.demo.weekdays\").each do |day| %>\n <span class=\"drp__weekday\"><%= day %></span>\n <% end %>\n </div>\n\n <div class=\"drp__grid\" role=\"grid\" aria-labelledby=\"drp-month\"\n data-stimeo--date-range-picker-target=\"grid\">\n <% 6.times do %>\n <div class=\"drp__row\" role=\"row\">\n <% 7.times do %>\n <button class=\"drp__cell\" type=\"button\" role=\"gridcell\" tabindex=\"-1\"\n data-stimeo--date-range-picker-target=\"cell\"\n data-action=\"click->stimeo--date-range-picker#selectDate\n mouseenter->stimeo--date-range-picker#previewTo\n focus->stimeo--date-range-picker#previewTo\n keydown->stimeo--date-range-picker#onKeydown\"></button>\n <% end %>\n </div>\n <% end %>\n </div>\n\n <div class=\"drp__presets\" role=\"group\"\n aria-label=\"<%= t(\"components.date_range_picker.demo.presets_label\") %>\">\n <button class=\"drp__preset\" type=\"button\" data-range=\"today\"\n data-action=\"click->stimeo--date-range-picker#applyPreset\">\n <%= t(\"components.date_range_picker.demo.preset_today\") %>\n </button>\n <button class=\"drp__preset\" type=\"button\" data-range=\"last7\"\n data-action=\"click->stimeo--date-range-picker#applyPreset\">\n <%= t(\"components.date_range_picker.demo.preset_last7\") %>\n </button>\n <button class=\"drp__preset\" type=\"button\" data-range=\"thisMonth\"\n data-action=\"click->stimeo--date-range-picker#applyPreset\">\n <%= t(\"components.date_range_picker.demo.preset_this_month\") %>\n </button>\n </div>\n\n <span class=\"drp__status\" role=\"status\" aria-live=\"polite\"\n data-stimeo--date-range-picker-target=\"status\"></span>\n\n <%# Says on screen why two days are struck out. The dates move with today, so\n without this the exclusion reads as a glitch rather than a demonstration. %>\n <p class=\"drp__note\"><%= t(\"components.date_range_picker.demo.blackout_note\") %></p>\n\n <input type=\"hidden\" name=\"start_date\" data-stimeo--date-range-picker-target=\"startField\" />\n <input type=\"hidden\" name=\"end_date\" data-stimeo--date-range-picker-target=\"endField\" />\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.field\") %></span>\n <span class=\"demo-readout__value\" data-readout\n data-empty-text=\"<%= t(\"catalog.readout.empty\") %>\">—</span>\n</p>\n"
|
|
107
107
|
},
|
|
108
108
|
"stimeo--dialog": {
|
|
109
109
|
"file": "examples/dialog/_demo.html.erb",
|
|
110
|
-
"source": "<%# Markup for the dialog demo.\n The single source used for both the live render and the copy-paste code.\n stimeo--dialog provides the focus trap, Esc, and background scroll lock.\n The behavior is the library's; the look (classes) is the Playground's CSS. %>\n<div class=\"dialog\" data-controller=\"stimeo--dialog\">\n <button\n type=\"button\"\n class=\"demo-trigger\"\n data-stimeo--dialog-target=\"trigger\"\n data-action=\"click->stimeo--dialog#open\">\n <%= t(\"components.dialog.demo.open_button\") %>\n </button>\n\n <%# The role=\"dialog\" + aria-modal region. Starts hidden (closed).\n Clicking this element itself (the backdrop) also closes it. %>\n <div\n class=\"dialog__backdrop\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"dialog-title\"\n data-stimeo--dialog-target=\"dialog\"\n data-action=\"click->stimeo--dialog#closeOnBackdrop\"\n hidden>\n <div class=\"dialog__panel\">\n <h3 id=\"dialog-title\" class=\"dialog__title\"><%= t(\n \"components.dialog.demo.confirm_title\"\n ) %></h3>\n <p><%= t(\"components.dialog.demo.confirm_desc\") %></p>\n <div class=\"dialog__actions\">\n <button\n type=\"button\"\n class=\"demo-trigger\"\n data-action=\"click->stimeo--dialog#close\"><%= t(\n \"components.dialog.demo.cancel\"\n ) %></button>\n <button\n type=\"button\"\n class=\"demo-trigger demo-trigger--primary\"\n data-action=\"click->stimeo--dialog#close\"><%= t(\n \"components.dialog.demo.ok\"\n ) %></button>\n </div>\n </div>\n </div>\n</div>\n"
|
|
110
|
+
"source": "<%# Markup for the dialog demo.\n The single source used for both the live render and the copy-paste code.\n stimeo--dialog provides the focus trap, Esc, and background scroll lock.\n The behavior is the library's; the look (classes) is the Playground's CSS. %>\n<div class=\"dialog\" data-controller=\"stimeo--dialog\">\n <button\n type=\"button\"\n class=\"demo-trigger\"\n data-stimeo--dialog-target=\"trigger\"\n data-action=\"click->stimeo--dialog#open\">\n <%= t(\"components.dialog.demo.open_button\") %>\n </button>\n\n <%# The role=\"dialog\" + aria-modal region. Starts hidden (closed).\n Clicking this element itself (the backdrop) also closes it. %>\n <div\n class=\"dialog__backdrop\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"dialog-title\"\n data-stimeo--dialog-target=\"dialog\"\n data-action=\"click->stimeo--dialog#closeOnBackdrop\"\n hidden>\n <div class=\"dialog__panel\">\n <h3 id=\"dialog-title\" class=\"dialog__title\"><%= t(\n \"components.dialog.demo.confirm_title\"\n ) %></h3>\n <p><%= t(\"components.dialog.demo.confirm_desc\") %></p>\n <div class=\"dialog__actions\">\n <button\n type=\"button\"\n class=\"demo-trigger\"\n data-action=\"click->stimeo--dialog#close\"><%= t(\n \"components.dialog.demo.cancel\"\n ) %></button>\n <button\n type=\"button\"\n class=\"demo-trigger demo-trigger--primary\"\n data-action=\"click->stimeo--dialog#close\"><%= t(\n \"components.dialog.demo.ok\"\n ) %></button>\n </div>\n </div>\n </div>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.events\") %></span>\n <span class=\"demo-readout__value\" data-readout>—</span>\n</p>\n"
|
|
111
111
|
},
|
|
112
112
|
"stimeo--direct-upload": {
|
|
113
113
|
"file": "examples/direct_upload/_demo.html.erb",
|
|
@@ -123,11 +123,11 @@
|
|
|
123
123
|
},
|
|
124
124
|
"stimeo--drawer": {
|
|
125
125
|
"file": "examples/drawer/_demo.html.erb",
|
|
126
|
-
"source": "<%# Markup for the drawer (side panel) demo.\n A modal panel that slides in from the right edge. In addition to focus move/trap,\n Esc, background scroll lock, background inert, and returning focus to the trigger,\n the library syncs data-state (open/closed) and applies hidden once the transition\n finishes. Which edge it moves from and how (the slide) and the interpretation of\n placement are expressed by the consumer's CSS (demo.css) reading data-placement /\n data-state. %>\n<div\n class=\"drawer\"\n data-controller=\"stimeo--drawer\"\n data-stimeo--drawer-placement-value=\"right\">\n <button\n type=\"button\"\n class=\"demo-trigger\"\n data-stimeo--drawer-target=\"trigger\"\n data-action=\"click->stimeo--drawer#open\">\n <%= t(\"components.drawer.demo.open_button\") %>\n </button>\n\n <%# Overlay (backdrop). Click to close. data-state stays in sync with the panel. %>\n <div\n class=\"drawer__overlay\"\n data-stimeo--drawer-target=\"overlay\"\n data-action=\"click->stimeo--drawer#closeOnBackdrop\"\n hidden>\n <%# The role=\"dialog\" + aria-modal panel. Starts closed / hidden. %>\n <div\n class=\"drawer__panel\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"drawer-title\"\n data-stimeo--drawer-target=\"panel\"\n data-state=\"closed\"\n hidden>\n <h3 id=\"drawer-title\" class=\"drawer__title\">\n <%= t(\"components.drawer.demo.title\") %>\n </h3>\n <p><%= t(\"components.drawer.demo.body\") %></p>\n <button\n type=\"button\"\n class=\"demo-trigger drawer__close\"\n data-action=\"click->stimeo--drawer#close\">\n <%= t(\"components.drawer.demo.close\") %>\n </button>\n </div>\n </div>\n</div>\n"
|
|
126
|
+
"source": "<%# Markup for the drawer (side panel) demo.\n A modal panel that slides in from the right edge. In addition to focus move/trap,\n Esc, background scroll lock, background inert, and returning focus to the trigger,\n the library syncs data-state (open/closed) and applies hidden once the transition\n finishes. Which edge it moves from and how (the slide) and the interpretation of\n placement are expressed by the consumer's CSS (demo.css) reading data-placement /\n data-state. %>\n<div\n class=\"drawer\"\n data-controller=\"stimeo--drawer\"\n data-stimeo--drawer-placement-value=\"right\">\n <button\n type=\"button\"\n class=\"demo-trigger\"\n data-stimeo--drawer-target=\"trigger\"\n data-action=\"click->stimeo--drawer#open\">\n <%= t(\"components.drawer.demo.open_button\") %>\n </button>\n\n <%# Overlay (backdrop). Click to close. data-state stays in sync with the panel. %>\n <div\n class=\"drawer__overlay\"\n data-stimeo--drawer-target=\"overlay\"\n data-action=\"click->stimeo--drawer#closeOnBackdrop\"\n hidden>\n <%# The role=\"dialog\" + aria-modal panel. Starts closed / hidden. %>\n <div\n class=\"drawer__panel\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"drawer-title\"\n data-stimeo--drawer-target=\"panel\"\n data-state=\"closed\"\n hidden>\n <h3 id=\"drawer-title\" class=\"drawer__title\">\n <%= t(\"components.drawer.demo.title\") %>\n </h3>\n <p><%= t(\"components.drawer.demo.body\") %></p>\n <button\n type=\"button\"\n class=\"demo-trigger drawer__close\"\n data-action=\"click->stimeo--drawer#close\">\n <%= t(\"components.drawer.demo.close\") %>\n </button>\n </div>\n </div>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.events\") %></span>\n <span class=\"demo-readout__value\" data-readout>—</span>\n</p>\n"
|
|
127
127
|
},
|
|
128
128
|
"stimeo--dropdown": {
|
|
129
129
|
"file": "examples/dropdown/_demo.html.erb",
|
|
130
|
-
"source": "<%# Markup for the dropdown demo.\n The single source used for both the live render and the copy-paste code.\n Connect to stimeo--dropdown via data-controller / data-*-target / data-action.\n The behavior is the library's; the look (classes) is the Playground's CSS. %>\n<div class=\"dropdown\" data-controller=\"stimeo--dropdown\">\n <button\n type=\"button\"\n class=\"demo-trigger\"\n aria-expanded=\"false\"\n data-stimeo--dropdown-target=\"trigger\"\n data-action=\"click->stimeo--dropdown#toggle\">\n <%= t(\"components.dropdown.demo.trigger\") %>\n </button>\n\n <%# The toggled menu. Starts hidden (closed).\n Each link uses click->stimeo--dropdown#close to close the menu on selection.\n (The links are inside the controller element, so an outside click won't close\n it — wire it explicitly.) %>\n <ul class=\"dropdown__menu\" data-stimeo--dropdown-target=\"menu\" hidden>\n <li><a class=\"demo-menuitem\" href=\"#profile\" data-action=\"click->stimeo--dropdown#close\"><%= t(\n \"components.dropdown.demo.profile\"\n ) %></a></li>\n <li><a class=\"demo-menuitem\" href=\"#settings\" data-action=\"click->stimeo--dropdown#close\"><%= t(\n \"components.dropdown.demo.settings\"\n ) %></a></li>\n <li><a class=\"demo-menuitem\" href=\"#sign-out\" data-action=\"click->stimeo--dropdown#close\"><%= t(\n \"components.dropdown.demo.sign_out\"\n ) %></a></li>\n </ul>\n</div>\n"
|
|
130
|
+
"source": "<%# Markup for the dropdown demo.\n The single source used for both the live render and the copy-paste code.\n Connect to stimeo--dropdown via data-controller / data-*-target / data-action.\n The behavior is the library's; the look (classes) is the Playground's CSS. %>\n<div class=\"dropdown\" data-controller=\"stimeo--dropdown\">\n <button\n type=\"button\"\n class=\"demo-trigger\"\n aria-expanded=\"false\"\n data-stimeo--dropdown-target=\"trigger\"\n data-action=\"click->stimeo--dropdown#toggle\">\n <%= t(\"components.dropdown.demo.trigger\") %>\n </button>\n\n <%# The toggled menu. Starts hidden (closed).\n Each link uses click->stimeo--dropdown#close to close the menu on selection.\n (The links are inside the controller element, so an outside click won't close\n it — wire it explicitly.) %>\n <ul class=\"dropdown__menu\" data-stimeo--dropdown-target=\"menu\" hidden>\n <li><a class=\"demo-menuitem\" href=\"#profile\" data-action=\"click->stimeo--dropdown#close\"><%= t(\n \"components.dropdown.demo.profile\"\n ) %></a></li>\n <li><a class=\"demo-menuitem\" href=\"#settings\" data-action=\"click->stimeo--dropdown#close\"><%= t(\n \"components.dropdown.demo.settings\"\n ) %></a></li>\n <li><a class=\"demo-menuitem\" href=\"#sign-out\" data-action=\"click->stimeo--dropdown#close\"><%= t(\n \"components.dropdown.demo.sign_out\"\n ) %></a></li>\n </ul>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.events\") %></span>\n <span class=\"demo-readout__value\" data-readout>—</span>\n</p>\n"
|
|
131
131
|
},
|
|
132
132
|
"stimeo--editable": {
|
|
133
133
|
"file": "examples/editable/_demo.html.erb",
|
|
@@ -143,11 +143,11 @@
|
|
|
143
143
|
},
|
|
144
144
|
"stimeo--filter": {
|
|
145
145
|
"file": "examples/filter/_demo.html.erb",
|
|
146
|
-
"source": "<%# Markup for the filter (faceted list) demo. Behavior only — no consumer JS.\n The toggle-group owns the chips' pressed state + roving focus; stimeo--filter\n reads the pressed tokens (data-value) and shows/hides items by their\n data-stimeo--filter-tokens. match=\"all\" means an item must carry every active\n token. The empty element appears when nothing matches; Clear resets the chips. %>\n<div class=\"filter-demo\" data-controller=\"stimeo--filter\"\n data-stimeo--filter-match-value=\"all\"\n data-action=\"stimeo--toggle-group:change->stimeo--filter#apply\">\n <div class=\"filter-demo__bar\">\n <div class=\"filter-demo__chips\" role=\"group\"\n aria-label=\"<%= t('components.filter.demo.legend') %>\"\n data-controller=\"stimeo--toggle-group\">\n <button type=\"button\" class=\"filter-demo__chip\" aria-pressed=\"false\" tabindex=\"0\"\n data-value=\"veg\"\n data-stimeo--filter-target=\"control\"\n data-stimeo--toggle-group-target=\"item\"\n data-action=\"click->stimeo--toggle-group#toggle\n keydown->stimeo--toggle-group#onKeydown\">\n <%= t(\"components.filter.demo.vegetarian\") %>\n </button>\n <button type=\"button\" class=\"filter-demo__chip\" aria-pressed=\"false\" tabindex=\"-1\"\n data-value=\"spicy\"\n data-stimeo--filter-target=\"control\"\n data-stimeo--toggle-group-target=\"item\"\n data-action=\"click->stimeo--toggle-group#toggle\n keydown->stimeo--toggle-group#onKeydown\">\n <%= t(\"components.filter.demo.spicy\") %>\n </button>\n </div>\n <button type=\"button\" class=\"filter-demo__clear\" data-action=\"click->stimeo--filter#clear\">\n <%= t(\"components.filter.demo.clear\") %>\n </button>\n </div>\n\n <%# Each item shows its facet tokens as tags so it is clear why a chip filters it in/out. %>\n <%\n token_labels = {\n \"veg\" => t(\"components.filter.demo.vegetarian\"),\n \"spicy\" => t(\"components.filter.demo.spicy\"),\n }\n dishes = [\n { key: \"margherita\", tokens: \"veg\" },\n { key: \"pepperoni\", tokens: \"\" },\n { key: \"curry\", tokens: \"veg spicy\" },\n { key: \"wings\", tokens: \"spicy\" },\n ]\n %>\n <ul class=\"filter-demo__list\">\n <% dishes.each do |dish| %>\n <li class=\"filter-demo__item\" data-stimeo--filter-target=\"item\"\n data-stimeo--filter-tokens=\"<%= dish[:tokens] %>\">\n <span class=\"filter-demo__name\"><%= t(\"components.filter.demo.#{dish[:key]}\") %></span>\n <span class=\"filter-demo__tags\">\n <% dish[:tokens].split.each do |tok| %>\n <span class=\"filter-demo__tag\"><%= token_labels[tok] %></span>\n <% end %>\n </span>\n </li>\n <% end %>\n </ul>\n\n <p class=\"filter-demo__empty\" role=\"status\" data-stimeo--filter-target=\"empty\" hidden>\n <%= t(\"components.filter.demo.empty\") %>\n </p>\n</div>\n"
|
|
146
|
+
"source": "<%# Markup for the filter (faceted list) demo. Behavior only — no consumer JS.\n The toggle-group owns the chips' pressed state + roving focus; stimeo--filter\n reads the pressed tokens (data-value) and shows/hides items by their\n data-stimeo--filter-tokens. match=\"all\" means an item must carry every active\n token. The empty element appears when nothing matches; Clear resets the chips.\n Both toggle-group events re-filter: change for a chip the user presses, and\n reconcile for a pressed set the page moves (a morph, a script). %>\n<div class=\"filter-demo\" data-controller=\"stimeo--filter\"\n data-stimeo--filter-match-value=\"all\"\n data-action=\"stimeo--toggle-group:change->stimeo--filter#apply\n stimeo--toggle-group:reconcile->stimeo--filter#apply\">\n <div class=\"filter-demo__bar\">\n <div class=\"filter-demo__chips\" role=\"group\"\n aria-label=\"<%= t('components.filter.demo.legend') %>\"\n data-controller=\"stimeo--toggle-group\">\n <button type=\"button\" class=\"filter-demo__chip\" aria-pressed=\"false\" tabindex=\"0\"\n data-value=\"veg\"\n data-stimeo--filter-target=\"control\"\n data-stimeo--toggle-group-target=\"item\"\n data-action=\"click->stimeo--toggle-group#toggle\n keydown->stimeo--toggle-group#onKeydown\">\n <%= t(\"components.filter.demo.vegetarian\") %>\n </button>\n <button type=\"button\" class=\"filter-demo__chip\" aria-pressed=\"false\" tabindex=\"-1\"\n data-value=\"spicy\"\n data-stimeo--filter-target=\"control\"\n data-stimeo--toggle-group-target=\"item\"\n data-action=\"click->stimeo--toggle-group#toggle\n keydown->stimeo--toggle-group#onKeydown\">\n <%= t(\"components.filter.demo.spicy\") %>\n </button>\n </div>\n <button type=\"button\" class=\"filter-demo__clear\" data-action=\"click->stimeo--filter#clear\">\n <%= t(\"components.filter.demo.clear\") %>\n </button>\n </div>\n\n <%# Each item shows its facet tokens as tags so it is clear why a chip filters it in/out. %>\n <%\n token_labels = {\n \"veg\" => t(\"components.filter.demo.vegetarian\"),\n \"spicy\" => t(\"components.filter.demo.spicy\"),\n }\n dishes = [\n { key: \"margherita\", tokens: \"veg\" },\n { key: \"pepperoni\", tokens: \"\" },\n { key: \"curry\", tokens: \"veg spicy\" },\n { key: \"wings\", tokens: \"spicy\" },\n ]\n %>\n <ul class=\"filter-demo__list\">\n <% dishes.each do |dish| %>\n <li class=\"filter-demo__item\" data-stimeo--filter-target=\"item\"\n data-stimeo--filter-tokens=\"<%= dish[:tokens] %>\">\n <span class=\"filter-demo__name\"><%= t(\"components.filter.demo.#{dish[:key]}\") %></span>\n <span class=\"filter-demo__tags\">\n <% dish[:tokens].split.each do |tok| %>\n <span class=\"filter-demo__tag\"><%= token_labels[tok] %></span>\n <% end %>\n </span>\n </li>\n <% end %>\n </ul>\n\n <p class=\"filter-demo__empty\" role=\"status\" data-stimeo--filter-target=\"empty\" hidden>\n <%= t(\"components.filter.demo.empty\") %>\n </p>\n</div>\n"
|
|
147
147
|
},
|
|
148
148
|
"stimeo--flash": {
|
|
149
149
|
"file": "examples/flash/_demo.html.erb",
|
|
150
|
-
"source": "<%# Flash-bridge demo: the buttons append flash messages into the region (standing in\n for a Turbo Stream that renders server flash). The controller maps data-flash-type\n to role=status/alert, auto-dismisses after the duration (paused on hover/focus), and\n a close button wired to the dismiss action removes one. The library only sets roles
|
|
150
|
+
"source": "<%# Flash-bridge demo: the buttons append flash messages into the region (standing in\n for a Turbo Stream that renders server flash). The controller maps data-flash-type\n to role=status/alert, auto-dismisses after the duration (paused on hover/focus), and\n a close button wired to the dismiss action removes one. max caps the stack at three:\n past it the oldest message goes, passing over any the pointer is over or focus is\n inside until that is released. The library only sets roles and data-flash-state;\n demo.css owns the look and the visible/leaving transition. The message text and the\n dismiss label are owned here for i18n. %>\n<div class=\"flash-demo\" data-dismiss-label=\"<%= t(\"components.flash.demo.dismiss\") %>\">\n <div class=\"flash-demo__bar\">\n <button\n type=\"button\"\n class=\"demo-trigger\"\n data-flash-demo=\"notice\"\n data-flash-text=\"<%= t(\"components.flash.demo.notice_text\") %>\">\n <%= t(\"components.flash.demo.notice\") %>\n </button>\n <button\n type=\"button\"\n class=\"demo-trigger\"\n data-flash-demo=\"alert\"\n data-flash-text=\"<%= t(\"components.flash.demo.alert_text\") %>\">\n <%= t(\"components.flash.demo.alert\") %>\n </button>\n </div>\n <div\n data-controller=\"stimeo--flash\"\n data-stimeo--flash-duration-value=\"4000\"\n data-stimeo--flash-max-value=\"3\">\n <div class=\"flash-demo__region\" data-stimeo--flash-target=\"region\"></div>\n </div>\n</div>\n"
|
|
151
151
|
},
|
|
152
152
|
"stimeo--focus": {
|
|
153
153
|
"file": "examples/focus/_demo.html.erb",
|
|
@@ -171,11 +171,11 @@
|
|
|
171
171
|
},
|
|
172
172
|
"stimeo--hover-card": {
|
|
173
173
|
"file": "examples/hover_card/_demo.html.erb",
|
|
174
|
-
"source": "<%# Markup for the hover_card demo.\n Hover/focus on the link opens a rich supplementary card after a delay. The card\n has no role=\"dialog\" (it's purely supplementary), and its contents are assumed to\n be reachable from the trigger's target too. The open/close delay, the hoverable\n bridge, and Escape-to-dismiss are the library's. %>\n<span class=\"hover-card\" data-controller=\"stimeo--hover-card\">\n <a\n class=\"hover-card__trigger\"\n href=\"#jane\"\n data-stimeo--hover-card-target=\"trigger\"\n aria-expanded=\"false\"\n aria-controls=\"hover-card-panel\"\n data-action=\"\n mouseenter->stimeo--hover-card#open\n mouseleave->stimeo--hover-card#close\n focusin->stimeo--hover-card#open\n focusout->stimeo--hover-card#close\">\n <%= t(\"components.hover_card.demo.trigger\") %>\n </a>\n\n <%# The card has no role=\"dialog\" (supplementary display, not an interrupting dialog). %>\n <div\n class=\"hover-card__panel\"\n id=\"hover-card-panel\"\n data-stimeo--hover-card-target=\"card\"\n data-action=\"\n mouseenter->stimeo--hover-card#open\n mouseleave->stimeo--hover-card#close\n focusin->stimeo--hover-card#open\n focusout->stimeo--hover-card#close\"\n hidden>\n <p class=\"hover-card__name\"><%= t(\"components.hover_card.demo.name\") %></p>\n <p class=\"hover-card__role\"><%= t(\"components.hover_card.demo.role\") %></p>\n <a class=\"hover-card__link\" href=\"#follow\"><%= t(\"components.hover_card.demo.follow\") %></a>\n </div>\n</span>\n"
|
|
174
|
+
"source": "<%# Markup for the hover_card demo.\n Hover/focus on the link opens a rich supplementary card after a delay. The card\n has no role=\"dialog\" (it's purely supplementary), and its contents are assumed to\n be reachable from the trigger's target too. The open/close delay, the hoverable\n bridge, and Escape-to-dismiss are the library's. %>\n<span class=\"hover-card\" data-controller=\"stimeo--hover-card\">\n <a\n class=\"hover-card__trigger\"\n href=\"#jane\"\n data-stimeo--hover-card-target=\"trigger\"\n aria-expanded=\"false\"\n aria-controls=\"hover-card-panel\"\n data-action=\"\n mouseenter->stimeo--hover-card#open\n mouseleave->stimeo--hover-card#close\n focusin->stimeo--hover-card#open\n focusout->stimeo--hover-card#close\">\n <%= t(\"components.hover_card.demo.trigger\") %>\n </a>\n\n <%# The card has no role=\"dialog\" (supplementary display, not an interrupting dialog). %>\n <div\n class=\"hover-card__panel\"\n id=\"hover-card-panel\"\n data-stimeo--hover-card-target=\"card\"\n data-action=\"\n mouseenter->stimeo--hover-card#open\n mouseleave->stimeo--hover-card#close\n focusin->stimeo--hover-card#open\n focusout->stimeo--hover-card#close\"\n hidden>\n <p class=\"hover-card__name\"><%= t(\"components.hover_card.demo.name\") %></p>\n <p class=\"hover-card__role\"><%= t(\"components.hover_card.demo.role\") %></p>\n <a class=\"hover-card__link\" href=\"#follow\"><%= t(\"components.hover_card.demo.follow\") %></a>\n </div>\n</span>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.events\") %></span>\n <span class=\"demo-readout__value\" data-readout>—</span>\n</p>\n"
|
|
175
175
|
},
|
|
176
176
|
"stimeo--idle": {
|
|
177
177
|
"file": "examples/idle/_demo.html.erb",
|
|
178
|
-
"source": "<%# Idle / session-timeout demo: the controller watches document-level activity and,\n after a short demo timeout, fires prompt -> idle; interacting again fires active.\n Real apps use a ~15-minute timeout; this demo shortens it (6s, warning at 3s) so the\n transitions are visible. The
|
|
178
|
+
"source": "<%# Idle / session-timeout demo: the controller watches document-level activity and,\n after a short demo timeout, fires prompt -> idle; interacting again fires active.\n Real apps use a ~15-minute timeout; this demo shortens it (6s, warning at 3s) so the\n transitions are visible. The two notices are declared regions: the controller owns\n hidden on them and shows each only while its own phase holds, so both are authored\n hidden and no consumer JS is needed. Status semantics are this markup's to give. %>\n<div\n class=\"idle-demo\"\n data-controller=\"stimeo--idle\"\n data-stimeo--idle-timeout-value=\"6000\"\n data-stimeo--idle-prompt-before-value=\"3000\">\n <p class=\"idle-demo__hint\"><%= t(\"components.idle.demo.hint\") %></p>\n <p\n class=\"idle-demo__notice idle-demo__notice--prompt\"\n role=\"status\"\n data-stimeo--idle-target=\"prompt\"\n hidden><%= t(\"components.idle.demo.prompt\") %></p>\n <p\n class=\"idle-demo__notice idle-demo__notice--idle\"\n role=\"status\"\n data-stimeo--idle-target=\"idle\"\n hidden><%= t(\"components.idle.demo.idle\") %></p>\n</div>\n"
|
|
179
179
|
},
|
|
180
180
|
"stimeo--input-mask": {
|
|
181
181
|
"file": "examples/input_mask/_demo.html.erb",
|
|
@@ -207,11 +207,11 @@
|
|
|
207
207
|
},
|
|
208
208
|
"stimeo--menu": {
|
|
209
209
|
"file": "examples/menu/_demo.html.erb",
|
|
210
|
-
"source": "<%# Markup for the menu (APG Menu Button) demo.\n stimeo--menu is a full role=\"menu\"/\"menuitem\" menu providing arrow-key roving\n focus, Esc, and outside click (distinct from the disclosure dropdown).\n Positioning (static placement) is the Playground's CSS. %>\n<div class=\"menu\" data-controller=\"stimeo--menu\">\n <button\n id=\"menu-trigger\"\n type=\"button\"\n class=\"demo-trigger\"\n aria-haspopup=\"menu\"\n aria-expanded=\"false\"\n aria-controls=\"menu-list\"\n data-stimeo--menu-target=\"trigger\"\n data-action=\"click->stimeo--menu#toggle keydown->stimeo--menu#onTriggerKeydown\">\n <%= t(\"components.menu.demo.trigger\") %>\n </button>\n\n <%# The trigger labels the menu; each item is a role=\"menuitem\" button (tabindex=-1).\n Items need no data-action: the controller handles their clicks and keys from its own\n element, so items added or moved in later work without being wired up. %>\n <ul id=\"menu-list\" class=\"menu__list\" role=\"menu\" aria-labelledby=\"menu-trigger\"\n data-stimeo--menu-target=\"menu\" hidden>\n <li role=\"none\">\n <button type=\"button\" role=\"menuitem\" class=\"demo-menuitem\" tabindex=\"-1\"\n data-stimeo--menu-target=\"item\"><%= t(\"components.menu.demo.edit\") %></button>\n </li>\n <li role=\"none\">\n <button type=\"button\" role=\"menuitem\" class=\"demo-menuitem\" tabindex=\"-1\"\n data-stimeo--menu-target=\"item\"><%= t(\"components.menu.demo.duplicate\") %></button>\n </li>\n <li role=\"none\">\n <button type=\"button\" role=\"menuitem\" class=\"demo-menuitem\" tabindex=\"-1\"\n data-stimeo--menu-target=\"item\"><%= t(\"components.menu.demo.delete\") %></button>\n </li>\n </ul>\n</div>\n"
|
|
210
|
+
"source": "<%# Markup for the menu (APG Menu Button) demo.\n stimeo--menu is a full role=\"menu\"/\"menuitem\" menu providing arrow-key roving\n focus, Esc, and outside click (distinct from the disclosure dropdown).\n Positioning (static placement) is the Playground's CSS. %>\n<div class=\"menu\" data-controller=\"stimeo--menu\">\n <button\n id=\"menu-trigger\"\n type=\"button\"\n class=\"demo-trigger\"\n aria-haspopup=\"menu\"\n aria-expanded=\"false\"\n aria-controls=\"menu-list\"\n data-stimeo--menu-target=\"trigger\"\n data-action=\"click->stimeo--menu#toggle keydown->stimeo--menu#onTriggerKeydown\">\n <%= t(\"components.menu.demo.trigger\") %>\n </button>\n\n <%# The trigger labels the menu; each item is a role=\"menuitem\" button (tabindex=-1).\n Items need no data-action: the controller handles their clicks and keys from its own\n element, so items added or moved in later work without being wired up. %>\n <ul id=\"menu-list\" class=\"menu__list\" role=\"menu\" aria-labelledby=\"menu-trigger\"\n data-stimeo--menu-target=\"menu\" hidden>\n <li role=\"none\">\n <button type=\"button\" role=\"menuitem\" class=\"demo-menuitem\" tabindex=\"-1\"\n data-stimeo--menu-target=\"item\"><%= t(\"components.menu.demo.edit\") %></button>\n </li>\n <li role=\"none\">\n <button type=\"button\" role=\"menuitem\" class=\"demo-menuitem\" tabindex=\"-1\"\n data-stimeo--menu-target=\"item\"><%= t(\"components.menu.demo.duplicate\") %></button>\n </li>\n <li role=\"none\">\n <button type=\"button\" role=\"menuitem\" class=\"demo-menuitem\" tabindex=\"-1\"\n data-stimeo--menu-target=\"item\"><%= t(\"components.menu.demo.delete\") %></button>\n </li>\n </ul>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.events\") %></span>\n <span class=\"demo-readout__value\" data-readout>—</span>\n</p>\n"
|
|
211
211
|
},
|
|
212
212
|
"stimeo--menubar": {
|
|
213
213
|
"file": "examples/menubar/_demo.html.erb",
|
|
214
|
-
"source": "<%# Markup for the menubar demo.\n Top-level items directly under role=\"menubar\" each open a role=\"menu\". The library\n handles roving between top items (left/right keys), opening a menu with\n ArrowDown/Enter, up/down movement and typeahead within a menu, moving sideways to\n an adjacent menu, returning on Escape, and closing on outside click / Tab. Top\n items ↔ menus are linked via aria-controls / id. The look is in demo.css. %>\n<div\n class=\"menubar\"\n data-controller=\"stimeo--menubar\"\n role=\"menubar\"\n aria-label=\"<%= t(\"components.menubar.demo.label\") %>\"\n>\n <button\n type=\"button\"\n class=\"demo-baritem\"\n role=\"menuitem\"\n aria-haspopup=\"menu\"\n aria-expanded=\"false\"\n aria-controls=\"menubar-file\"\n data-stimeo--menubar-target=\"top\"\n data-action=\"click->stimeo--menubar#toggle keydown->stimeo--menubar#onTopKeydown\">\n <%= t(\"components.menubar.demo.menus.file.label\") %>\n </button>\n <ul\n id=\"menubar-file\"\n class=\"menubar__menu\"\n role=\"menu\"\n aria-label=\"<%= t(\"components.menubar.demo.menus.file.label\") %>\"\n hidden\n data-stimeo--menubar-target=\"menu\"\n >\n <% %w[new open save].each do |action| %>\n <li role=\"none\">\n <button\n type=\"button\"\n class=\"demo-menuitem\"\n role=\"menuitem\"\n tabindex=\"-1\"\n data-stimeo--menubar-target=\"item\"\n data-action=\"click->stimeo--menubar#activate keydown->stimeo--menubar#onItemKeydown\">\n <%= t(\"components.menubar.demo.menus.file.items.#{action}\") %>\n </button>\n </li>\n <% end %>\n </ul>\n\n <button\n type=\"button\"\n class=\"demo-baritem\"\n role=\"menuitem\"\n aria-haspopup=\"menu\"\n aria-expanded=\"false\"\n aria-controls=\"menubar-edit\"\n data-stimeo--menubar-target=\"top\"\n data-action=\"click->stimeo--menubar#toggle keydown->stimeo--menubar#onTopKeydown\">\n <%= t(\"components.menubar.demo.menus.edit.label\") %>\n </button>\n <ul\n id=\"menubar-edit\"\n class=\"menubar__menu\"\n role=\"menu\"\n aria-label=\"<%= t(\"components.menubar.demo.menus.edit.label\") %>\"\n hidden\n data-stimeo--menubar-target=\"menu\"\n >\n <% %w[cut copy paste].each do |action| %>\n <li role=\"none\">\n <button\n type=\"button\"\n class=\"demo-menuitem\"\n role=\"menuitem\"\n tabindex=\"-1\"\n data-stimeo--menubar-target=\"item\"\n data-action=\"click->stimeo--menubar#activate keydown->stimeo--menubar#onItemKeydown\">\n <%= t(\"components.menubar.demo.menus.edit.items.#{action}\") %>\n </button>\n </li>\n <% end %>\n </ul>\n</div>\n"
|
|
214
|
+
"source": "<%# Markup for the menubar demo.\n Top-level items directly under role=\"menubar\" each open a role=\"menu\". The library\n handles roving between top items (left/right keys), opening a menu with\n ArrowDown/Enter, up/down movement and typeahead within a menu, moving sideways to\n an adjacent menu, returning on Escape, and closing on outside click / Tab. Top\n items ↔ menus are linked via aria-controls / id. The look is in demo.css. %>\n<div\n class=\"menubar\"\n data-controller=\"stimeo--menubar\"\n role=\"menubar\"\n aria-label=\"<%= t(\"components.menubar.demo.label\") %>\"\n>\n <button\n type=\"button\"\n class=\"demo-baritem\"\n role=\"menuitem\"\n aria-haspopup=\"menu\"\n aria-expanded=\"false\"\n aria-controls=\"menubar-file\"\n data-stimeo--menubar-target=\"top\"\n data-action=\"click->stimeo--menubar#toggle keydown->stimeo--menubar#onTopKeydown\">\n <%= t(\"components.menubar.demo.menus.file.label\") %>\n </button>\n <ul\n id=\"menubar-file\"\n class=\"menubar__menu\"\n role=\"menu\"\n aria-label=\"<%= t(\"components.menubar.demo.menus.file.label\") %>\"\n hidden\n data-stimeo--menubar-target=\"menu\"\n >\n <% %w[new open save].each do |action| %>\n <li role=\"none\">\n <button\n type=\"button\"\n class=\"demo-menuitem\"\n role=\"menuitem\"\n tabindex=\"-1\"\n data-stimeo--menubar-target=\"item\"\n data-action=\"click->stimeo--menubar#activate keydown->stimeo--menubar#onItemKeydown\">\n <%= t(\"components.menubar.demo.menus.file.items.#{action}\") %>\n </button>\n </li>\n <% end %>\n </ul>\n\n <button\n type=\"button\"\n class=\"demo-baritem\"\n role=\"menuitem\"\n aria-haspopup=\"menu\"\n aria-expanded=\"false\"\n aria-controls=\"menubar-edit\"\n data-stimeo--menubar-target=\"top\"\n data-action=\"click->stimeo--menubar#toggle keydown->stimeo--menubar#onTopKeydown\">\n <%= t(\"components.menubar.demo.menus.edit.label\") %>\n </button>\n <ul\n id=\"menubar-edit\"\n class=\"menubar__menu\"\n role=\"menu\"\n aria-label=\"<%= t(\"components.menubar.demo.menus.edit.label\") %>\"\n hidden\n data-stimeo--menubar-target=\"menu\"\n >\n <% %w[cut copy paste].each do |action| %>\n <li role=\"none\">\n <button\n type=\"button\"\n class=\"demo-menuitem\"\n role=\"menuitem\"\n tabindex=\"-1\"\n data-stimeo--menubar-target=\"item\"\n data-action=\"click->stimeo--menubar#activate keydown->stimeo--menubar#onItemKeydown\">\n <%= t(\"components.menubar.demo.menus.edit.items.#{action}\") %>\n </button>\n </li>\n <% end %>\n </ul>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.events\") %></span>\n <span class=\"demo-readout__value\" data-readout>—</span>\n</p>\n"
|
|
215
215
|
},
|
|
216
216
|
"stimeo--meter": {
|
|
217
217
|
"file": "examples/meter/_demo.html.erb",
|
|
@@ -219,11 +219,11 @@
|
|
|
219
219
|
},
|
|
220
220
|
"stimeo--multi-select": {
|
|
221
221
|
"file": "examples/multi_select/_demo.html.erb",
|
|
222
|
-
"source": "<%# Markup for the multi-select (multiple-selection combobox) demo.\n Filter candidates as you type, select several, and show the selected ones as chips.\n Focus stays on the input; the active candidate is shown via aria-activedescendant\n and selection via aria-selected. The library handles filtering, multi-select\n toggling, chip create/remove, roving, dismiss, and the
|
|
222
|
+
"source": "<%# Markup for the multi-select (multiple-selection combobox) demo.\n Filter candidates as you type, select several, and show the selected ones as chips.\n Focus stays on the input; the active candidate is shown via aria-activedescendant\n and selection via aria-selected. The library handles filtering, multi-select\n toggling, chip create/remove, roving, dismiss, the no-match message's hidden, and the\n selection announcements read by the shared stimeo--announcer your app seats once, in\n its layout (selecting and removing a value are the transitions worth reading; the\n multi-select owns no live region of its own). Placement lives in demo.css. %>\n<% announce_selected = t(\"components.multi_select.demo.announce_selected\") %>\n<% announce_removed = t(\"components.multi_select.demo.announce_removed\") %>\n<% remove_label = t(\"components.multi_select.demo.remove_label\") %>\n<div\n class=\"multi-select\"\n data-controller=\"stimeo--multi-select\"\n data-stimeo--multi-select-announce-text-value=\"<%= announce_selected %>\"\n data-stimeo--multi-select-announce-removed-text-value=\"<%= announce_removed %>\">\n <%# The container the selected values are generated into as hidden inputs;\n it is optional. %>\n <div data-stimeo--multi-select-target=\"fields\"></div>\n\n <span id=\"multi-select-label\" class=\"multi-select__label\">\n <%= t(\"components.multi_select.demo.label\") %>\n </span>\n\n <ul\n class=\"multi-select__tags\"\n aria-label=\"<%= t(\"components.multi_select.demo.selected_label\") %>\"\n data-stimeo--multi-select-target=\"tags\"></ul>\n\n <input\n type=\"text\"\n class=\"multi-select__input\"\n role=\"combobox\"\n aria-expanded=\"false\"\n aria-autocomplete=\"list\"\n aria-controls=\"multi-select-list\"\n aria-labelledby=\"multi-select-label\"\n placeholder=\"<%= t(\"components.multi_select.demo.placeholder\") %>\"\n data-stimeo--multi-select-target=\"input\"\n data-action=\"input->stimeo--multi-select#filter\n keydown->stimeo--multi-select#onKeydown\n focus->stimeo--multi-select#open\" />\n\n <ul\n id=\"multi-select-list\"\n class=\"multi-select__list\"\n role=\"listbox\"\n aria-multiselectable=\"true\"\n aria-label=\"<%= t(\"components.multi_select.demo.options_label\") %>\"\n hidden\n data-stimeo--multi-select-target=\"list\">\n <% %w[apple banana cherry grape orange melon].each_with_index do |fruit, index| %>\n <li\n id=\"multi-select-opt-<%= index %>\"\n class=\"multi-select__option\"\n role=\"option\"\n aria-selected=\"false\"\n data-value=\"<%= fruit %>\"\n data-stimeo--multi-select-target=\"option\"\n data-action=\"click->stimeo--multi-select#toggleOption\">\n <%= t(\"components.multi_select.demo.options.#{fruit}\") %>\n </li>\n <% end %>\n </ul>\n\n <%# The no-match message. It is a sibling of the listbox, whose children are all\n options, and the library owns its hidden: it stands only while the open list\n has nothing left to offer. %>\n <p class=\"multi-select__empty\" data-stimeo--multi-select-target=\"empty\" hidden>\n <%= t(\"components.multi_select.demo.empty\") %>\n </p>\n\n <template data-stimeo--multi-select-target=\"tagTemplate\">\n <li class=\"multi-select__tag\" data-stimeo--multi-select-target=\"tag\">\n <span data-stimeo--multi-select-target=\"label\"></span>\n <%# Removal is handled by a delegated listener on the tags container, so it\n works instantly without waiting on Stimulus wiring a data-action onto the\n dynamically-added button. %>\n <button\n type=\"button\"\n class=\"multi-select__remove\"\n tabindex=\"-1\"\n aria-label=\"<%= remove_label %>\"\n data-stimeo--multi-select-target=\"remove\">×</button>\n </li>\n </template>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.field\") %></span>\n <span class=\"demo-readout__value\" data-readout\n data-empty-text=\"<%= t(\"catalog.readout.empty\") %>\">—</span>\n</p>\n"
|
|
223
223
|
},
|
|
224
224
|
"stimeo--navigation-menu": {
|
|
225
225
|
"file": "examples/navigation_menu/_demo.html.erb",
|
|
226
|
-
"source": "<%# Markup for the navigation-menu demo.\n Two arrangements are shown.\n\n 1. Click-only (the default): a global nav where each top item opens/closes a\n sub-panel (a set of links). The contents are links and don't use role=\"menu\"\n (APG Disclosure navigation). The library handles syncing aria-expanded,\n single-open behavior, closing on Escape / outside click / focus leaving, and\n moving between top items with the left/right keys.\n 2. Hover (opt-in): openOnHover plus a hoverArea wrapper — the APG \"Disclosure\n Navigation with Top-Level Links\" arrangement, where each <li> holds a real\n link, a small disclosure button, and the panel. Hovering anywhere over the\n <li> opens that item's panel; every keyboard path stays identical.\n\n Panel placement and styling are the consumer's CSS (demo.css). %>\n<p class=\"nav-menu__caption\"><%= t(\"components.navigation_menu.demo.click_caption\") %></p>\n<nav class=\"nav-menu\" data-controller=\"stimeo--navigation-menu\"\n aria-label=\"<%= t(\"components.navigation_menu.demo.label\") %>\">\n <ul class=\"nav-menu__list\">\n <li class=\"nav-menu__item\">\n <button\n type=\"button\"\n class=\"demo-baritem\"\n aria-expanded=\"false\"\n aria-controls=\"nav-menu-products\"\n data-stimeo--navigation-menu-target=\"trigger\"\n data-action=\"click->stimeo--navigation-menu#toggle\n keydown->stimeo--navigation-menu#onTriggerKeydown\">\n <%= t(\"components.navigation_menu.demo.products.label\") %>\n </button>\n <div id=\"nav-menu-products\" class=\"nav-menu__panel\"\n data-stimeo--navigation-menu-target=\"panel\" hidden>\n <a class=\"demo-menuitem\" href=\"#analytics\"><%= t(\n \"components.navigation_menu.demo.products.links.analytics\"\n ) %></a>\n <a class=\"demo-menuitem\" href=\"#automation\"><%= t(\n \"components.navigation_menu.demo.products.links.automation\"\n ) %></a>\n <a class=\"demo-menuitem\" href=\"#reports\"><%= t(\n \"components.navigation_menu.demo.products.links.reports\"\n ) %></a>\n </div>\n </li>\n <li class=\"nav-menu__item\">\n <button\n type=\"button\"\n class=\"demo-baritem\"\n aria-expanded=\"false\"\n aria-controls=\"nav-menu-company\"\n data-stimeo--navigation-menu-target=\"trigger\"\n data-action=\"click->stimeo--navigation-menu#toggle\n keydown->stimeo--navigation-menu#onTriggerKeydown\">\n <%= t(\"components.navigation_menu.demo.company.label\") %>\n </button>\n <div id=\"nav-menu-company\" class=\"nav-menu__panel\"\n data-stimeo--navigation-menu-target=\"panel\" hidden>\n <a class=\"demo-menuitem\" href=\"#about\"><%= t(\n \"components.navigation_menu.demo.company.links.about\"\n ) %></a>\n <a class=\"demo-menuitem\" href=\"#careers\"><%= t(\n \"components.navigation_menu.demo.company.links.careers\"\n ) %></a>\n </div>\n </li>\n </ul>\n</nav>\n\n<p class=\"nav-menu__caption\"><%= t(\"components.navigation_menu.demo.hover_caption\") %></p>\n<%# openOnHover is opt-in; hoverArea widens the hover region to the whole <li>, so\n hovering the top-level link (not just the disclosure button) opens the panel.\n The button keeps its own accessible name so keyboard and SR users can tell the\n link and its disclosure apart. %>\n<nav class=\"nav-menu\" data-controller=\"stimeo--navigation-menu\"\n data-stimeo--navigation-menu-open-on-hover-value=\"true\"\n aria-label=\"<%= t(\"components.navigation_menu.demo.hover.label\") %>\">\n <ul class=\"nav-menu__list\">\n <li class=\"nav-menu__item\" data-stimeo--navigation-menu-target=\"hoverArea\">\n <a class=\"demo-baritem nav-menu__link\" href=\"#solutions\">\n <%= t(\"components.navigation_menu.demo.hover.solutions.label\") %>\n </a>\n <button\n type=\"button\"\n class=\"demo-baritem nav-menu__disclosure\"\n aria-expanded=\"false\"\n aria-controls=\"nav-menu-solutions\"\n data-stimeo--navigation-menu-target=\"trigger\"\n data-action=\"click->stimeo--navigation-menu#toggle\n keydown->stimeo--navigation-menu#onTriggerKeydown\">\n <span aria-hidden=\"true\">▾</span>\n <span class=\"visually-hidden\"><%= t(\n \"components.navigation_menu.demo.hover.solutions.toggle\"\n ) %></span>\n </button>\n <div id=\"nav-menu-solutions\" class=\"nav-menu__panel\"\n data-stimeo--navigation-menu-target=\"panel\" hidden>\n <a class=\"demo-menuitem\" href=\"#retail\"><%= t(\n \"components.navigation_menu.demo.hover.solutions.links.retail\"\n ) %></a>\n <a class=\"demo-menuitem\" href=\"#finance\"><%= t(\n \"components.navigation_menu.demo.hover.solutions.links.finance\"\n ) %></a>\n </div>\n </li>\n <li class=\"nav-menu__item\" data-stimeo--navigation-menu-target=\"hoverArea\">\n <a class=\"demo-baritem nav-menu__link\" href=\"#resources\">\n <%= t(\"components.navigation_menu.demo.hover.resources.label\") %>\n </a>\n <button\n type=\"button\"\n class=\"demo-baritem nav-menu__disclosure\"\n aria-expanded=\"false\"\n aria-controls=\"nav-menu-resources\"\n data-stimeo--navigation-menu-target=\"trigger\"\n data-action=\"click->stimeo--navigation-menu#toggle\n keydown->stimeo--navigation-menu#onTriggerKeydown\">\n <span aria-hidden=\"true\">▾</span>\n <span class=\"visually-hidden\"><%= t(\n \"components.navigation_menu.demo.hover.resources.toggle\"\n ) %></span>\n </button>\n <div id=\"nav-menu-resources\" class=\"nav-menu__panel\"\n data-stimeo--navigation-menu-target=\"panel\" hidden>\n <a class=\"demo-menuitem\" href=\"#guides\"><%= t(\n \"components.navigation_menu.demo.hover.resources.links.guides\"\n ) %></a>\n <a class=\"demo-menuitem\" href=\"#blog\"><%= t(\n \"components.navigation_menu.demo.hover.resources.links.blog\"\n ) %></a>\n </div>\n </li>\n </ul>\n</nav>\n"
|
|
226
|
+
"source": "<%# Markup for the navigation-menu demo.\n Two arrangements are shown.\n\n 1. Click-only (the default): a global nav where each top item opens/closes a\n sub-panel (a set of links). The contents are links and don't use role=\"menu\"\n (APG Disclosure navigation). The library handles syncing aria-expanded,\n single-open behavior, closing on Escape / outside click / focus leaving, and\n moving between top items with the left/right keys.\n 2. Hover (opt-in): openOnHover plus a hoverArea wrapper — the APG \"Disclosure\n Navigation with Top-Level Links\" arrangement, where each <li> holds a real\n link, a small disclosure button, and the panel. Hovering anywhere over the\n <li> opens that item's panel; every keyboard path stays identical.\n\n Panel placement and styling are the consumer's CSS (demo.css). %>\n<p class=\"nav-menu__caption\"><%= t(\"components.navigation_menu.demo.click_caption\") %></p>\n<nav class=\"nav-menu\" data-controller=\"stimeo--navigation-menu\"\n aria-label=\"<%= t(\"components.navigation_menu.demo.label\") %>\">\n <ul class=\"nav-menu__list\">\n <li class=\"nav-menu__item\">\n <button\n type=\"button\"\n class=\"demo-baritem\"\n aria-expanded=\"false\"\n aria-controls=\"nav-menu-products\"\n data-stimeo--navigation-menu-target=\"trigger\"\n data-action=\"click->stimeo--navigation-menu#toggle\n keydown->stimeo--navigation-menu#onTriggerKeydown\">\n <%= t(\"components.navigation_menu.demo.products.label\") %>\n </button>\n <div id=\"nav-menu-products\" class=\"nav-menu__panel\"\n data-stimeo--navigation-menu-target=\"panel\" hidden>\n <a class=\"demo-menuitem\" href=\"#analytics\"><%= t(\n \"components.navigation_menu.demo.products.links.analytics\"\n ) %></a>\n <a class=\"demo-menuitem\" href=\"#automation\"><%= t(\n \"components.navigation_menu.demo.products.links.automation\"\n ) %></a>\n <a class=\"demo-menuitem\" href=\"#reports\"><%= t(\n \"components.navigation_menu.demo.products.links.reports\"\n ) %></a>\n </div>\n </li>\n <li class=\"nav-menu__item\">\n <button\n type=\"button\"\n class=\"demo-baritem\"\n aria-expanded=\"false\"\n aria-controls=\"nav-menu-company\"\n data-stimeo--navigation-menu-target=\"trigger\"\n data-action=\"click->stimeo--navigation-menu#toggle\n keydown->stimeo--navigation-menu#onTriggerKeydown\">\n <%= t(\"components.navigation_menu.demo.company.label\") %>\n </button>\n <div id=\"nav-menu-company\" class=\"nav-menu__panel\"\n data-stimeo--navigation-menu-target=\"panel\" hidden>\n <a class=\"demo-menuitem\" href=\"#about\"><%= t(\n \"components.navigation_menu.demo.company.links.about\"\n ) %></a>\n <a class=\"demo-menuitem\" href=\"#careers\"><%= t(\n \"components.navigation_menu.demo.company.links.careers\"\n ) %></a>\n </div>\n </li>\n </ul>\n</nav>\n\n<p class=\"nav-menu__caption\"><%= t(\"components.navigation_menu.demo.hover_caption\") %></p>\n<%# openOnHover is opt-in; hoverArea widens the hover region to the whole <li>, so\n hovering the top-level link (not just the disclosure button) opens the panel.\n The button keeps its own accessible name so keyboard and SR users can tell the\n link and its disclosure apart. %>\n<nav class=\"nav-menu\" data-controller=\"stimeo--navigation-menu\"\n data-stimeo--navigation-menu-open-on-hover-value=\"true\"\n aria-label=\"<%= t(\"components.navigation_menu.demo.hover.label\") %>\">\n <ul class=\"nav-menu__list\">\n <li class=\"nav-menu__item\" data-stimeo--navigation-menu-target=\"hoverArea\">\n <a class=\"demo-baritem nav-menu__link\" href=\"#solutions\">\n <%= t(\"components.navigation_menu.demo.hover.solutions.label\") %>\n </a>\n <button\n type=\"button\"\n class=\"demo-baritem nav-menu__disclosure\"\n aria-expanded=\"false\"\n aria-controls=\"nav-menu-solutions\"\n data-stimeo--navigation-menu-target=\"trigger\"\n data-action=\"click->stimeo--navigation-menu#toggle\n keydown->stimeo--navigation-menu#onTriggerKeydown\">\n <span aria-hidden=\"true\">▾</span>\n <span class=\"visually-hidden\"><%= t(\n \"components.navigation_menu.demo.hover.solutions.toggle\"\n ) %></span>\n </button>\n <div id=\"nav-menu-solutions\" class=\"nav-menu__panel\"\n data-stimeo--navigation-menu-target=\"panel\" hidden>\n <a class=\"demo-menuitem\" href=\"#retail\"><%= t(\n \"components.navigation_menu.demo.hover.solutions.links.retail\"\n ) %></a>\n <a class=\"demo-menuitem\" href=\"#finance\"><%= t(\n \"components.navigation_menu.demo.hover.solutions.links.finance\"\n ) %></a>\n </div>\n </li>\n <li class=\"nav-menu__item\" data-stimeo--navigation-menu-target=\"hoverArea\">\n <a class=\"demo-baritem nav-menu__link\" href=\"#resources\">\n <%= t(\"components.navigation_menu.demo.hover.resources.label\") %>\n </a>\n <button\n type=\"button\"\n class=\"demo-baritem nav-menu__disclosure\"\n aria-expanded=\"false\"\n aria-controls=\"nav-menu-resources\"\n data-stimeo--navigation-menu-target=\"trigger\"\n data-action=\"click->stimeo--navigation-menu#toggle\n keydown->stimeo--navigation-menu#onTriggerKeydown\">\n <span aria-hidden=\"true\">▾</span>\n <span class=\"visually-hidden\"><%= t(\n \"components.navigation_menu.demo.hover.resources.toggle\"\n ) %></span>\n </button>\n <div id=\"nav-menu-resources\" class=\"nav-menu__panel\"\n data-stimeo--navigation-menu-target=\"panel\" hidden>\n <a class=\"demo-menuitem\" href=\"#guides\"><%= t(\n \"components.navigation_menu.demo.hover.resources.links.guides\"\n ) %></a>\n <a class=\"demo-menuitem\" href=\"#blog\"><%= t(\n \"components.navigation_menu.demo.hover.resources.links.blog\"\n ) %></a>\n </div>\n </li>\n </ul>\n</nav>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.events\") %></span>\n <span class=\"demo-readout__value\" data-readout>—</span>\n</p>\n"
|
|
227
227
|
},
|
|
228
228
|
"stimeo--nested-form": {
|
|
229
229
|
"file": "examples/nested_form/_demo.html.erb",
|
|
@@ -235,7 +235,7 @@
|
|
|
235
235
|
},
|
|
236
236
|
"stimeo--number-input": {
|
|
237
237
|
"file": "examples/number_input/_demo.html.erb",
|
|
238
|
-
"source": "<%# Markup for the number-input (APG Spinbutton) demo.\n Increment/decrement buttons and the arrow keys step by `step`, clamped to min/max.\n The input is the only tab stop (buttons are tabindex=\"-1\"); a button is disabled at\n its boundary. %>\n<div class=\"number-input-demo\" data-controller=\"stimeo--number-input\"\n data-stimeo--number-input-min-value=\"0\"\n data-stimeo--number-input-max-value=\"10\"\n data-stimeo--number-input-step-value=\"1\">\n <button type=\"button\" class=\"number-input-demo__btn\"\n aria-label=\"<%= t('components.number_input.demo.decrease') %>\" tabindex=\"-1\"\n data-stimeo--number-input-target=\"decrement\"\n data-action=\"click->stimeo--number-input#decrement\">\n <svg class=\"demo-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line>\n </svg>\n </button>\n\n <input type=\"number\" class=\"number-input-demo__input\" min=\"0\" max=\"10\" step=\"1\" value=\"1\"\n aria-label=\"<%= t('components.number_input.demo.quantity') %>\"\n data-stimeo--number-input-target=\"input\"\n data-action=\"change->stimeo--number-input#onInput\n keydown->stimeo--number-input#onKeydown\" />\n\n <button type=\"button\" class=\"number-input-demo__btn\"\n aria-label=\"<%= t('components.number_input.demo.increase') %>\" tabindex=\"-1\"\n data-stimeo--number-input-target=\"increment\"\n data-action=\"click->stimeo--number-input#increment\">\n <svg class=\"demo-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"></line>\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line>\n </svg>\n </button>\n</div>\n"
|
|
238
|
+
"source": "<%# Markup for the number-input (APG Spinbutton) demo.\n Increment/decrement buttons and the arrow keys step by `step`, clamped to min/max.\n The input is the only tab stop (buttons are tabindex=\"-1\"); a button is disabled at\n its boundary.\n\n The widget owns the stepping, so it reports a step the way the browser reports its\n own: a bubbling `input` then a bubbling `change` on its own input. That is why the\n surrounding `stimeo--auto-submit` reacts to a button or an arrow key with nothing\n wired between them. %>\n<form class=\"number-input-demo__form\"\n data-controller=\"stimeo--auto-submit\"\n data-stimeo--auto-submit-debounce-value=\"400\"\n data-action=\"change->stimeo--auto-submit#submit\">\n<div class=\"number-input-demo\" data-controller=\"stimeo--number-input\"\n data-stimeo--number-input-min-value=\"0\"\n data-stimeo--number-input-max-value=\"10\"\n data-stimeo--number-input-step-value=\"1\">\n <button type=\"button\" class=\"number-input-demo__btn\"\n aria-label=\"<%= t('components.number_input.demo.decrease') %>\" tabindex=\"-1\"\n data-stimeo--number-input-target=\"decrement\"\n data-action=\"click->stimeo--number-input#decrement\">\n <svg class=\"demo-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line>\n </svg>\n </button>\n\n <input type=\"number\" class=\"number-input-demo__input\" name=\"quantity\"\n min=\"0\" max=\"10\" step=\"1\" value=\"1\"\n aria-label=\"<%= t('components.number_input.demo.quantity') %>\"\n data-stimeo--number-input-target=\"input\"\n data-action=\"change->stimeo--number-input#onInput\n keydown->stimeo--number-input#onKeydown\" />\n\n <button type=\"button\" class=\"number-input-demo__btn\"\n aria-label=\"<%= t('components.number_input.demo.increase') %>\" tabindex=\"-1\"\n data-stimeo--number-input-target=\"increment\"\n data-action=\"click->stimeo--number-input#increment\">\n <svg class=\"demo-icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <line x1=\"12\" y1=\"5\" x2=\"12\" y2=\"19\"></line>\n <line x1=\"5\" y1=\"12\" x2=\"19\" y2=\"12\"></line>\n </svg>\n </button>\n</div>\n</form>\n\n<%# The readout is aria-hidden: the value is already in the field the screen reader\n reads, so repeating it here would say it twice. The value is a code fragment\n (API identifiers and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.field\") %></span>\n <span class=\"demo-readout__value\" data-readout\n data-empty-text=\"<%= t(\"catalog.readout.empty\") %>\">—</span>\n</p>\n"
|
|
239
239
|
},
|
|
240
240
|
"stimeo--optimistic": {
|
|
241
241
|
"file": "examples/optimistic/_demo.html.erb",
|
|
@@ -247,7 +247,7 @@
|
|
|
247
247
|
},
|
|
248
248
|
"stimeo--overflow-indicator": {
|
|
249
249
|
"file": "examples/overflow_indicator/_demo.html.erb",
|
|
250
|
-
"source": "<%# Markup for the overflow-indicator (horizontal-scroll affordance) demo.\n The library exposes the viewport's remaining scroll room via data-overflow-start /\n data-overflow-end and syncs the prev/next buttons' disabled to that room. The\n shadow/arrow look is drawn by demo.css. %>\n<div class=\"overflow-demo\" data-controller=\"stimeo--overflow-indicator\"\n data-stimeo--overflow-indicator-orientation-value=\"horizontal\">\n <button\n type=\"button\"\n class=\"overflow-demo__nav\"\n aria-label=\"<%= t(\"components.overflow_indicator.demo.prev\") %>\"\n data-stimeo--overflow-indicator-direction-param=\"start\"\n data-action=\"click->stimeo--overflow-indicator#scrollByPage\">‹</button>\n\n <div class=\"overflow-demo__viewport\"\n data-stimeo--overflow-indicator-target=\"viewport\"\n
|
|
250
|
+
"source": "<%# Markup for the overflow-indicator (horizontal-scroll affordance) demo.\n The library exposes the viewport's remaining scroll room via data-overflow-start /\n data-overflow-end and syncs the prev/next buttons' disabled to that room. The\n shadow/arrow look is drawn by demo.css. %>\n<div class=\"overflow-demo\" data-controller=\"stimeo--overflow-indicator\"\n data-stimeo--overflow-indicator-orientation-value=\"horizontal\">\n <button\n type=\"button\"\n class=\"overflow-demo__nav\"\n aria-label=\"<%= t(\"components.overflow_indicator.demo.prev\") %>\"\n data-stimeo--overflow-indicator-direction-param=\"start\"\n data-action=\"click->stimeo--overflow-indicator#scrollByPage\">‹</button>\n\n <div class=\"overflow-demo__viewport\"\n data-stimeo--overflow-indicator-target=\"viewport\"\n tabindex=\"0\"\n role=\"region\"\n aria-label=\"<%= t(\"components.overflow_indicator.demo.label\") %>\">\n <% 10.times do |i| %>\n <div class=\"overflow-demo__card\"><%= t(\n \"components.overflow_indicator.demo.card\", number: i + 1\n ) %></div>\n <% end %>\n </div>\n\n <button\n type=\"button\"\n class=\"overflow-demo__nav\"\n aria-label=\"<%= t(\"components.overflow_indicator.demo.next\") %>\"\n data-stimeo--overflow-indicator-direction-param=\"end\"\n data-action=\"click->stimeo--overflow-indicator#scrollByPage\">›</button>\n</div>\n"
|
|
251
251
|
},
|
|
252
252
|
"stimeo--overflow-menu": {
|
|
253
253
|
"file": "examples/overflow_menu/_demo.html.erb",
|
|
@@ -259,7 +259,7 @@
|
|
|
259
259
|
},
|
|
260
260
|
"stimeo--password-reveal": {
|
|
261
261
|
"file": "examples/password_reveal/_demo.html.erb",
|
|
262
|
-
"source": "<%# Markup for the password-reveal demo.\n The toggle switches the input's type between password ↔ text and syncs aria-pressed /\n data-state. If the input was focused, focus and caret position are preserved. The
|
|
262
|
+
"source": "<%# Markup for the password-reveal demo.\n The toggle switches the input's type between password ↔ text and syncs aria-pressed /\n data-state. If the input was focused, focus and caret position are preserved. The toggle\n carries one glyph per state as an off-label / on-label pair; the controller shows the half\n that matches the state and hides the other, so demo.css needs no rule for the swap. Both\n halves are aria-hidden, so the accessible name stays the toggle's aria-label in either\n state. %>\n<div class=\"password-reveal\" data-controller=\"stimeo--password-reveal\">\n <label class=\"password-reveal__label\" for=\"password-reveal-demo-input\">\n <%= t(\"components.password_reveal.demo.label\") %>\n </label>\n <div class=\"password-reveal__field\">\n <input\n class=\"password-reveal__input\"\n id=\"password-reveal-demo-input\"\n type=\"password\"\n value=\"hunter2\"\n autocomplete=\"current-password\"\n data-stimeo--password-reveal-target=\"input\">\n <button\n class=\"password-reveal__toggle\"\n type=\"button\"\n aria-pressed=\"false\"\n aria-label=\"<%= t('components.password_reveal.demo.show') %>\"\n data-stimeo--password-reveal-target=\"toggle\"\n data-action=\"click->stimeo--password-reveal#toggle\">\n <span\n class=\"password-reveal__icon\"\n aria-hidden=\"true\"\n data-stimeo--password-reveal-target=\"offLabel\">👁</span>\n <span\n class=\"password-reveal__icon\"\n aria-hidden=\"true\"\n hidden\n data-stimeo--password-reveal-target=\"onLabel\">🙈</span>\n </button>\n </div>\n</div>\n"
|
|
263
263
|
},
|
|
264
264
|
"stimeo--password-strength": {
|
|
265
265
|
"file": "examples/password_strength/_demo.html.erb",
|
|
@@ -275,7 +275,7 @@
|
|
|
275
275
|
},
|
|
276
276
|
"stimeo--popover": {
|
|
277
277
|
"file": "examples/popover/_demo.html.erb",
|
|
278
|
-
"source": "<%# Markup for the popover demo.\n A non-modal floating panel toggled by a trigger click. The panel is role=\"dialog\"\n with no aria-modal (the background stays interactive). Static placement lives in\n this Playground's CSS; the library only handles open/close, focus, and dismiss. %>\n<div class=\"popover\" data-controller=\"stimeo--popover\">\n <button\n class=\"demo-trigger\"\n type=\"button\"\n data-stimeo--popover-target=\"trigger\"\n aria-haspopup=\"dialog\"\n aria-expanded=\"false\"\n aria-controls=\"popover-panel\"\n data-action=\"click->stimeo--popover#toggle\">\n <%= t(\"components.popover.demo.trigger\") %>\n </button>\n\n <div\n class=\"popover__panel\"\n id=\"popover-panel\"\n role=\"dialog\"\n aria-label=\"<%= t(\"components.popover.demo.title\") %>\"\n data-stimeo--popover-target=\"panel\"\n hidden>\n <label class=\"popover__field\">\n <%= t(\"components.popover.demo.name_label\") %>\n <input type=\"text\" name=\"display_name\" />\n </label>\n <button\n class=\"demo-trigger\"\n type=\"button\"\n data-action=\"click->stimeo--popover#close\">\n <%= t(\"components.popover.demo.done\") %>\n </button>\n </div>\n</div>\n"
|
|
278
|
+
"source": "<%# Markup for the popover demo.\n A non-modal floating panel toggled by a trigger click. The panel is role=\"dialog\"\n with no aria-modal (the background stays interactive). Static placement lives in\n this Playground's CSS; the library only handles open/close, focus, and dismiss. %>\n<div class=\"popover\" data-controller=\"stimeo--popover\">\n <button\n class=\"demo-trigger\"\n type=\"button\"\n data-stimeo--popover-target=\"trigger\"\n aria-haspopup=\"dialog\"\n aria-expanded=\"false\"\n aria-controls=\"popover-panel\"\n data-action=\"click->stimeo--popover#toggle\">\n <%= t(\"components.popover.demo.trigger\") %>\n </button>\n\n <div\n class=\"popover__panel\"\n id=\"popover-panel\"\n role=\"dialog\"\n aria-label=\"<%= t(\"components.popover.demo.title\") %>\"\n data-stimeo--popover-target=\"panel\"\n hidden>\n <label class=\"popover__field\">\n <%= t(\"components.popover.demo.name_label\") %>\n <input type=\"text\" name=\"display_name\" />\n </label>\n <button\n class=\"demo-trigger\"\n type=\"button\"\n data-action=\"click->stimeo--popover#close\">\n <%= t(\"components.popover.demo.done\") %>\n </button>\n </div>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.events\") %></span>\n <span class=\"demo-readout__value\" data-readout>—</span>\n</p>\n"
|
|
279
279
|
},
|
|
280
280
|
"stimeo--portal": {
|
|
281
281
|
"file": "examples/portal/_demo.html.erb",
|
|
@@ -295,19 +295,19 @@
|
|
|
295
295
|
},
|
|
296
296
|
"stimeo--radio-group": {
|
|
297
297
|
"file": "examples/radio_group/_demo.html.erb",
|
|
298
|
-
"source": "<%# Markup for the radio-group (APG Radio Group) demo.\n A custom card-style radio. Single selection is shown via aria-checked and the single\n tab stop via roving tabindex. Arrows move the selection (focus = selection). The group\n delegates click and keydown, so the radios carry no data-action of their own. The\n selected value is reflected into a hidden field; the look is the consumer's CSS. %>\n<div class=\"radio-group-demo\" role=\"radiogroup\" aria-labelledby=\"rg-label\"\n data-controller=\"stimeo--radio-group\">\n <span class=\"radio-group-demo__legend\" id=\"rg-label\">\n <%= t(\"components.radio_group.demo.legend\") %>\n </span>\n <p class=\"radio-group-demo__hint\"><%= t(\"components.radio_group.demo.hint\") %></p>\n\n <div class=\"radio-group-demo__options\">\n <div class=\"radio-group-demo__option\" role=\"radio\" aria-checked=\"false\" tabindex=\"0\"\n data-value=\"basic\" data-stimeo--radio-group-target=\"radio\">\n <span class=\"radio-group-demo__name\"><%= t(\"components.radio_group.demo.basic\") %></span>\n <span class=\"radio-group-demo__desc\"><%= t(\"components.radio_group.demo.basic_desc\") %></span>\n </div>\n <div class=\"radio-group-demo__option\" role=\"radio\" aria-checked=\"false\" tabindex=\"-1\"\n data-value=\"pro\" data-stimeo--radio-group-target=\"radio\">\n <span class=\"radio-group-demo__name\"><%= t(\"components.radio_group.demo.pro\") %></span>\n <span class=\"radio-group-demo__desc\"><%= t(\"components.radio_group.demo.pro_desc\") %></span>\n </div>\n <div class=\"radio-group-demo__option\" role=\"radio\" aria-checked=\"false\" tabindex=\"-1\"\n data-value=\"max\" data-stimeo--radio-group-target=\"radio\">\n <span class=\"radio-group-demo__name\"><%= t(\"components.radio_group.demo.max\") %></span>\n <span class=\"radio-group-demo__desc\"><%= t(\"components.radio_group.demo.max_desc\") %></span>\n </div>\n </div>\n\n <input type=\"hidden\" name=\"plan\" value=\"\" data-stimeo--radio-group-target=\"field\" />\n\n <p class=\"radio-group-demo__status\" aria-live=\"polite\">\n <%= t(\"components.radio_group.demo.selected\") %>\n <span data-radio-value
|
|
298
|
+
"source": "<%# Markup for the radio-group (APG Radio Group) demo.\n A custom card-style radio. Single selection is shown via aria-checked and the single\n tab stop via roving tabindex. Arrows move the selection (focus = selection). The group\n delegates click and keydown, so the radios carry no data-action of their own. The\n selected value is reflected into a hidden field; the look is the consumer's CSS. %>\n<div class=\"radio-group-demo\" role=\"radiogroup\" aria-labelledby=\"rg-label\"\n data-controller=\"stimeo--radio-group\">\n <span class=\"radio-group-demo__legend\" id=\"rg-label\">\n <%= t(\"components.radio_group.demo.legend\") %>\n </span>\n <p class=\"radio-group-demo__hint\"><%= t(\"components.radio_group.demo.hint\") %></p>\n\n <div class=\"radio-group-demo__options\">\n <div class=\"radio-group-demo__option\" role=\"radio\" aria-checked=\"false\" tabindex=\"0\"\n data-value=\"basic\" data-stimeo--radio-group-target=\"radio\">\n <span class=\"radio-group-demo__name\"><%= t(\"components.radio_group.demo.basic\") %></span>\n <span class=\"radio-group-demo__desc\"><%= t(\"components.radio_group.demo.basic_desc\") %></span>\n </div>\n <div class=\"radio-group-demo__option\" role=\"radio\" aria-checked=\"false\" tabindex=\"-1\"\n data-value=\"pro\" data-stimeo--radio-group-target=\"radio\">\n <span class=\"radio-group-demo__name\"><%= t(\"components.radio_group.demo.pro\") %></span>\n <span class=\"radio-group-demo__desc\"><%= t(\"components.radio_group.demo.pro_desc\") %></span>\n </div>\n <div class=\"radio-group-demo__option\" role=\"radio\" aria-checked=\"false\" tabindex=\"-1\"\n data-value=\"max\" data-stimeo--radio-group-target=\"radio\">\n <span class=\"radio-group-demo__name\"><%= t(\"components.radio_group.demo.max\") %></span>\n <span class=\"radio-group-demo__desc\"><%= t(\"components.radio_group.demo.max_desc\") %></span>\n </div>\n </div>\n\n <input type=\"hidden\" name=\"plan\" value=\"\" data-stimeo--radio-group-target=\"field\" />\n\n <p class=\"radio-group-demo__status\" aria-live=\"polite\">\n <%= t(\"components.radio_group.demo.selected\") %>\n <span data-radio-value data-empty-text=\"<%= t(\"components.radio_group.demo.none\") %>\">\n <%= t(\"components.radio_group.demo.none\") %>\n </span>\n </p>\n</div>\n"
|
|
299
299
|
},
|
|
300
300
|
"stimeo--range-slider": {
|
|
301
301
|
"file": "examples/range_slider/_demo.html.erb",
|
|
302
|
-
"source": "<%# Markup for the range-slider (APG Slider, multi-thumb) demo.\n stimeo--range-slider handles the two thumbs' (start / end) mutual constraint\n (lower ≤ upper), keyboard / drag operation, and dynamic updates of each thumb's\n aria-valuemin/max/now, and exposes the range as the root CSS variables\n --stimeo--range-slider-start / --stimeo--range-slider-end (0..1). The thumb\n and range placement is the Playground's CSS using those variables. %>\n<div\n class=\"range-slider\"\n data-controller=\"stimeo--range-slider\"\n data-stimeo--range-slider-min-value=\"0\"\n data-stimeo--range-slider-max-value=\"100\"\n data-stimeo--range-slider-step-value=\"1\"\n data-stimeo--range-slider-start-value=\"20\"\n data-stimeo--range-slider-end-value=\"80\">\n <div class=\"range-slider__track\" data-stimeo--range-slider-target=\"track\"\n data-action=\"pointerdown->stimeo--range-slider#onPointerDown\">\n <div class=\"range-slider__range\" aria-hidden=\"true\"></div>\n <div class=\"range-slider__thumb\" role=\"slider\" tabindex=\"0\"\n aria-label=\"<%= t(\"components.range_slider.demo.min_label\") %>\"\n data-stimeo--range-slider-target=\"startThumb\"\n data-action=\"keydown->stimeo--range-slider#onKeydown\"></div>\n <div class=\"range-slider__thumb\" role=\"slider\" tabindex=\"0\"\n aria-label=\"<%= t(\"components.range_slider.demo.max_label\") %>\"\n data-stimeo--range-slider-target=\"endThumb\"\n data-action=\"keydown->stimeo--range-slider#onKeydown\"></div>\n </div>\n <output class=\"range-slider__output\" data-range-slider-output aria-live=\"polite\">20 – 80</output>\n</div>\n"
|
|
302
|
+
"source": "<%# Markup for the range-slider (APG Slider, multi-thumb) demo.\n stimeo--range-slider handles the two thumbs' (start / end) mutual constraint\n (lower ≤ upper), keyboard / drag operation, and dynamic updates of each thumb's\n aria-valuemin/max/now, and exposes the range as the root CSS variables\n --stimeo--range-slider-start / --stimeo--range-slider-end (0..1). The thumb\n and range placement is the Playground's CSS using those variables. %>\n<div\n class=\"range-slider\"\n data-controller=\"stimeo--range-slider\"\n data-stimeo--range-slider-min-value=\"0\"\n data-stimeo--range-slider-max-value=\"100\"\n data-stimeo--range-slider-step-value=\"1\"\n data-stimeo--range-slider-start-value=\"20\"\n data-stimeo--range-slider-end-value=\"80\">\n <%# The hidden fields carry the range into the form; both are optional. %>\n <input type=\"hidden\" name=\"price_min\" data-stimeo--range-slider-target=\"startField\" />\n <input type=\"hidden\" name=\"price_max\" data-stimeo--range-slider-target=\"endField\" />\n <div class=\"range-slider__track\" data-stimeo--range-slider-target=\"track\"\n data-action=\"pointerdown->stimeo--range-slider#onPointerDown\">\n <div class=\"range-slider__range\" aria-hidden=\"true\"></div>\n <div class=\"range-slider__thumb\" role=\"slider\" tabindex=\"0\"\n aria-label=\"<%= t(\"components.range_slider.demo.min_label\") %>\"\n data-stimeo--range-slider-target=\"startThumb\"\n data-action=\"keydown->stimeo--range-slider#onKeydown\"></div>\n <div class=\"range-slider__thumb\" role=\"slider\" tabindex=\"0\"\n aria-label=\"<%= t(\"components.range_slider.demo.max_label\") %>\"\n data-stimeo--range-slider-target=\"endThumb\"\n data-action=\"keydown->stimeo--range-slider#onKeydown\"></div>\n </div>\n <output class=\"range-slider__output\" data-range-slider-output aria-live=\"polite\">20 – 80</output>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.field\") %></span>\n <span class=\"demo-readout__value\" data-readout\n data-empty-text=\"<%= t(\"catalog.readout.empty\") %>\">—</span>\n</p>\n"
|
|
303
303
|
},
|
|
304
304
|
"stimeo--rating": {
|
|
305
305
|
"file": "examples/rating/_demo.html.erb",
|
|
306
|
-
"source": "<%# Markup for the rating (APG Radio Group, ordinal scale) demo.\n Each symbol is role=\"radio\" with an aria-label (\"3 stars\", etc.). Selection is\n aria-checked; the currently filled range is data-rating-hover (the selected value or\n a hover/focus preview). DOM order defines values 1..N. The star look is the consumer's CSS. %>\n<div class=\"rating-demo-wrap\">\n <p class=\"rating-demo__hint\"><%= t(\"components.rating.demo.hint\") %></p>\n <div class=\"rating-demo\" role=\"radiogroup\" aria-label=\"<%= t('components.rating.demo.label') %>\"\n data-controller=\"stimeo--rating\"\n data-stimeo--rating-value-value=\"0\">\n <% (1..5).each do |n| %>\n <span class=\"rating-demo__star\" role=\"radio\" aria-checked=\"false\"\n aria-label=\"<%= t('components.rating.demo.star', count: n) %>\"\n tabindex=\"<%= n == 1 ? 0 : -1 %>\"\n data-stimeo--rating-target=\"symbol\"\n data-action=\"click->stimeo--rating#select\n mouseenter->stimeo--rating#preview\n mouseleave->stimeo--rating#endPreview\n focus->stimeo--rating#preview\n blur->stimeo--rating#endPreview\n keydown->stimeo--rating#onKeydown\">\n <svg class=\"rating-demo__icon\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path d=\"M12 2l2.9 6.26 6.86.6-5.2 4.52 1.56 6.72L12 17.1 5.88 20.6l1.56-6.72-5.2-4.52\n 6.86-.6z\"></path>\n </svg>\n </span>\n <% end %>\n\n <input type=\"hidden\" name=\"rating\" value=\"0\" data-stimeo--rating-target=\"field\" />\n\n <%# Subscribe to committed and reconciled values to update this instance's status. %>\n <span class=\"rating-demo__status\" aria-live=\"polite\"\n data-empty-text=\"<%= t('components.rating.demo.empty') %>\"\n data-rated-template=\"<%= t('components.rating.demo.rated') %>\"><%= t(\n 'components.rating.demo.empty'\n ) %></span>\n </div>\n</div>\n"
|
|
306
|
+
"source": "<%# Markup for the rating (APG Radio Group, ordinal scale) demo.\n Each symbol is role=\"radio\" with an aria-label (\"3 stars\", etc.). Selection is\n aria-checked; the currently filled range is data-rating-hover (the selected value or\n a hover/focus preview). DOM order defines values 1..N. The star look is the consumer's CSS. %>\n<div class=\"rating-demo-wrap\">\n <p class=\"rating-demo__hint\"><%= t(\"components.rating.demo.hint\") %></p>\n <div class=\"rating-demo\" role=\"radiogroup\" aria-label=\"<%= t('components.rating.demo.label') %>\"\n data-controller=\"stimeo--rating\"\n data-stimeo--rating-value-value=\"0\">\n <% (1..5).each do |n| %>\n <span class=\"rating-demo__star\" role=\"radio\" aria-checked=\"false\"\n aria-label=\"<%= t('components.rating.demo.star', count: n) %>\"\n tabindex=\"<%= n == 1 ? 0 : -1 %>\"\n data-stimeo--rating-target=\"symbol\"\n data-action=\"click->stimeo--rating#select\n mouseenter->stimeo--rating#preview\n mouseleave->stimeo--rating#endPreview\n focus->stimeo--rating#preview\n blur->stimeo--rating#endPreview\n keydown->stimeo--rating#onKeydown\">\n <svg class=\"rating-demo__icon\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n <path d=\"M12 2l2.9 6.26 6.86.6-5.2 4.52 1.56 6.72L12 17.1 5.88 20.6l1.56-6.72-5.2-4.52\n 6.86-.6z\"></path>\n </svg>\n </span>\n <% end %>\n\n <input type=\"hidden\" name=\"rating\" value=\"0\" data-stimeo--rating-target=\"field\" />\n\n <%# Subscribe to committed and reconciled values to update this instance's status. %>\n <span class=\"rating-demo__status\" aria-live=\"polite\"\n data-empty-text=\"<%= t('components.rating.demo.empty') %>\"\n data-rated-template=\"<%= t('components.rating.demo.rated') %>\"><%= t(\n 'components.rating.demo.empty'\n ) %></span>\n </div>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.field\") %></span>\n <span class=\"demo-readout__value\" data-readout\n data-empty-text=\"<%= t(\"catalog.readout.empty\") %>\">—</span>\n</p>\n"
|
|
307
307
|
},
|
|
308
308
|
"stimeo--read-more": {
|
|
309
309
|
"file": "examples/read_more/_demo.html.erb",
|
|
310
|
-
"source": "<%# Markup for the read-more demo.\n The body is visually truncated with a CSS line clamp, and a toggle switches to the\n full text. The library syncs aria-expanded / data-state and
|
|
310
|
+
"source": "<%# Markup for the read-more demo.\n The body is visually truncated with a CSS line clamp, and a toggle switches to the\n full text. The toggle carries both wordings: the library shows the half that belongs\n to the current state and hides the other. It also syncs aria-expanded / data-state and\n hides the whole toggle when there is no overflow (so no needless button appears).\n The clamp itself lives in demo.css. %>\n<div class=\"read-more\" data-controller=\"stimeo--read-more\">\n <p\n class=\"read-more__content\"\n id=\"read-more-demo-content\"\n data-state=\"collapsed\"\n data-stimeo--read-more-target=\"content\">\n <%= t(\"components.read_more.demo.body\") %>\n </p>\n <button\n class=\"read-more__trigger\"\n type=\"button\"\n aria-expanded=\"false\"\n aria-controls=\"read-more-demo-content\"\n hidden\n data-stimeo--read-more-target=\"trigger\"\n data-action=\"click->stimeo--read-more#toggle\">\n <span data-stimeo--read-more-target=\"collapsedLabel\">\n <%= t(\"components.read_more.demo.trigger\") %>\n </span>\n <span data-stimeo--read-more-target=\"expandedLabel\" hidden>\n <%= t(\"components.read_more.demo.trigger_expanded\") %>\n </span>\n </button>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.events\") %></span>\n <span class=\"demo-readout__value\" data-readout>—</span>\n</p>\n"
|
|
311
311
|
},
|
|
312
312
|
"stimeo--reading-progress": {
|
|
313
313
|
"file": "examples/reading_progress/_demo.html.erb",
|
|
@@ -351,7 +351,7 @@
|
|
|
351
351
|
},
|
|
352
352
|
"stimeo--sidebar": {
|
|
353
353
|
"file": "examples/sidebar/_demo.html.erb",
|
|
354
|
-
"source": "<%# Markup for the sidebar (collapsible sidebar) demo.\n This demo focuses on the INLINE rail: the toggle collapses / expands it and the\n preference persists in localStorage across reloads. (The same sidebar can also\n switch to a modal off-canvas panel below a breakpoint — that document-level modal\n mode is described in the text and is the same off-canvas pattern the Drawer demo\n shows; it is not staged here because a page-level modal inside a catalog card reads\n as taking over the page.) breakpoint=0 keeps this demo always inline. The library\n syncs aria-expanded, data-mode, and data-state; the rail width / animation are\n demo.css's. role=\"dialog\" is intentionally not applied — the panel stays a nav. %>\n<div\n class=\"sidebar-demo\"\n data-controller=\"stimeo--sidebar\"\n data-stimeo--sidebar-breakpoint-value=\"0\"\n data-stimeo--sidebar-key-value=\"catalog-demo\">\n <div class=\"sidebar-demo__bar\">\n <button\n type=\"button\"\n class=\"sidebar-demo__toggle\"\n data-stimeo--sidebar-target=\"trigger\"\n data-action=\"click->stimeo--sidebar#toggle\"\n aria-expanded=\"true\"\n aria-controls=\"sidebar-demo-panel\">\n <%= t(\"components.sidebar.demo.toggle\") %>\n </button>\n <span class=\"sidebar-demo__brand\"><%= t(\"components.sidebar.demo.brand\") %></span>\n </div>\n\n <div class=\"sidebar-demo__body\">\n <nav\n id=\"sidebar-demo-panel\"\n class=\"sidebar-demo__panel\"\n data-stimeo--sidebar-target=\"panel\"\n aria-label=\"<%= t('components.sidebar.demo.nav_label') %>\"\n data-mode=\"inline\"\n data-state=\"expanded\">\n <% t(\"components.sidebar.demo.items\").each do |label| %>\n <a class=\"sidebar-demo__link\" href=\"#\"><%= label %></a>\n <% end %>\n </nav>\n\n <main class=\"sidebar-demo__content\">\n <p><%= t(\"components.sidebar.demo.hint\") %></p>\n </main>\n </div>\n</div>\n"
|
|
354
|
+
"source": "<%# Markup for the sidebar (collapsible sidebar) demo.\n This demo focuses on the INLINE rail: the toggle collapses / expands it and the\n preference persists in localStorage across reloads. (The same sidebar can also\n switch to a modal off-canvas panel below a breakpoint — that document-level modal\n mode is described in the text and is the same off-canvas pattern the Drawer demo\n shows; it is not staged here because a page-level modal inside a catalog card reads\n as taking over the page.) breakpoint=0 keeps this demo always inline. The library\n syncs aria-expanded, data-mode, and data-state; the rail width / animation are\n demo.css's. role=\"dialog\" is intentionally not applied — the panel stays a nav. %>\n<div\n class=\"sidebar-demo\"\n data-controller=\"stimeo--sidebar\"\n data-stimeo--sidebar-breakpoint-value=\"0\"\n data-stimeo--sidebar-key-value=\"catalog-demo\">\n <div class=\"sidebar-demo__bar\">\n <button\n type=\"button\"\n class=\"sidebar-demo__toggle\"\n data-stimeo--sidebar-target=\"trigger\"\n data-action=\"click->stimeo--sidebar#toggle\"\n aria-expanded=\"true\"\n aria-controls=\"sidebar-demo-panel\">\n <%= t(\"components.sidebar.demo.toggle\") %>\n </button>\n <span class=\"sidebar-demo__brand\"><%= t(\"components.sidebar.demo.brand\") %></span>\n </div>\n\n <div class=\"sidebar-demo__body\">\n <nav\n id=\"sidebar-demo-panel\"\n class=\"sidebar-demo__panel\"\n data-stimeo--sidebar-target=\"panel\"\n aria-label=\"<%= t('components.sidebar.demo.nav_label') %>\"\n data-mode=\"inline\"\n data-state=\"expanded\">\n <% t(\"components.sidebar.demo.items\").each do |label| %>\n <a class=\"sidebar-demo__link\" href=\"#\"><%= label %></a>\n <% end %>\n </nav>\n\n <main class=\"sidebar-demo__content\">\n <p><%= t(\"components.sidebar.demo.hint\") %></p>\n </main>\n </div>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.events\") %></span>\n <span class=\"demo-readout__value\" data-readout>—</span>\n</p>\n"
|
|
355
355
|
},
|
|
356
356
|
"stimeo--skeleton": {
|
|
357
357
|
"file": "examples/skeleton/_demo.html.erb",
|
|
@@ -359,7 +359,7 @@
|
|
|
359
359
|
},
|
|
360
360
|
"stimeo--slider": {
|
|
361
361
|
"file": "examples/slider/_demo.html.erb",
|
|
362
|
-
"source": "<%# Markup for the slider (APG Slider / single thumb) demo.\n stimeo--slider provides aria-valuemin/max/now plus keyboard and drag operation, and\n exposes the thumb position fraction (0..1) as the root CSS variable\n --stimeo--slider-fraction. The thumb's actual placement is the Playground's CSS\n using that variable. %>\n<div\n class=\"slider\"\n data-controller=\"stimeo--slider\"\n data-stimeo--slider-min-value=\"0\"\n data-stimeo--slider-max-value=\"100\"\n data-stimeo--slider-step-value=\"1\"\n data-stimeo--slider-value-value=\"40\">\n <div class=\"slider__track\" data-stimeo--slider-target=\"track\"\n data-action=\"pointerdown->stimeo--slider#onPointerDown\">\n <div class=\"slider__range\" aria-hidden=\"true\"></div>\n <div class=\"slider__thumb\" role=\"slider\" tabindex=\"0\"\n aria-label=\"<%= t(\"components.slider.demo.label\") %>\"\n data-stimeo--slider-target=\"thumb\"\n data-action=\"keydown->stimeo--slider#onKeydown\"></div>\n </div>\n</div>\n"
|
|
362
|
+
"source": "<%# Markup for the slider (APG Slider / single thumb) demo.\n stimeo--slider provides aria-valuemin/max/now plus keyboard and drag operation, and\n exposes the thumb position fraction (0..1) as the root CSS variable\n --stimeo--slider-fraction. The thumb's actual placement is the Playground's CSS\n using that variable. %>\n<div\n class=\"slider\"\n data-controller=\"stimeo--slider\"\n data-stimeo--slider-min-value=\"0\"\n data-stimeo--slider-max-value=\"100\"\n data-stimeo--slider-step-value=\"1\"\n data-stimeo--slider-value-value=\"40\">\n <%# The hidden field carries the value into the form; it is optional. %>\n <input type=\"hidden\" name=\"volume\" data-stimeo--slider-target=\"field\" />\n <div class=\"slider__track\" data-stimeo--slider-target=\"track\"\n data-action=\"pointerdown->stimeo--slider#onPointerDown\">\n <div class=\"slider__range\" aria-hidden=\"true\"></div>\n <div class=\"slider__thumb\" role=\"slider\" tabindex=\"0\"\n aria-label=\"<%= t(\"components.slider.demo.label\") %>\"\n data-stimeo--slider-target=\"thumb\"\n data-action=\"keydown->stimeo--slider#onKeydown\"></div>\n </div>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.field\") %></span>\n <span class=\"demo-readout__value\" data-readout\n data-empty-text=\"<%= t(\"catalog.readout.empty\") %>\">—</span>\n</p>\n"
|
|
363
363
|
},
|
|
364
364
|
"stimeo--smart-sticky-header": {
|
|
365
365
|
"file": "examples/smart_sticky_header/_demo.html.erb",
|
|
@@ -375,7 +375,7 @@
|
|
|
375
375
|
},
|
|
376
376
|
"stimeo--step-indicator": {
|
|
377
377
|
"file": "examples/step_indicator/_demo.html.erb",
|
|
378
|
-
"source": "<%# Markup for the step-indicator (read-only progress) demo.\n The library holds the current
|
|
378
|
+
"source": "<%# Markup for the step-indicator (read-only progress) demo.\n The library holds the current position, sets data-state on each li, sets\n aria-current=\"step\" on the current li, and updates the progress CSS variable\n (--stimeo--step-indicator-ratio). The steps themselves aren't interactive, so the\n position is moved from the outside: a stepper sits inside and dispatches\n stimeo--stepper:change with { index, previous, total, step }, which the indicator\n receives through setIndex. No consumer JS is involved. %>\n<div class=\"step-indicator-demo\" data-controller=\"stimeo--stepper\"\n data-stimeo--stepper-index-value=\"1\">\n <%# --steps lets the CSS put the track between the first and last dot centres:\n the library's ratio is \"how far along the range\", and the range runs from\n centre to centre, not edge to edge. %>\n <ol\n class=\"step-indicator\"\n style=\"--steps: 4\"\n data-controller=\"stimeo--step-indicator\"\n aria-label=\"<%= t(\"components.step_indicator.demo.label\") %>\"\n data-stimeo--step-indicator-index-value=\"1\"\n data-action=\"stimeo--stepper:change@window->stimeo--step-indicator#setIndex\">\n <% %w[cart shipping payment confirm].each_with_index do |step, index| %>\n <li\n class=\"step-indicator__step\"\n data-stimeo--step-indicator-target=\"step\"\n <%= \"data-state=\\\"complete\\\"\".html_safe if index < 1 %>\n <%= \"data-state=\\\"current\\\" aria-current=\\\"step\\\"\".html_safe if index == 1 %>\n <%= \"data-state=\\\"upcoming\\\"\".html_safe if index > 1 %>>\n <span class=\"step-indicator__dot\"></span>\n <span class=\"step-indicator__label\"><%= t(\n \"components.step_indicator.demo.steps.#{step}\"\n ) %></span>\n </li>\n <% end %>\n </ol>\n\n <%# The stepper owns the position; its own steps stay visually hidden because the\n indicator above is what this demo shows. %>\n <ol class=\"step-indicator__driver\">\n <% %w[cart shipping payment confirm].each_with_index do |step, index| %>\n <li data-stimeo--stepper-target=\"step\">\n <button\n type=\"button\"\n class=\"demo-trigger\"\n data-stimeo--stepper-index-param=\"<%= index %>\"\n data-action=\"click->stimeo--stepper#goto\">\n <%= t(\"components.step_indicator.demo.steps.#{step}\") %>\n </button>\n </li>\n <% end %>\n </ol>\n\n <div class=\"step-indicator__controls\">\n <button type=\"button\" class=\"demo-trigger\" data-action=\"click->stimeo--stepper#prev\">\n <%= t(\"components.step_indicator.demo.back\") %>\n </button>\n <button type=\"button\" class=\"demo-trigger\" data-action=\"click->stimeo--stepper#next\">\n <%= t(\"components.step_indicator.demo.advance\") %>\n </button>\n </div>\n</div>\n"
|
|
379
379
|
},
|
|
380
380
|
"stimeo--stepper": {
|
|
381
381
|
"file": "examples/stepper/_demo.html.erb",
|
|
@@ -383,7 +383,7 @@
|
|
|
383
383
|
},
|
|
384
384
|
"stimeo--stick-to-bottom": {
|
|
385
385
|
"file": "examples/stick_to_bottom/_demo.html.erb",
|
|
386
|
-
"source": "<%# Stick-to-bottom demo: the scrollable log follows new messages while you're at the\n bottom, but holds and
|
|
386
|
+
"source": "<%# Stick-to-bottom demo: the scrollable log follows new messages while you're at the\n bottom, but holds and flags them if you've scrolled up. This catalog has no Action\n Cable / Turbo Stream, so the Add button appends a <li> — exactly the mutation a Turbo\n Stream broadcast would make — and the controller reacts. The jump button lives inside\n the log (a descendant, wired with a plain data-action) and is declared as the hasNew\n target: it carries hidden here, and the controller shows it only while messages have\n arrived that the log did not follow. pin-on-connect starts the log at the bottom so the\n first message is followed rather than flagged — a fresh scroll container renders at the\n top, and the controller does this on every connect, which a once-per-document page event\n cannot. The library follows/flags, reflects data-pinned / data-has-new and owns hidden\n on the jump button; demo.css owns the look.\n\n The log scrolls but its only control — the jump button — is hidden until there is\n something to jump to, so most of the time a keyboard user cannot reach it at all\n (WCAG 2.1.1). Rather than hand-write a tab stop, compose stimeo--scroll-area over it:\n that controller exists for exactly this and gives the viewport tabindex=\"0\" only while\n it holds no rendered focusable content, so the tab stop appears and disappears in step\n with the jump button instead of doubling up with it. It goes on a wrapper because\n stick-to-bottom must sit on the scrolling element itself, and it takes the log as its\n viewport target. role=\"region\" comes free with the label below. %>\n<div class=\"stb-demo\">\n <div class=\"stb-demo__log-wrap\" data-controller=\"stimeo--scroll-area\">\n <div\n class=\"stb-demo__log\"\n data-controller=\"stimeo--stick-to-bottom\"\n data-stimeo--stick-to-bottom-behavior-value=\"smooth\"\n data-stimeo--stick-to-bottom-pin-on-connect-value=\"true\"\n data-stimeo--scroll-area-target=\"viewport\"\n aria-label=\"<%= t(\"components.stick_to_bottom.demo.viewport_label\") %>\">\n <ul class=\"stb-demo__messages\" data-stimeo--stick-to-bottom-target=\"content\">\n <% (1..8).each do |i| %>\n <li><%= t(\"components.stick_to_bottom.demo.message\") %> <%= i %></li>\n <% end %>\n </ul>\n <button\n type=\"button\"\n class=\"stb-demo__jump\"\n data-stimeo--stick-to-bottom-target=\"hasNew\"\n data-action=\"click->stimeo--stick-to-bottom#scrollToBottom\"\n hidden>\n <%= t(\"components.stick_to_bottom.demo.jump\") %>\n </button>\n </div>\n </div>\n <button\n type=\"button\"\n class=\"demo-trigger\"\n data-stb-demo-add\n data-message-label=\"<%= t(\"components.stick_to_bottom.demo.message\") %>\">\n <%= t(\"components.stick_to_bottom.demo.add\") %>\n </button>\n</div>\n"
|
|
387
387
|
},
|
|
388
388
|
"stimeo--sticky-observer": {
|
|
389
389
|
"file": "examples/sticky_observer/_demo.html.erb",
|
|
@@ -395,15 +395,15 @@
|
|
|
395
395
|
},
|
|
396
396
|
"stimeo--switch": {
|
|
397
397
|
"file": "examples/switch/_demo.html.erb",
|
|
398
|
-
"source": "<%# Markup for the switch (APG Switch) demo.\n The controller element itself is a role=\"switch\" button, with state expressed only via\n aria-checked. Space/Enter and click toggle it. The look switches on aria-checked in\n the Playground's CSS. %>\n<button\n type=\"button\"\n class=\"switch\"\n role=\"switch\"\n aria-checked=\"false\"\n data-controller=\"stimeo--switch\"\n data-action=\"click->stimeo--switch#toggle keydown->stimeo--switch#onKeydown\">\n <span class=\"switch__track\" aria-hidden=\"true\"><span class=\"switch__thumb\"></span></span>\n <span class=\"switch__label\"><%= t(\"components.switch.demo.label\") %></span>\n</button>\n"
|
|
398
|
+
"source": "<%# Markup for the switch (APG Switch) demo.\n The controller element itself is a role=\"switch\" button, with state expressed only via\n aria-checked. Space/Enter and click toggle it. The look switches on aria-checked in\n the Playground's CSS. %>\n<button\n type=\"button\"\n class=\"switch\"\n role=\"switch\"\n aria-checked=\"false\"\n data-controller=\"stimeo--switch\"\n data-action=\"click->stimeo--switch#toggle keydown->stimeo--switch#onKeydown\">\n <span class=\"switch__track\" aria-hidden=\"true\"><span class=\"switch__thumb\"></span></span>\n <span class=\"switch__label\"><%= t(\"components.switch.demo.label\") %></span>\n <%# The hidden field carries the on/off state into the form; it is optional.\n A hidden input is not interactive content, so it is valid inside the button. %>\n <input type=\"hidden\" name=\"notify\" data-stimeo--switch-target=\"field\" />\n</button>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.field\") %></span>\n <span class=\"demo-readout__value\" data-readout\n data-empty-text=\"<%= t(\"catalog.readout.empty\") %>\">—</span>\n</p>\n"
|
|
399
399
|
},
|
|
400
400
|
"stimeo--tabs": {
|
|
401
401
|
"file": "examples/tabs/_demo.html.erb",
|
|
402
|
-
"source": "<%# Markup for the tabs (APG Tabs / automatic activation) demo.\n stimeo--tabs provides aria-selected, roving tabindex, arrow-key switching, and panel\n visibility control. The initially selected tab has aria-selected=\"true\" and\n non-selected panels carry hidden (to prevent SSR flicker). %>\n<div class=\"tabs\" data-controller=\"stimeo--tabs\">\n <div class=\"tabs__list\" role=\"tablist\" aria-label=\"<%= t(\"components.tabs.demo.label\") %>\"\n data-stimeo--tabs-target=\"list\">\n <button class=\"tabs__tab\" role=\"tab\" id=\"tab-overview\" aria-controls=\"panel-overview\"\n aria-selected=\"true\"\n data-stimeo--tabs-target=\"tab\"\n data-action=\"click->stimeo--tabs#select\n keydown->stimeo--tabs#onKeydown\"><%= t(\n \"components.tabs.demo.overview\"\n ) %></button>\n <button class=\"tabs__tab\" role=\"tab\" id=\"tab-profile\" aria-controls=\"panel-profile\"\n aria-selected=\"false\" tabindex=\"-1\"\n data-stimeo--tabs-target=\"tab\"\n data-action=\"click->stimeo--tabs#select\n keydown->stimeo--tabs#onKeydown\"><%= t(\n \"components.tabs.demo.profile\"\n ) %></button>\n <button class=\"tabs__tab\" role=\"tab\" id=\"tab-billing\" aria-controls=\"panel-billing\"\n aria-selected=\"false\" tabindex=\"-1\"\n data-stimeo--tabs-target=\"tab\"\n data-action=\"click->stimeo--tabs#select\n keydown->stimeo--tabs#onKeydown\"><%= t(\n \"components.tabs.demo.billing\"\n ) %></button>\n </div>\n\n <div class=\"tabs__panel\" role=\"tabpanel\" id=\"panel-overview\" aria-labelledby=\"tab-overview\"\n data-stimeo--tabs-target=\"panel\"><%= t(\"components.tabs.demo.overview_content\") %></div>\n <div class=\"tabs__panel\" role=\"tabpanel\" id=\"panel-profile\" aria-labelledby=\"tab-profile\"\n data-stimeo--tabs-target=\"panel\" hidden><%= t(\n \"components.tabs.demo.profile_content\"\n ) %></div>\n <div class=\"tabs__panel\" role=\"tabpanel\" id=\"panel-billing\" aria-labelledby=\"tab-billing\"\n data-stimeo--tabs-target=\"panel\" hidden><%= t(\n \"components.tabs.demo.billing_content\"\n ) %></div>\n</div>\n"
|
|
402
|
+
"source": "<%# Markup for the tabs (APG Tabs / automatic activation) demo.\n stimeo--tabs provides aria-selected, roving tabindex, arrow-key switching, and panel\n visibility control. The initially selected tab has aria-selected=\"true\" and\n non-selected panels carry hidden (to prevent SSR flicker). %>\n<div class=\"tabs\" data-controller=\"stimeo--tabs\">\n <div class=\"tabs__list\" role=\"tablist\" aria-label=\"<%= t(\"components.tabs.demo.label\") %>\"\n data-stimeo--tabs-target=\"list\">\n <button class=\"tabs__tab\" role=\"tab\" id=\"tab-overview\" aria-controls=\"panel-overview\"\n aria-selected=\"true\"\n data-stimeo--tabs-target=\"tab\"\n data-action=\"click->stimeo--tabs#select\n keydown->stimeo--tabs#onKeydown\"><%= t(\n \"components.tabs.demo.overview\"\n ) %></button>\n <button class=\"tabs__tab\" role=\"tab\" id=\"tab-profile\" aria-controls=\"panel-profile\"\n aria-selected=\"false\" tabindex=\"-1\"\n data-stimeo--tabs-target=\"tab\"\n data-action=\"click->stimeo--tabs#select\n keydown->stimeo--tabs#onKeydown\"><%= t(\n \"components.tabs.demo.profile\"\n ) %></button>\n <button class=\"tabs__tab\" role=\"tab\" id=\"tab-billing\" aria-controls=\"panel-billing\"\n aria-selected=\"false\" tabindex=\"-1\"\n data-stimeo--tabs-target=\"tab\"\n data-action=\"click->stimeo--tabs#select\n keydown->stimeo--tabs#onKeydown\"><%= t(\n \"components.tabs.demo.billing\"\n ) %></button>\n </div>\n\n <div class=\"tabs__panel\" role=\"tabpanel\" id=\"panel-overview\" aria-labelledby=\"tab-overview\"\n data-stimeo--tabs-target=\"panel\"><%= t(\"components.tabs.demo.overview_content\") %></div>\n <div class=\"tabs__panel\" role=\"tabpanel\" id=\"panel-profile\" aria-labelledby=\"tab-profile\"\n data-stimeo--tabs-target=\"panel\" hidden><%= t(\n \"components.tabs.demo.profile_content\"\n ) %></div>\n <div class=\"tabs__panel\" role=\"tabpanel\" id=\"panel-billing\" aria-labelledby=\"tab-billing\"\n data-stimeo--tabs-target=\"panel\" hidden><%= t(\n \"components.tabs.demo.billing_content\"\n ) %></div>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.events\") %></span>\n <span class=\"demo-readout__value\" data-readout\n data-change-template=\"<%= t(\"catalog.readout.tabs_change\") %>\">—</span>\n</p>\n"
|
|
403
403
|
},
|
|
404
404
|
"stimeo--tags-input": {
|
|
405
405
|
"file": "examples/tags_input/_demo.html.erb",
|
|
406
|
-
"source": "<%# Markup for the tags-input demo.\n Enter or a comma (delimiter) turns the input value into a tag, blocking duplicates /\n empties / over-limit. Tag remove buttons move via roving (left/right keys), and\n Backspace on an empty input deletes the previous tag. The library handles tag\n create/remove, hidden-field sync, focus handoff, and the add / remove announcements\n read by the shared stimeo--announcer your app seats once, in its layout (the tag list\n owns no live region of its own). %>\n<% announce_added = t(\"components.tags_input.demo.announce_added\") %>\n<% announce_removed = t(\"components.tags_input.demo.announce_removed\") %>\n<% remove_label = t(\"components.tags_input.demo.remove_label\") %>\n<div class=\"tags-input\" data-controller=\"stimeo--tags-input\"\n data-stimeo--tags-input-delimiter-value=\",\"\n data-stimeo--tags-input-name-value=\"frameworks[]\"\n data-stimeo--tags-input-announce-text-value=\"<%= announce_added %>\"\n data-stimeo--tags-input-announce-removed-text-value=\"<%= announce_removed %>\">\n <ul\n class=\"tags-input__tags\"\n role=\"list\"\n aria-label=\"<%= t(\"components.tags_input.demo.tags_label\") %>\"\n data-stimeo--tags-input-target=\"tags\"
|
|
406
|
+
"source": "<%# Markup for the tags-input demo.\n Enter or a comma (delimiter) turns the input value into a tag, blocking duplicates /\n empties / over-limit. Tag remove buttons move via roving (left/right keys), and\n Backspace on an empty input deletes the previous tag. The library handles tag\n create/remove, hidden-field sync, focus handoff, and the add / remove announcements\n read by the shared stimeo--announcer your app seats once, in its layout (the tag list\n owns no live region of its own). %>\n<% announce_added = t(\"components.tags_input.demo.announce_added\") %>\n<% announce_removed = t(\"components.tags_input.demo.announce_removed\") %>\n<% remove_label = t(\"components.tags_input.demo.remove_label\") %>\n<%# Tags the demo starts with, so the list is not empty on arrival and the hidden\n fields already carry a value. Framework names are product names, not copy, so\n they are written here rather than in the locales. %>\n<% initial_tags = %w[Rails Hotwire] %>\n<div class=\"tags-input\" data-controller=\"stimeo--tags-input\"\n data-stimeo--tags-input-delimiter-value=\",\"\n data-stimeo--tags-input-name-value=\"frameworks[]\"\n data-stimeo--tags-input-announce-text-value=\"<%= announce_added %>\"\n data-stimeo--tags-input-announce-removed-text-value=\"<%= announce_removed %>\">\n <ul\n class=\"tags-input__tags\"\n role=\"list\"\n aria-label=\"<%= t(\"components.tags_input.demo.tags_label\") %>\"\n data-stimeo--tags-input-target=\"tags\">\n <%# Same shape the tagTemplate clones; the controller reads data-value and\n seeds the roving tabindex from these on connect. %>\n <% initial_tags.each do |tag| %>\n <li class=\"tags-input__tag\" role=\"listitem\"\n data-stimeo--tags-input-target=\"tag\" data-value=\"<%= tag %>\">\n <span data-stimeo--tags-input-target=\"label\"><%= tag %></span>\n <button\n type=\"button\"\n class=\"tags-input__remove\"\n tabindex=\"-1\"\n aria-label=\"<%= remove_label.sub(\"{label}\", tag) %>\"\n data-stimeo--tags-input-target=\"remove\">×</button>\n </li>\n <% end %>\n </ul>\n\n <input\n type=\"text\"\n class=\"tags-input__input\"\n aria-label=\"<%= t(\"components.tags_input.demo.input_label\") %>\"\n placeholder=\"<%= t(\"components.tags_input.demo.input_label\") %>\"\n aria-describedby=\"tags-input-help\"\n data-stimeo--tags-input-target=\"input\"\n data-action=\"keydown->stimeo--tags-input#onKeydown\" />\n\n <span id=\"tags-input-help\" class=\"tags-input__help\">\n <%= t(\"components.tags_input.demo.help\") %>\n </span>\n\n <%# The library creates and syncs the submit hidden inputs as name=\"frameworks[]\". %>\n <div hidden data-stimeo--tags-input-target=\"fields\"></div>\n\n <template data-stimeo--tags-input-target=\"tagTemplate\">\n <li class=\"tags-input__tag\" role=\"listitem\" data-stimeo--tags-input-target=\"tag\">\n <span data-stimeo--tags-input-target=\"label\"></span>\n <%# Removal is handled by a delegated listener on the tags container, so it\n works instantly without waiting on Stimulus wiring a data-action onto the\n dynamically-added button. %>\n <button\n type=\"button\"\n class=\"tags-input__remove\"\n tabindex=\"-1\"\n aria-label=\"<%= remove_label %>\"\n data-stimeo--tags-input-target=\"remove\">×</button>\n </li>\n </template>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.field\") %></span>\n <span class=\"demo-readout__value\" data-readout\n data-empty-text=\"<%= t(\"catalog.readout.empty\") %>\">—</span>\n</p>\n"
|
|
407
407
|
},
|
|
408
408
|
"stimeo--textarea-autosize": {
|
|
409
409
|
"file": "examples/textarea_autosize/_demo.html.erb",
|
|
@@ -419,11 +419,11 @@
|
|
|
419
419
|
},
|
|
420
420
|
"stimeo--toast": {
|
|
421
421
|
"file": "examples/toast/_demo.html.erb",
|
|
422
|
-
"source": "<%# Markup for the toast demo.\n The single source used for both the live render and the copy-paste code.\n stimeo--toast provides max-count management, WAI-ARIA live region support, and\n pausing the auto-dismiss timer on hover or keyboard focus.\n\n Showing a toast is done with attributes alone (no hand-written JS):\n put data-action=\"click->stimeo--toast#show\" plus\n data-stimeo--toast-
|
|
422
|
+
"source": "<%# Markup for the toast demo.\n The single source used for both the live render and the copy-paste code.\n stimeo--toast provides max-count management, WAI-ARIA live region support, and\n pausing the auto-dismiss timer on hover or keyboard focus.\n\n Showing a toast is done with attributes alone (no hand-written JS):\n put data-action=\"click->stimeo--toast#show\" plus\n data-stimeo--toast-message-param / data-stimeo--toast-type-param on the trigger button.\n For advanced cases where you want to trigger it remotely from JS, the controller\n element keeps show->stimeo--toast#show, so CustomEvent('show', { detail }) works too. %>\n<div\n class=\"toast-demo\"\n data-controller=\"stimeo--toast\"\n data-stimeo--toast-duration-value=\"5000\"\n data-stimeo--toast-max-value=\"3\"\n data-action=\"show->stimeo--toast#show\">\n\n <div class=\"toast-demo__triggers\">\n <button\n type=\"button\"\n class=\"demo-trigger toast-demo__btn--status\"\n data-action=\"click->stimeo--toast#show\"\n data-stimeo--toast-message-param=\"<%= t(\"components.toast.demo.status_message\") %>\"\n data-stimeo--toast-type-param=\"status\">\n <%= t(\"components.toast.demo.show_status\") %>\n </button>\n\n <button\n type=\"button\"\n class=\"demo-trigger toast-demo__btn--alert\"\n data-action=\"click->stimeo--toast#show\"\n data-stimeo--toast-message-param=\"<%= t(\"components.toast.demo.alert_message\") %>\"\n data-stimeo--toast-type-param=\"alert\">\n <%= t(\"components.toast.demo.show_alert\") %>\n </button>\n </div>\n\n <%# The live region is a descendant of the controller. The controller element only\n needs to contain the trigger and the list/template; role=\"region\" goes on this\n inner container. %>\n <div\n id=\"playground-toast\"\n role=\"region\"\n aria-label=\"<%= t(\"components.toast.demo.region_label\") %>\"\n class=\"toast-container\">\n \n <%# The element where notifications are placed. %>\n <ol class=\"toast-list\" data-stimeo--toast-target=\"list\"></ol>\n\n <%# Template used to create new toasts. %>\n <template data-stimeo--toast-target=\"template\">\n <li\n class=\"toast-item\"\n data-stimeo--toast-target=\"item\"\n tabindex=\"0\">\n <div class=\"toast-item__content\">\n <span role=\"status\" data-toast-slot=\"message\" class=\"toast-item__body\"></span>\n <button\n type=\"button\"\n class=\"toast-item__dismiss\"\n data-toast-dismiss\n aria-label=\"<%= t(\"components.toast.demo.dismiss_label\") %>\">\n <svg\n class=\"toast-item__icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </button>\n </div>\n </li>\n </template>\n </div>\n</div>\n"
|
|
423
423
|
},
|
|
424
424
|
"stimeo--toggle-group": {
|
|
425
425
|
"file": "examples/toggle_group/_demo.html.erb",
|
|
426
|
-
"source": "<%# Markup for the toggle-group demo: multiple selection, single selection, and\n unavailable items. The group delegates click and keydown, so the items carry\n no data-action of their own. %>\n<div class=\"toggle-group-demo-suite\">\n <section class=\"toggle-group-demo__example\">\n <h3 class=\"toggle-group-demo__heading\" id=\"toggle-group-multiple-heading\">\n <%= t(\"components.toggle_group.demo.multiple_heading\") %>\n </h3>\n <div class=\"toggle-group-demo\" role=\"group\"\n aria-labelledby=\"toggle-group-multiple-heading\"\n data-controller=\"stimeo--toggle-group\">\n <button type=\"button\" class=\"toggle-group-demo__item\" aria-pressed=\"false\" tabindex=\"0\"\n aria-label=\"<%= t('components.toggle_group.demo.bold') %>\" data-value=\"bold\"\n data-stimeo--toggle-group-target=\"item\">\n <svg class=\"demo-icon\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M6 4h8a4 4 0 0 1 0 8H6z\"></path>\n <path d=\"M6 12h9a4 4 0 0 1 0 8H6z\"></path>\n </svg>\n </button>\n <button type=\"button\" class=\"toggle-group-demo__item\" aria-pressed=\"false\" tabindex=\"-1\"\n aria-label=\"<%= t('components.toggle_group.demo.italic') %>\" data-value=\"italic\"\n data-stimeo--toggle-group-target=\"item\">\n <svg class=\"demo-icon\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <line x1=\"19\" y1=\"4\" x2=\"10\" y2=\"4\"></line>\n <line x1=\"14\" y1=\"20\" x2=\"5\" y2=\"20\"></line>\n <line x1=\"15\" y1=\"4\" x2=\"9\" y2=\"20\"></line>\n </svg>\n </button>\n <button type=\"button\" class=\"toggle-group-demo__item\" aria-pressed=\"false\" tabindex=\"-1\"\n aria-label=\"<%= t('components.toggle_group.demo.underline') %>\" data-value=\"underline\"\n data-stimeo--toggle-group-target=\"item\">\n <svg class=\"demo-icon\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M6 3v7a6 6 0 0 0 12 0V3\"></path>\n <line x1=\"4\" y1=\"21\" x2=\"20\" y2=\"21\"></line>\n </svg>\n </button>\n </div>\n </section>\n\n <section class=\"toggle-group-demo__example\">\n <h3 class=\"toggle-group-demo__heading\" id=\"toggle-group-single-heading\">\n <%= t(\"components.toggle_group.demo.single_heading\") %>\n </h3>\n <div class=\"toggle-group-demo\" role=\"group\"\n aria-labelledby=\"toggle-group-single-heading\"\n data-controller=\"stimeo--toggle-group\"\n data-stimeo--toggle-group-mode-value=\"single\">\n <button type=\"button\" class=\"toggle-group-demo__item\" aria-pressed=\"true\" tabindex=\"0\"\n aria-label=\"<%= t('components.toggle_group.demo.align_left') %>\" data-value=\"left\"\n data-stimeo--toggle-group-target=\"item\">\n <svg class=\"demo-icon\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" aria-hidden=\"true\">\n <path d=\"M4 6h16M4 10h11M4 14h16M4 18h9\"></path>\n </svg>\n </button>\n <button type=\"button\" class=\"toggle-group-demo__item\" aria-pressed=\"false\" tabindex=\"-1\"\n aria-label=\"<%= t('components.toggle_group.demo.align_center') %>\" data-value=\"center\"\n data-stimeo--toggle-group-target=\"item\">\n <svg class=\"demo-icon\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" aria-hidden=\"true\">\n <path d=\"M4 6h16M6 10h12M4 14h16M7 18h10\"></path>\n </svg>\n </button>\n <button type=\"button\" class=\"toggle-group-demo__item\" aria-pressed=\"false\" tabindex=\"-1\"\n aria-label=\"<%= t('components.toggle_group.demo.align_right') %>\" data-value=\"right\"\n data-stimeo--toggle-group-target=\"item\">\n <svg class=\"demo-icon\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" aria-hidden=\"true\">\n <path d=\"M4 6h16M9 10h11M4 14h16M11 18h9\"></path>\n </svg>\n </button>\n </div>\n </section>\n\n <section class=\"toggle-group-demo__example\">\n <h3 class=\"toggle-group-demo__heading\" id=\"toggle-group-disabled-heading\">\n <%= t(\"components.toggle_group.demo.disabled_heading\") %>\n </h3>\n <div class=\"toggle-group-demo\" role=\"group\"\n aria-labelledby=\"toggle-group-disabled-heading\"\n data-controller=\"stimeo--toggle-group\">\n <button type=\"button\" class=\"toggle-group-demo__item toggle-group-demo__item--wide\"\n aria-pressed=\"false\" tabindex=\"0\" data-value=\"available\"\n data-stimeo--toggle-group-target=\"item\">\n <%= t(\"components.toggle_group.demo.available\") %>\n </button>\n <button type=\"button\" class=\"toggle-group-demo__item toggle-group-demo__item--wide\"\n aria-pressed=\"false\" tabindex=\"-1\" data-value=\"native-disabled\" disabled\n data-stimeo--toggle-group-target=\"item\">\n <%= t(\"components.toggle_group.demo.native_disabled\") %>\n </button>\n <button type=\"button\" class=\"toggle-group-demo__item toggle-group-demo__item--wide\"\n aria-pressed=\"false\" tabindex=\"-1\" data-value=\"aria-disabled\" aria-disabled=\"true\"\n data-stimeo--toggle-group-target=\"item\">\n <%= t(\"components.toggle_group.demo.aria_disabled\") %>\n </button>\n </div>\n </section>\n</div>\n"
|
|
426
|
+
"source": "<%# Markup for the toggle-group demo: multiple selection, single selection, and\n unavailable items. The group delegates click and keydown, so the items carry\n no data-action of their own. %>\n<div class=\"toggle-group-demo-suite\">\n <section class=\"toggle-group-demo__example\">\n <h3 class=\"toggle-group-demo__heading\" id=\"toggle-group-multiple-heading\">\n <%= t(\"components.toggle_group.demo.multiple_heading\") %>\n </h3>\n <div class=\"toggle-group-demo\" role=\"group\"\n aria-labelledby=\"toggle-group-multiple-heading\"\n data-controller=\"stimeo--toggle-group\"\n data-stimeo--toggle-group-name-value=\"styles[]\">\n <%# The container the pressed items' data-value are generated into as hidden\n inputs; it is optional. %>\n <div data-stimeo--toggle-group-target=\"fields\"></div>\n <button type=\"button\" class=\"toggle-group-demo__item\" aria-pressed=\"false\" tabindex=\"0\"\n aria-label=\"<%= t('components.toggle_group.demo.bold') %>\" data-value=\"bold\"\n data-stimeo--toggle-group-target=\"item\">\n <svg class=\"demo-icon\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M6 4h8a4 4 0 0 1 0 8H6z\"></path>\n <path d=\"M6 12h9a4 4 0 0 1 0 8H6z\"></path>\n </svg>\n </button>\n <button type=\"button\" class=\"toggle-group-demo__item\" aria-pressed=\"false\" tabindex=\"-1\"\n aria-label=\"<%= t('components.toggle_group.demo.italic') %>\" data-value=\"italic\"\n data-stimeo--toggle-group-target=\"item\">\n <svg class=\"demo-icon\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <line x1=\"19\" y1=\"4\" x2=\"10\" y2=\"4\"></line>\n <line x1=\"14\" y1=\"20\" x2=\"5\" y2=\"20\"></line>\n <line x1=\"15\" y1=\"4\" x2=\"9\" y2=\"20\"></line>\n </svg>\n </button>\n <button type=\"button\" class=\"toggle-group-demo__item\" aria-pressed=\"false\" tabindex=\"-1\"\n aria-label=\"<%= t('components.toggle_group.demo.underline') %>\" data-value=\"underline\"\n data-stimeo--toggle-group-target=\"item\">\n <svg class=\"demo-icon\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M6 3v7a6 6 0 0 0 12 0V3\"></path>\n <line x1=\"4\" y1=\"21\" x2=\"20\" y2=\"21\"></line>\n </svg>\n </button>\n </div>\n </section>\n\n <section class=\"toggle-group-demo__example\">\n <h3 class=\"toggle-group-demo__heading\" id=\"toggle-group-single-heading\">\n <%= t(\"components.toggle_group.demo.single_heading\") %>\n </h3>\n <div class=\"toggle-group-demo\" role=\"group\"\n aria-labelledby=\"toggle-group-single-heading\"\n data-controller=\"stimeo--toggle-group\"\n data-stimeo--toggle-group-mode-value=\"single\"\n data-stimeo--toggle-group-name-value=\"align\">\n <%# single mode submits 0 or 1 value through the same container. %>\n <div data-stimeo--toggle-group-target=\"fields\"></div>\n <button type=\"button\" class=\"toggle-group-demo__item\" aria-pressed=\"true\" tabindex=\"0\"\n aria-label=\"<%= t('components.toggle_group.demo.align_left') %>\" data-value=\"left\"\n data-stimeo--toggle-group-target=\"item\">\n <svg class=\"demo-icon\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" aria-hidden=\"true\">\n <path d=\"M4 6h16M4 10h11M4 14h16M4 18h9\"></path>\n </svg>\n </button>\n <button type=\"button\" class=\"toggle-group-demo__item\" aria-pressed=\"false\" tabindex=\"-1\"\n aria-label=\"<%= t('components.toggle_group.demo.align_center') %>\" data-value=\"center\"\n data-stimeo--toggle-group-target=\"item\">\n <svg class=\"demo-icon\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" aria-hidden=\"true\">\n <path d=\"M4 6h16M6 10h12M4 14h16M7 18h10\"></path>\n </svg>\n </button>\n <button type=\"button\" class=\"toggle-group-demo__item\" aria-pressed=\"false\" tabindex=\"-1\"\n aria-label=\"<%= t('components.toggle_group.demo.align_right') %>\" data-value=\"right\"\n data-stimeo--toggle-group-target=\"item\">\n <svg class=\"demo-icon\" viewBox=\"0 0 24 24\" fill=\"none\"\n stroke=\"currentColor\" stroke-width=\"2\"\n stroke-linecap=\"round\" aria-hidden=\"true\">\n <path d=\"M4 6h16M9 10h11M4 14h16M11 18h9\"></path>\n </svg>\n </button>\n </div>\n </section>\n\n <section class=\"toggle-group-demo__example\">\n <h3 class=\"toggle-group-demo__heading\" id=\"toggle-group-disabled-heading\">\n <%= t(\"components.toggle_group.demo.disabled_heading\") %>\n </h3>\n <div class=\"toggle-group-demo\" role=\"group\"\n aria-labelledby=\"toggle-group-disabled-heading\"\n data-controller=\"stimeo--toggle-group\"\n data-stimeo--toggle-group-name-value=\"filters[]\">\n <%# Unavailable items can never be pressed, so they never reach the container. %>\n <div data-stimeo--toggle-group-target=\"fields\"></div>\n <button type=\"button\" class=\"toggle-group-demo__item toggle-group-demo__item--wide\"\n aria-pressed=\"false\" tabindex=\"0\" data-value=\"available\"\n data-stimeo--toggle-group-target=\"item\">\n <%= t(\"components.toggle_group.demo.available\") %>\n </button>\n <button type=\"button\" class=\"toggle-group-demo__item toggle-group-demo__item--wide\"\n aria-pressed=\"false\" tabindex=\"-1\" data-value=\"native-disabled\" disabled\n data-stimeo--toggle-group-target=\"item\">\n <%= t(\"components.toggle_group.demo.native_disabled\") %>\n </button>\n <button type=\"button\" class=\"toggle-group-demo__item toggle-group-demo__item--wide\"\n aria-pressed=\"false\" tabindex=\"-1\" data-value=\"aria-disabled\" aria-disabled=\"true\"\n data-stimeo--toggle-group-target=\"item\">\n <%= t(\"components.toggle_group.demo.aria_disabled\") %>\n </button>\n </div>\n </section>\n</div>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.field\") %></span>\n <span class=\"demo-readout__value\" data-readout\n data-empty-text=\"<%= t(\"catalog.readout.empty\") %>\">—</span>\n</p>\n"
|
|
427
427
|
},
|
|
428
428
|
"stimeo--toolbar": {
|
|
429
429
|
"file": "examples/toolbar/_demo.html.erb",
|
|
@@ -431,7 +431,7 @@
|
|
|
431
431
|
},
|
|
432
432
|
"stimeo--tooltip": {
|
|
433
433
|
"file": "examples/tooltip/_demo.html.erb",
|
|
434
|
-
"source": "<%# Markup for the tooltip demo.\n Hover/focus on the trigger shows the supplementary description. The content is\n role=\"tooltip\", referenced from the trigger via aria-describedby. The show/hide delay\n and the hoverable bridge between trigger and tooltip are the library's. Placement is\n the consumer's CSS. %>\n<span class=\"tooltip\" data-controller=\"stimeo--tooltip\"\n data-stimeo--tooltip-show-delay-value=\"150\"\n data-stimeo--tooltip-hide-delay-value=\"200\">\n <button\n class=\"demo-trigger\"\n type=\"button\"\n data-stimeo--tooltip-target=\"trigger\"\n aria-describedby=\"tooltip-content\"\n data-action=\"\n mouseenter->stimeo--tooltip#show\n mouseleave->stimeo--tooltip#hide\n focusin->stimeo--tooltip#show\n focusout->stimeo--tooltip#hide\">\n <%= t(\"components.tooltip.demo.trigger\") %>\n </button>\n <span\n class=\"tooltip__content\"\n id=\"tooltip-content\"\n role=\"tooltip\"\n data-stimeo--tooltip-target=\"content\"\n data-action=\"\n mouseenter->stimeo--tooltip#show\n mouseleave->stimeo--tooltip#hide\"\n hidden>\n <%= t(\"components.tooltip.demo.body\") %>\n </span>\n</span>\n"
|
|
434
|
+
"source": "<%# Markup for the tooltip demo.\n Hover/focus on the trigger shows the supplementary description. The content is\n role=\"tooltip\", referenced from the trigger via aria-describedby. The show/hide delay\n and the hoverable bridge between trigger and tooltip are the library's. Placement is\n the consumer's CSS. %>\n<span class=\"tooltip\" data-controller=\"stimeo--tooltip\"\n data-stimeo--tooltip-show-delay-value=\"150\"\n data-stimeo--tooltip-hide-delay-value=\"200\">\n <button\n class=\"demo-trigger\"\n type=\"button\"\n data-stimeo--tooltip-target=\"trigger\"\n aria-describedby=\"tooltip-content\"\n data-action=\"\n mouseenter->stimeo--tooltip#show\n mouseleave->stimeo--tooltip#hide\n focusin->stimeo--tooltip#show\n focusout->stimeo--tooltip#hide\">\n <%= t(\"components.tooltip.demo.trigger\") %>\n </button>\n <span\n class=\"tooltip__content\"\n id=\"tooltip-content\"\n role=\"tooltip\"\n data-stimeo--tooltip-target=\"content\"\n data-action=\"\n mouseenter->stimeo--tooltip#show\n mouseleave->stimeo--tooltip#hide\"\n hidden>\n <%= t(\"components.tooltip.demo.body\") %>\n </span>\n</span>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.events\") %></span>\n <span class=\"demo-readout__value\" data-readout>—</span>\n</p>\n"
|
|
435
435
|
},
|
|
436
436
|
"stimeo--transition": {
|
|
437
437
|
"file": "examples/transition/_demo.html.erb",
|
|
@@ -439,7 +439,7 @@
|
|
|
439
439
|
},
|
|
440
440
|
"stimeo--tree-view": {
|
|
441
441
|
"file": "examples/tree_view/_demo.html.erb",
|
|
442
|
-
"source": "<%# Markup for the tree-view (tree view / single selection) demo.\n Nested role=\"tree\" / \"treeitem\" / \"group\" express the hierarchy. Arrows move between\n visible items; ArrowRight / ArrowLeft expand/collapse and move between parent/child;\n Home/End, typeahead, and Enter/Space select a single item. The library handles roving,\n aria-expanded / aria-selected sync, and toggling each group's hidden. Across the whole\n tree only one treeitem is tabindex=0.\n The chevron is an optional pointer affordance wired to the toggle action. It stays\n tabindex=\"-1\" (the tree remains a single Tab stop) and aria-hidden (the item itself\n already announces its expanded state); clicking it expands/collapses without selecting,\n because the tree never consumes events raised inside a nested control. The toggle action\n hands focus to the row afterwards, so focus never rests on this decorative button and\n the arrow keys keep working right after a click. %>\n<ul class=\"tree-view\" data-controller=\"stimeo--tree-view\" role=\"tree\"\n aria-label=\"<%= t('components.tree_view.demo.label') %>\">\n <li\n class=\"tree-view__item\"\n role=\"treeitem\"\n aria-expanded=\"true\"\n aria-selected=\"false\"\n tabindex=\"0\"\n data-stimeo--tree-view-target=\"item\"\n data-action=\"keydown->stimeo--tree-view#onKeydown click->stimeo--tree-view#onClick\">\n <button type=\"button\" class=\"tree-view__chevron\" tabindex=\"-1\" aria-hidden=\"true\"\n data-action=\"click->stimeo--tree-view#toggle\"></button>\n <span class=\"tree-view__label\">app</span>\n <ul class=\"tree-view__group\" role=\"group\" data-stimeo--tree-view-target=\"group\">\n <li\n class=\"tree-view__item\"\n role=\"treeitem\"\n aria-expanded=\"false\"\n aria-selected=\"false\"\n tabindex=\"-1\"\n data-stimeo--tree-view-target=\"item\"\n data-action=\"keydown->stimeo--tree-view#onKeydown click->stimeo--tree-view#onClick\">\n <button type=\"button\" class=\"tree-view__chevron\" tabindex=\"-1\" aria-hidden=\"true\"\n data-action=\"click->stimeo--tree-view#toggle\"></button>\n <span class=\"tree-view__label\">controllers</span>\n <ul class=\"tree-view__group\" role=\"group\" data-stimeo--tree-view-target=\"group\" hidden>\n <li class=\"tree-view__item\" role=\"treeitem\" aria-selected=\"false\"
|
|
442
|
+
"source": "<%# Markup for the tree-view (tree view / single selection) demo.\n Nested role=\"tree\" / \"treeitem\" / \"group\" express the hierarchy. Arrows move between\n visible items; ArrowRight / ArrowLeft expand/collapse and move between parent/child;\n Home/End, typeahead, and Enter/Space select a single item. The library handles roving,\n aria-expanded / aria-selected sync, and toggling each group's hidden. Across the whole\n tree only one treeitem is tabindex=0.\n The chevron is an optional pointer affordance wired to the toggle action. It stays\n tabindex=\"-1\" (the tree remains a single Tab stop) and aria-hidden (the item itself\n already announces its expanded state); clicking it expands/collapses without selecting,\n because the tree never consumes events raised inside a nested control. The toggle action\n hands focus to the row afterwards, so focus never rests on this decorative button and\n the arrow keys keep working right after a click. %>\n<ul class=\"tree-view\" data-controller=\"stimeo--tree-view\" role=\"tree\"\n aria-label=\"<%= t('components.tree_view.demo.label') %>\">\n <%# The hidden field carries the selected item's data-value into the form; both\n the field and the values are optional. An item without a data-value submits\n an empty string, so give one to every item that should be selectable. %>\n <input type=\"hidden\" name=\"path\" data-stimeo--tree-view-target=\"field\" />\n <li\n class=\"tree-view__item\"\n role=\"treeitem\"\n aria-expanded=\"true\"\n aria-selected=\"false\"\n tabindex=\"0\"\n data-value=\"app\"\n data-stimeo--tree-view-target=\"item\"\n data-action=\"keydown->stimeo--tree-view#onKeydown click->stimeo--tree-view#onClick\">\n <button type=\"button\" class=\"tree-view__chevron\" tabindex=\"-1\" aria-hidden=\"true\"\n data-action=\"click->stimeo--tree-view#toggle\"></button>\n <span class=\"tree-view__label\">app</span>\n <ul class=\"tree-view__group\" role=\"group\" data-stimeo--tree-view-target=\"group\">\n <li\n class=\"tree-view__item\"\n role=\"treeitem\"\n aria-expanded=\"false\"\n aria-selected=\"false\"\n tabindex=\"-1\"\n data-value=\"app/controllers\"\n data-stimeo--tree-view-target=\"item\"\n data-action=\"keydown->stimeo--tree-view#onKeydown click->stimeo--tree-view#onClick\">\n <button type=\"button\" class=\"tree-view__chevron\" tabindex=\"-1\" aria-hidden=\"true\"\n data-action=\"click->stimeo--tree-view#toggle\"></button>\n <span class=\"tree-view__label\">controllers</span>\n <ul class=\"tree-view__group\" role=\"group\" data-stimeo--tree-view-target=\"group\" hidden>\n <li class=\"tree-view__item\" role=\"treeitem\" aria-selected=\"false\"\n tabindex=\"-1\" data-value=\"app/controllers/application_controller.rb\"\n data-stimeo--tree-view-target=\"item\"\n data-action=\"keydown->stimeo--tree-view#onKeydown click->stimeo--tree-view#onClick\">\n <span class=\"tree-view__label\">application_controller.rb</span>\n </li>\n <li class=\"tree-view__item\" role=\"treeitem\" aria-selected=\"false\"\n tabindex=\"-1\" data-value=\"app/controllers/components_controller.rb\"\n data-stimeo--tree-view-target=\"item\"\n data-action=\"keydown->stimeo--tree-view#onKeydown click->stimeo--tree-view#onClick\">\n <span class=\"tree-view__label\">components_controller.rb</span>\n </li>\n </ul>\n </li>\n <li class=\"tree-view__item\" role=\"treeitem\" aria-selected=\"false\"\n tabindex=\"-1\" data-value=\"app/application.rb\"\n data-stimeo--tree-view-target=\"item\"\n data-action=\"keydown->stimeo--tree-view#onKeydown click->stimeo--tree-view#onClick\">\n <span class=\"tree-view__label\">application.rb</span>\n </li>\n </ul>\n </li>\n <li class=\"tree-view__item\" role=\"treeitem\" aria-selected=\"false\"\n tabindex=\"-1\" data-value=\"README.md\"\n data-stimeo--tree-view-target=\"item\"\n data-action=\"keydown->stimeo--tree-view#onKeydown click->stimeo--tree-view#onClick\">\n <span class=\"tree-view__label\">README.md</span>\n </li>\n <li class=\"tree-view__item\" role=\"treeitem\" aria-selected=\"false\"\n tabindex=\"-1\" data-value=\"Gemfile\"\n data-stimeo--tree-view-target=\"item\"\n data-action=\"keydown->stimeo--tree-view#onKeydown click->stimeo--tree-view#onClick\">\n <span class=\"tree-view__label\">Gemfile</span>\n </li>\n</ul>\n\n<%# Readout: what the component just reported. Purely visual — the component\n already announces what a screen reader needs, so this line is aria-hidden to\n keep it from being read twice. The value is a code fragment (API identifiers\n and values), so only the label is translated. %>\n<p class=\"demo-readout\" aria-hidden=\"true\">\n <span><%= t(\"catalog.readout.field\") %></span>\n <span class=\"demo-readout__value\" data-readout\n data-empty-text=\"<%= t(\"catalog.readout.empty\") %>\">—</span>\n</p>\n"
|
|
443
443
|
},
|
|
444
444
|
"stimeo--typing-indicator": {
|
|
445
445
|
"file": "examples/typing_indicator/_demo.html.erb",
|