@adia-ai/web-components 0.8.39 → 0.8.41
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 +59 -0
- package/MIGRATION.md +1269 -3
- package/README.md +25 -30
- package/USAGE.md +26 -0
- package/bin/audit-template-children.mjs +556 -0
- package/components/accordion/accordion-item.a2ui.json +4 -0
- package/components/accordion/accordion-item.yaml +2 -0
- package/components/accordion/accordion.a2ui.json +4 -0
- package/components/accordion/accordion.yaml +2 -0
- package/components/action-list/action-item.a2ui.json +24 -2
- package/components/action-list/action-item.yaml +28 -3
- package/components/action-list/action-list.a2ui.json +6 -1
- package/components/action-list/action-list.class.js +52 -11
- package/components/action-list/action-list.css +43 -3
- package/components/action-list/action-list.d.ts +4 -2
- package/components/action-list/action-list.yaml +5 -0
- package/components/adia-mark/adia-mark.a2ui.json +1 -0
- package/components/adia-wordmark/adia-wordmark.a2ui.json +1 -0
- package/components/agent-artifact/agent-artifact.a2ui.json +1 -0
- package/components/agent-artifact/agent-artifact.css +1 -1
- package/components/agent-feedback-bar/agent-feedback-bar.a2ui.json +6 -5
- package/components/agent-feedback-bar/agent-feedback-bar.yaml +6 -2
- package/components/agent-questions/agent-questions.a2ui.json +1 -0
- package/components/agent-reasoning/agent-reasoning.a2ui.json +6 -5
- package/components/agent-reasoning/agent-reasoning.css +2 -2
- package/components/agent-reasoning/agent-reasoning.yaml +6 -2
- package/components/agent-suggestions/agent-suggestions.a2ui.json +11 -2
- package/components/agent-suggestions/agent-suggestions.class.js +2 -1
- package/components/agent-suggestions/agent-suggestions.d.ts +4 -4
- package/components/agent-suggestions/agent-suggestions.yaml +4 -2
- package/components/agent-trace/agent-trace.a2ui.json +6 -5
- package/components/agent-trace/agent-trace.css +3 -3
- package/components/agent-trace/agent-trace.yaml +6 -2
- package/components/alert/alert.a2ui.json +1 -0
- package/components/alert/alert.css +2 -2
- package/components/anchor-bar/anchor-bar.a2ui.json +1 -0
- package/components/aside/aside.a2ui.json +1 -0
- package/components/avatar/avatar-group.a2ui.json +7 -1
- package/components/avatar/avatar-group.yaml +1 -0
- package/components/avatar/avatar.a2ui.json +12 -11
- package/components/avatar/avatar.css +1 -1
- package/components/avatar/avatar.d.ts +1 -1
- package/components/avatar/avatar.yaml +4 -4
- package/components/badge/badge.a2ui.json +1 -0
- package/components/badge/badge.css +1 -1
- package/components/block/block.a2ui.json +1 -0
- package/components/blockquote/blockquote.a2ui.json +1 -0
- package/components/breadcrumb/breadcrumb.a2ui.json +1 -0
- package/components/button/button.a2ui.json +1 -3
- package/components/button/button.css +6 -5
- package/components/button/button.yaml +1 -3
- package/components/calendar-grid/calendar-grid.a2ui.json +1 -0
- package/components/calendar-grid/calendar-grid.class.js +2 -1
- package/components/calendar-picker/calendar-picker.a2ui.json +143 -24
- package/components/calendar-picker/calendar-picker.class.js +490 -197
- package/components/calendar-picker/calendar-picker.css +121 -172
- package/components/calendar-picker/calendar-picker.yaml +225 -47
- package/components/canvas/canvas.a2ui.json +6 -5
- package/components/canvas/canvas.d.ts +37 -0
- package/components/canvas/canvas.js +72 -3
- package/components/canvas/canvas.yaml +6 -2
- package/components/card/card.a2ui.json +25 -2
- package/components/card/card.class.js +3 -0
- package/components/card/card.css +34 -4
- package/components/card/card.d.ts +2 -2
- package/components/card/card.examples.md +3 -3
- package/components/card/card.yaml +28 -4
- package/components/chart/chart.a2ui.json +13 -8
- package/components/chart/chart.class.js +10 -10
- package/components/chart/chart.css +12 -10
- package/components/chart/chart.d.ts +2 -2
- package/components/chart/chart.yaml +8 -5
- package/components/chart-legend/chart-legend.a2ui.json +1 -0
- package/components/chat-thread/chat-input.a2ui.json +1 -0
- package/components/chat-thread/chat-thread.a2ui.json +10 -9
- package/components/chat-thread/chat-thread.css +1 -1
- package/components/chat-thread/chat-thread.yaml +13 -20
- package/components/check/check.a2ui.json +10 -9
- package/components/check/check.yaml +4 -4
- package/components/code/code.a2ui.json +1 -0
- package/components/code/code.css +6 -6
- package/components/col/col.a2ui.json +1 -0
- package/components/color-input/color-input.a2ui.json +1 -0
- package/components/color-picker/color-picker.a2ui.json +1 -0
- package/components/combobox/combobox.a2ui.json +3 -2
- package/components/combobox/combobox.css +2 -2
- package/components/combobox/combobox.yaml +2 -2
- package/components/command/command.a2ui.json +12 -10
- package/components/command/command.class.js +3 -2
- package/components/command/command.css +3 -3
- package/components/command/command.yaml +17 -4
- package/components/context-menu/context-menu.a2ui.json +1 -0
- package/components/date-range-picker/date-range-picker.a2ui.json +2 -1
- package/components/date-range-picker/date-range-picker.css +1 -1
- package/components/date-range-picker/date-range-picker.yaml +1 -1
- package/components/datetime-picker/datetime-picker.a2ui.json +15 -108
- package/components/datetime-picker/datetime-picker.class.js +37 -690
- package/components/datetime-picker/datetime-picker.css +11 -183
- package/components/datetime-picker/datetime-picker.d.ts +4 -5
- package/components/datetime-picker/datetime-picker.yaml +44 -135
- package/components/demo-toggle/demo-toggle.a2ui.json +1 -0
- package/components/demo-toggle/demo-toggle.css +1 -1
- package/components/description-list/description-list.a2ui.json +1 -0
- package/components/description-list/description-list.css +2 -2
- package/components/display-field/display-field.a2ui.json +1 -0
- package/components/display-field/display-field.css +3 -3
- package/components/divider/divider.a2ui.json +1 -0
- package/components/divider/divider.css +1 -1
- package/components/drawer/drawer.a2ui.json +1 -3
- package/components/drawer/drawer.css +3 -3
- package/components/drawer/drawer.yaml +0 -2
- package/components/drilldown/drilldown.a2ui.json +22 -20
- package/components/drilldown/drilldown.class.js +4 -3
- package/components/drilldown/drilldown.css +8 -8
- package/components/drilldown/drilldown.yaml +40 -9
- package/components/embed/embed.a2ui.json +6 -5
- package/components/embed/embed.yaml +2 -2
- package/components/empty-state/empty-state.a2ui.json +1 -0
- package/components/empty-state/empty-state.css +2 -2
- package/components/feed/feed-item.a2ui.json +25 -5
- package/components/feed/feed-item.yaml +28 -7
- package/components/feed/feed.a2ui.json +9 -2
- package/components/feed/feed.class.js +19 -12
- package/components/feed/feed.css +8 -8
- package/components/feed/feed.yaml +14 -1
- package/components/field/field.a2ui.json +1 -0
- package/components/field/field.css +1 -1
- package/components/field/field.examples.md +1 -1
- package/components/fields/fields.a2ui.json +1 -0
- package/components/fields/fields.examples.md +1 -1
- package/components/footer/footer.a2ui.json +1 -0
- package/components/frame/frame.a2ui.json +1 -0
- package/components/grid/grid.a2ui.json +1 -0
- package/components/header/header.a2ui.json +3 -2
- package/components/header/header.yaml +3 -3
- package/components/heatmap/heatmap.a2ui.json +2 -1
- package/components/heatmap/heatmap.class.js +1 -1
- package/components/heatmap/heatmap.css +6 -6
- package/components/heatmap/heatmap.yaml +1 -1
- package/components/icon/icon.a2ui.json +1 -0
- package/components/image/image.a2ui.json +28 -14
- package/components/image/image.class.js +38 -23
- package/components/image/image.css +18 -8
- package/components/image/image.d.ts +2 -2
- package/components/image/image.examples.md +3 -3
- package/components/image/image.yaml +23 -7
- package/components/inline-edit/inline-edit.a2ui.json +1 -0
- package/components/inline-message/inline-message.a2ui.json +3 -1
- package/components/inline-message/inline-message.class.js +3 -1
- package/components/inline-message/inline-message.css +1 -1
- package/components/inline-message/inline-message.d.ts +2 -2
- package/components/inline-message/inline-message.yaml +2 -1
- package/components/input/input.a2ui.json +66 -16
- package/components/input/input.class.js +64 -7
- package/components/input/input.css +19 -18
- package/components/input/input.d.ts +9 -4
- package/components/input/input.yaml +83 -10
- package/components/inspector/inspector.a2ui.json +1 -0
- package/components/integration-card/integration-card.a2ui.json +1 -0
- package/components/integration-card/integration-card.css +4 -4
- package/components/kbd/kbd.a2ui.json +1 -0
- package/components/kbd/kbd.css +1 -1
- package/components/link/link.a2ui.json +2 -1
- package/components/link/link.yaml +1 -1
- package/components/list/list-item.a2ui.json +9 -0
- package/components/list/list-item.yaml +12 -0
- package/components/list/list.a2ui.json +9 -3
- package/components/list/list.class.js +14 -1
- package/components/list/list.css +14 -3
- package/components/list/list.d.ts +7 -5
- package/components/list/list.yaml +16 -6
- package/components/list-window/list-window.a2ui.json +1 -0
- package/components/list-window/list-window.class.js +2 -1
- package/components/loading-overlay/loading-overlay.a2ui.json +1 -0
- package/components/mark/mark.a2ui.json +2 -1
- package/components/mark/mark.yaml +1 -1
- package/components/menu/menu-divider.a2ui.json +1 -0
- package/components/menu/menu-item.a2ui.json +3 -1
- package/components/menu/menu-item.yaml +6 -0
- package/components/menu/menu-label.a2ui.json +1 -0
- package/components/menu/menu.a2ui.json +3 -2
- package/components/menu/menu.class.js +2 -2
- package/components/menu/menu.d.ts +2 -2
- package/components/menu/menu.yaml +3 -3
- package/components/modal/modal.a2ui.json +1 -0
- package/components/nav/nav.a2ui.json +1 -0
- package/components/nav/nav.class.js +14 -3
- package/components/nav/nav.css +2 -2
- package/components/nav-group/nav-group.a2ui.json +1 -0
- package/components/nav-group/nav-group.class.js +3 -1
- package/components/nav-group/nav-group.css +3 -3
- package/components/nav-item/nav-item.a2ui.json +1 -0
- package/components/nav-item/nav-item.css +2 -2
- package/components/noodles/noodles.a2ui.json +1 -0
- package/components/noodles/noodles.class.js +5 -1
- package/components/number-format/number-format.a2ui.json +1 -0
- package/components/option-card/option-card.a2ui.json +1 -0
- package/components/option-card/option-card.css +1 -1
- package/components/otp-input/otp-input.a2ui.json +3 -2
- package/components/otp-input/otp-input.css +1 -1
- package/components/otp-input/otp-input.yaml +9 -2
- package/components/page/page.a2ui.json +13 -0
- package/components/page/page.css +2 -2
- package/components/page/page.d.ts +1 -1
- package/components/page/page.yaml +1 -0
- package/components/pagination/pagination.a2ui.json +1 -0
- package/components/pagination/pagination.class.js +3 -2
- package/components/pagination/pagination.css +1 -1
- package/components/pane/pane.a2ui.json +6 -0
- package/components/pane/pane.class.js +3 -3
- package/components/pane/pane.css +3 -3
- package/components/pane/pane.yaml +3 -0
- package/components/password-strength/password-strength.a2ui.json +1 -0
- package/components/pipeline-status/pipeline-status.a2ui.json +1 -0
- package/components/popover/popover.a2ui.json +7 -6
- package/components/popover/popover.class.js +2 -2
- package/components/popover/popover.d.ts +2 -2
- package/components/popover/popover.yaml +4 -4
- package/components/preview/preview.a2ui.json +1 -0
- package/components/preview/preview.class.js +5 -1
- package/components/progress/progress.a2ui.json +47 -24
- package/components/progress/progress.class.js +66 -11
- package/components/progress/progress.css +44 -26
- package/components/progress/progress.d.ts +7 -5
- package/components/progress/progress.examples.md +2 -2
- package/components/progress/progress.yaml +235 -53
- package/components/progress-row/progress-row.a2ui.json +16 -12
- package/components/progress-row/progress-row.css +2 -2
- package/components/progress-row/progress-row.d.ts +2 -2
- package/components/progress-row/progress-row.examples.md +2 -14
- package/components/progress-row/progress-row.yaml +28 -36
- package/components/qr-code/qr-code.a2ui.json +13 -12
- package/components/qr-code/qr-code.class.js +7 -7
- package/components/qr-code/qr-code.css +1 -1
- package/components/qr-code/qr-code.d.ts +10 -7
- package/components/qr-code/qr-code.yaml +18 -12
- package/components/radio/radio.a2ui.json +8 -7
- package/components/radio/radio.class.js +8 -0
- package/components/radio/radio.yaml +3 -3
- package/components/radio-group/radio-group.a2ui.json +5 -3
- package/components/radio-group/radio-group.class.js +11 -0
- package/components/radio-group/radio-group.yaml +7 -1
- package/components/range/range.a2ui.json +6 -0
- package/components/range/range.class.js +2 -2
- package/components/range/range.css +3 -3
- package/components/range/range.yaml +3 -0
- package/components/rating/rating.a2ui.json +1 -0
- package/components/rating/rating.css +1 -1
- package/components/relative-time/relative-time.a2ui.json +1 -0
- package/components/richtext/richtext.a2ui.json +2 -1
- package/components/richtext/richtext.css +3 -3
- package/components/richtext/richtext.yaml +1 -1
- package/components/row/row.a2ui.json +1 -0
- package/components/search/search.a2ui.json +1 -0
- package/components/search/search.class.js +4 -1
- package/components/section/section.a2ui.json +1 -0
- package/components/segment/segment.a2ui.json +21 -10
- package/components/segment/segment.css +20 -4
- package/components/segment/segment.d.ts +2 -1
- package/components/segment/segment.yaml +20 -13
- package/components/segmented/segmented.a2ui.json +36 -7
- package/components/segmented/segmented.class.js +113 -22
- package/components/segmented/segmented.css +3 -0
- package/components/segmented/segmented.d.ts +3 -1
- package/components/segmented/segmented.yaml +80 -8
- package/components/select/select.a2ui.json +18 -13
- package/components/select/select.class.js +61 -37
- package/components/select/select.css +18 -16
- package/components/select/select.yaml +18 -7
- package/components/skeleton/skeleton.a2ui.json +8 -7
- package/components/skeleton/skeleton.class.js +8 -7
- package/components/skeleton/skeleton.css +21 -6
- package/components/skeleton/skeleton.d.ts +2 -2
- package/components/skeleton/skeleton.examples.md +2 -2
- package/components/skeleton/skeleton.yaml +3 -2
- package/components/skip-nav/skip-nav.a2ui.json +1 -0
- package/components/slider/slider.a2ui.json +6 -0
- package/components/slider/slider.class.js +20 -3
- package/components/slider/slider.css +2 -2
- package/components/slider/slider.yaml +3 -0
- package/components/spinner/spinner.a2ui.json +1 -0
- package/components/spinner/spinner.css +1 -1
- package/components/stack/stack.a2ui.json +1 -0
- package/components/stat/stat.a2ui.json +1 -0
- package/components/stat/stat.css +3 -3
- package/components/stat/stat.js +2 -2
- package/components/step-progress/step-progress.a2ui.json +1 -0
- package/components/step-progress/step-progress.css +1 -1
- package/components/step-progress/step-progress.yaml +1 -1
- package/components/stepper/stepper-item.a2ui.json +7 -3
- package/components/stepper/stepper-item.yaml +15 -5
- package/components/stepper/stepper.a2ui.json +5 -1
- package/components/stepper/stepper.class.js +31 -16
- package/components/stepper/stepper.css +2 -2
- package/components/stepper/stepper.d.ts +1 -1
- package/components/stepper/stepper.yaml +4 -2
- package/components/stream/stream.a2ui.json +1 -0
- package/components/swatch/swatch.a2ui.json +1 -0
- package/components/swatch/swatch.css +2 -2
- package/components/swiper/swiper.a2ui.json +1 -0
- package/components/swiper/swiper.class.js +5 -1
- package/components/switch/switch.a2ui.json +12 -11
- package/components/switch/switch.css +1 -1
- package/components/switch/switch.yaml +6 -6
- package/components/table/table.a2ui.json +1 -10
- package/components/table/table.class.js +18 -16
- package/components/table/table.css +17 -18
- package/components/table/table.d.ts +0 -2
- package/components/table/table.yaml +0 -9
- package/components/table-toolbar/table-toolbar.a2ui.json +1 -0
- package/components/table-toolbar/table-toolbar.class.js +38 -19
- package/components/table-toolbar/table-toolbar.css +2 -2
- package/components/tabs/tab.a2ui.json +9 -0
- package/components/tabs/tab.js +4 -0
- package/components/tabs/tab.yaml +15 -0
- package/components/tabs/tabs.a2ui.json +9 -4
- package/components/tabs/tabs.class.js +13 -1
- package/components/tabs/tabs.css +9 -1
- package/components/tabs/tabs.d.ts +2 -0
- package/components/tabs/tabs.yaml +9 -2
- package/components/tag/tag.a2ui.json +1 -0
- package/components/tag/tag.css +2 -2
- package/components/tags-input/tags-input.a2ui.json +22 -17
- package/components/tags-input/tags-input.class.js +13 -11
- package/components/tags-input/tags-input.css +11 -7
- package/components/tags-input/tags-input.d.ts +16 -7
- package/components/tags-input/tags-input.examples.md +2 -2
- package/components/tags-input/tags-input.yaml +25 -8
- package/components/text/text.a2ui.json +6 -5
- package/components/text/text.css +10 -5
- package/components/text/text.d.ts +2 -2
- package/components/text/text.yaml +9 -4
- package/components/textarea/textarea.a2ui.json +2 -1
- package/components/textarea/textarea.css +1 -1
- package/components/textarea/textarea.yaml +1 -1
- package/components/theme-provider/theme-provider.a2ui.json +2 -1
- package/components/theme-provider/theme-provider.d.ts +5 -3
- package/components/theme-provider/theme-provider.yaml +5 -3
- package/components/time-picker/time-picker.a2ui.json +1 -0
- package/components/time-picker/time-picker.class.js +4 -2
- package/components/time-picker/time-picker.css +1 -1
- package/components/timeline/timeline-item.a2ui.json +26 -3
- package/components/timeline/timeline-item.yaml +22 -7
- package/components/timeline/timeline.a2ui.json +4 -0
- package/components/timeline/timeline.class.js +29 -18
- package/components/timeline/timeline.css +4 -4
- package/components/timeline/timeline.d.ts +3 -3
- package/components/timeline/timeline.yaml +2 -0
- package/components/toast/toast.a2ui.json +10 -3
- package/components/toast/toast.yaml +20 -13
- package/components/toc/toc.a2ui.json +1 -0
- package/components/toc/toc.css +1 -1
- package/components/toggle-group/toggle-group.a2ui.json +7 -3
- package/components/toggle-group/toggle-group.class.js +43 -12
- package/components/toggle-group/toggle-group.css +7 -4
- package/components/toggle-group/toggle-group.d.ts +3 -4
- package/components/toggle-group/toggle-group.yaml +22 -16
- package/components/toggle-group/toggle-option.a2ui.json +8 -4
- package/components/toggle-group/toggle-option.yaml +15 -13
- package/components/toggle-scheme/toggle-scheme.a2ui.json +2 -1
- package/components/toggle-scheme/toggle-scheme.yaml +1 -1
- package/components/toolbar/toolbar-group.a2ui.json +1 -0
- package/components/toolbar/toolbar.a2ui.json +1 -0
- package/components/toolbar/toolbar.class.js +3 -0
- package/components/tooltip/tooltip.a2ui.json +1 -0
- package/components/tooltip/tooltip.css +1 -1
- package/components/tour/tour-step.a2ui.json +4 -0
- package/components/tour/tour-step.yaml +2 -0
- package/components/tour/tour.a2ui.json +4 -0
- package/components/tour/tour.css +2 -2
- package/components/tour/tour.yaml +2 -0
- package/components/tree/tree-item.a2ui.json +5 -0
- package/components/tree/tree-item.yaml +3 -0
- package/components/tree/tree.a2ui.json +4 -0
- package/components/tree/tree.class.js +2 -1
- package/components/tree/tree.css +1 -1
- package/components/tree/tree.yaml +2 -0
- package/components/upload/upload.a2ui.json +8 -1
- package/components/upload/upload.class.js +35 -5
- package/components/upload/upload.css +28 -0
- package/components/upload/upload.d.ts +16 -0
- package/components/upload/upload.yaml +27 -7
- package/components/visually-hidden/visually-hidden.a2ui.json +1 -0
- package/core/dom.d.ts +11 -0
- package/core/dom.js +34 -0
- package/core/form.js +7 -0
- package/core/index.d.ts +1 -0
- package/core/index.js +1 -0
- package/core/responsive.js +16 -4
- package/core/template.js +2 -1
- package/custom-elements.json +442 -502
- package/dist/host.min.css +1 -1
- package/dist/host.sheet.js +1 -1
- package/dist/theme-provider.min.js +5 -5
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +91 -104
- package/dist/web-components.sheet.js +1 -1
- package/package.json +4 -2
- package/patterns/conversion-funnel/conversion-funnel.examples.html +15 -15
- package/patterns/inline-dialog/inline-dialog.examples.html +2 -2
- package/patterns/inline-dialog/inline-dialog.html +4 -0
- package/patterns/timezone-selector/timezone-selector.examples.html +1 -1
- package/patterns/timezone-selector/timezone-selector.html +2 -2
- package/styles/api/text.css +7 -0
- package/styles/type/scale.css +6 -7
- package/traits/_catalog.json +129 -41
- package/traits/anchor-positioning/anchor-positioning.js +1 -0
- package/traits/announcer/announcer.js +1 -0
- package/traits/arrow-grid-nav/arrow-grid-nav.js +1 -0
- package/traits/attention-pulse/attention-pulse.js +1 -0
- package/traits/count-up/count-up.js +1 -0
- package/traits/define.js +78 -0
- package/traits/focus-restore/focus-restore.js +2 -1
- package/traits/haptic-feedback/haptic-feedback.js +1 -0
- package/traits/input-mask/input-mask.js +1 -0
- package/traits/intersection-observer/intersection-observer.js +1 -0
- package/traits/layout-animation/layout-animation.js +1 -0
- package/traits/noise-texture/noise-texture.js +1 -0
- package/traits/resize-observer/resize-observer.js +1 -0
- package/traits/scroll-progress/scroll-progress.js +1 -0
- package/traits/snap-to-grid/snap-to-grid.js +1 -0
- package/traits/sound-feedback/sound-feedback.js +1 -0
- package/traits/spring-animate/spring-animate.js +1 -0
- package/traits/validation/validation.js +1 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://adiaui.dev/a2ui/v0_9/components/Segment.json",
|
|
4
4
|
"title": "Segment",
|
|
5
|
-
"description": "Individual segment child of <segmented-ui> — carries the [value],\n[text], optional [icon], and [selected] state for one option in\na horizontal segmented selector. Distinct from <tab-ui> (a view\nswitcher's child) and <option> (native option for <select-ui>).\nUse segment-ui only as a direct child of <segmented-ui>; never\nstandalone.\n",
|
|
5
|
+
"description": "Individual segment child of <segmented-ui> — carries the [value],\n[text], optional [icon], and [selected] state for one option in\na horizontal segmented selector, single- or multi-select\n(<segmented-ui multiple>, gh#1369). Distinct from <tab-ui> (a view\nswitcher's child) and <option> (native option for <select-ui>).\nUse segment-ui only as a direct child of <segmented-ui>; never\nstandalone.\n",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"allOf": [
|
|
8
8
|
{
|
|
@@ -47,6 +47,9 @@
|
|
|
47
47
|
],
|
|
48
48
|
"unevaluatedProperties": false,
|
|
49
49
|
"x-adiaui": {
|
|
50
|
+
"allowedParents": [
|
|
51
|
+
"Segmented"
|
|
52
|
+
],
|
|
50
53
|
"anti_patterns": [],
|
|
51
54
|
"category": "navigation",
|
|
52
55
|
"composes": [
|
|
@@ -56,36 +59,39 @@
|
|
|
56
59
|
"examples": [
|
|
57
60
|
{
|
|
58
61
|
"description": "Segmented control with 3 segment options for tab-like switching.",
|
|
59
|
-
"a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"
|
|
62
|
+
"a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Segmented\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"text\": \"Overview\",\n \"selected\": true\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"text\": \"Features\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"text\": \"Pricing\"\n }\n]",
|
|
60
63
|
"name": "segmented-control"
|
|
61
64
|
},
|
|
62
65
|
{
|
|
63
66
|
"description": "Three segments inside a segmented control for view switching.",
|
|
64
|
-
"a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"
|
|
67
|
+
"a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Segmented\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"value\": \"overview\",\n \"text\": \"Overview\"\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"value\": \"features\",\n \"text\": \"Features\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"value\": \"pricing\",\n \"text\": \"Pricing\"\n }\n]",
|
|
65
68
|
"name": "basic"
|
|
66
69
|
},
|
|
67
70
|
{
|
|
68
71
|
"description": "Segmented control showing four time-range segments labeled via text attribute.",
|
|
69
|
-
"a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"
|
|
72
|
+
"a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Segmented\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\",\n \"s4\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"value\": \"d\",\n \"text\": \"Daily\"\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"value\": \"w\",\n \"text\": \"Weekly\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"value\": \"m\",\n \"text\": \"Monthly\"\n },\n {\n \"id\": \"s4\",\n \"component\": \"Segment\",\n \"value\": \"y\",\n \"text\": \"Yearly\"\n }\n]",
|
|
70
73
|
"name": "text"
|
|
71
74
|
},
|
|
72
75
|
{
|
|
73
76
|
"description": "Segmented control with one disabled segment that cannot be selected.",
|
|
74
|
-
"a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"
|
|
77
|
+
"a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Segmented\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"value\": \"free\",\n \"text\": \"Free\"\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"value\": \"pro\",\n \"text\": \"Pro\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"value\": \"enterprise\",\n \"text\": \"Enterprise\",\n \"disabled\": true\n }\n]",
|
|
75
78
|
"name": "disabled"
|
|
76
79
|
},
|
|
77
80
|
{
|
|
78
81
|
"description": "Segmented control with icon+text segments for view-mode toggles (list, grid, board).",
|
|
79
|
-
"a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"
|
|
82
|
+
"a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Segmented\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"value\": \"list\",\n \"text\": \"List\",\n \"icon\": \"list\"\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"value\": \"grid\",\n \"text\": \"Grid\",\n \"icon\": \"squares-four\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"value\": \"board\",\n \"text\": \"Board\",\n \"icon\": \"kanban\"\n }\n]",
|
|
80
83
|
"name": "icons"
|
|
81
84
|
}
|
|
82
85
|
],
|
|
83
86
|
"keywords": [
|
|
84
|
-
"segment"
|
|
87
|
+
"segment",
|
|
88
|
+
"toggle-option"
|
|
85
89
|
],
|
|
86
90
|
"name": "UISegment",
|
|
91
|
+
"parts": {},
|
|
87
92
|
"related": [
|
|
88
|
-
"segmented-control"
|
|
93
|
+
"segmented-control",
|
|
94
|
+
"ToggleOption"
|
|
89
95
|
],
|
|
90
96
|
"slots": {},
|
|
91
97
|
"states": [
|
|
@@ -104,11 +110,16 @@
|
|
|
104
110
|
"segment": [
|
|
105
111
|
"segment-button",
|
|
106
112
|
"segmented-option",
|
|
107
|
-
"option-button"
|
|
113
|
+
"option-button",
|
|
114
|
+
"toggle-option"
|
|
108
115
|
]
|
|
109
116
|
},
|
|
110
117
|
"tag": "segment-ui",
|
|
111
|
-
"tokens": {
|
|
118
|
+
"tokens": {
|
|
119
|
+
"--segment-bg-selected": {
|
|
120
|
+
"description": "Background color of a selected segment under the parent's [multiple] mode (no sliding indicator in that mode)."
|
|
121
|
+
}
|
|
122
|
+
},
|
|
112
123
|
"traits": [],
|
|
113
124
|
"version": 1
|
|
114
125
|
}
|
|
@@ -8,6 +8,16 @@ segment-ui[selected] {
|
|
|
8
8
|
color: var(--segment-fg-selected);
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
/* [multiple] (gh#1369, #1363 C1): the parent segmented-ui[multiple] never
|
|
12
|
+
creates a sliding indicator (segmented.class.js render()), so each
|
|
13
|
+
selected segment paints its own background instead — mirrors the
|
|
14
|
+
deprecated toggle-option-ui[selected] treatment it replaces. Scoped to
|
|
15
|
+
the multiple ancestor so single-select's indicator-driven look is
|
|
16
|
+
unchanged. */
|
|
17
|
+
segmented-ui[multiple] > segment-ui[selected] {
|
|
18
|
+
background: var(--segment-bg-selected);
|
|
19
|
+
}
|
|
20
|
+
|
|
11
21
|
@scope (segment-ui) {
|
|
12
22
|
:where(:scope) {
|
|
13
23
|
/* ── Layout ── */
|
|
@@ -23,15 +33,21 @@ segment-ui[selected] {
|
|
|
23
33
|
`line-height: 1` is deliberate, but the label's ::after clips to its
|
|
24
34
|
own line box, so inheriting 1 makes half-leading negative and shears
|
|
25
35
|
descenders (g/j/p/q/y, parentheses) by ~0.93px at the default size —
|
|
26
|
-
gh#906.
|
|
27
|
-
mirrors --button-label-line-height.
|
|
28
|
-
|
|
36
|
+
gh#906. Normal (1.35) contains the font's content box at every
|
|
37
|
+
[size]; mirrors --button-label-line-height. Value-nearest migration
|
|
38
|
+
from the retired --a-leading-snug (1.3) — ADR-0052. */
|
|
39
|
+
--segment-label-line-height: var(--a-font-leading-normal);
|
|
29
40
|
|
|
30
41
|
/* ── Colors ── */
|
|
31
42
|
--segment-fg: var(--a-ui-text-subtle);
|
|
32
43
|
--segment-fg-hover: var(--a-ui-text-hover);
|
|
33
44
|
--segment-fg-selected: var(--a-chrome-dark);
|
|
34
45
|
--segment-fg-disabled: var(--a-ui-text-disabled);
|
|
46
|
+
/* [multiple] only — see the moved-out selector above (Safari 17.x bug
|
|
47
|
+
note at top of file). Same default the deprecated
|
|
48
|
+
toggle-option-ui[selected] background used, for visual continuity
|
|
49
|
+
across the merge (gh#1369). */
|
|
50
|
+
--segment-bg-selected: var(--md-sys-color-primary-container);
|
|
35
51
|
|
|
36
52
|
/* ── Transition ── */
|
|
37
53
|
--segment-duration: var(--a-duration-fast);
|
|
@@ -60,7 +76,7 @@ segment-ui[selected] {
|
|
|
60
76
|
font-family: var(--segment-font-family);
|
|
61
77
|
font-size: var(--segment-font-size);
|
|
62
78
|
font-weight: var(--segment-font-weight);
|
|
63
|
-
line-height:
|
|
79
|
+
line-height: var(--a-font-leading-none);
|
|
64
80
|
color: var(--segment-fg);
|
|
65
81
|
white-space: nowrap;
|
|
66
82
|
overflow: hidden;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `<segment-ui>` — Individual segment child of <segmented-ui> — carries the [value],
|
|
3
3
|
[text], optional [icon], and [selected] state for one option in
|
|
4
|
-
a horizontal segmented selector
|
|
4
|
+
a horizontal segmented selector, single- or multi-select
|
|
5
|
+
(<segmented-ui multiple>, gh#1369). Distinct from <tab-ui> (a view
|
|
5
6
|
switcher's child) and <option> (native option for <select-ui>).
|
|
6
7
|
Use segment-ui only as a direct child of <segmented-ui>; never
|
|
7
8
|
standalone.
|
|
@@ -10,7 +10,8 @@ version: 1
|
|
|
10
10
|
description: |
|
|
11
11
|
Individual segment child of <segmented-ui> — carries the [value],
|
|
12
12
|
[text], optional [icon], and [selected] state for one option in
|
|
13
|
-
a horizontal segmented selector
|
|
13
|
+
a horizontal segmented selector, single- or multi-select
|
|
14
|
+
(<segmented-ui multiple>, gh#1369). Distinct from <tab-ui> (a view
|
|
14
15
|
switcher's child) and <option> (native option for <select-ui>).
|
|
15
16
|
Use segment-ui only as a direct child of <segmented-ui>; never
|
|
16
17
|
standalone.
|
|
@@ -51,14 +52,18 @@ states:
|
|
|
51
52
|
description: Non-interactive; dimmed.
|
|
52
53
|
attribute: disabled
|
|
53
54
|
traits: []
|
|
54
|
-
tokens:
|
|
55
|
+
tokens:
|
|
56
|
+
--segment-bg-selected:
|
|
57
|
+
description: Background color of a selected segment under the parent's [multiple] mode (no sliding indicator in that mode).
|
|
55
58
|
a2ui:
|
|
59
|
+
allowedParents:
|
|
60
|
+
- Segmented
|
|
56
61
|
rules:
|
|
57
|
-
- rule: 'Child of <segmented-ui> — one selectable option button
|
|
62
|
+
- rule: 'Child of <segmented-ui> — one selectable option button; the parent''s [multiple] axis decides single- or multi-select, segment-ui itself is unchanged either way.'
|
|
58
63
|
reason: 'Cluster contract.'
|
|
59
|
-
- rule: '
|
|
60
|
-
reason: '
|
|
61
|
-
- rule: 'Selected state managed by parent <segmented-ui>
|
|
64
|
+
- rule: '<toggle-option-ui> (deprecated, gh#1369) is the same concept — use segment-ui inside <segmented-ui multiple> instead.'
|
|
65
|
+
reason: 'Deprecation redirect.'
|
|
66
|
+
- rule: 'Selected state managed by the parent <segmented-ui> — it syncs the selected attribute onto every child whose value is in its own value (single value, or the [multiple] comma-separated set); do not set selected directly on segment.'
|
|
62
67
|
reason: 'Parent owns selection state.'
|
|
63
68
|
anti_patterns: []
|
|
64
69
|
examples:
|
|
@@ -68,7 +73,7 @@ examples:
|
|
|
68
73
|
[
|
|
69
74
|
{
|
|
70
75
|
"id": "root",
|
|
71
|
-
"component": "
|
|
76
|
+
"component": "Segmented",
|
|
72
77
|
"children": [
|
|
73
78
|
"s1",
|
|
74
79
|
"s2",
|
|
@@ -79,7 +84,7 @@ examples:
|
|
|
79
84
|
"id": "s1",
|
|
80
85
|
"component": "Segment",
|
|
81
86
|
"text": "Overview",
|
|
82
|
-
"
|
|
87
|
+
"selected": true
|
|
83
88
|
},
|
|
84
89
|
{
|
|
85
90
|
"id": "s2",
|
|
@@ -98,7 +103,7 @@ examples:
|
|
|
98
103
|
[
|
|
99
104
|
{
|
|
100
105
|
"id": "root",
|
|
101
|
-
"component": "
|
|
106
|
+
"component": "Segmented",
|
|
102
107
|
"children": [
|
|
103
108
|
"s1",
|
|
104
109
|
"s2",
|
|
@@ -130,7 +135,7 @@ examples:
|
|
|
130
135
|
[
|
|
131
136
|
{
|
|
132
137
|
"id": "root",
|
|
133
|
-
"component": "
|
|
138
|
+
"component": "Segmented",
|
|
134
139
|
"children": [
|
|
135
140
|
"s1",
|
|
136
141
|
"s2",
|
|
@@ -169,7 +174,7 @@ examples:
|
|
|
169
174
|
[
|
|
170
175
|
{
|
|
171
176
|
"id": "root",
|
|
172
|
-
"component": "
|
|
177
|
+
"component": "Segmented",
|
|
173
178
|
"children": [
|
|
174
179
|
"s1",
|
|
175
180
|
"s2",
|
|
@@ -202,7 +207,7 @@ examples:
|
|
|
202
207
|
[
|
|
203
208
|
{
|
|
204
209
|
"id": "root",
|
|
205
|
-
"component": "
|
|
210
|
+
"component": "Segmented",
|
|
206
211
|
"children": [
|
|
207
212
|
"s1",
|
|
208
213
|
"s2",
|
|
@@ -233,7 +238,9 @@ examples:
|
|
|
233
238
|
]
|
|
234
239
|
keywords:
|
|
235
240
|
- segment
|
|
241
|
+
- toggle-option
|
|
236
242
|
synonyms:
|
|
237
|
-
segment: [segment-button, segmented-option, option-button]
|
|
243
|
+
segment: [segment-button, segmented-option, option-button, toggle-option]
|
|
238
244
|
related:
|
|
239
245
|
- segmented-control
|
|
246
|
+
- ToggleOption
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://adiaui.dev/a2ui/v0_9/components/Segmented.json",
|
|
4
4
|
"title": "Segmented",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Toggle group with an animated sliding indicator (single-select) or independently-toggleable segments (multi-select via [multiple]). Children must be segment-ui elements.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"allOf": [
|
|
8
8
|
{
|
|
@@ -14,15 +14,20 @@
|
|
|
14
14
|
],
|
|
15
15
|
"properties": {
|
|
16
16
|
"allowEmpty": {
|
|
17
|
-
"description": "Suppresses the connect-time self-select of the first enabled segment when value is falsy. Without it, an empty value silently selects the first segment; with it, a falsy value renders every segment unselected until a real value arrives — for path-bound consumers whose bound value can be a genuine empty state.",
|
|
17
|
+
"description": "Suppresses the connect-time self-select of the first enabled segment when value is falsy. Without it, an empty value silently selects the first segment; with it, a falsy value renders every segment unselected until a real value arrives — for path-bound consumers whose bound value can be a genuine empty state. No effect under [multiple] — multi-select never self-selects (empty value already means \"nothing chosen\").",
|
|
18
18
|
"type": "boolean",
|
|
19
19
|
"default": false
|
|
20
20
|
},
|
|
21
21
|
"component": {
|
|
22
22
|
"const": "Segmented"
|
|
23
23
|
},
|
|
24
|
+
"multiple": {
|
|
25
|
+
"description": "Enables multi-select — value becomes a comma-separated set, the sliding indicator is suppressed (each selected segment carries its own background instead), and Space/Enter toggles a focused segment instead of arrow-move selecting it. Positive polarity, matching select-ui[multiple]. Absorbs the role of the deprecated <toggle-group-ui> + <toggle-option-ui> pair (gh#1369, #1363 C1). Unlike <toggle-group-ui single>, re-clicking an already-selected segment does NOT clear the selection — segmented-ui's single-select is standard radiogroup semantics (always exactly one selected once a value is set).",
|
|
26
|
+
"type": "boolean",
|
|
27
|
+
"default": false
|
|
28
|
+
},
|
|
24
29
|
"value": {
|
|
25
|
-
"description": "Value of the currently selected segment.",
|
|
30
|
+
"description": "Value of the currently selected segment. Under [multiple], a comma-separated set of selected values (same encoding as select-ui[multiple]).",
|
|
26
31
|
"type": "string",
|
|
27
32
|
"default": ""
|
|
28
33
|
}
|
|
@@ -32,6 +37,9 @@
|
|
|
32
37
|
],
|
|
33
38
|
"unevaluatedProperties": false,
|
|
34
39
|
"x-adiaui": {
|
|
40
|
+
"allowedChildren": [
|
|
41
|
+
"Segment"
|
|
42
|
+
],
|
|
35
43
|
"anti_patterns": [],
|
|
36
44
|
"category": "navigation",
|
|
37
45
|
"composes": [],
|
|
@@ -45,6 +53,11 @@
|
|
|
45
53
|
"description": "Segmented control with three segment-ui children for view switching.",
|
|
46
54
|
"a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Card\",\n \"children\": [\n \"sec\"\n ]\n },\n {\n \"id\": \"sec\",\n \"component\": \"Section\",\n \"children\": [\n \"comp\"\n ]\n },\n {\n \"id\": \"comp\",\n \"component\": \"Segmented\",\n \"value\": \"daily\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"value\": \"daily\",\n \"text\": \"Daily\"\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"value\": \"weekly\",\n \"text\": \"Weekly\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"value\": \"monthly\",\n \"text\": \"Monthly\"\n }\n]",
|
|
47
55
|
"name": "basic-segmented"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"description": "Multi-select segmented control (gh#1369) for filter chips — [multiple] set, value is a comma-separated set of active segments.",
|
|
59
|
+
"a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Card\",\n \"children\": [\n \"sec\"\n ]\n },\n {\n \"id\": \"sec\",\n \"component\": \"Section\",\n \"children\": [\n \"comp\"\n ]\n },\n {\n \"id\": \"comp\",\n \"component\": \"Segmented\",\n \"multiple\": true,\n \"value\": \"bold,italic\",\n \"children\": [\n \"s1\",\n \"s2\",\n \"s3\"\n ]\n },\n {\n \"id\": \"s1\",\n \"component\": \"Segment\",\n \"value\": \"bold\",\n \"text\": \"Bold\"\n },\n {\n \"id\": \"s2\",\n \"component\": \"Segment\",\n \"value\": \"italic\",\n \"text\": \"Italic\"\n },\n {\n \"id\": \"s3\",\n \"component\": \"Segment\",\n \"value\": \"underline\",\n \"text\": \"Underline\"\n }\n]",
|
|
60
|
+
"name": "multi-select-filter-chips"
|
|
48
61
|
}
|
|
49
62
|
],
|
|
50
63
|
"keywords": [
|
|
@@ -55,21 +68,27 @@
|
|
|
55
68
|
"switch",
|
|
56
69
|
"tab",
|
|
57
70
|
"tabs",
|
|
58
|
-
"button-group"
|
|
71
|
+
"button-group",
|
|
72
|
+
"filter",
|
|
73
|
+
"multi-select",
|
|
74
|
+
"filter-chips"
|
|
59
75
|
],
|
|
60
76
|
"name": "UISegmented",
|
|
77
|
+
"parts": {
|
|
78
|
+
"indicator": {
|
|
79
|
+
"description": "Auto-created sliding indicator element prepended on first render — template-owned anatomy part, not a light-DOM insertion point (gh#1454). Lazily created once via an internal-field guard, never adopted from a consumer-authored element."
|
|
80
|
+
}
|
|
81
|
+
},
|
|
61
82
|
"related": [
|
|
62
83
|
"Segment",
|
|
63
84
|
"ToggleGroup",
|
|
85
|
+
"ToggleOption",
|
|
64
86
|
"Tabs",
|
|
65
87
|
"Radio"
|
|
66
88
|
],
|
|
67
89
|
"slots": {
|
|
68
90
|
"default": {
|
|
69
91
|
"description": "Child segment-ui elements that form the toggle group. Children MUST be segment-ui — bare segment tags render text but are silently ignored for the sliding indicator and role/aria-checked state."
|
|
70
|
-
},
|
|
71
|
-
"indicator": {
|
|
72
|
-
"description": "Auto-created sliding indicator element prepended on first render."
|
|
73
92
|
}
|
|
74
93
|
},
|
|
75
94
|
"states": [
|
|
@@ -85,6 +104,16 @@
|
|
|
85
104
|
"button",
|
|
86
105
|
"segmented"
|
|
87
106
|
],
|
|
107
|
+
"filter": [
|
|
108
|
+
"segmented",
|
|
109
|
+
"toggle-group",
|
|
110
|
+
"filter-chips"
|
|
111
|
+
],
|
|
112
|
+
"multi-select": [
|
|
113
|
+
"segmented",
|
|
114
|
+
"toggle-group",
|
|
115
|
+
"select"
|
|
116
|
+
],
|
|
88
117
|
"options": [
|
|
89
118
|
"settings",
|
|
90
119
|
"radio",
|
|
@@ -18,8 +18,19 @@
|
|
|
18
18
|
* <segment-ui value="tab3" text="Tab 3"></segment-ui>
|
|
19
19
|
* </segmented-ui>
|
|
20
20
|
*
|
|
21
|
-
* Mutually exclusive toggle group with animated indicator
|
|
22
|
-
* Indicator uses CSS transform (GPU-accelerated).
|
|
21
|
+
* Mutually exclusive (single-select) toggle group with animated indicator
|
|
22
|
+
* pill. Indicator uses CSS transform (GPU-accelerated).
|
|
23
|
+
*
|
|
24
|
+
* <segmented-ui multiple value="bold,italic">
|
|
25
|
+
* <segment-ui value="bold" text="B"></segment-ui>
|
|
26
|
+
* <segment-ui value="italic" text="I"></segment-ui>
|
|
27
|
+
* </segmented-ui>
|
|
28
|
+
*
|
|
29
|
+
* [multiple] (gh#1369, #1363 C1): multi-select mode — `value` is a
|
|
30
|
+
* comma-separated set, no sliding indicator (each selected segment carries
|
|
31
|
+
* its own background instead), Space/Enter toggles instead of arrow-move.
|
|
32
|
+
* Absorbs <toggle-group-ui>/<toggle-option-ui>'s role, which are deprecated
|
|
33
|
+
* in favor of this axis.
|
|
23
34
|
*/
|
|
24
35
|
|
|
25
36
|
import { UIFormElement } from '../../core/form.js';
|
|
@@ -28,6 +39,13 @@ import '../segment/segment.js';
|
|
|
28
39
|
export class UISegmented extends UIFormElement {
|
|
29
40
|
static properties = {
|
|
30
41
|
...UIFormElement.properties,
|
|
42
|
+
// gh#1369 (#1363 C1): multi-select axis, positive polarity matching
|
|
43
|
+
// <select-ui multiple> — not toggle-group's inverted `single`. Under
|
|
44
|
+
// [multiple], `value` becomes a comma-separated set (same encoding
|
|
45
|
+
// toggle-group-ui and select-ui[multiple] already use); the sliding
|
|
46
|
+
// indicator is suppressed and each selected segment carries its own
|
|
47
|
+
// background instead (segment.css).
|
|
48
|
+
multiple: { type: Boolean, default: false, reflect: true },
|
|
31
49
|
value: { type: String, default: '', reflect: true },
|
|
32
50
|
// gh#693: absent (default false) preserves the original self-select
|
|
33
51
|
// behavior below. A path-bound consumer whose bound value can be a
|
|
@@ -55,7 +73,7 @@ export class UISegmented extends UIFormElement {
|
|
|
55
73
|
|
|
56
74
|
connected() {
|
|
57
75
|
super.connected();
|
|
58
|
-
this.setAttribute('role', 'radiogroup');
|
|
76
|
+
this.setAttribute('role', this.multiple ? 'group' : 'radiogroup');
|
|
59
77
|
|
|
60
78
|
if (!this.#bound) {
|
|
61
79
|
this.#bound = true;
|
|
@@ -65,8 +83,10 @@ export class UISegmented extends UIFormElement {
|
|
|
65
83
|
|
|
66
84
|
// Default to first segment if no value — unless allow-empty opts out
|
|
67
85
|
// (a falsy path-bound value must render as truly empty, not silently
|
|
68
|
-
// pick one, gh#693).
|
|
69
|
-
|
|
86
|
+
// pick one, gh#693). Multi-select never self-selects: an empty
|
|
87
|
+
// [multiple] value legitimately means "nothing chosen yet", the same
|
|
88
|
+
// default toggle-group-ui always had.
|
|
89
|
+
if (!this.multiple && !this.value && !this.allowEmpty) {
|
|
70
90
|
const first = this.querySelector('segment-ui:not([disabled])');
|
|
71
91
|
if (first) this.value = first.value || first.getAttribute('value') || '';
|
|
72
92
|
}
|
|
@@ -112,7 +132,19 @@ export class UISegmented extends UIFormElement {
|
|
|
112
132
|
return this.#segments.filter(s => !s.disabled);
|
|
113
133
|
}
|
|
114
134
|
|
|
135
|
+
// [multiple] value encoding — comma-separated, matching toggle-group-ui
|
|
136
|
+
// and select-ui[multiple] (gh#1369).
|
|
137
|
+
get #valueSet() {
|
|
138
|
+
return new Set(this.value ? this.value.split(',').map(v => v.trim()).filter(Boolean) : []);
|
|
139
|
+
}
|
|
140
|
+
|
|
115
141
|
render() {
|
|
142
|
+
// gh#1369 review: connected() only sets the host role ONCE — if
|
|
143
|
+
// `multiple` flips after connect, that one-shot value goes stale while
|
|
144
|
+
// children's roles (below) already update reactively every render.
|
|
145
|
+
// Keep the host role synchronized here too, every render.
|
|
146
|
+
this.setAttribute('role', this.multiple ? 'group' : 'radiogroup');
|
|
147
|
+
|
|
116
148
|
// FEEDBACK-23: flag a non-<segment-ui> direct child once per element.
|
|
117
149
|
// Runs before the empty-guard so an all-bare-<segment> group still warns.
|
|
118
150
|
if (!UISegmented.#warnedNonSegment.has(this)) {
|
|
@@ -137,11 +169,14 @@ export class UISegmented extends UIFormElement {
|
|
|
137
169
|
const segs = this.#segments;
|
|
138
170
|
if (!segs.length) return;
|
|
139
171
|
|
|
140
|
-
// Sync selection state
|
|
172
|
+
// Sync selection state — [multiple] checks Set membership (comma-
|
|
173
|
+
// separated value), single-select checks direct string equality.
|
|
174
|
+
const selectedSet = this.multiple ? this.#valueSet : null;
|
|
141
175
|
let anyActive = false;
|
|
142
176
|
for (const seg of segs) {
|
|
143
177
|
const segVal = seg.value || seg.getAttribute('value') || '';
|
|
144
|
-
const isActive = segVal === this.value;
|
|
178
|
+
const isActive = this.multiple ? selectedSet.has(segVal) : segVal === this.value;
|
|
179
|
+
seg.setAttribute('role', this.multiple ? 'checkbox' : 'radio');
|
|
145
180
|
if (isActive) {
|
|
146
181
|
seg.setAttribute('selected', '');
|
|
147
182
|
anyActive = true;
|
|
@@ -152,6 +187,8 @@ export class UISegmented extends UIFormElement {
|
|
|
152
187
|
}
|
|
153
188
|
// allow-empty's "nothing selected" state must still be keyboard
|
|
154
189
|
// reachable — mirrors list-ui's roving-tabindex fallback (list.class.js).
|
|
190
|
+
// [multiple] can legitimately have nothing selected at all times, same
|
|
191
|
+
// fallback applies.
|
|
155
192
|
if (!anyActive) {
|
|
156
193
|
const firstEnabled = segs.find((s) => !s.disabled);
|
|
157
194
|
firstEnabled?.setAttribute('tabindex', '0');
|
|
@@ -159,10 +196,33 @@ export class UISegmented extends UIFormElement {
|
|
|
159
196
|
|
|
160
197
|
if (this.label) this.setAttribute('aria-label', this.label);
|
|
161
198
|
|
|
199
|
+
// Sliding indicator is a single-select-only affordance — exactly one
|
|
200
|
+
// pill can slide to exactly one position. [multiple] relies on each
|
|
201
|
+
// segment's own [selected] background instead (segment.css).
|
|
202
|
+
// #updateIndicator itself guards on `this.multiple` (gh#1369 review) —
|
|
203
|
+
// call it unconditionally so this is the one call site, same as every
|
|
204
|
+
// other caller (ResizeObserver, document.fonts.ready).
|
|
162
205
|
this.#updateIndicator(segs);
|
|
163
206
|
}
|
|
164
207
|
|
|
165
208
|
#updateIndicator(segs) {
|
|
209
|
+
// gh#1369 review: render() only skips this call in [multiple] mode —
|
|
210
|
+
// the ResizeObserver (connected()) and document.fonts.ready callbacks
|
|
211
|
+
// call #updateIndicator directly and asynchronously, bypassing that
|
|
212
|
+
// guard entirely. Without a guard HERE, a multiple-mode instance with
|
|
213
|
+
// exactly one segment selected (this.value has no comma, so it can
|
|
214
|
+
// exactly match a segment's own value) can grow a spurious sliding
|
|
215
|
+
// indicator after a late resize or font-load event. Guard the method
|
|
216
|
+
// itself so every call site — sync or async — is covered.
|
|
217
|
+
if (this.multiple) {
|
|
218
|
+
for (const stale of this.querySelectorAll(':scope > [data-indicator]')) {
|
|
219
|
+
stale.remove();
|
|
220
|
+
}
|
|
221
|
+
this.#indicator = null;
|
|
222
|
+
this.removeAttribute('data-indicator-ready');
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
|
|
166
226
|
const selectedIdx = segs.findIndex(s => (s.value || s.getAttribute('value') || '') === this.value);
|
|
167
227
|
|
|
168
228
|
if (selectedIdx < 0) {
|
|
@@ -205,7 +265,18 @@ export class UISegmented extends UIFormElement {
|
|
|
205
265
|
|
|
206
266
|
#select(seg) {
|
|
207
267
|
if (seg.disabled) return;
|
|
208
|
-
|
|
268
|
+
const segVal = seg.value || seg.getAttribute('value') || '';
|
|
269
|
+
|
|
270
|
+
if (this.multiple) {
|
|
271
|
+
if (!segVal) return;
|
|
272
|
+
const selected = this.#valueSet;
|
|
273
|
+
if (selected.has(segVal)) selected.delete(segVal);
|
|
274
|
+
else selected.add(segVal);
|
|
275
|
+
this.value = [...selected].join(',');
|
|
276
|
+
} else {
|
|
277
|
+
this.value = segVal;
|
|
278
|
+
}
|
|
279
|
+
|
|
209
280
|
this.syncValue();
|
|
210
281
|
this.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: this.value } }));
|
|
211
282
|
}
|
|
@@ -215,26 +286,46 @@ export class UISegmented extends UIFormElement {
|
|
|
215
286
|
if (seg && this.contains(seg)) this.#select(seg);
|
|
216
287
|
};
|
|
217
288
|
|
|
289
|
+
// Shared roving-focus navigation — Home/End/Arrow keys move focus among
|
|
290
|
+
// enabled segments. Selection semantics diverge below: single-select is
|
|
291
|
+
// a radiogroup (arrow-move selects, native radio behavior); [multiple]
|
|
292
|
+
// is a checkbox toolbar (arrow-move only focuses, Space/Enter toggles).
|
|
293
|
+
#nextFocusTarget(current, key) {
|
|
294
|
+
const segs = this.#enabledSegments;
|
|
295
|
+
const idx = segs.indexOf(current);
|
|
296
|
+
if (idx < 0) return null; // current isn't an enabled segment — nothing to do
|
|
297
|
+
switch (key) {
|
|
298
|
+
case 'ArrowRight': case 'ArrowDown':
|
|
299
|
+
return segs[idx < segs.length - 1 ? idx + 1 : 0];
|
|
300
|
+
case 'ArrowLeft': case 'ArrowUp':
|
|
301
|
+
return segs[idx > 0 ? idx - 1 : segs.length - 1];
|
|
302
|
+
case 'Home': return segs[0];
|
|
303
|
+
case 'End': return segs[segs.length - 1];
|
|
304
|
+
default: return null; // key not handled
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
218
308
|
#handleKeydown = (e) => {
|
|
219
309
|
const target = e.target;
|
|
220
310
|
if (target.tagName !== 'SEGMENT-UI') return;
|
|
221
|
-
const segs = this.#enabledSegments;
|
|
222
|
-
const idx = segs.indexOf(target);
|
|
223
|
-
if (idx < 0) return;
|
|
224
311
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
312
|
+
if (this.multiple) {
|
|
313
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
314
|
+
e.preventDefault();
|
|
315
|
+
this.#select(target);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const next = this.#nextFocusTarget(target, e.key);
|
|
319
|
+
if (!next) return;
|
|
320
|
+
e.preventDefault();
|
|
321
|
+
next.focus();
|
|
322
|
+
return;
|
|
234
323
|
}
|
|
235
324
|
|
|
325
|
+
const next = this.#nextFocusTarget(target, e.key);
|
|
326
|
+
if (!next) return;
|
|
236
327
|
e.preventDefault();
|
|
237
|
-
|
|
238
|
-
this.#select(
|
|
328
|
+
next.focus();
|
|
329
|
+
this.#select(next);
|
|
239
330
|
};
|
|
240
331
|
}
|
|
@@ -68,6 +68,9 @@
|
|
|
68
68
|
display: none;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
/* [multiple] never sets data-indicator-ready (segmented.class.js render())
|
|
72
|
+
— the indicator span is never created/prepended in multi-select mode,
|
|
73
|
+
so it stays display:none via the rule above. */
|
|
71
74
|
:scope[data-indicator-ready] > [data-indicator] {
|
|
72
75
|
display: block;
|
|
73
76
|
position: absolute;
|
|
@@ -12,8 +12,10 @@ export interface SegmentedChangeEventDetail<V extends string = string> {
|
|
|
12
12
|
export type SegmentedChangeEvent<V extends string = string> = CustomEvent<SegmentedChangeEventDetail<V>>;
|
|
13
13
|
|
|
14
14
|
export class UISegmented extends UIFormElement {
|
|
15
|
-
/** Selected segment's value. */
|
|
15
|
+
/** Selected segment's value. Under `multiple`, a comma-separated set. */
|
|
16
16
|
value: string;
|
|
17
|
+
/** Enables multi-select — comma-separated `value`, no sliding indicator, Space/Enter toggles (gh#1369). */
|
|
18
|
+
multiple: boolean;
|
|
17
19
|
|
|
18
20
|
addEventListener<K extends keyof HTMLElementEventMap>(
|
|
19
21
|
type: K,
|