@skdx/docs-kit 0.35.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/LICENSE +21 -0
- package/README.md +22 -0
- package/dist/component-aliases.json +12 -0
- package/dist/data/THIRD-PARTY-NOTICES.md +21 -0
- package/dist/data/angular-inputs.json +1 -0
- package/dist/data/api-manifest.json +1 -0
- package/dist/data/exports-by-framework.json +1 -0
- package/dist/data/honoured-slots.json +1 -0
- package/dist/data/styling-hooks-manifest.json +10331 -0
- package/dist/frameworks.mjs +64 -0
- package/dist/shared/contracts/accordion.d.ts +3 -0
- package/dist/shared/contracts/accordion.js +1 -0
- package/dist/shared/contracts/alert.d.ts +3 -0
- package/dist/shared/contracts/alert.js +1 -0
- package/dist/shared/contracts/angle-slider.d.ts +3 -0
- package/dist/shared/contracts/angle-slider.js +1 -0
- package/dist/shared/contracts/aspect-ratio.d.ts +3 -0
- package/dist/shared/contracts/aspect-ratio.js +1 -0
- package/dist/shared/contracts/autocomplete.d.ts +3 -0
- package/dist/shared/contracts/autocomplete.js +1 -0
- package/dist/shared/contracts/avatar.d.ts +3 -0
- package/dist/shared/contracts/avatar.js +1 -0
- package/dist/shared/contracts/badge.d.ts +3 -0
- package/dist/shared/contracts/badge.js +1 -0
- package/dist/shared/contracts/box.d.ts +3 -0
- package/dist/shared/contracts/box.js +1 -0
- package/dist/shared/contracts/breadcrumb.d.ts +3 -0
- package/dist/shared/contracts/breadcrumb.js +1 -0
- package/dist/shared/contracts/button.d.ts +3 -0
- package/dist/shared/contracts/button.js +1 -0
- package/dist/shared/contracts/calendar.d.ts +5 -0
- package/dist/shared/contracts/calendar.js +1 -0
- package/dist/shared/contracts/card.d.ts +3 -0
- package/dist/shared/contracts/card.js +1 -0
- package/dist/shared/contracts/carousel.d.ts +3 -0
- package/dist/shared/contracts/carousel.js +1 -0
- package/dist/shared/contracts/change-reason.d.ts +29 -0
- package/dist/shared/contracts/change-reason.js +1 -0
- package/dist/shared/contracts/chat-composer.d.ts +3 -0
- package/dist/shared/contracts/chat-composer.js +1 -0
- package/dist/shared/contracts/chat-message.d.ts +3 -0
- package/dist/shared/contracts/chat-message.js +1 -0
- package/dist/shared/contracts/checkbox-card.d.ts +3 -0
- package/dist/shared/contracts/checkbox-card.js +1 -0
- package/dist/shared/contracts/checkbox-group.d.ts +3 -0
- package/dist/shared/contracts/checkbox-group.js +1 -0
- package/dist/shared/contracts/checkbox.d.ts +3 -0
- package/dist/shared/contracts/checkbox.js +1 -0
- package/dist/shared/contracts/clipboard.d.ts +3 -0
- package/dist/shared/contracts/clipboard.js +1 -0
- package/dist/shared/contracts/collapsible.d.ts +3 -0
- package/dist/shared/contracts/collapsible.js +1 -0
- package/dist/shared/contracts/color-picker.d.ts +3 -0
- package/dist/shared/contracts/color-picker.js +1 -0
- package/dist/shared/contracts/combobox.d.ts +3 -0
- package/dist/shared/contracts/combobox.js +1 -0
- package/dist/shared/contracts/command.d.ts +3 -0
- package/dist/shared/contracts/command.js +1 -0
- package/dist/shared/contracts/comment-thread.d.ts +3 -0
- package/dist/shared/contracts/comment-thread.js +1 -0
- package/dist/shared/contracts/comment.d.ts +3 -0
- package/dist/shared/contracts/comment.js +1 -0
- package/dist/shared/contracts/confirm-dialog.d.ts +3 -0
- package/dist/shared/contracts/confirm-dialog.js +1 -0
- package/dist/shared/contracts/conversation-list.d.ts +3 -0
- package/dist/shared/contracts/conversation-list.js +1 -0
- package/dist/shared/contracts/dashboard-layout.d.ts +3 -0
- package/dist/shared/contracts/dashboard-layout.js +1 -0
- package/dist/shared/contracts/date-field.d.ts +3 -0
- package/dist/shared/contracts/date-field.js +1 -0
- package/dist/shared/contracts/date-picker.d.ts +3 -0
- package/dist/shared/contracts/date-picker.js +1 -0
- package/dist/shared/contracts/date-value.d.ts +11 -0
- package/dist/shared/contracts/date-value.js +1 -0
- package/dist/shared/contracts/dialog.d.ts +3 -0
- package/dist/shared/contracts/dialog.js +1 -0
- package/dist/shared/contracts/divider.d.ts +5 -0
- package/dist/shared/contracts/divider.js +1 -0
- package/dist/shared/contracts/drawer.d.ts +3 -0
- package/dist/shared/contracts/drawer.js +1 -0
- package/dist/shared/contracts/editable.d.ts +3 -0
- package/dist/shared/contracts/editable.js +1 -0
- package/dist/shared/contracts/empty-state.d.ts +3 -0
- package/dist/shared/contracts/empty-state.js +1 -0
- package/dist/shared/contracts/field.d.ts +3 -0
- package/dist/shared/contracts/field.js +1 -0
- package/dist/shared/contracts/file-upload.d.ts +3 -0
- package/dist/shared/contracts/file-upload.js +1 -0
- package/dist/shared/contracts/filter-bar.d.ts +3 -0
- package/dist/shared/contracts/filter-bar.js +1 -0
- package/dist/shared/contracts/floating-panel.d.ts +3 -0
- package/dist/shared/contracts/floating-panel.js +1 -0
- package/dist/shared/contracts/forgot-password-page.d.ts +3 -0
- package/dist/shared/contracts/forgot-password-page.js +1 -0
- package/dist/shared/contracts/form-property.d.ts +3 -0
- package/dist/shared/contracts/form-property.js +1 -0
- package/dist/shared/contracts/form-section.d.ts +3 -0
- package/dist/shared/contracts/form-section.js +1 -0
- package/dist/shared/contracts/form-validity.d.ts +7 -0
- package/dist/shared/contracts/form-validity.js +1 -0
- package/dist/shared/contracts/form.d.ts +3 -0
- package/dist/shared/contracts/form.js +1 -0
- package/dist/shared/contracts/heading.d.ts +3 -0
- package/dist/shared/contracts/heading.js +1 -0
- package/dist/shared/contracts/image.d.ts +3 -0
- package/dist/shared/contracts/image.js +1 -0
- package/dist/shared/contracts/index.d.ts +8 -0
- package/dist/shared/contracts/index.js +1 -0
- package/dist/shared/contracts/kbd.d.ts +3 -0
- package/dist/shared/contracts/kbd.js +1 -0
- package/dist/shared/contracts/label.d.ts +3 -0
- package/dist/shared/contracts/label.js +1 -0
- package/dist/shared/contracts/link.d.ts +3 -0
- package/dist/shared/contracts/link.js +1 -0
- package/dist/shared/contracts/list.d.ts +3 -0
- package/dist/shared/contracts/list.js +1 -0
- package/dist/shared/contracts/listbox.d.ts +3 -0
- package/dist/shared/contracts/listbox.js +1 -0
- package/dist/shared/contracts/loading-overlay.d.ts +3 -0
- package/dist/shared/contracts/loading-overlay.js +1 -0
- package/dist/shared/contracts/member-id.d.ts +18 -0
- package/dist/shared/contracts/member-id.js +1 -0
- package/dist/shared/contracts/mentions.d.ts +3 -0
- package/dist/shared/contracts/mentions.js +1 -0
- package/dist/shared/contracts/menu.d.ts +3 -0
- package/dist/shared/contracts/menu.js +1 -0
- package/dist/shared/contracts/menubar.d.ts +3 -0
- package/dist/shared/contracts/menubar.js +1 -0
- package/dist/shared/contracts/navigation-menu.d.ts +6 -0
- package/dist/shared/contracts/navigation-menu.js +1 -0
- package/dist/shared/contracts/notification-center.d.ts +3 -0
- package/dist/shared/contracts/notification-center.js +1 -0
- package/dist/shared/contracts/number-field.d.ts +5 -0
- package/dist/shared/contracts/number-field.js +1 -0
- package/dist/shared/contracts/onboarding-checklist.d.ts +3 -0
- package/dist/shared/contracts/onboarding-checklist.js +1 -0
- package/dist/shared/contracts/overlay-parts.d.ts +73 -0
- package/dist/shared/contracts/overlay-parts.js +1 -0
- package/dist/shared/contracts/page-container.d.ts +3 -0
- package/dist/shared/contracts/page-container.js +1 -0
- package/dist/shared/contracts/pagination.d.ts +5 -0
- package/dist/shared/contracts/pagination.js +1 -0
- package/dist/shared/contracts/password-input.d.ts +6 -0
- package/dist/shared/contracts/password-input.js +1 -0
- package/dist/shared/contracts/pin-input.d.ts +6 -0
- package/dist/shared/contracts/pin-input.js +1 -0
- package/dist/shared/contracts/polymorphic.d.ts +6 -0
- package/dist/shared/contracts/polymorphic.js +1 -0
- package/dist/shared/contracts/popover.d.ts +7 -0
- package/dist/shared/contracts/popover.js +1 -0
- package/dist/shared/contracts/progress.d.ts +6 -0
- package/dist/shared/contracts/progress.js +1 -0
- package/dist/shared/contracts/qr-code.d.ts +5 -0
- package/dist/shared/contracts/qr-code.js +1 -0
- package/dist/shared/contracts/radio-card.d.ts +6 -0
- package/dist/shared/contracts/radio-card.js +1 -0
- package/dist/shared/contracts/radio-group.d.ts +6 -0
- package/dist/shared/contracts/radio-group.js +1 -0
- package/dist/shared/contracts/rating.d.ts +6 -0
- package/dist/shared/contracts/rating.js +1 -0
- package/dist/shared/contracts/reset-password-page.d.ts +3 -0
- package/dist/shared/contracts/reset-password-page.js +1 -0
- package/dist/shared/contracts/resizable.d.ts +7 -0
- package/dist/shared/contracts/resizable.js +1 -0
- package/dist/shared/contracts/rules.d.ts +11 -0
- package/dist/shared/contracts/rules.js +1 -0
- package/dist/shared/contracts/scroll-area.d.ts +6 -0
- package/dist/shared/contracts/scroll-area.js +1 -0
- package/dist/shared/contracts/select.d.ts +5 -0
- package/dist/shared/contracts/select.js +1 -0
- package/dist/shared/contracts/selection-value.d.ts +20 -0
- package/dist/shared/contracts/selection-value.js +1 -0
- package/dist/shared/contracts/sign-in-page.d.ts +3 -0
- package/dist/shared/contracts/sign-in-page.js +1 -0
- package/dist/shared/contracts/sign-up-page.d.ts +3 -0
- package/dist/shared/contracts/sign-up-page.js +1 -0
- package/dist/shared/contracts/skeleton.d.ts +5 -0
- package/dist/shared/contracts/skeleton.js +1 -0
- package/dist/shared/contracts/slider.d.ts +7 -0
- package/dist/shared/contracts/slider.js +1 -0
- package/dist/shared/contracts/speed-dial.d.ts +6 -0
- package/dist/shared/contracts/speed-dial.js +1 -0
- package/dist/shared/contracts/spinner.d.ts +6 -0
- package/dist/shared/contracts/spinner.js +1 -0
- package/dist/shared/contracts/split-button.d.ts +6 -0
- package/dist/shared/contracts/split-button.js +1 -0
- package/dist/shared/contracts/stat-card.d.ts +3 -0
- package/dist/shared/contracts/stat-card.js +1 -0
- package/dist/shared/contracts/stepper.d.ts +6 -0
- package/dist/shared/contracts/stepper.js +1 -0
- package/dist/shared/contracts/styling-hooks.d.ts +8 -0
- package/dist/shared/contracts/styling-hooks.js +1 -0
- package/dist/shared/contracts/switch.d.ts +6 -0
- package/dist/shared/contracts/switch.js +1 -0
- package/dist/shared/contracts/table.d.ts +7 -0
- package/dist/shared/contracts/table.js +1 -0
- package/dist/shared/contracts/tabs.d.ts +5 -0
- package/dist/shared/contracts/tabs.js +1 -0
- package/dist/shared/contracts/tag-group.d.ts +7 -0
- package/dist/shared/contracts/tag-group.js +1 -0
- package/dist/shared/contracts/tags-input.d.ts +8 -0
- package/dist/shared/contracts/tags-input.js +1 -0
- package/dist/shared/contracts/text-field.d.ts +6 -0
- package/dist/shared/contracts/text-field.js +1 -0
- package/dist/shared/contracts/text.d.ts +6 -0
- package/dist/shared/contracts/text.js +1 -0
- package/dist/shared/contracts/textarea.d.ts +5 -0
- package/dist/shared/contracts/textarea.js +1 -0
- package/dist/shared/contracts/time-field.d.ts +5 -0
- package/dist/shared/contracts/time-field.js +1 -0
- package/dist/shared/contracts/time.d.ts +6 -0
- package/dist/shared/contracts/time.js +1 -0
- package/dist/shared/contracts/timeline.d.ts +5 -0
- package/dist/shared/contracts/timeline.js +1 -0
- package/dist/shared/contracts/toast.d.ts +6 -0
- package/dist/shared/contracts/toast.js +1 -0
- package/dist/shared/contracts/toggle-group.d.ts +6 -0
- package/dist/shared/contracts/toggle-group.js +1 -0
- package/dist/shared/contracts/toggle.d.ts +5 -0
- package/dist/shared/contracts/toggle.js +1 -0
- package/dist/shared/contracts/toolbar.d.ts +3 -0
- package/dist/shared/contracts/toolbar.js +1 -0
- package/dist/shared/contracts/tour.d.ts +5 -0
- package/dist/shared/contracts/tour.js +1 -0
- package/dist/shared/contracts/transfer.d.ts +6 -0
- package/dist/shared/contracts/transfer.js +1 -0
- package/dist/shared/contracts/tree-select.d.ts +6 -0
- package/dist/shared/contracts/tree-select.js +1 -0
- package/dist/shared/contracts/tree.d.ts +6 -0
- package/dist/shared/contracts/tree.js +1 -0
- package/dist/shared/contracts/types.d.ts +230 -0
- package/dist/shared/contracts/types.js +1 -0
- package/dist/shared/contracts/usage-card.d.ts +3 -0
- package/dist/shared/contracts/usage-card.js +1 -0
- package/dist/shared/contracts/user-menu.d.ts +3 -0
- package/dist/shared/contracts/user-menu.js +1 -0
- package/dist/shared/contracts/verification-page.d.ts +3 -0
- package/dist/shared/contracts/verification-page.js +1 -0
- package/dist/shared/contracts/workspace-switcher.d.ts +3 -0
- package/dist/shared/contracts/workspace-switcher.js +1 -0
- package/dist/shared/core/announcer.d.ts +17 -0
- package/dist/shared/core/announcer.js +1 -0
- package/dist/shared/core/appearance.d.ts +14 -0
- package/dist/shared/core/appearance.js +1 -0
- package/dist/shared/core/arrow-keys.d.ts +7 -0
- package/dist/shared/core/arrow-keys.js +1 -0
- package/dist/shared/core/calendar-locale.d.ts +35 -0
- package/dist/shared/core/calendar-locale.js +1 -0
- package/dist/shared/core/color.d.ts +80 -0
- package/dist/shared/core/color.js +1 -0
- package/dist/shared/core/controllable.d.ts +42 -0
- package/dist/shared/core/controllable.js +1 -0
- package/dist/shared/core/csv.d.ts +43 -0
- package/dist/shared/core/csv.js +2 -0
- package/dist/shared/core/date-segments.d.ts +223 -0
- package/dist/shared/core/date-segments.js +1 -0
- package/dist/shared/core/date-value.d.ts +57 -0
- package/dist/shared/core/date-value.js +1 -0
- package/dist/shared/core/dev-mode.d.ts +12 -0
- package/dist/shared/core/dev-mode.js +1 -0
- package/dist/shared/core/dialogs.d.ts +96 -0
- package/dist/shared/core/dialogs.js +1 -0
- package/dist/shared/core/dismissal.d.ts +56 -0
- package/dist/shared/core/dismissal.js +1 -0
- package/dist/shared/core/field-core.d.ts +250 -0
- package/dist/shared/core/field-core.js +1 -0
- package/dist/shared/core/focus-targets.d.ts +77 -0
- package/dist/shared/core/focus-targets.js +1 -0
- package/dist/shared/core/format-file-size.d.ts +9 -0
- package/dist/shared/core/format-file-size.js +1 -0
- package/dist/shared/core/glyph-data.d.ts +13 -0
- package/dist/shared/core/glyph-data.js +1 -0
- package/dist/shared/core/measure-auto-resize.d.ts +5 -0
- package/dist/shared/core/measure-auto-resize.js +1 -0
- package/dist/shared/core/media-query.d.ts +7 -0
- package/dist/shared/core/media-query.js +1 -0
- package/dist/shared/core/mentions.d.ts +116 -0
- package/dist/shared/core/mentions.js +2 -0
- package/dist/shared/core/pin-chars.d.ts +13 -0
- package/dist/shared/core/pin-chars.js +1 -0
- package/dist/shared/core/placement.d.ts +102 -0
- package/dist/shared/core/placement.js +1 -0
- package/dist/shared/core/qr-encoder.d.ts +33 -0
- package/dist/shared/core/qr-encoder.js +1 -0
- package/dist/shared/core/roving-tab-stop.d.ts +37 -0
- package/dist/shared/core/roving-tab-stop.js +1 -0
- package/dist/shared/core/select-keyboard.d.ts +80 -0
- package/dist/shared/core/select-keyboard.js +1 -0
- package/dist/shared/core/selection.d.ts +58 -0
- package/dist/shared/core/selection.js +1 -0
- package/dist/shared/core/tabbable.d.ts +8 -0
- package/dist/shared/core/tabbable.js +1 -0
- package/dist/shared/core/timer.d.ts +82 -0
- package/dist/shared/core/timer.js +1 -0
- package/dist/shared/core/tree-columns.d.ts +48 -0
- package/dist/shared/core/tree-columns.js +1 -0
- package/dist/shared/core/typeahead.d.ts +27 -0
- package/dist/shared/core/typeahead.js +1 -0
- package/dist/shared/index.d.ts +113 -0
- package/dist/shared/index.js +1 -0
- package/dist/skins-src/_foundation-fallback.css +124 -0
- package/dist/skins-src/base.css +328 -0
- package/dist/skins-src/components/_actuator.css +203 -0
- package/dist/skins-src/components/_arrow.css +20 -0
- package/dist/skins-src/components/_card-control.css +27 -0
- package/dist/skins-src/components/_collection.css +281 -0
- package/dist/skins-src/components/_hit-target.css +28 -0
- package/dist/skins-src/components/_overlay.css +214 -0
- package/dist/skins-src/components/_status.css +38 -0
- package/dist/skins-src/components/_trigger.css +85 -0
- package/dist/skins-src/components/accordion.css +85 -0
- package/dist/skins-src/components/alert.css +118 -0
- package/dist/skins-src/components/angle-slider.css +110 -0
- package/dist/skins-src/components/aspect-ratio.css +26 -0
- package/dist/skins-src/components/autocomplete.css +112 -0
- package/dist/skins-src/components/avatar.css +87 -0
- package/dist/skins-src/components/badge.css +164 -0
- package/dist/skins-src/components/box.css +9 -0
- package/dist/skins-src/components/breadcrumb.css +78 -0
- package/dist/skins-src/components/button.css +304 -0
- package/dist/skins-src/components/calendar.css +269 -0
- package/dist/skins-src/components/card.css +116 -0
- package/dist/skins-src/components/carousel.css +192 -0
- package/dist/skins-src/components/chat-composer.css +89 -0
- package/dist/skins-src/components/chat-message.css +98 -0
- package/dist/skins-src/components/checkbox-card.css +153 -0
- package/dist/skins-src/components/checkbox-group.css +72 -0
- package/dist/skins-src/components/checkbox.css +141 -0
- package/dist/skins-src/components/clipboard.css +126 -0
- package/dist/skins-src/components/collapsible.css +64 -0
- package/dist/skins-src/components/color-picker.css +304 -0
- package/dist/skins-src/components/combobox.css +111 -0
- package/dist/skins-src/components/command.css +73 -0
- package/dist/skins-src/components/comment-thread.css +56 -0
- package/dist/skins-src/components/comment.css +59 -0
- package/dist/skins-src/components/confirm-dialog.css +43 -0
- package/dist/skins-src/components/conversation-list.css +142 -0
- package/dist/skins-src/components/dashboard-layout.css +106 -0
- package/dist/skins-src/components/date-field.css +95 -0
- package/dist/skins-src/components/date-picker.css +79 -0
- package/dist/skins-src/components/dialog.css +161 -0
- package/dist/skins-src/components/divider.css +64 -0
- package/dist/skins-src/components/drawer.css +166 -0
- package/dist/skins-src/components/editable.css +121 -0
- package/dist/skins-src/components/empty-state.css +85 -0
- package/dist/skins-src/components/field.css +104 -0
- package/dist/skins-src/components/file-upload.css +164 -0
- package/dist/skins-src/components/filter-bar.css +48 -0
- package/dist/skins-src/components/floating-panel.css +168 -0
- package/dist/skins-src/components/forgot-password-page.css +45 -0
- package/dist/skins-src/components/form-section.css +75 -0
- package/dist/skins-src/components/form.css +115 -0
- package/dist/skins-src/components/heading.css +38 -0
- package/dist/skins-src/components/image.css +43 -0
- package/dist/skins-src/components/kbd.css +76 -0
- package/dist/skins-src/components/label.css +45 -0
- package/dist/skins-src/components/link.css +72 -0
- package/dist/skins-src/components/list.css +104 -0
- package/dist/skins-src/components/listbox.css +90 -0
- package/dist/skins-src/components/loading-overlay.css +89 -0
- package/dist/skins-src/components/mentions.css +79 -0
- package/dist/skins-src/components/menu.css +102 -0
- package/dist/skins-src/components/menubar.css +130 -0
- package/dist/skins-src/components/navigation-menu.css +145 -0
- package/dist/skins-src/components/notification-center.css +139 -0
- package/dist/skins-src/components/number-field.css +95 -0
- package/dist/skins-src/components/onboarding-checklist.css +156 -0
- package/dist/skins-src/components/page-container.css +29 -0
- package/dist/skins-src/components/pagination.css +147 -0
- package/dist/skins-src/components/password-input.css +116 -0
- package/dist/skins-src/components/pin-input.css +115 -0
- package/dist/skins-src/components/popover.css +108 -0
- package/dist/skins-src/components/progress.css +207 -0
- package/dist/skins-src/components/qr-code.css +62 -0
- package/dist/skins-src/components/radio-card.css +158 -0
- package/dist/skins-src/components/radio-group.css +148 -0
- package/dist/skins-src/components/rating.css +150 -0
- package/dist/skins-src/components/reset-password-page.css +51 -0
- package/dist/skins-src/components/resizable.css +131 -0
- package/dist/skins-src/components/scroll-area.css +101 -0
- package/dist/skins-src/components/select.css +239 -0
- package/dist/skins-src/components/sign-in-page.css +47 -0
- package/dist/skins-src/components/sign-up-page.css +55 -0
- package/dist/skins-src/components/skeleton.css +55 -0
- package/dist/skins-src/components/skip-link.css +51 -0
- package/dist/skins-src/components/slider.css +164 -0
- package/dist/skins-src/components/speed-dial.css +162 -0
- package/dist/skins-src/components/spinner.css +59 -0
- package/dist/skins-src/components/split-button.css +167 -0
- package/dist/skins-src/components/stat-card.css +117 -0
- package/dist/skins-src/components/stepper.css +153 -0
- package/dist/skins-src/components/switch.css +155 -0
- package/dist/skins-src/components/table.css +336 -0
- package/dist/skins-src/components/tabs.css +116 -0
- package/dist/skins-src/components/tag-group.css +72 -0
- package/dist/skins-src/components/tags-input.css +176 -0
- package/dist/skins-src/components/text-field.css +182 -0
- package/dist/skins-src/components/text.css +83 -0
- package/dist/skins-src/components/textarea.css +118 -0
- package/dist/skins-src/components/time-field.css +43 -0
- package/dist/skins-src/components/time.css +13 -0
- package/dist/skins-src/components/timeline.css +206 -0
- package/dist/skins-src/components/toast.css +133 -0
- package/dist/skins-src/components/toggle-group.css +185 -0
- package/dist/skins-src/components/toggle.css +89 -0
- package/dist/skins-src/components/toolbar.css +84 -0
- package/dist/skins-src/components/tour.css +67 -0
- package/dist/skins-src/components/transfer.css +112 -0
- package/dist/skins-src/components/tree-select.css +124 -0
- package/dist/skins-src/components/tree.css +110 -0
- package/dist/skins-src/components/usage-card.css +129 -0
- package/dist/skins-src/components/user-menu.css +83 -0
- package/dist/skins-src/components/verification-page.css +64 -0
- package/dist/skins-src/components/workspace-switcher.css +133 -0
- package/dist/skins-src/utilities.css +130 -0
- package/dist/skins-src/web-components.css +64 -0
- package/dist/strip-paint.d.mts +7 -0
- package/dist/strip-paint.mjs +131 -0
- package/dist/themes/AntDark.md +14 -0
- package/dist/themes/AntDark.ts +47 -0
- package/dist/themes/AntLight.md +21 -0
- package/dist/themes/AntLight.ts +95 -0
- package/dist/themes/CatppuccinLatte.md +20 -0
- package/dist/themes/CatppuccinLatte.ts +93 -0
- package/dist/themes/CatppuccinMocha.md +15 -0
- package/dist/themes/CatppuccinMocha.ts +93 -0
- package/dist/themes/ChakraDark.md +8 -0
- package/dist/themes/ChakraDark.ts +47 -0
- package/dist/themes/ChakraLight.md +14 -0
- package/dist/themes/ChakraLight.ts +93 -0
- package/dist/themes/Contrast.test.ts +80 -0
- package/dist/themes/CupcakeDark.md +8 -0
- package/dist/themes/CupcakeDark.ts +39 -0
- package/dist/themes/CupcakeLight.md +31 -0
- package/dist/themes/CupcakeLight.ts +93 -0
- package/dist/themes/DefaultTheme.md +8 -0
- package/dist/themes/DefaultTheme.test.ts +96 -0
- package/dist/themes/DefaultTheme.ts +137 -0
- package/dist/themes/DraculaDark.md +14 -0
- package/dist/themes/DraculaDark.ts +93 -0
- package/dist/themes/DraculaLight.md +8 -0
- package/dist/themes/DraculaLight.ts +55 -0
- package/dist/themes/EmeraldDark.md +8 -0
- package/dist/themes/EmeraldDark.ts +35 -0
- package/dist/themes/EmeraldLight.md +8 -0
- package/dist/themes/EmeraldLight.ts +93 -0
- package/dist/themes/EverforestDark.md +26 -0
- package/dist/themes/EverforestDark.ts +99 -0
- package/dist/themes/EverforestLight.md +31 -0
- package/dist/themes/EverforestLight.ts +51 -0
- package/dist/themes/FluentDark.md +8 -0
- package/dist/themes/FluentDark.ts +47 -0
- package/dist/themes/FluentLight.md +8 -0
- package/dist/themes/FluentLight.ts +100 -0
- package/dist/themes/GraphiteDark.md +8 -0
- package/dist/themes/GraphiteDark.ts +35 -0
- package/dist/themes/GraphiteLight.md +14 -0
- package/dist/themes/GraphiteLight.ts +93 -0
- package/dist/themes/GruvboxDark.md +14 -0
- package/dist/themes/GruvboxDark.ts +93 -0
- package/dist/themes/GruvboxLight.md +27 -0
- package/dist/themes/GruvboxLight.ts +49 -0
- package/dist/themes/MaterialDark.md +8 -0
- package/dist/themes/MaterialDark.ts +47 -0
- package/dist/themes/MaterialLight.md +8 -0
- package/dist/themes/MaterialLight.ts +104 -0
- package/dist/themes/MidnightDark.md +8 -0
- package/dist/themes/MidnightDark.ts +19 -0
- package/dist/themes/MidnightLight.md +8 -0
- package/dist/themes/MidnightLight.ts +23 -0
- package/dist/themes/NordDark.md +28 -0
- package/dist/themes/NordDark.ts +93 -0
- package/dist/themes/NordLight.md +20 -0
- package/dist/themes/NordLight.ts +50 -0
- package/dist/themes/OneDark.md +26 -0
- package/dist/themes/OneDark.ts +93 -0
- package/dist/themes/OneLight.md +20 -0
- package/dist/themes/OneLight.ts +51 -0
- package/dist/themes/PrimerDark.md +26 -0
- package/dist/themes/PrimerDark.ts +99 -0
- package/dist/themes/PrimerLight.md +14 -0
- package/dist/themes/PrimerLight.ts +93 -0
- package/dist/themes/RosePine.md +23 -0
- package/dist/themes/RosePine.ts +93 -0
- package/dist/themes/RosePineDawn.md +20 -0
- package/dist/themes/RosePineDawn.ts +51 -0
- package/dist/themes/SkandaDark.md +8 -0
- package/dist/themes/SkandaDark.ts +57 -0
- package/dist/themes/SkandaLight.md +8 -0
- package/dist/themes/SkandaLight.ts +96 -0
- package/dist/themes/SolarizedDark.md +8 -0
- package/dist/themes/SolarizedDark.ts +93 -0
- package/dist/themes/SolarizedLight.md +32 -0
- package/dist/themes/SolarizedLight.ts +93 -0
- package/dist/themes/SynthwaveDark.md +8 -0
- package/dist/themes/SynthwaveDark.ts +93 -0
- package/dist/themes/SynthwaveLight.md +20 -0
- package/dist/themes/SynthwaveLight.ts +48 -0
- package/dist/themes/Themes.test.ts +110 -0
- package/dist/themes/brands.test.ts +63 -0
- package/dist/themes/brands.ts +121 -0
- package/dist/themes/createBrandTheme.test.ts +223 -0
- package/dist/themes/createBrandTheme.ts +298 -0
- package/dist/themes/index.ts +54 -0
- package/package.json +73 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{changeDetail as e}from"./change-reason.js";import{DATE_MALFORMED_RULE as t,DATE_OUTPUT_RULE as a}from"./date-value.js";import{constraintValidationMethods as n,setCustomValidityMethod as i}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as r}from"./styling-hooks.js";var m={name:"TimeField",purpose:'Segmented keyboard entry of a time of day: one role="spinbutton" per segment (hour, minute, optionally second, plus AM/PM in a 12-hour locale), with locale-derived segment order from Intl.DateTimeFormat.formatToParts. Shares its segment engine with DateField.',lightDom:!0,props:[{name:"value",type:"string | Date | null",required:!1,description:`Current time as 24-hour HH:mm (or HH:mm:ss) string. null while any segment is untyped. Independent of hourCycle, which is display only. A Date reads its local time; the date part is discarded, as a time is not an instant. ${t}`},{name:"defaultValue",type:"string | Date | null",required:!1,frameworks:["react","vue","svelte","angular"],exception:"wc-default",frameworksReason:"Its value attribute is the single source of truth like a native input; formResetCallback restores it.",description:"Initial time for uncontrolled usage (HH:mm[:ss]). React, Vue, Svelte and Angular only."},{name:"granularity",type:"'minute' | 'second'",defaultValue:"'minute'",required:!1,description:"How far down the field is editable. 'minute' renders hour and minute; 'second' adds a seconds segment. There is deliberately no 'hour': hour and minute always render together (a bare hour field is not a time anyone types, and HH:00 is what it would submit), so 'hour' and 'minute' named the same field and the name with no distinct meaning was removed."},{name:"hourCycle",type:"12 | 24",required:!1,description:"Forces 12-hour or 24-hour display. Defaults to the locale. Presentation only \u2014 value is always 24 hour."},{name:"locale",type:"string",required:!1,description:"BCP-47 locale deciding segment order, the literals between segments, and the AM/PM names. Defaults to the runtime locale."},{name:"min",type:"string | Date",required:!1,description:`Earliest accepted time, in the same 24-hour HH:mm[:ss] shape as value. A value before it sets aria-invalid="true" and data-invalid on the group and fails constraint validation, so checkValidity() reports rangeUnderflow the way <input type="time" min> does. Home on a segment then clamps to this bound rather than to the segment's own natural minimum.`},{name:"max",type:"string | Date",required:!1,description:"Latest accepted time, same HH:mm[:ss] shape. A value after it is aria-invalid/data-invalid and fails constraint validation with rangeOverflow, and End clamps to it."},{name:"step",type:"number",defaultValue:"one unit of the finest rendered segment \u2014 60 on a 'minute' field, 1 on a 'second' one",required:!1,description:'Increment in seconds, like <input type="time" step>. ArrowUp/ArrowDown on finest segment step by step value; coarser segments step by one. Times off-grid fail stepMismatch validation measured from min or midnight. Non-whole units or values \u2265 segment range are not honored by arrows but still constrain validity. Grid anchors on segment minimum, not min bound. Default is one finest-segment unit, not 60.'},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the field and removes every segment from the tab order."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:"Segments stay focusable and readable but refuse every edit."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Marks the field as invalid."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Marks the field required. valueMissing while any segment is untyped, and the segments announce aria-required. Independent of name: the mirrored native control is rendered for a required field even when it submits nothing, so a requirement that is announced is also a requirement checkValidity() enforces."},{name:"name",type:"string",required:!1,description:"Form field name. Without it the field submits nothing. With it, the time submits as the 24-hour HH:mm[:ss] string."},{name:"dir",type:"'ltr' | 'rtl'",required:!1,frameworks:["react","vue","svelte","angular"],exception:"attribute-passthrough",frameworksReason:"<skdx-time-field> declares no `dir` input by design: it resolves direction by climbing from the host to the nearest `[dir]` ancestor, crossing shadow boundaries, so the native `dir` attribute on the element itself is already the per-instance override. A declared property would be a second source of truth for an attribute the platform owns.",description:"Writing direction of the field, which decides which arrow key moves focus *forward* through the segments: under rtl, ArrowLeft moves to the next segment and ArrowRight to the previous one. Omit it and direction is read off the DOM (a dir attribute on any ancestor), which is the normal case \u2014 this prop is the per-instance override for a field whose direction disagrees with the page's. Contracted because it changes keyboard behaviour, not only layout: an uncontracted prop that decides what a key does is a behaviour no parity tool can see."},{name:"getSegmentLabel",type:"(type: 'hour' | 'minute' | 'second' | 'dayPeriod') => string",required:!1,description:'Words the accessible name per segment type. Segment order and literals come from Intl; these names do not, as they describe the widget. Defaults to English ("hour", "minute", "AM/PM", \u2026). **Property-only**: it is a function, so no attribute form.'},{name:"emptySegmentText",type:"string",required:!1,description:'The aria-valuetext an untyped segment announces instead of a number it does not have; aria-valuenow has to stay present, so this is the text that actually gets read. Defaults to "Empty".'},{name:"getSegmentPlaceholder",type:"(type: 'hour' | 'minute' | 'second' | 'dayPeriod') => string",required:!1,description:'Words the placeholder letters per segment type. Segment order and literals come from Intl; the placeholder does not, as CLDR has nothing to say about the absence of value. Defaults to English ("hh", "mm", "ss", "--").'},{name:"form",type:"string",required:!1,description:"Id of the <form> that owns this field when rendered elsewhere. React/Vue/Svelte/Angular forward it to the hidden input; Web Components use the native FormAssociated API."}],events:[{name:"value-change",detail:e("string | null"),description:`Fires with the new HH:mm[:ss] string once every segment is filled, and with null as soon as a segment is cleared, whichever form the value was authored in. Never fires with a half-typed time. ${a.replace("the native Date shape","the canonical 24-hour string")}`}],parts:[{name:"Segment",description:"One editable piece of the value (hour, minute, second, dayPeriod), rendered by the root in the locale order. Exposed for styling via ::part(segment) and [data-segment]; not instantiated by the consumer."}],slots:[],states:["default","disabled","readonly","invalid","placeholder"],controlledUncontrolled:'Controlled via value + a change event, or uncontrolled via defaultValue. value is controlled only while it is not undefined: null is a legitimate controlled "no time entered" and must not fall back to the internal value, otherwise a consumer could never clear a controlled field. Web Components have no defaultValue: like a native input, value is the single source of truth with no controlled/uncontrolled split, so <skdx-time-field value="09:30"> is the initial time and that value attribute is what a form reset restores.',formBehavior:'Form-associated: submits 24-hour HH:mm[:ss] string with a name; empty when incomplete. Form reset restores initial value. React/Vue/Svelte/Angular validate through hidden <input type="time">; Web Components through ElementInternals. Its segments (spinbuttons) are not disabled by <fieldset disabled> but submission is.',validationBehavior:`Ranges may wrap past midnight: min="14:00" max="02:00" is valid through midnight. Browser enforces min/max; wrapping works without a JS validator. aria-invalid/data-invalid computed by string comparison (doesn't wrap). Incomplete is valueMissing; out-of-bounds is rangeUnderflow/rangeOverflow (painted aria-invalid). stepMismatch not painted. All frameworks validate identically through browser or ElementInternals. invalid is presentational.`,accessibility:{role:"group on the root; spinbutton on each editable segment",keyboard:[{key:"ArrowUp",behavior:"Increments the focused segment, wrapping at maximum. Untyped segment starts from current wall-clock value, not floor. With step > 1, only lands on the step grid."},{key:"ArrowDown",behavior:"Decrements the focused segment, wrapping at minimum on the same step grid. Off-grid values snap to the next grid point in the pressed direction."},{key:"ArrowLeft / ArrowRight",behavior:'Moves focus to the previous/next editable segment, mirrored under dir="rtl" so ArrowLeft always means "forward through the value as it reads".'},{key:"Home / End",behavior:"Sets segment to minimum/maximum, clamped to min/max bounds when set. Only Home/End clamp; typing and arrows must reach out-of-range times for validation."},{key:"0-9",behavior:"Types into the focused segment, rolling over when a keystroke would overflow it and advancing to the next segment once no further digit could fit."},{key:"A / P (or the first letter of the locale's own day-period names)",behavior:"Sets AM/PM segment in 12-hour locales. A and P always work; other keys match the first character of localised names (case- and accent-insensitive). Ambiguous keystrokes are ignored."},{key:"Backspace / Delete",behavior:"Clears the focused segment back to its placeholder."}],ariaAttributes:['role="group" on the root, so assistive technology reads the segments as one control','aria-valuenow/aria-valuemin/aria-valuemax on each segment; a placeholder segment reports aria-valuenow at its minimum and announces itself via aria-valuetext="Empty"',"aria-valuenow is always inside [aria-valuemin, aria-valuemax], including mid-entry: a half-typed segment may hold a value below its minimum so the next keystroke can extend it, but the spinbutton publishes the clamped number and puts the typed digits in aria-valuetext, which is what a spinbutton announces in preference to the number",'aria-valuetext on each segment carries the rendered text (the AM/PM name, or "Empty")','aria-disabled and aria-invalid (both global ARIA) go on the group; aria-readonly and aria-required go on each spinbutton, because role="group" does not allow them'],focusManagement:"Each editable segment is individually focusable (tabindex 0, or -1 while disabled); digit entry advances focus to the next segment automatically. Literals are aria-hidden and never focusable.",namingRequirement:"The root needs an accessible name (aria-label or aria-labelledby, e.g. from a Label); each segment is self-labelled with its segment type."},styling:{cssParts:["time-field","segment","literal"],dataAttributes:[...r,"data-disabled","data-readonly","data-invalid","data-segment","data-placeholder"],cssCustomProperties:[]},publicMethods:[...n,i]};export{m as timeFieldContract};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{DATE_INPUT_RULE as e,DATE_MALFORMED_RULE as t,DATE_PARSE_RULE as a}from"./date-value.js";import{ROOT_DATA_ATTRIBUTES as o}from"./styling-hooks.js";var n={name:"Time",purpose:'A <time> element: datetime is the machine-readable instant, text is that instant for a human in their locale or as a relative label like "3 hours ago". With relative labels, the absolute date moves to title.',props:[{name:"value",type:"Date | string",required:!0,description:`The instant to render. ${e} ${a} ${t}`},{name:"relative",type:"boolean",defaultValue:"false",required:!1,description:'Render text as a relative label ("3 hours ago", "in 2 days") from `now` via Intl.RelativeTimeFormat. The datetime attribute stays absolute, since that is the machine-readable half.'},{name:"absoluteTitle",type:"boolean",defaultValue:"true",required:!1,description:"While `relative` is set, put the absolute formatted date in title. On by default because relative labels are lossy. Set false only when title would duplicate nearby text."},{name:"locale",type:"string",required:!1,description:"BCP-47 locale for the formatted text. Omitted, it resolves to the runtime's own locale \u2014 the same one toLocaleDateString() would pick \u2014 so the default matches the rest of the page without the consumer restating it."},{name:"now",type:"Date | number",required:!1,description:"The instant a relative label measures from. Omit it and this component starts no timer of its own; supply it and the consumer owns the clock\u2014one interval re-renders every instance and hydration reads the same value."}],events:[],slots:[{name:"default",description:"Overrides the formatted text. The datetime attribute still comes from `value`, so overriding the text cannot desynchronise the machine-readable half."}],states:["default"],controlledUncontrolled:"Stateless \u2014 Time derives its text from `value` and `now` on every render and holds nothing between them.",formBehavior:"Not applicable \u2014 Time participates in no form.",validationBehavior:"Not applicable \u2014 a malformed `value` is ignored and warns once in development; it is never coerced to today or to an Invalid Date.",accessibility:{role:"time (the native <time> element)",keyboard:[],ariaAttributes:[],focusManagement:"Not focusable itself; not part of the tab order."},styling:{cssParts:["time"],dataAttributes:[...o],cssCustomProperties:[]},publicMethods:[]};export{n as timeContract};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var n={name:"Timeline",purpose:"A purely structural timeline of events. Renders an <ol>; layout and connecting lines are entirely up to consumer CSS. Composed of Item, Indicator, Divider, and Content parts.",props:[{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'vertical'",required:!1,description:"Layout axis, exposed as data-orientation only \u2014 no ARIA orientation or keyboard handling, since neither changes how the list is read. Both values are implemented via CSS."},{name:"items",type:"ReadonlyArray<{ content: unknown; opposite?: unknown; indicator?: unknown; indicatorLabel?: string; state?: 'complete' | 'current' | 'pending' }>",required:!1,description:"Event data for self-rendering instead of hand-written children: `content` is the body, `opposite` the metadata across the marker, `indicator` what goes in the marker, `state` the entry's place in the sequence (written to Item's data-state), and `indicatorLabel` names the marker (per-event, not per-root). Composition is the default; when supplied this is the source of truth."},{name:"renderContent",type:"(item: { content: unknown; opposite?: unknown; indicator?: unknown; indicatorLabel?: string; state?: string }) => unknown",required:!1,frameworks:["react","svelte","angular","webComponents"],exception:"render-prop",frameworksReason:"Vue and Angular have no render-function member to name: Vue spells this as a `content` scoped slot receiving the same entry, and Angular as a TemplateRef taking it as template context. It is the same content hole in each framework's own idiom \u2014 the gate matches member names literally and has no per-prop rename mechanism, which is how tree's `renderLabel` is already declared.",description:"Renders an event's body from its `items` entry, for content beyond the entry's `content` value. Ignored without `items`. Vue ships this as a `content` scoped slot; Angular as a TemplateRef. Property-only in Web Components (no attribute form for functions)."},{name:"renderOpposite",type:"(item: { content: unknown; opposite?: unknown; indicator?: unknown; indicatorLabel?: string; state?: string }, index: number) => unknown",required:!1,frameworks:["webComponents"],exception:"render-prop",frameworksReason:"React, Svelte and Angular put markup straight into an item's `opposite` as a node, snippet or template, and Vue spells it as the `opposite` scoped slot. A custom element's `items` property carries strings, so markup for the opposite region reaches it only through a render callback.",description:"Renders an event's opposite metadata in place of its `opposite` string, for markup rather than text. Ignored without `items`. Property-only, since a function has no attribute form."},{name:"align",type:"'end' | 'alternate' | (string & {})",required:!1,description:"Marker-side rung, written to data-align on the root; the data-align attribute may be set directly instead."}],events:[],parts:[{name:"Item",description:'One event. Composes an Indicator, an optional Divider, a Content and an optional Opposite, in that order \u2014 the skin places by grid column rather than by DOM order, so DOM order is free to be the reading order. Carries an explicit role="listitem", because the skin gives it display: grid and an item that is no longer display: list-item loses its implicit role in Safari/VoiceOver.',props:[{name:"state",type:"'complete' | 'current' | 'pending'",required:!1,description:"Where the event sits in the sequence, written to data-state on the item; the data-state attribute may be set directly instead."}]},{name:"Indicator",description:'The marker: a dot or custom content. Decorative by default (aria-hidden="true" when empty), since an announced dot before every event is noise. When rendering content, it must carry an accessible name (a meaningful icon with no name announces as nothing useful).'},{name:"Separator",description:'The connector between two markers. role="presentation" + aria-hidden="true": it is a line, and a line has nothing to say.'},{name:"Content",description:"The event itself \u2014 the Item's body content."},{name:"Opposite",description:"The metadata region on the far side of the marker (timestamp, actor, elapsed time). Optional. Exists because metadata would otherwise live inside Content; here the skin gives it its own column. Render before the Indicator: the skin places by grid column, but screen readers read DOM order."}],slots:[{name:"default",description:"Timeline items. Item elements and nothing else \u2014 anything else breaks the <ol> content model, which is what carries the list semantics this family has instead of a role of its own."},{name:"indicator",description:"A TimelineItem's dot/icon marker."},{name:"separator",description:"The connecting line between two TimelineItems."},{name:"content",description:"A TimelineItem's body content."},{name:"opposite",description:"A TimelineItem's metadata region, opposite the event across the marker."}],appearance:[{attribute:"data-align",values:["end","alternate"],stylesheet:"timeline.css"}],states:["complete","current","pending"],controlledUncontrolled:"Stateless \u2014 Timeline holds no internal state.",formBehavior:"Not applicable \u2014 Timeline does not participate in forms.",validationBehavior:"Not applicable \u2014 Timeline carries no value and participates in no validation.",accessibility:{role:'list (native <ol>, with an explicit role="list"); each item is an explicit role="listitem"',keyboard:[],ariaAttributes:['Root carries an explicit role="list", and each item an explicit role="listitem"','Separator is role="presentation" + aria-hidden="true"','Indicator is aria-hidden="true" when it renders nothing, and carries its own accessible name when it renders content'],focusManagement:"Not focusable; not part of the tab order."},styling:{cssParts:["timeline","item","indicator","separator","content","opposite"],dataAttributes:[...e,"data-orientation","data-align","data-state",{name:"data-skdx-timeline-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[]},publicMethods:[]};export{n as timelineContract};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ComponentContract } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* An app-level `ToastProvider` supplying a default auto-dismiss duration and
|
|
4
|
+
* a persistent `aria-live` announcer, with individual `Toast`s rendered into a `ToastViewport`.
|
|
5
|
+
*/
|
|
6
|
+
export declare const toastContract: ComponentContract;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{forceMountProp as e}from"./overlay-parts.js";import{ROOT_DATA_ATTRIBUTES as t}from"./styling-hooks.js";var a={...e,description:`Keep the toast in the DOM while closed so an exit animation has a data-state="closed" element. Pair with open-change-complete to drop the entry from the consumer's list.`,frameworks:["react","vue","svelte","angular"],exception:"force-mount",frameworksReason:"Web Components toggles `hidden` instead of unmounting, so a mount switch would have no state."},r={name:"Toast",purpose:"Accessible, auto-dismissing notifications. ToastProvider renders an aria-live announcer; Toasts auto-dismiss unless hovered or focused. The toaster store (createToaster/SkdxToastService) queues entries and publishes create/update/dismiss/promise.",props:[{name:"open",type:"boolean",required:!1,description:"Controlled open state, on Toast itself. Pair with the open-change event."},{name:"defaultOpen",type:"boolean",defaultValue:"true",required:!1,description:"Initial open state for uncontrolled usage. Defaults to true: a toast mounts after an event has already occurred."},{name:"duration",type:"number",required:!1,description:"Auto-dismiss duration in ms for this Toast. Infinity disables auto-dismiss. Falls back to the ancestor ToastProvider's duration when unset."},a,{name:"type",type:"'foreground' | 'background'",defaultValue:"'background'",required:!1,description:`"foreground" announces assertively; "background" politely. Picks which of ToastProvider's two announcer regions the toast enters. The root carries no live-region role.`}],events:[{name:"open-change",detail:"boolean",description:"Fired with the new open state when it changes: timer expiring, Close, Escape, or swipe past swipeThreshold. A swipe routes through open-change for unified handling."},{name:"open-change-complete",detail:"boolean",description:"Fired after the toast's enter or exit animation ends, or immediately when none. Signals when a forceMounted toast should be dropped from the consumer's list."},{name:"escape-key-down",detail:"Event",description:"Fired when Escape is pressed while the toast has focus. Preventing default keeps the toast open."},{name:"pause",detail:"void",description:"Fired when the auto-dismiss timer pauses: pointer enters, focus lands inside, or page is hidden. Not cancelable (WCAG 2.2 SC 2.2.1)."},{name:"resume",detail:"void",description:"Fired when the auto-dismiss timer restarts on the remaining time: the pointer leaves, focus leaves, or the page becomes visible again. Not cancelable."}],parts:[{name:"Provider",description:"App-level ancestor mounted once near root. Supplies default auto-dismiss duration and region label, and renders two persistent aria-live regions that announce toasts.",props:[{name:"label",type:"string",defaultValue:"'Notification'",required:!1,description:"Accessible name for the ToastViewport landmark. Store-rendered regions use 'Notifications'; hand-mounted Providers use 'Notification'."},{name:"duration",type:"number",defaultValue:"5000",required:!1,description:"Default auto-dismiss duration (ms) for descendant Toasts. 5000 is a floor: WCAG 2.2.1 requires time to read; timer pauses on hover/focus/page-hidden."},{name:"swipeDirection",type:"'up' | 'down' | 'left' | 'right' | 'start' | 'end'",defaultValue:"'end'",required:!1,description:"Drag direction to dismiss. start/end resolve against writing direction and mirror under RTL; the four physical values are absolute."},{name:"swipeThreshold",type:"number",defaultValue:"50",required:!1,description:'Pixels along swipeDirection to dismiss. Short of it, the drag snaps back (data-swipe="cancel").'}]},{name:"Toaster",aliases:[{name:"Region",frameworks:["webComponents"],frameworksReason:"A custom element is named by its tag, and <skdx-toaster> would read as the store rather than the landmark it renders; <skdx-toast-region> names the region a page mounts once."}],description:"The region component that renders at most `max` entries from the store into a ToastProvider + ToastViewport. React/Vue/Svelte/Web Components take the store as a `toaster` prop; Angular injects SkdxToastService instead. Takes no props: max/placement/duration/label are set on the store (see contextApi). Translates each entry's type onto data-type (queue's vocabulary) and data-status (severity vocabulary for styling)."},{name:"Viewport",description:'Fixed region the toasts stack in: role="region", labelled by Provider, tabindex="-1", data-placement for docking.',props:[{name:"hotkey",type:"string[]",defaultValue:"['F6']",required:!1,description:"Keys to move focus into the region and (with Shift) back out. Modifiers (Alt/Control/Meta/Shift) precede the KeyboardEvent.key. Appended to the region's accessible name so users know about it."}]},{name:"Title",description:"The toast's heading, published as aria-labelledby for keyboard entry."},{name:"Description",description:"The toast's body text, published as aria-describedby."},{name:"Action",description:'Optional actionable button ("Undo"). Runs the handler then closes the toast.',props:[{name:"altText",type:"string",required:!0,description:'What the action does (e.g., "Undo upload"). Required: the verb alone means nothing after the toast disappears.'}]},{name:"Close",description:'Dismissal button. Defaults to aria-label="Dismiss".'}],slots:[{name:"default",description:"Toast's body (Title, Description, Action, Close)."}],states:["open","closed","queued"],controlledUncontrolled:"Uncontrolled by default: starts open and self-closes. Controlled via open prop.",formBehavior:'Not applicable \u2014 Toast participates in no form; Action and Close are type="button".',validationBehavior:"Not applicable.",accessibility:{role:`none \u2014 the toast root is a generic element; announcement is the ToastProvider announcer's job, and a role="status"/"alert" here would duplicate it. The one carve-out: a standalone <skdx-toast> with no provider above it sets role="status" on itself, because with no announcer in the tree the host is the only channel left`,keyboard:[{key:"Escape",behavior:"Closes the toast."},{key:"Tab",behavior:"Reaches Action/Close while the toast is visible; pauses the auto-dismiss timer while any part of it is focused."},{key:"F6 (ToastViewport's hotkey)",behavior:"Moves focus into the ToastViewport region from anywhere on the page \u2014 the way in for a keyboard user, since a toast never steals focus. Configurable per region via the Viewport part's hotkey, and appended to the region's accessible name so it is announced on arrival."},{key:"Shift+F6 (Shift + ToastViewport's hotkey)",behavior:"Returns focus to its previous location."}],ariaAttributes:["ToastProvider renders two persistent visually-hidden aria-live regions (polite and assertive) that announce toasts",'ToastViewport is role="region", labelled by ToastProvider with hotkey appended ("Notifications (F6)"), tabindex="-1"',"Toast root carries no live-region role: its text reaches exactly one aria-live region (the announcer)","Toast root aria-labelledby points at Title, aria-describedby at Description (keyboard entry users benefit)",'ToastClose carries aria-label="Dismiss" by default',"ToastAction carries its altText as aria-label"],namingRequirement:'ToastClose must have an accessible name. Defaults to aria-label="Dismiss" so screen-reader users can dismiss it.',focusManagement:"Does not steal focus \u2014 announced via aria-live instead. F6 enters the region, Shift+F6 leaves. Focus restores if the focused toast is removed. Hover/focus/page-hidden pauses the timer. Swipe is addition to Close/Escape/timer (WCAG 2.2 SC 2.5.1, 2.5.7)."},styling:{cssParts:["viewport","root","title","description","action","close"],dataAttributes:[...t,"data-state","data-type","data-status","data-paused","data-swipe","data-swipe-direction","data-placement","data-skdx-toast-announcer"],cssCustomProperties:["--skdx-toast-swipe-move-x","--skdx-toast-swipe-move-y"]},publicMethods:[{name:"setOpen",signature:"(open: boolean) => void",frameworks:["webComponents"],exception:"imperative",frameworksReason:"Only the custom element publishes it. The other four re-render with a new open prop and never expose a setter; a Web Components consumer holds the element itself, so the same change is made by calling this method on it.",description:"Shows or dismisses this toast and emits open-change, exactly as its close control would."}],contextApi:[{name:"createToaster",signature:"(options?: { max?: number; placement?: ToastPlacement; duration?: number; label?: string }) => ToasterStore",description:"Creates the queue once per app. Options are read-only on the store; no component accepts them as props.",accessors:{react:"createToaster({ max, placement, duration, label }) from '@skdx/react'",vue:"createToaster({ max, placement, duration, label }) from '@skdx/vue'",svelte:"createToaster({ max, placement, duration, label }) from '@skdx/svelte'",angular:"{ provide: SKDX_TOASTER_OPTIONS, useValue: { max, placement, duration, label } } in the root providers",webComponents:"createToaster({ max, placement, duration, label }) from '@skdx/web-components', assigned to <skdx-toast-region>.toaster"}},{name:"max",signature:"readonly max: number",defaultValue:"3",description:"Visible toasts at once; rest queue in FIFO order. Set in createToaster/SKDX_TOASTER_OPTIONS.",accessors:{react:"createToaster().max",vue:"createToaster().max",svelte:"createToaster().max",angular:"inject(SkdxToastService).max",webComponents:"createToaster().max"}},{name:"placement",signature:"readonly placement: 'top-start' | 'top' | 'top-end' | 'bottom-start' | 'bottom' | 'bottom-end'",defaultValue:"'bottom-end'",description:"Region position, emitted as data-placement for layout. Set in createToaster/SKDX_TOASTER_OPTIONS.",accessors:{react:"createToaster().placement",vue:"createToaster().placement",svelte:"createToaster().placement",angular:"inject(SkdxToastService).placement",webComponents:"createToaster().placement"}},{name:"duration",signature:"readonly duration: number",defaultValue:"5000",description:"Default auto-dismiss duration (ms) for queued toasts, minimum 5000: WCAG 2.2.1. Loading toasts never auto-dismiss. Set in createToaster/SKDX_TOASTER_OPTIONS.",accessors:{react:"createToaster().duration",vue:"createToaster().duration",svelte:"createToaster().duration",angular:"inject(SkdxToastService).duration",webComponents:"createToaster().duration"}},{name:"label",signature:"readonly label: string",defaultValue:"'Notifications'",description:"Accessible label for the region landmark. Set in createToaster/SKDX_TOASTER_OPTIONS.",accessors:{react:"createToaster().label",vue:"createToaster().label",svelte:"createToaster().label",angular:"inject(SkdxToastService).label",webComponents:"createToaster().label"}},{name:"create",signature:"(options?: { id?, title?, description?, type?, duration?, action?, closeLabel? }) => string",description:"Queues a toast and returns its id. Creating with an existing id replaces that entry.",accessors:{react:"createToaster().create",vue:"createToaster().create",svelte:"createToaster().create",angular:"inject(SkdxToastService).create",webComponents:"createToaster().create"}},{name:"update",signature:"(id: string, options: ToastOptions) => void",description:"Merges options into a queued toast and re-announces it.",accessors:{react:"createToaster().update",vue:"createToaster().update",svelte:"createToaster().update",angular:"inject(SkdxToastService).update",webComponents:"createToaster().update"}},{name:"dismiss",signature:"(id?: string) => void",description:"Removes one toast or the entire queue.",accessors:{react:"createToaster().dismiss",vue:"createToaster().dismiss",svelte:"createToaster().dismiss",angular:"inject(SkdxToastService).dismiss",webComponents:"createToaster().dismiss"}},{name:"promise",signature:"<T>(promise: Promise<T>, messages: { loading, success, error }, options?: ToastOptions) => Promise<T>",description:"Shows a loading toast, then success or error when the promise settles. Rejections are re-thrown.",accessors:{react:"createToaster().promise",vue:"createToaster().promise",svelte:"createToaster().promise",angular:"inject(SkdxToastService).promise",webComponents:"createToaster().promise"}}]};export{r as toastContract};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{changeDetail as e}from"./change-reason.js";import{constraintValidationMethods as o,setCustomValidityMethod as r}from"./form-validity.js";import{SELECTION_ATTRIBUTE_RULE as t,SELECTION_INPUT_RULE as a,SELECTION_OUTPUT_RULE as s}from"./selection-value.js";import{ROOT_DATA_ATTRIBUTES as i}from"./styling-hooks.js";var h={name:"ToggleGroup",purpose:'A group of toggle buttons with either single or multiple selection, chosen via a type prop. Manages roving tabindex and arrow-key/Home/End navigation between items. A segmented control is this component with type="single", variant="segmented" and selectOnFocus: one exclusive choice, a strip skin, and an Indicator that slides behind the pressed item.',props:[{name:"type",type:"'single' | 'multiple'",required:!0,description:"Whether one item or several can be pressed. Required in all packages: React makes it a union discriminant (type error if omitted), Vue/Svelte non-optional, Angular/Web Components enforce at runtime. Prevents silent defaults that would quietly unpress the user's choice."},{name:"value",type:"string | string[]",required:!1,description:`Pressed item value(s), for controlled usage. ${a} ${s} ${t}`},{name:"defaultValue",type:"string | string[]",required:!1,description:`Initially pressed item value(s), for uncontrolled usage. Same shape as \`value\`. ${a} ${t}`},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables every item in the group, blocking activation and taking the whole group out of the tab order."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:"Displays a committed choice the user may not change. Items stay focusable and navigable, so the group keeps its tab stop; the root carries data-readonly, and the value still submits."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Marks the group invalid via data-invalid on the root. Presentational only \u2014 use required or setCustomValidity() to actually block a submit."},{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Layout axis for arrow-key roving focus, exposed as data-orientation. Two axes only, no 'both': a strip of buttons is a line, and the cross-axis arrows already work on either one."},{name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Whether arrow-key navigation wraps from the last item back to the first. Pass false alongside selectOnFocus, where wrapping past the end would silently re-select the item at the other end for a user who pressed one time too many."},{name:"deselectable",type:"boolean",defaultValue:"true",required:!1,description:"Whether a single-selection group may be emptied by pressing its pressed item again. Ignored when type is 'multiple'. Default true \u2014 a toggle group is buttons, not a radio."},{name:"selectOnFocus",type:"boolean",defaultValue:"false",required:!1,description:"Whether moving the roving focus onto an item also presses it, so arrow keys browse the choices rather than only the focus. Only meaningful with type='single', where exactly one item can be pressed; a multiple group would accumulate a pressed item per arrow press. Off by default \u2014 a group of buttons activates on Space or Enter \u2014 and on for a segmented strip, where the choice follows focus the way a radio group's does. Focus arriving from outside the group never presses, only focus moving between siblings does."},{name:"rovingFocus",type:"boolean",defaultValue:"true",required:!1,description:"Whether the group manages a single tab stop with arrow-key navigation. When false, every enabled item is a tab stop and arrow keys are unhandled \u2014 for groups inside a Toolbar."},{name:"name",type:"string",required:!1,description:"Form field name. Pressed item value(s) are submitted under it; without it the group submits nothing."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Marks the group required. valueMissing while no item is pressed."},{name:"form",type:"string | undefined",required:!1,defaultValue:"undefined",description:"Id of the `<form>` to submit into. Forwarded to mirrored controls so the group can live outside its form (filter bar, portal, sticky footer). Requires `name`. **Web Components** exposes as `formId` (property) not `form` (which is read-only on form-associated elements), though the attribute is `form` in all packages."},{name:"options",type:"ReadonlyArray<{ value: string; label: string; disabled?: boolean }>",required:!1,description:`The toggle buttons the group derives from \u2014 one Item per entry, keyed by value so list changes preserve the pressed item's element and roving tab stop. Flat only, no option-group shape. Under variant="segmented" the derived anatomy also carries an Indicator.`},{name:"variant",type:"'segmented' | (string & {})",required:!1,description:'Shape rung, written to data-variant on the root; the data-variant attribute may be set directly instead. "segmented" paints the group as one joined strip with a sliding Indicator rather than separate buttons.'},{name:"fullWidth",type:"boolean",required:!1,description:"Stretches the group to its container width, written to data-full-width on the root; the data-full-width attribute may be set directly instead."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the root; the data-size attribute may be set directly instead."}],events:[{name:"value-change",description:`Fires whenever the pressed items change, controlled or not. With selectOnFocus an arrow key that moves focus also presses, so keyboard browsing reports 'keyboard' on every step. ${s}`,detail:e("string[]","selectedValue: string | null")},{name:"value-change-detail",frameworks:["angular"],exception:"event-shape",frameworksReason:"Angular's `valueChange` emits the whole `string[]` selection so `[(value)]` round-trips it; this second output carries the detail object the other four hand to `value-change`.",description:"Fires with valueChange, carrying the pressed item values plus the item that changed.",detail:e("string[]","selectedValue: string | null")}],parts:[{name:"Item",description:"One toggle button in the group, pressed when its value is in the group's value. Same paint as standalone Toggle (wears both skdx-toggle-group__item and skdx-toggle classes). Separate component \u2014 group holds string[] of values, item owns nothing; standalone holds boolean. Same visual, different state model.",props:[{name:"value",type:"string",required:!0,description:"Identifier compared against the group's pressed value(s)."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables this item alone, on top of the group's own disabled, and excludes it from the roving focus order. Every package renders the item as a native button, so the disabled attribute carries the state. Under readOnly the item keeps its tab stop instead, since a committed choice still has to be readable by keyboard."},{name:"pressed",type:"boolean",required:!1,frameworks:["webComponents"],exception:"wc-internals",frameworksReason:"Only the custom element publishes it. The other four hand this derived state down to their parts through context, so a consumer never reads it off a part; here every part is its own element with no such channel, and reading it back is the only way to reflect the state in surrounding markup.",description:"Whether this item currently holds one of the group's pressed values. Read-only: press or clear it through the root's value."}]},{name:"Indicator",description:'The highlight that slides behind the pressed item, measuring its rect into --skdx-toggle-group-x, --skdx-toggle-group-y, --skdx-toggle-group-width and --skdx-toggle-group-height. The movement itself is one CSS transition the consumer writes, so the component publishes geometry and animates nothing. Decorative and aria-hidden, because the items already report which one is pressed. Publishes nothing until it has measured and renders data-state="hidden" until then, so a skin must supply a fallback: var(--skdx-toggle-group-width, 0). Belongs to the segmented variant, where a single pressed item makes one highlight meaningful.'}],slots:[{name:"default",description:"ToggleGroupItem children, plus an Indicator when the group is painted as a segmented strip."}],states:["on","off","disabled","readonly","invalid","hidden"],appearance:[{attribute:"data-variant",values:["segmented"],stylesheet:"toggle-group.css"},{attribute:"data-full-width",values:[],stylesheet:"toggle-group.css"},{attribute:"data-size",values:["sm","lg"],stylesheet:"toggle-group.css"}],controlledUncontrolled:"Controlled via value + a change event, or uncontrolled via defaultValue. With nothing pressed at all the group is still operable \u2014 the first enabled item carries the tab stop. In Angular the pair is split: `valueChange` emits the whole `string[]` selection for `[(value)]`, `valueChangeDetail` carries the detail.",formBehavior:'Form-associated: with a name, single group submits one entry (radio-like), multiple group submits one per pressed item. Empty group submits nothing, valueMissing when required. React/Vue/Svelte/Angular use visually-hidden native text inputs (never type="hidden" and never readonly, both bar constraint validation); Web Components uses ElementInternals.setFormValue. Empty *required* groups: four packages submit empty entry, Web Components submits nothing (same trade-off as Select and Rating). Form reset restores value attribute in Web Components only. Only disabled withholds the value \u2014 a readOnly group still submits the choice it is displaying.',validationBehavior:"required participates in native constraint validation, reported through checkValidity()/reportValidity(), and setCustomValidity() applies on top. invalid is presentational only: it paints and announces the group as invalid without failing a constraint, so a group that must block a submit needs required or a custom validity message.",accessibility:{role:"group",keyboard:[{key:"ArrowRight/ArrowDown",behavior:"Moves focus to the next item. Both keys, on both axes \u2014 orientation sets layout, not which arrows work."},{key:"ArrowLeft/ArrowUp",behavior:"Moves focus to the previous item. Both keys, on both axes."},{key:"Arrow keys at either end",behavior:"Wrap to the other end, unless loop is false, where focus stays put. With selectOnFocus a wrap also re-presses, which is why a segmented strip turns looping off."},{key:"Home",behavior:"Moves focus to the first item."},{key:"End",behavior:"Moves focus to the last item."},{key:"Space",behavior:"Activates or deactivates the focused item. In 'multiple' mode a pressed item unpresses. In 'single' mode a different item takes selection; pressed item unpresses only when deselectable is true. With selectOnFocus the arrow key has already pressed it, so Space is the second route rather than the only one."},{key:"Enter",behavior:"Identical to Space."},{key:"Tab",behavior:"Enters and leaves the group at its single tab stop, moving focus without pressing anything, even under selectOnFocus. Every item is its own tab stop only under rovingFocus={false}."}],ariaAttributes:["each item exposes aria-pressed","aria-disabled on an item disabled while the group is readOnly, so it keeps its place in the roving order",'no aria-readonly, aria-invalid or aria-required on the root, which role="group" does not permit; data-readonly, data-invalid and data-required carry those states for the skin',"aria-hidden on the Indicator, which redraws a state the items already report"],focusManagement:"Roving tabindex \u2014 the first pressed enabled item holds the tab stop, in single and multiple mode alike; with nothing pressed the first enabled item holds it. Once resolved the stop stays where it is for as long as its item is still enabled and still pressed. Disabled by rovingFocus={false}. selectOnFocus couples pressing to that movement, but only when focus arrives from a sibling item: tabbing in from outside moves focus and presses nothing.",namingRequirement:'A ToggleGroup is role="group" and must be named with aria-label or aria-labelledby. Without a name, screen-reader users hear buttons with no context of what they choose.'},styling:{cssParts:["toggle-group","item","indicator"],dataAttributes:[...i,"data-orientation","data-disabled","data-readonly","data-invalid","data-required","data-variant","data-full-width","data-size","data-skdx-toggle-group-item",{name:"data-skdx-toggle-group-item-wrapper",description:"On the display:contents host Angular renders around each Item, so a skin can reach past it to the button.",frameworks:["angular"],exception:"framework-host",frameworksReason:"Angular alone renders a component host around the item button and neutralises it with display:contents. React, Vue, Svelte and Web Components render the button as the item element itself, so there is no wrapper node for the attribute to sit on."},"data-state","data-value",{name:"data-skdx-toggle-group-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:["--skdx-toggle-group-x","--skdx-toggle-group-y","--skdx-toggle-group-width","--skdx-toggle-group-height"]},publicMethods:[...o,r],frameworkExtensions:[{framework:"webComponents",name:"requiredMessage",type:"string",description:"Custom message shown when the required constraint fails; Web Components only, set from markup with the required-message attribute."}]};export{h as toggleGroupContract};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var a={name:"Toggle",purpose:"A two-state button (e.g. bold in a toolbar). Renders aria-pressed, data-state, and data-disabled; toggles pressed state on click. Works controlled or uncontrolled.",props:[{name:"pressed",type:"boolean",required:!1,description:"Pressed state, for controlled usage. Pair with a pressed-change event."},{name:"defaultPressed",type:"boolean",defaultValue:"false",required:!1,frameworks:["react","vue","svelte","angular"],exception:"wc-default",frameworksReason:"<skdx-toggle>'s reflected `pressed` attribute is the uncontrolled seed; a second prop would be redundant.",description:"Initial pressed state, for uncontrolled usage."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:'Disables toggling and excludes the toggle from the tab order, announced via the native disabled attribute where the platform honours it and via aria-disabled="true" otherwise.'},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the root; the data-size attribute may be set directly instead."}],events:[{name:"pressed-change",detail:"boolean",description:"Fires with the new pressed state whenever it changes."}],slots:[{name:"default",description:"Button content."}],appearance:[{attribute:"data-size",values:["sm","lg"],stylesheet:"toggle.css"}],states:["on","off","disabled"],controlledUncontrolled:"Controlled via pressed + change event, or uncontrolled via defaultPressed. Web Components: no defaultPressed (reflected attribute is the seed) and the element mutates pressed before dispatching pressed-change.",formBehavior:"Not applicable \u2014 Toggle does not participate in forms.",validationBehavior:"Not applicable \u2014 Toggle carries no value and participates in no validation.",accessibility:{role:"button (aria-pressed carries the state; every package renders a native <button>)",keyboard:[{key:"Enter",behavior:"Activates the toggle (native button behavior)."},{key:"Space",behavior:"Activates the toggle (native button behavior)."}],ariaAttributes:["aria-pressed reflects the pressed state",'aria-disabled="true" while disabled, on elements the native disabled attribute cannot disable.'],focusManagement:"Native button focus behavior; part of the normal tab order unless disabled.",namingRequirement:"Must have a non-empty accessible name, and the name must stay stable across states \u2014 a Mute button that becomes Unmute on press reports a different control, since state is aria-pressed's role."},styling:{cssParts:["toggle"],dataAttributes:[...e,"data-state","data-disabled","data-size"],cssCustomProperties:[]},publicMethods:[]};export{a as toggleContract};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ComponentContract } from './types.js';
|
|
2
|
+
/** The Toolbar contract: every framework's Toolbar implements a single flat roving-tabindex group spanning every focusable descendant, matching a native OS toolbar. */
|
|
3
|
+
export declare const toolbarContract: ComponentContract;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{changeDetail as e}from"./change-reason.js";import{SELECTION_ATTRIBUTE_RULE as t,SELECTION_INPUT_RULE as a,SELECTION_OUTPUT_RULE as o}from"./selection-value.js";import{ROOT_DATA_ATTRIBUTES as r}from"./styling-hooks.js";var l={name:"Toolbar",purpose:"A roving-tabindex group of controls (buttons, links, toggles) \u2014 one Tab stop, arrow keys move between items. Use for three or more; two buttons don't need it. Avoid nested components that own arrow keys (Tabs, Slider, Listbox, RadioGroup, Menu). ToggleGroup is safe (no key claims).",props:[{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Layout axis for arrow-key roving-tabindex navigation."},{name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Whether arrow-key navigation wraps from the last item back to the first."},{name:"items",type:"ToolbarItem[]",required:!1,description:"Controls for the derived toolbar (Button, Link, Separator, or ToggleGroup), narrowed by optional `type` discriminant. Renders the row from data instead of hand-composed parts."},{name:"renderItem",type:"(item: ToolbarItem) => React.ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:'Vue expresses this as a scoped #item slot, Web Components as a light-DOM slot="item" child keyed by data-value \u2014 neither a declared prop an extractor can see, and Web Components falls back to the plain label when nothing matches. Angular ships the same name as a TemplateRef input.',description:"Customises what renders *inside* a derived control, never the control itself \u2014 the element's role, id, data attributes, roving tab stop and disabled state stay the library's; only read while `items` is deriving the anatomy."}],events:[{name:"value-change",description:`Fires from ToggleGroup (not the root) whenever an item is pressed or unpressed, controlled or not \u2014 declared here since the contract has one events array. ${o}`,detail:e("string[]","selectedValue: string | null")},{name:"value-change-detail",frameworks:["angular"],exception:"event-shape",frameworksReason:"Angular's `valueChange` emits the whole `string[]` selection so `[(value)]` round-trips it; this second output carries the detail object the other four hand to `value-change`.",description:"Fires with valueChange from ToggleGroup, carrying the pressed values plus the item that changed.",detail:e("string[]","selectedValue: string | null")}],parts:[{name:"Button",description:"A plain action button in the toolbar, carrying the roving tab stop like every other item.",props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the button and takes it out of the roving-tabindex ring, so arrow keys skip it and it never claims the single tab stop."}]},{name:"ToggleGroup",description:'Groups a set of ToggleItems and owns their pressed state, as a role="group" inside the toolbar; tab-stop management stays with the root.',props:[{name:"type",type:"'single' | 'multiple'",required:!0,description:"'single' keeps at most one item pressed at a time, 'multiple' allows any number; required in all five packages with no default (a union discriminant in React/Vue/Svelte, thrown when absent in Angular/Web Components) since a silent fallback would quietly unpress the user's choice."},{name:"value",type:"string | string[]",required:!1,description:`Pressed item value(s), for controlled usage. Pair with value-change. ${a} ${o} ${t}`},{name:"defaultValue",type:"string | string[]",required:!1,description:`Initially pressed item value(s), for uncontrolled usage. Same shape as \`value\`. ${a} ${t}`},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables every ToggleItem in the group; an item is disabled when either this or its own `disabled` prop is set \u2014 OR-ed, never overridden."}]},{name:"ToggleItem",description:"One pressable item inside a ToggleGroup, exposing its pressed state through aria-pressed and data-state.",props:[{name:"value",type:"string",required:!0,description:"This item's value \u2014 what the group reports as pressed, and what it matches against value/defaultValue."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables this item alone, on top of the group's; every package renders it as a native button, so the `disabled` attribute carries the state, blocks activation, and is skipped by the roving-tabindex order."}]}],slots:[{name:"default",description:"Toolbar items \u2014 buttons, links, separators, toggle groups."}],states:["default"],controlledUncontrolled:"Stateless at the root \u2014 only the roving-tabindex current-stop is internal state. Its ToggleGroup splits the Angular pair: `valueChange` emits the whole `string[]` selection for `[(value)]`, `valueChangeDetail` carries the detail.",formBehavior:"Not applicable \u2014 Toolbar does not participate in forms.",validationBehavior:"Not applicable \u2014 Toolbar carries no value and participates in no validation.",accessibility:{role:"toolbar",keyboard:[{key:"ArrowLeft/ArrowRight (horizontal) or ArrowUp/ArrowDown (vertical)",behavior:"Moves focus between items."},{key:"Home",behavior:"Moves focus to the first enabled item \u2014 no state change, no event, just the roving tab stop."},{key:"End",behavior:"Moves focus to the last enabled item. No state change and no event."}],ariaAttributes:["aria-orientation reflects the orientation prop",'aria-label or aria-labelledby on the root, supplied by the consumer \u2014 role="toolbar" takes no name from its items, so an unnamed one announces as a bare "toolbar". No prop needed: passthrough already carries both.'],focusManagement:"Roving tabindex spans every focusable item, in two phases. Before hydration (SSR, an Astro island, an unhydrated RSC subtree) *every enabled item* is a tab stop, since the stop is resolved from a layout effect that hasn't run \u2014 an unreachable group is worse than a degraded one. From the first layout effect onward, exactly one item holds it; a disabled item never claims it, and the stop is re-seeded whenever the item holding it is removed."},styling:{cssParts:["root","button","link","separator","toggle-group","toggle-item"],dataAttributes:[...r,"data-orientation","data-disabled","data-skdx-toolbar-item","data-state","data-value",{name:"data-skdx-toolbar-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[]},publicMethods:[]};export{l as toolbarContract};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{arrowPart as t,autoFocusEvents as r,dismissalEvents as a,forceMountProp as e,openChangeCompleteEvent as o,popperContentProps as n,portalPart as i}from"./overlay-parts.js";import{PART_DATA_ATTRIBUTES as s}from"./styling-hooks.js";var p={name:"Tour",purpose:'Stepped walkthrough with spotlight and focus trap. Root resolves targets (polling for late mounts), tracks index, publishes geometry as CSS vars. Content (role="dialog") positioned via popper against target or centered. Parts: Trigger, Portal, Backdrop, Spotlight, Content, Arrow, Title, Description, ProgressText, NextTrigger, PrevTrigger, SkipTrigger, CloseTrigger.',props:[{name:"steps",type:'Array<{ id?: string; target?: string | Element; title?: string; description?: string; placement?: Side; align?: Align; type?: "tooltip" | "dialog" | "floating"; backdrop?: boolean }>',required:!0,description:"Ordered steps (required). Empty steps render centered, spotlighting nothing \u2014 the open/close pattern. Stepper with no target emit step-target-missing. Step may carry id (stable across list changes, reported with index), description (adds aria-describedby to Content), and backdrop: false (hides dimming)."},{name:"open",type:"boolean",required:!1,description:"Controlled running state. Pair with the open-change event."},{name:"defaultOpen",type:"boolean",defaultValue:"false",required:!1,description:"Whether the tour is running on mount, for uncontrolled usage. The tour waits for a trigger by default, so a first-visit tour is started deliberately rather than on every render."},{name:"step",type:"number",required:!1,description:"Controlled index of the active step. Pair with the step-change event."},{name:"defaultStep",type:"number",defaultValue:"0",required:!1,description:"Index the tour starts on, for uncontrolled usage \u2014 useful for resuming a tour the user abandoned."},{name:"preventInteraction",type:"boolean",defaultValue:"false",required:!1,description:'Whether to inert the page. When true, Content declares aria-modal="true" and siblings are marked inert. When false (default), the page stays readable and operable; Content declares no aria-modal because claiming modality over a clickable page contradicts assistive technology. Focus trap holds either way.'},{name:"closeOnEscape",type:"boolean",defaultValue:"true",required:!1,description:"Whether Escape ends the tour. Set false only when tour cannot be abandoned; then provide SkipTrigger or CloseTrigger inside Content."},{name:"closeOnInteractOutside",type:"boolean",defaultValue:"false",required:!1,description:"Whether pointer-down outside content skips the tour. Off by default; outside clicks usually target the UI being explained."},{name:"spotlightPadding",type:"number",defaultValue:"8",required:!1,description:"Pixels of breathing room added around the target on every side when the spotlight geometry is published, so the cutout clears the target's own focus ring instead of clipping it."},{name:"spotlightRadius",type:"number",defaultValue:"0",required:!1,description:"Corner radius of the spotlight cutout in pixels, published as --skdx-tour-radius. Clip-path polygons cannot round their own corners."},{name:"scrollIntoView",type:"boolean | ScrollIntoViewOptions",defaultValue:"{ block: 'center', inline: 'center' }",required:!1,description:"Whether and how to scroll target into view. true (default) centers it; false suppresses scroll; object retunes. behavior forced to auto when prefers-reduced-motion: reduce. Web Components attribute is scroll-into-view; property is scrollIntoViewOption (scrollIntoView is an HTMLElement method)."},{name:"targetTimeout",type:"number",defaultValue:"2000",required:!1,description:"Milliseconds to keep polling for a step's target before giving up on it. Covers targets that mount late \u2014 a lazy route, a panel that opens on the previous step's action. Long enough for a lazy chunk to land, short enough that a genuinely absent target does not strand the tour."},{name:"keyboardNavigation",type:"boolean",defaultValue:"false",required:!1,description:"Whether ArrowRight/Left advance/step back while Content has focus (mirrored under RTL). Off by default; arrows belong to the target element. Published as data-keyboard-navigation; ignored in input fields inside the panel."},{name:"getAnnouncement",type:"(step: TourStep, index: number, total: number) => string",required:!1,description:`Builds the string announced to screen readers on every step change. Override it to translate, or to include more of the step than its title. Defaults to the step's title (when set) followed by "Step {n} of {total}", in English.`},{name:"showProgress",type:"boolean",defaultValue:"true",required:!1,description:"Whether derived anatomy includes ProgressText. Ignored under hand composition."},{name:"showSkip",type:"boolean",defaultValue:"true",required:!1,description:"Whether derived anatomy includes SkipTrigger. Ignored under hand composition. CloseTrigger never gated."},{name:"spotlight",type:"boolean",defaultValue:"true",required:!1,description:"Whether derived anatomy includes Spotlight cutout. Ignored under hand composition."}],events:[{name:"open-change",detail:"boolean",description:"Fired with the new open state whenever the tour starts or ends, controlled or not."},o("tour"),{name:"step-change",description:"Fired on step change with zero-based index and step id (if declared). Not fired on completion/skip.",detail:"{ index: number; id?: string }"},{name:"complete",detail:"void",description:"Fired when the user advances past the last step. The tour closes either way; this is where the consumer records that the user has seen it."},{name:"skip",detail:"void",description:"Fired when the tour ends early \u2014 the skip trigger, the close trigger, or Escape."},{name:"step-target-missing",description:"Fired when a step's target never appeared within targetTimeout. The tour then skips forward rather than rendering an unanchored popup. One argument, always the detail object `{ index, step }` \u2014 never the index and the step as two positional arguments.",detail:"{ index: number; step: TourStep }"},...a("tour"),...r("tour")],parts:[{name:"Trigger",description:'The button that starts the tour. Carries aria-haspopup="dialog", aria-expanded, and aria-controls.'},i,{name:"Backdrop",description:"The dimming layer, reading --skdx-tour-x/y/width/height so cutouts are drawable in pure CSS (clip-path, box-shadow, or panels). Renders nothing when active step sets backdrop: false; Content publishes data-backdrop when kept.",props:[e]},{name:"Spotlight",description:"Highlight box publishing --skdx-tour-x/y/width/height. Renders nothing when active step has no target.",props:[e]},{name:"Content",description:'Step panel with role="dialog", aria-modal="true" only when preventInteraction is set. Labeled by Title, described by Description. Carries data-step/type/backdrop (when dimming), data-keyboard-navigation (when arrows bound). Anchored via popper (data-side/align); centered steps get data-centered. Stays mounted so focus returns on each step. Positioning props are defaults that step placement/align override.',props:[...n({sideOffset:"8"}),e]},t,{name:"Title",description:"The active step's accessible name, referenced by Content's aria-labelledby."},{name:"Description",description:"Step's accessible description (Content's aria-describedby)."},{name:"ProgressText",description:"Progress display (data-step, data-total selectable from CSS).",props:[{name:"format",type:"(index: number, total: number) => string",required:!1,description:'Builds progress string from zero-based index and total (default: "Step {index + 1} of {total}").'}]},{name:"Actions",description:"Container for navigation triggers (Prev, Next, Skip, Close). No role, no label \u2014 Content already names the dialog. Gives the design layer a layout hook."},{name:"NextTrigger",description:"Advances the tour (completes on last step). Carries data-last for label changes."},{name:"PrevTrigger",description:"Stepper the tour back. Disabled on first step.",props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the back button. Set automatically on the first step, where there is nowhere to step back to; an explicit true disables it on any step."}]},{name:"SkipTrigger",description:"Ends the tour early (same as Escape)."},{name:"CloseTrigger",description:"Dismiss affordance (same as SkipTrigger)."}],slots:[{name:"trigger",description:"Trigger's content \u2014 the button that starts the tour."},{name:"default",description:"Content's body \u2014 Title, Description, ProgressText, and the navigation triggers. It is the same markup for every step; only the data behind it changes."}],states:["content:closed","content:open","content:tooltip","content:dialog","content:floating","content:centered","content:backdrop","content:keyboard-navigation","next-trigger:last","prev-trigger:disabled"],controlledUncontrolled:"Two independent controlled/uncontrolled axes \u2014 open and step \u2014 each starting from its default* prop and switching to controlled when the matching prop is passed. The steps array itself is always supplied by the consumer.",formBehavior:'Not applicable \u2014 Tour participates in no form; every trigger is type="button".',validationBehavior:"Not applicable \u2014 Tour collects no value.",accessibility:{role:'dialog (Content; aria-modal="true" only while preventInteraction is set, since the page is otherwise still interactive)',keyboard:[{key:"Enter / Space (on Trigger)",behavior:"Starts the tour."},{key:"Tab / Shift+Tab",behavior:"Cycle focus within the panel; does not escape to the page."},{key:"Enter / Space (on a navigation trigger)",behavior:"Advance, step back, skip, or close per trigger."},{key:"Escape",behavior:"End the tour when closeOnEscape is set (default); cancelable via escape-key-down."},{key:"ArrowRight / ArrowLeft (on Content)",behavior:"Unbound by default (arrows belong to the target element). With keyboardNavigation set, advance/step back (swapped under RTL). Ignored in input fields inside the panel. ArrowRight on last step completes."}],ariaAttributes:['aria-haspopup="dialog", aria-expanded, aria-controls on Trigger',`role="dialog" on Content, matching Trigger's aria-controls`,'aria-modal="true" on Content only when preventInteraction is set; siblings marked inert',"aria-labelledby on Content \u2192 Title; aria-describedby \u2192 Description","aria-hidden on Backdrop and Spotlight (decorative)","Each step change announced politely through live announcer (getAnnouncement)"],focusManagement:"Focus trapped inside Content regardless of preventInteraction; Tab containment makes the panel findable. With closeOnEscape false, provide focusable SkipTrigger or CloseTrigger. Focus is returned to whatever was focused before the tour started when it completes or is skipped. Panel stays mounted, so focus is pulled back onto it on every step (announced as open-auto-focus). Trap declared before step-change move, recording restore target first. open-auto-focus / close-auto-focus events are cancelable (first lets consumers place focus; second suppresses return). per-step re-focus is announced the same way; consumers can veto to keep focus where placed. Close override matters more here than other overlays.",namingRequirement:"Content must be named by Title. Each navigation trigger needs a descriptive label."},styling:{cssParts:["trigger","backdrop","spotlight","content","arrow","title","description","progress-text","actions","next-trigger","prev-trigger","skip-trigger","close-trigger"],dataAttributes:[...s,"data-state","data-step","data-total","data-type","data-side","data-align","data-centered","data-backdrop","data-keyboard-navigation","data-last","data-disabled",{name:"data-skdx-tour-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:["--skdx-tour-x","--skdx-tour-y","--skdx-tour-width","--skdx-tour-height","--skdx-tour-radius","--skdx-tour-available-width"]},publicMethods:[]};export{p as tourContract};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{changeDetail as e}from"./change-reason.js";import{ROOT_DATA_ATTRIBUTES as t}from"./styling-hooks.js";var a={name:"Transfer",purpose:'A dual-listbox picker: two multi-select role="listbox" sides derived from one items collection plus the target-side id array, with move triggers between them, optional per-list search, and every move announced politely. Composed of a root plus List, ListHeader, ListSearch, Item, Controls, MoveTrigger, MoveAllTrigger, and Empty parts.',props:[{name:"items",type:"Array<{ value: string; label: string; disabled?: boolean }>",required:!0,description:"The whole collection. Each side is derived from this plus value, never stored separately, so the two lists cannot drift apart."},{name:"value",type:"string[]",required:!1,description:"Controlled ids on the target side. Pair with the value-change event. Rendering order follows items, not this array."},{name:"defaultValue",type:"string[]",required:!1,description:"Initial target-side ids for uncontrolled usage. Omit to start all items on the source side."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables both lists and all move triggers. Individual items are disabled through the collection."},{name:"name",type:"string",required:!1,description:"Form field name. When set, each target-side id submits as a separate entry (like `<select multiple>`), not a joined string. Omit to submit nothing."},{name:"form",type:"string",required:!1,description:"Form id for a Transfer outside its ancestor form. Mirrors the native form attribute."},{name:"searchable",type:"boolean",defaultValue:"false",required:!1,description:"Enables per-list filtering. When false, ListSearch renders nothing and filter is never called."},{name:"filter",type:"(item: TransferItemData, query: string) => boolean",required:!1,description:"Decides whether an item survives a list's query. Consulted only while searchable. Defaults to case-insensitive substring match on the label. Overrides filterMatchMode when set. Property-only: <skdx-transfer> has no attribute form."},{name:"filterMatchMode",type:"'startsWith' | 'contains' | 'endsWith'",defaultValue:"'contains'",required:!1,description:"How the built-in matcher compares queries to item labels. Case-insensitive and trimmed. Ignored while a custom filter is set."},{name:"getMoveLabel",type:"(count: number, direction: TransferDirection, all: boolean) => string",required:!1,description:'Words the accessible name of each MoveTrigger and MoveAllTrigger. The all flag distinguishes between single and multi-item triggers, and count shows items that would move (zero included, so "why disabled" is clear). Computed from live counts, so only a function can express this \u2014 a static aria-label cannot. Defaults to English, e.g., "Move 3 items to selected". Property-only, no attribute form.'},{name:"getMoveAnnouncement",type:"(detail: { moved: number; remaining: number; direction: TransferDirection; from: TransferSide; to: TransferSide }) => string",required:!1,description:'Words the polite live-region announcement after each move. Return empty string to announce nothing. Defaults to English, e.g., "3 items moved to selected. 5 remaining in available." Property-only.'},{name:"getSearchResultsAnnouncement",type:"(detail: { shown: number; total: number; side: TransferSide; query: string }) => string",required:!1,description:`Words the polite live-region announcement when a list's search query settles. Return empty string to announce nothing. Fired per side, searchable only, never for empty query. Defaults to English, e.g., "4 of 20 items shown in available." Property-only.`},{name:"targetOrder",type:"'items' | 'append' | 'prepend'",defaultValue:"'items'",required:!1,description:"Where an item lands on the target side when moved. 'items' keeps the collection order on both sides. 'append' / 'prepend' place new items at the end or start, following the value array's order, so users see what they added."},{name:"titles",type:"{ source?: string; target?: string }",defaultValue:"{ source: 'Available items', target: 'Selected items' }",required:!1,description:"Headings for the two derived ListHeaders. Ignored with hand-composed children."},{name:"emptyText",type:"{ empty?: string; noMatch?: string }",defaultValue:`{ empty: 'Nothing here.', noMatch: 'No match for "{query}".' }`,required:!1,description:"Wording for the two derived Empty states: empty when the side holds no items, noMatch when search filtered all out. The {query} literal is replaced with the search text. Ignored with hand-composed children."},{name:"showMoveAll",type:"boolean",defaultValue:"false",required:!1,description:"Whether the derived Controls include a MoveAllTrigger per direction. Off by default, since bulk moves are destructive. Ignored with hand-composed children."},{name:"renderItem",type:"(item: TransferItemData) => React.ReactNode",required:!1,description:"Renders each derived Item's content in place of its label. Forwarded to each derived List. Ignored with hand-composed children."},{name:"density",type:"'compact' | (string & {})",required:!1,description:"Vertical rhythm rung forwarded to both Lists' data-density; either attribute may be written directly instead."},{name:"shape",type:"'square' | 'rounded' | (string & {})",required:!1,description:"Corner rounding rung forwarded to both Lists' data-shape; either attribute may be written directly instead."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Size rung forwarded to both Lists' data-size; either attribute may be written directly instead."}],events:[{name:"value-change",description:"Fired with the whole new target-side id array whenever a move happens, controlled or not.",detail:e("string[]","selectedValue: string | null")},{name:"move",description:"Fired alongside value-change with the items that moved and which way. For side effects that need the moved rows, not just new membership. The handler takes one argument, always the detail object `{ items, direction }` \u2014 never the two as separate positional arguments.",detail:"{ items: TransferItemData[]; direction: 'toTarget' | 'toSource' }"},{name:"list-scroll",description:"Fired when a list is scrolled, carrying which side and scroll geometry, so consumers can load next pages. Named list-scroll, not scroll, to avoid shadowing the native scroll event. Virtualization is not offered: headless components cannot know item height.",detail:"{ side: TransferSide; scrollTop: number; scrollHeight: number; clientHeight: number }"}],parts:[{name:"List",description:'One side of the widget: a multi-select role="listbox" with roving tab stop, typeahead, and per-side marked-for-move selection. Renders one Item per visible item.',props:[{name:"side",type:"'source' | 'target'",required:!0,description:"Which of the two sides this list renders the items for."},{name:"renderItem",type:"(item: TransferItemData) => React.ReactNode",required:!1,description:"Renders one item's content, in place of its label. The part that actually does the per-item rendering \u2014 the root's own renderItem is only forwarded here when the anatomy is derived."},{name:"density",type:"'compact' | (string & {})",required:!1,description:"Vertical rhythm rung, written to data-density on the list; the data-density attribute may be set directly instead."},{name:"shape",type:"'square' | 'rounded' | (string & {})",required:!1,description:"Corner rounding rung, written to data-shape on the list; the data-shape attribute may be set directly instead."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the list; the data-size attribute may be set directly instead."}]},{name:"ListHeader",description:`The visible heading naming one list, pointed to by aria-labelledby. Switches its list from fallback name to this heading's text. Sits beside its List (role="listbox" may only contain options), and takes its own side prop.`,props:[{name:"side",type:"'source' | 'target'",required:!0,description:"Which side this header names. Must match the side of the list it sits beside."}]},{name:"ListSearch",lightDom:!0,description:"The filter input for one list. Renders nothing while the root is not searchable.",props:[{name:"side",type:"'source' | 'target'",required:!0,description:"Which of the two sides this input filters the items of."}]},{name:"Item",description:'One option (role="option") in a list. Click, Enter, or Space toggles it into the marked set. Shift+Click marks the range from the anchor, mirroring Shift+Arrow keys.',props:[{name:"value",type:"string",required:!0,description:"The id of the collection entry this option renders."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Excludes this option from marking, navigation, and moves."},{name:"textValue",type:"string",required:!1,description:"Text typeahead matches this option against. Falls back to the option's rendered text content."}]},{name:"Controls",description:'The named role="group" holding the move triggers. Announced as the thing that moves items, not loose controls between lists.'},{name:"MoveTrigger",description:"Moves the marked items one way. Carries data-count with the count. Is aria-disabled when nothing is marked on its origin side \u2014 never natively disabled, so Tab keeps it in the tab order. Its accessible name names the direction and count so nothing-to-move is explained, not mysterious.",props:[{name:"direction",type:"'toTarget' | 'toSource'",required:!0,description:"Which way this trigger moves: 'toTarget' adds to the value, 'toSource' removes from it."}]},{name:"MoveAllTrigger",description:"Moves every visible item one way \u2014 visible, not every item, so a move-all under an active search moves what the user can see.",props:[{name:"direction",type:"'toTarget' | 'toSource'",required:!0,description:"Which way this trigger moves: 'toTarget' adds to the value, 'toSource' removes from it."}]},{name:"Empty",description:"Shown while one side has nothing to render. Covers two states: empty (no items) and no-results (search filtered all). Publishes data-reason and data-query in all five ports, and additionally passes them to content: function child in React, default-slot props in Vue/Svelte, contentTemplate TemplateRef in Angular, named slots in Web Components.",props:[{name:"side",type:"'source' | 'target'",required:!0,description:"Which side's emptiness this message covers."}]}],slots:[{name:"default",description:"The widget's body \u2014 two Lists (each optionally with a ListHeader, a ListSearch, and an Empty) with a Controls group of move triggers between them."}],states:["selected","empty","disabled"],controlledUncontrolled:"Uncontrolled by default: starts from defaultValue and tracks target membership internally. Passing value switches to controlled. Marked-for-move selection and search queries are always internal, transient state.",formBehavior:"With a name, each target-side id submits as a separate entry (like `<select multiple>`), not a joined string. An empty target side submits nothing. React/Vue/Svelte/Angular render one visually-hidden native control per id; <skdx-transfer> uses ElementInternals.setFormValue. Without a name, submits nothing.",validationBehavior:'None: no required flag. Validation rules like "pick at least one" belong to the surrounding Field/Form.',accessibility:{role:'listbox (List, aria-multiselectable="true"), option (Item), group (Controls)',keyboard:[{key:"ArrowUp / ArrowDown",behavior:"Move the roving tab stop between options within one list."},{key:"Home / End",behavior:"Jump to the first/last option in the list."},{key:"Enter / Space",behavior:"Toggles the focused option into or out of the marked set, and sets the range anchor."},{key:"Shift + ArrowUp / ArrowDown",behavior:"Extends the marked range from the anchor \u2014 the last option marked without Shift \u2014 which is the keyboard equivalent of Shift+Click."},{key:"ArrowRight (source) / ArrowLeft (target)",behavior:"Moves the marked options out of this list, or the focused option alone if nothing is marked. Focus follows to the vacated position. Direction-aware under dir: the key reverses under RTL. This is the widget's fastest keyboard path."},{key:"Ctrl/Cmd + A",behavior:"Marks every enabled option currently visible in the focused list \u2014 and clears them all instead when every one is already marked, which is the only keyboard way back out of a large marked set."},{key:"Typing a letter",behavior:"Jumps to the next option in that list matching the typed text."},{key:"Tab",behavior:"Moves between lists, search inputs, and triggers. Each list is one tab stop."}],ariaAttributes:['role="listbox" with aria-multiselectable="true" on each List',"aria-labelledby on a List pointing at its ListHeader, fallback to aria-label","aria-selected on each Item reflecting marked-for-move state","aria-disabled on disabled options, skipped by navigation and dropped from moves","aria-controls on each ListSearch pointing at the list it filters",'role="group" with an accessible name on Controls',"Moves are announced politely with direction and count","Settled search queries are announced with visible and total counts","data-reason on Empty region distinguishes empty from filtered-to-nothing"],focusManagement:"Roving DOM focus. Each list is a single tab stop, so Tab crosses the widget in few presses. After a move, focus lands on the list the items left, at the vacated position. Focus never stays on a now-disabled trigger, and never falls to <body>.",namingRequirement:'Each List must be named, by a ListHeader or explicit aria-label. MoveTriggers must use logical names ("Add to selected"), never a direction ("Move right") that reverses under RTL.'},styling:{cssParts:["list-header","item","controls","empty","root","list-search","move-trigger","move-all-trigger"],dataAttributes:[...t,"data-side","data-direction","data-selected","data-disabled","data-empty","data-reason","data-query","data-count","data-value","data-text-value","data-multiple","data-state","data-density","data-shape","data-size",{name:"data-skdx-transfer-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[]},publicMethods:[{name:"checkValidity",signature:"(): boolean",description:"Returns whether the current selection satisfies the constraints, firing an invalid event if not. Same contract as the native method.",frameworks:["webComponents"],exception:"imperative",frameworksReason:"Only the custom element is itself a form-associated control; React, Vue, Svelte and Angular submit through a hidden input the consumer owns and validate it directly."},{name:"reportValidity",signature:"(): boolean",description:"Same as checkValidity, but also shows the browser's validation message when the selection is invalid.",frameworks:["webComponents"],exception:"imperative",frameworksReason:"Same as checkValidity."},{name:"setCustomValidity",signature:"(message: string): void",description:"Sets an externally-computed error on the element, exactly like the native method: a non-empty message makes it invalid and is what reportValidity() shows; '' clears it.",frameworks:["webComponents"],exception:"imperative",frameworksReason:"Same as checkValidity."}]};export{a as transferContract};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{changeDetail as n}from"./change-reason.js";import{webComponentsValidationMethods as a}from"./form-validity.js";import{dismissalEvents as o,forceMountProp as e,openChangeCompleteEvent as r,popperContentProps as i,popperMeasurementProperties as s,portalPart as t,portalPropsSansForceMount as l}from"./overlay-parts.js";import{VIRTUAL_FOCUS_RULE as d}from"./rules.js";import{PART_DATA_ATTRIBUTES as h}from"./styling-hooks.js";import{withoutScope as c}from"./types.js";var w={name:"TreeSelect",purpose:'A picker that chooses one or many nodes from hierarchical data with tri-state cascading checks and optional filter. The trigger is role="combobox"; the popup holds an optional filter input and role="tree" with virtual focus and announced match counts, laid out either as one indented tree or, under layout="columns", as one tree per open level side by side. Without hand-composed children, the root derives the anatomy from collection.',props:[{name:"renderNode",type:"(node: TreeSelectNode) => React.ReactNode",required:!1,frameworks:["react","vue","svelte","angular"],exception:"render-prop",frameworksReason:'Web Components uses a named light-DOM slot (`slot="node"`) rather than a function property, since HTML attributes cannot carry functions. Angular ships a `TemplateRef` input instead of a function. Content falls back to plain label when no slotted node matches.',description:"Renders a node's content in the derived anatomy, forwarded to the Tree part's own renderLabel so the two never drift."},{name:"placeholder",type:"string",required:!1,description:"Stand-in content the derived trigger's Value shows while nothing is checked."},{name:"aria-label",type:"string",required:!1,frameworks:["react","vue","svelte","angular"],exception:"attribute-passthrough",frameworksReason:"All five packages settle one resolution rule: the derived name is `aria-label ?? placeholder`. React, Vue, and Svelte declare it as a prop; Angular uses `ariaLabel`. Web Components claims the native `aria-label` attribute off the host and relocates it onto the derived control.",description:"Accessible name shared by the derived Trigger, filter Input, and Tree, each taking no name from content or from each other."},{name:"emptyMessage",type:"string",required:!1,defaultValue:"'No matches'",description:"Content for the derived Empty part, shown when the filter matches nothing."},{name:"collection",type:"ReadonlyArray<{ value: string; label?: string; disabled?: boolean; hasChildren?: boolean; children?: TreeSelectNode[] }>",required:!0,description:`The hierarchical data the popup's tree is built from; node values must be unique across the whole collection. A childless node is a leaf unless it sets hasChildren, which declares it a branch while its children are still unloaded, so it reports aria-expanded="false" and can be expanded; cascading treats such a branch as a leaf.`},{name:"value",type:"string[]",required:!1,description:"Controlled checked node values, always an array in the shape valueStrategy describes, paired with the value-change event. Activating the node that is already the single checked one clears the value, since single-select has no other way back to empty; otherwise a consumer's own button calling the value-change handler with [] is the clear affordance, as no part renders one."},{name:"defaultValue",type:"string[]",defaultValue:"[]",required:!1,description:"Initially checked node values for uncontrolled usage, in the same shape as value."},{name:"multiple",type:"boolean",defaultValue:"false",required:!1,description:"Allows more than one node to be checked, adding aria-multiselectable and toggle-based activation."},{name:"checkStrategy",type:"'cascade' | 'descendants' | 'ancestors' | 'independent'",defaultValue:"'cascade'",required:!1,description:"Whether, and in which direction, checking a node propagates through the hierarchy around it. 'cascade' propagates both ways, making it a tri-state tree; 'descendants' is the downward half alone, what a permissions tree wants; 'ancestors' is the upward half alone, what a category filter wants; 'independent' propagates nothing. Ignored unless multiple."},{name:"valueStrategy",type:"'all' | 'leaf' | 'shallowest'",defaultValue:"'all'",required:!1,description:"Which checked nodes appear in the emitted value: all, leaves only, or the shallowest node that implies a fully-checked subtree. Ignored (treated as 'all') wherever checkStrategy lacks the direction that would rebuild what the projection drops \u2014 'leaf' needs the upward one, 'shallowest' the downward one, and 'independent' has neither."},{name:"expanded",type:"string[]",required:!1,description:'Controlled expanded node ids, paired with the expanded-change event. While filtering, the ancestors of every match are expanded on top of this value without being written back to it. Under layout="columns" this same set is also which columns are showing \u2014 one column per expanded branch along a single open path.'},{name:"defaultExpanded",type:"string[]",defaultValue:"[]",required:!1,description:"Initially expanded node ids for uncontrolled usage; every branch starts collapsed."},{name:"layout",type:"'tree' | 'columns'",defaultValue:"'tree'",required:!1,description:`How the popup presents the hierarchy, changing nothing about the data. 'tree' is one indented role="tree" whose ArrowRight expands a branch in place. 'columns' is the cascader: one role="tree" per open level, side by side, whose ArrowRight opens the branch's column and moves focus into it. Both layouts share the same collection, checking, value projection, lazy loading and expanded state. While the filter text is non-empty, 'columns' renders the tree layout instead, because a match drags its whole ancestor chain into view and that has no column structure.`},{name:"open",type:"boolean",required:!1,description:"Controlled open state of the popup, paired with the open-change event."},{name:"defaultOpen",type:"boolean",defaultValue:"false",required:!1,description:"Initial open state, for uncontrolled usage."},{name:"inputValue",type:"string",required:!1,description:"Controlled filter text for the Input part, paired with the input-value-change event."},{name:"defaultInputValue",type:"string",defaultValue:"''",required:!1,description:"Initial filter text, for uncontrolled usage \u2014 unfiltered."},{name:"filter",type:"(node: TreeSelectNode, inputValue: string) => boolean",required:!1,description:"Decides whether a node matches the filter text; a match keeps its whole ancestor chain and subtree visible, which is why a filtered columns layout renders as a tree."},{name:"getValueLabel",type:"(value: string) => string",required:!1,description:"Supplies the label for a value whose node is not yet in collection, such as a lazily-loaded saved value."},{name:"expandOnClick",type:"boolean",defaultValue:"false",required:!1,description:'Whether clicking a branch row also toggles its expansion, instead of leaving that to the chevron alone. Ignored (treated as true) under layout="columns", where the row is the only thing that opens a column and a false value would leave the mouse no way to reach the next one.'},{name:"loadChildren",type:"(nodeValue: string) => void | Promise<void>",required:!1,description:`Loads a node's children the first time it is expanded, for a collection not fully materialised up front. Mark the branch with hasChildren so it is expandable before anything is under it; the node carries aria-busy="true" and data-loading until the returned promise settles, and a rejection leaves it eligible to retry. Loading does not run while filtering, which cannot match nodes that have not arrived.`},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Blocks the whole control: the trigger is a disabled button, the popup cannot open, and no key changes anything."},{name:"name",type:"string",required:!1,description:"Form field name; with one set, every selected node value submits as its own entry under formData.getAll(name)."},{name:"form",type:"string",required:!1,description:"Id of the form the submitted entries belong to, for a TreeSelect that is not a DOM descendant of it."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:"Lets the user open, navigate and read the tree but never change the value \u2014 unlike disabled, which also removes the control from the tab order."},{name:"closeOnSelect",type:"boolean",defaultValue:"!multiple",required:!1,description:"Closes the popup as soon as a node is checked, returning focus to the trigger."},{name:"getMatchCountLabel",type:"(count: number) => string",required:!1,description:"Formats the message announced each time the number of filter matches changes while the popup is open."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Size rung forwarded to the popup Content panel's data-size; the attribute may be written on Content directly instead."}],events:[{name:"value-change",description:"Fired with the whole new value whenever the checked set changes, projected through valueStrategy rather than the toggled node.",detail:n("string[]","selectedValue: string | null")},{name:"expanded-change",description:"Fired with the new expanded set whenever a branch is expanded or collapsed, controlled or not. Never fires for the transient expansion filtering adds.",detail:"string[]"},{name:"open-change",detail:"boolean",description:"Fired with the new open state whenever the popup opens or closes, controlled or not."},{name:"input-value-change",description:"Fired with the new filter text as the user types, controlled or not.",detail:"string"},r("popup"),...o("popup")],parts:[{name:"Trigger",lightDom:!0,description:'The role="combobox" button that opens the popup, carrying aria-expanded, aria-controls, aria-haspopup="tree", and \u2014 while no Input is mounted \u2014 aria-activedescendant naming the virtually-focused node.'},{name:"Value",description:"The trigger's read-out of the current selection, rendering one data-chip span per value while multiple.",props:[{name:"placeholder",type:"string",required:!1,description:"Stand-in content rendered while nothing at all is checked."}]},{...t,description:`${t.description} Not shipped by Angular, which positions with strategy: 'fixed' instead; Web Components hides parts via the hidden attribute rather than unmounting.`,frameworks:["react","vue","svelte","webComponents"],exception:"portal",frameworksReason:"Angular Content positions with strategy: 'fixed' to escape clipping ancestors, so no Portal is needed. Web Components hides parts via the hidden attribute rather than unmounting.",props:[...l,{...e,frameworks:["react","vue","svelte"],exception:"force-mount",frameworksReason:"Web Components parts never unmount; they hide via `hidden`, so force-mount has nothing to do."}]},{name:"Content",description:"The popup panel, positioned against the trigger and dismissed by Escape or an outside interaction; carries no ARIA role of its own.",props:[...i({align:"'start'",sideOffset:"4"}),{...e,frameworks:["react","vue","svelte"],exception:"force-mount",frameworksReason:"Angular and Web Components keep this panel mounted while closed, hidden via `[hidden]`/the hidden attribute, so force-mount has nothing to do."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the popup panel; the data-size attribute may be set directly instead."}]},{name:"Input",lightDom:!0,description:"The optional filter text field. When mounted, DOM focus and aria-activedescendant move from the trigger to the input. Printable keys become filter text; Space types a character rather than selecting."},{name:"Columns",lightDom:!0,description:'The horizontal track holding one Tree per open level while layout is "columns". It carries role="presentation", because each column Tree keeps the semantics; it is not rendered in the tree layout, nor while a filter is narrowing the popup.'},{name:"Tree",lightDom:!0,description:'The role="tree" inside the popup, rendering one Item per visible node in navigation order with aria-level, aria-posinset, and aria-setsize. Under layout="columns" the root renders one Tree per open level inside Columns, each listing a single sibling set, named by the branch it belongs to and marked with data-skdx-tree-parent-id \u2014 absent on the root column.',props:[{name:"renderLabel",type:"(node: TreeSelectNode) => unknown",required:!1,frameworks:["react","vue","svelte","webComponents"],exception:"render-prop",frameworksReason:"Angular ships this member as `labelTemplate`, a TemplateRef taking the same context \u2014 a render function has no Angular equivalent. Member-name matching alone cannot see this per-prop rename, so without this note an implemented member could appear undocumented.",description:"Renders a node's content \u2014 label, chevron, or checkmark. Defaults to the node's label, falling back to its value. Angular uses `labelTemplate` instead of a function."},{name:"rows",type:"ReadonlyArray<{ value: string; depth: number }>",required:!1,description:"Renders this row set instead of the whole collection. Rows render flat, one Item each with depth standing in for aria-level. aria-posinset/aria-setsize are still measured against the unwindowed collection. One column of the columns layout is exactly such a row set: a single sibling set at one depth."}],methods:[{name:"invalidate",signature:"(nodeId?: string): void",description:"Clears cached lazy-load state for one node, or for the whole tree when no id is given, so its children load again on next expand."}]},{name:"Item",lightDom:!0,description:'One role="treeitem" row, normally rendered by Tree. Reports aria-checked (true, false, or mixed under cascade) as its only selection attribute, aria-expanded on branches only, data-highlighted while virtually-focused, and aria-busy with data-loading while loadChildren is pending.',props:[{name:"node",type:"TreeSelectNode",required:!0,description:"The collection node this row stands for."}]},{name:"ItemIndicator",description:"The checkmark shown on a checked \u2014 or, under cascade, partially checked \u2014 node. Reads its state from the surrounding Item, so one indicator markup covers all three states.",props:[c(e)]},{name:"Empty",description:"Shown in place of the tree when the filter matches nothing."}],slots:[{name:"trigger",description:"Trigger's content \u2014 a Value and any decoration, such as a chevron."},{name:"default",description:"Content's body \u2014 an optional Input, the Tree (or a Columns track of them), and an Empty state."}],appearance:[{attribute:"data-size",values:["sm","lg"],stylesheet:"tree-select.css"}],states:["closed","open","checked","unchecked","mixed","highlighted","placeholder","disabled","readonly","loading"],controlledUncontrolled:'Four independent axes \u2014 value, expanded, open, and inputValue. Filter-driven expansion is layered on top of expanded and never written back to it. layout is a fifth, uncontrolled axis with no event: it is how the popup is drawn, not state the component changes. Under layout="columns" expanded keeps its type and its event but describes a single open path, so expanding a node collapses any other branch at the same depth; an expanded set naming two branches at one depth renders the first in collection order and ignores the rest rather than failing.',formBehavior:"Submits repeated same-name entries (one per selected value) so formData.getAll(name) reads them back. Empty selection submits nothing; there is no required flag. React, Vue, Svelte and Angular render one visually-hidden native control per value. Web Components uses ElementInternals.setFormValue instead.",validationBehavior:'None of its own: there is no required flag, so nothing native to fail. Rules like "choose at least one" belong to the surrounding Field/Form, which reads the value array directly.',accessibility:{role:"combobox (Trigger), tree (Tree), treeitem (Item)",keyboard:[{key:"ArrowDown",behavior:`Opens the popup and moves to the first node when closed; moves to the next visible node when open. Under layout="columns" it walks the active column alone and stays on that column's last enabled node rather than wrapping or crossing into another column.`},{key:"ArrowUp",behavior:`Opens the popup and moves to the last node when closed; moves to the previous visible node when open. Under layout="columns" it walks the active column alone and stays on that column's first enabled node.`},{key:"ArrowRight",behavior:`Expands a collapsed branch, moves to the first child of an expanded one, or moves to the next node when there is nothing to expand. Mirrored under dir="rtl", where ArrowLeft expands. Under layout="columns" one press does the whole move: it opens the active branch's column and makes that column's first enabled node active. On a leaf it does nothing at all \u2014 there is no column to the right. On a branch whose children are still loading it opens the empty column and leaves the branch active, moving in once the children arrive if the branch is still the active node; a column that loads with no enabled node leaves it active too.`},{key:"ArrowLeft",behavior:'Collapses an expanded branch, or moves to its parent when already collapsed. Mirrored under dir="rtl". Under layout="columns" it is the exact inverse of ArrowRight: the parent branch in the previous column becomes active and the column being left, with every column right of it, closes. In the first column it does nothing.'},{key:"Home / End",behavior:'Move to the first/last visible node while the popup is open \u2014 the first/last enabled node of the active column under layout="columns", since the column is the navigable unit there.'},{key:"*",behavior:`Expands every collapsed sibling of the active node \u2014 the nodes at the same level under the same parent. Visual focus does not move. Does nothing under layout="columns", where only one branch per level can be open at a time. The rest of the tree pattern's collection keys are deliberately absent: Shift+Arrow range extension is what a plain Tree needs and this does not, because cascade already checks a whole branch in one keystroke, and Ctrl+A over a cascading tree is "check everything", which is what checking the root already means.`},{key:"Enter",behavior:"Opens the popup when closed; checks or unchecks the active node when open, branch included and in either layout \u2014 opening a branch is ArrowRight's job, never Enter's."},{key:"Space",behavior:"Checks or unchecks the active node from the trigger. With an Input mounted it types a space instead \u2014 it is a character the user is entering, not a selection."},{key:"Typing a letter (on the Trigger)",behavior:'Jumps to the next matching visible node (typeahead). Only while open, and only with no Input mounted, where a printable key is filter text instead. Under layout="columns" it searches the active column alone, so a match never teleports the user into a column they cannot see.'},{key:"Escape",behavior:"Closes the popup and returns focus to the trigger, in both layouts \u2014 it never closes one column first."},{key:"Tab",behavior:"Closes the popup and lets focus move out of the control \u2014 deliberately not prevented."}],ariaAttributes:['role="combobox" with aria-expanded and aria-haspopup="tree" on Trigger, plus aria-controls naming the Tree. Only while the popup is mounted, since a dangling IDREF tells a screen reader there is no popup.',"aria-activedescendant on whichever element holds DOM focus \u2014 the Trigger, or the Input when one is mounted \u2014 naming the virtually-focused treeitem",'role="tree" with aria-multiselectable while multiple, and aria-readonly while readOnly, on the single tree and on every column tree alike',"aria-level, aria-posinset, and aria-setsize on every treeitem, describing its place in the hierarchy",`Under layout="columns" each column is its own role="tree" listing one sibling set, rather than one tree spanning the panels. A single tree cannot contain columns it does not enclose without aria-owns reparenting every level, which is the least reliably supported relation in ARIA; N trees keep the hierarchy in the attributes instead. aria-level therefore still carries the node's true depth and aria-posinset/aria-setsize are measured within the column, which is the node's whole sibling set \u2014 so depth survives the loss of the indentation that mirrored it, and each column is announced by name as focus enters it.`,'aria-controls on the anchor names the column tree that holds the active node and follows it across columns, because aria-activedescendant may only name a descendant of the element the combobox controls. aria-haspopup stays "tree" in both layouts, since every panel is still a tree.','aria-checked on each treeitem: true, false, or mixed for a partially-checked branch under cascade. Never emitted with aria-selected; a multiple TreeSelect sets selectionMode="none" and keeps aria-multiselectable on the tree.',`aria-expanded on branch nodes only, including nodes declaring hasChildren with unloaded children; under layout="columns" it is true exactly while that branch's column is showing`,'aria-busy="true" on a node whose loadChildren call is still pending',"aria-disabled and data-disabled on a disabled node and its whole subtree, which is skipped by navigation and excluded from cascade propagation",'Match counts are announced politely as the filter narrows and once on open. The Empty part is role="presentation".'],focusManagement:`${d} Here the anchor is the Trigger, or the Input when one is mounted. Opening seeds the active node from the first visible node in value, falling back to the first enabled row. Keyboard moves bring the active node into view via scrollIntoView({ block: "nearest" }). Escape and closeOnSelect return focus to the Trigger; Tab closes without preventing focus from leaving. The columns layout changes none of this: the same anchor keeps DOM focus, and exactly one Item in the whole popup carries data-highlighted, so the active column is the one a skin matches with :has([data-highlighted]) and needs no attribute of its own. Crossing a column rewrites aria-activedescendant and aria-controls in the same update, and scrolling adds inline: "nearest" so the new column comes into view. Opening still expands nothing \u2014 the seed is the first value already sitting in a showing column, falling back to the root column's first enabled node.`,namingRequirement:`The Trigger must be named by a label or aria-label. The Input needs its own name. The Tree needs a name too \u2014 APG requires one for any role="tree", and it cannot be inherited from the Trigger or the nodes inside it. Under layout="columns" that obligation multiplies: every column tree needs its own name, taken from the branch whose children it lists, while the root column takes the control's name.`},styling:{cssParts:["trigger","value","chip","content","input","columns","tree","item","item-indicator","empty"],dataAttributes:[...h,"data-state",{name:"data-layout",description:'On Content, and on the Columns track when one renders: the layout actually drawn, so it reads "tree" while a filter narrows a columns popup rather than the layout prop that was asked for.'},"data-checked","data-highlighted","data-loading","data-placeholder","data-multiple","data-disabled","data-readonly","data-value","data-side","data-align","data-chip","data-size","data-skdx-tree-node-id","data-skdx-tree-parent-id",{name:"data-skdx-tree-select-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[...s("tree-select"),"--skdx-tree-node-depth"]},publicMethods:[...a]};export{w as treeSelectContract};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var a={name:"Tree",purpose:"A hierarchical list following the WAI-ARIA treeview pattern. The root owns expanded/selected/active-node state; nodes with a nested TreeGroup are expandable.",props:[{name:"selectionMode",type:"'single' | 'multiple' | 'none'",defaultValue:"'single'",required:!1,description:'"none" makes the tree expand/collapse-only, with no node selection. "single" means at most one id on each axis \u2014 `selectedIds` and `checkedIds` hold one entry or none \u2014 because a checked set left to derive from selection can never outgrow it. "multiple" is what lifts that cap, and the only mode selectionPropagation means anything in.'},{name:"expandedIds",type:"string[]",required:!1,description:"Expanded node ids, for controlled usage."},{name:"defaultExpandedIds",type:"string[]",defaultValue:"[]",required:!1,description:"Initially expanded node ids, for uncontrolled usage."},{name:"selectedIds",type:"string[]",required:!1,description:"Selected node ids, for controlled usage."},{name:"defaultSelectedIds",type:"string[]",defaultValue:"[]",required:!1,description:"Initially selected node ids, for uncontrolled usage."},{name:"checkedIds",type:"string[]",required:!1,description:'Checked node ids, for controlled usage. A second axis from `selectedIds`, which means row highlight only \u2014 a tri-state checkbox tree has to be able to say "highlighted but unticked", and one set cannot. Omit it and `aria-checked` keeps deriving from `selectedIds` exactly as before, so an existing tree is unaffected; supply it and the two come apart.'},{name:"defaultCheckedIds",type:"string[]",required:!1,description:"Initially checked node ids, for uncontrolled usage. Omit it, like `checkedIds`, to keep checked state derived from selection."},{name:"selectionPropagation",type:"'none' | 'descendants'",defaultValue:"'none'",required:!1,description:'Turns the tree into a tri-state checkbox tree: toggling a node applies to its whole subtree. Only meaningful with selectionMode="multiple". Propagation reaches every descendant the tree has ever rendered, not only the mounted ones. A collapsed group is unmounted, so its parent stays reporting "mixed" rather than silently dropping to "false". A branch whose children have never been mounted \u2014 declared through hasChildren before loadChildren runs \u2014 reports its own selected state until first expanded.'},{name:"loadChildren",type:"(nodeId: string) => void | Promise<void>",required:!1,description:`Loads a node's children the first time it is expanded. The node carries aria-busy="true" and data-loading until the returned promise settles; on resolution getLoadedLabel is announced through the live region. A rejection clears the busy state and leaves the node eligible to retry. The node has to be declared a branch through the item's hasChildren to be expandable before anything is loaded, since nothing has been rendered under it yet.`},{name:"getLoadedLabel",type:"(nodeId: string) => string",defaultValue:"defaultGetLoadedLabel",required:!1,description:`Formats the message announced when a lazily-loaded node's children arrive. Return an empty string to announce nothing. The default announces the node's own id followed by "loaded", e.g. "src loaded".`},{name:"disabledBehavior",type:"'all' | 'selection'",defaultValue:"'all'",required:!1,description:`What an item's disabled takes away. 'all' makes the node inert: arrows step over it. 'selection' keeps it in the roving-focus order and typeahead list, refusing selection only, which is the only way its aria-disabled="true" is heard. Choose 'selection' when the reason a node is disabled is itself information the user needs.`},{name:"collection",type:"ReadonlyArray<{ nodeId: string; label?: string; disabled?: boolean; hasChildren?: boolean; textValue?: string; children?: TreeNode[] }>",required:!1,description:'Hierarchical data the tree renders instead of TreeItem/TreeGroup children. The source of truth when supplied; children slot is ignored. Node ids must be unique across the collection. A node without children is a leaf unless hasChildren declares it a branch whose children are still unloaded (aria-expanded="false"). The rendered structure is identical to hand-written composition. This is the same shape TreeSelect takes, spelled with nodeId rather than value.'},{name:"renderLabel",type:"(node: TreeNode) => unknown",required:!1,frameworks:["react","vue","svelte","webComponents"],exception:"render-prop",frameworksReason:"Angular ships this member as `labelTemplate`, a TemplateRef taking the same context \u2014 a render function has no Angular equivalent. Declared exactly as the sibling member on TreeSelect's Tree part is, and for the same reason: the gate matches member names literally and has no per-prop rename mechanism.",description:"Renders a collection node's content \u2014 label and any indicator. Ignored without collection, since composition already puts the consumer in charge. Defaults to the node's label, falling back to its nodeId. In Angular this is `labelTemplate`, a TemplateRef taking the same context."},{name:"expandOnClick",type:"boolean",defaultValue:"true",required:!1,description:"Whether clicking a branch row toggles its expansion as well as selecting it. false leaves expansion to the item indicator chevron alone. Keyboard ArrowRight/ArrowLeft are unaffected."}],events:[{name:"expanded-ids-change",description:"Fires with the new set of expanded ids.",detail:"string[]"},{name:"selected-ids-change",description:"Fires with the new set of selected ids.",detail:"string[]"},{name:"checked-ids-change",detail:"string[]",description:"Fires with the new set of checked ids. Only fires once the tree has a checked axis of its own \u2014 that is, when `checkedIds` or `defaultCheckedIds` is supplied."},{name:"activate",description:'Fires with the node id when a node is activated \u2014 Enter, or a pointer click on the row. Activation is not selection: APG separates Enter ("performs its default action") from Space ("toggles the selection state"), and a file tree needs both, one to open the file and one to tick it. Space never fires this. Selection still happens on both keys, so the two axes stay independent rather than one replacing the other.',detail:"string"},{name:"load-error",description:"Fires with { nodeId, error } when a node's loadChildren promise rejects. Without it a failed load is indistinguishable from an empty branch: the busy flag clears, nothing is announced, and the node sits expanded with no children and no explanation. The rejection is not rethrown \u2014 a floating unhandled rejection would be a worse failure mode \u2014 so this is the only place a retry affordance or a failure announcement can come from. The node is left eligible to retry.",detail:"{ nodeId: string; error: unknown }"}],parts:[{name:"Item",description:'One role="treeitem" node, carrying aria-level, aria-posinset/aria-setsize, and \u2014 on a branch \u2014 aria-expanded and data-state.',props:[{name:"nodeId",type:"string",required:!0,description:"This node's identity in every piece of state the root owns \u2014 expandedIds, selectedIds, the active (tabbable) node, the loading set and the parent/child hierarchy the tri-state derives from \u2014 and the value published on data-skdx-tree-node-id. Required rather than defaulted: an id the tree invented would change on every remount, so nothing controlled could ever address the node."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:`Excludes this node from selection and keyboard activation. Under the root's default disabledBehavior="all", takes it out of the roving-focus order so arrows step over it. It stays announced as aria-disabled="true", explaining why focus never arrives. Not inherited: the node is still rendered, its subtree still expands, and its descendants stay fully navigable and selectable.`},{name:"textValue",type:"string",required:!1,description:"The text typeahead matches this node against, instead of its rendered label, published as data-text-value. Use it when the label is not plain text \u2014 an icon plus a truncated name, a highlighted filter match \u2014 or when the searchable text differs from the visible one. Omitted, the node's own text is used, excluding its aria-hidden indicator and its nested group."},{name:"hasChildren",type:"boolean",required:!1,description:"Declares whether this node is a branch, overriding the nested-group scan. true makes the node report aria-expanded and accept ArrowRight with no group mounted at all, which a lazily-loaded branch needs. false forces the node to read as a leaf even with a group among its children. Inferred from the presence of a nested group when omitted."}]},{name:"Group",description:`One role="group" container for a branch's child items, rendered inside the TreeItem it belongs to. It is unmounted while its branch is collapsed rather than hidden, which is what makes the roving tabindex span currently-visible items for free.`,props:[{name:"forceMount",type:"boolean",defaultValue:"false",required:!1,description:"Keeps the group mounted while its branch is collapsed, for exit animations. The consumer owns hiding it. A force-mounted group's items stay registered, counting towards their parent's tri-state and reachable by roving focus."}]},{name:"ItemIndicator",description:"A branch's expand/collapse affordance, rendered inside the TreeItem it belongs to. It mirrors its item's data-state (expanded/collapsed) so the skin can rotate one glyph rather than swap two, and clicking it toggles the branch without selecting the row. Decorative to assistive technology: the item's own aria-expanded already carries the state. A collection tree derives one for every branch, so a hand-composed tree and a collection tree have the same affordance.",props:[]}],slots:[{name:"default",description:"Root content \u2014 TreeItems. Ignored while `collection` is supplied, which is then the source of truth."},{name:"indicator",description:"A TreeItem's expand/collapse affordance (e.g. a chevron)."}],states:["expanded","collapsed","selected","unselected","loading","indeterminate"],controlledUncontrolled:"Expansion and selection each support both controlled and uncontrolled usage, independently of one another.",formBehavior:"Not applicable \u2014 Tree does not participate in forms. Angular alone additionally registers as a ControlValueAccessor, which is an extension of that framework rather than a capability the other four owe; see frameworkExtensions.",validationBehavior:"Not applicable \u2014 Tree carries no value and participates in no validation.",accessibility:{role:"tree (root), treeitem (TreeItem), group (TreeGroup)",keyboard:[{key:"ArrowUp/ArrowDown",behavior:"Moves focus between currently-visible items, no wrap."},{key:"Home/End",behavior:"Moves focus to the first/last currently-visible item."},{key:"ArrowRight",behavior:"Expands a collapsed branch, or moves focus to its first child if already expanded. A node declared a branch through the item's hasChildren counts as one with nothing rendered under it yet, which is what lets ArrowRight trigger loadChildren."},{key:"ArrowLeft",behavior:"Collapses an expanded node with children, or moves focus to its parent."},{key:"Printable characters",behavior:"Typeahead: moves focus to the next currently-visible node whose label starts with what was typed, wrapping around. A 1s buffer accumulates characters into one search; repeating a single letter cycles through the nodes starting with it. A node's label is its `data-text-value` when it has one, otherwise its own text \u2014 excluding its aria-hidden TreeItemIndicator and any nested TreeGroup, so a chevron glyph and a child's text never enter the match. Typeahead moves focus only, it never selects; Space is claimed by selection, so it never starts a search."},{key:"*",behavior:"Expands every collapsed sibling of the focused node \u2014 the nodes at the same level under the same parent. Focus does not move."},{key:"Shift+ArrowUp/Shift+ArrowDown",behavior:`selectionMode="multiple" only: moves focus to the previous/next visible node and toggles that node's selection, extending the selection as focus travels. Plain ArrowUp/ArrowDown elsewhere.`},{key:"Shift+Space",behavior:'selectionMode="multiple" only: selects the contiguous run of visible nodes between the most recently *selected* node and the focused one, inclusive, in one update. The anchor is the last node selected, not the last node focused, so walking with plain arrows and then pressing Shift+Space extends from wherever the selection last landed \u2014 which is the point of the binding. With no anchor yet (or one that has since been collapsed away) it selects the focused node alone, exactly as Space would.'},{key:"Ctrl+ArrowUp/Ctrl+ArrowDown",behavior:"Identical to plain ArrowUp/ArrowDown: moves focus to the previous/next visible node without touching the selection. There is no separate handler, and none is needed \u2014 selection never follows focus in this tree, so the plain arrows already do what the modifier asks for. It is listed because a user arriving from APG's alternative multi-select model, where the plain arrows *do* move the selection, will reach for it; and because a Control-modified arrow must not start a typeahead search, which is the one thing that would otherwise differ."},{key:"Control+Shift+Home/Control+Shift+End",behavior:`selectionMode="multiple" only: moves focus to the first/last visible node and selects every node from the previously focused one through it. This is APG's binding. The bare Shift+Home/Shift+End form is kept as an alias for one release \u2014 it is what the component shipped with \u2014 but is not the documented one. Plain Home/End moves focus only.`},{key:"Ctrl+A",behavior:'selectionMode="multiple" only: selects every currently-visible node, or clears the selection when every one of them is already selected. Focus does not move. The toggle matters because the same chord is the only affordance a user has for undoing it. The scope is the *rendered* tree rather than the whole tree, which is as far as it can reach: a collapsed branch is unmounted, and the root holds no list of what is inside one.'},{key:"Enter",behavior:'Selects the focused node *and* fires the activate event. APG: "Activates a node, i.e., performs its default action."'},{key:"Space",behavior:'Selects the focused node and nothing else \u2014 never fires activate. APG: "Toggles the selection state of the focused node."'}],ariaAttributes:['aria-label or aria-labelledby on the root, supplied by the consumer \u2014 normative for role="tree" (see `namingRequirement`)','aria-multiselectable on the root when selectionMode is "multiple"',"each item's aria-level reflects its nesting depth","aria-setsize and aria-posinset (1-based) on every item, counting its siblings at the same level under the same parent \u2014 required rather than optional here because collapsed subtrees are unmounted, so assistive tech cannot infer a set it cannot see","author-supplied aria-level, aria-posinset and aria-setsize override the computed ones. This is contracted, not incidental: it is what the virtualization pattern depends on \u2014 a windowed tree renders a slice of the nodes and has to state the real positions itself \u2014 and it is exactly the case APG requires the attributes for. Every framework spreads consumer attributes after its own, and a Tree item given an explicit aria-posinset must render that value",`the computed pair is measured from the rendered DOM after mount, so server-rendered HTML carries neither. A non-hydrated tree \u2014 an Astro island, an RSC subtree \u2014 must supply them itself through the override above, which is the same instruction the virtualization pattern already gives. There is no equivalent of the roving tab stop's "every item is a tab stop until the effect runs" fallback here: a guessed position is a wrong position, and a wrong "3 of 7" is worse than none`,'aria-selected reflects selection unless selectionMode is "none" \u2014 or selectionPropagation is "descendants", where aria-checked carries the state instead and aria-selected is omitted entirely',"aria-expanded is set only on branch items \u2014 those with a nested TreeGroup, plus those declared as branches through the item's hasChildren, which is how a lazy branch announces itself before its children exist",'aria-busy="true" on an item whose loadChildren call is still pending','aria-checked (true/false/"mixed") on every item when selectionPropagation is "descendants" \u2014 never alongside aria-selected: APG allows either, and on a parent whose children are partly selected the two contradict each other ("false" and "mixed" at once)'],namingRequirement:`The root must carry an accessible name via aria-label or aria-labelledby, supplied by the consumer. This is normative rather than advisory \u2014 APG: "The element with role tree has either a visible label referenced by aria-labelledby or a value specified for aria-label." No prop is needed, because passthrough already carries both attributes in all five packages; and nothing inside the Tree can supply it, since role="tree" is name-from-author only and the node labels inside it name the tree no more than a list's items name the list. An unnamed tree announces as a bare "tree", which is indistinguishable from every other tree on the page.`,focusManagement:'Single tab stop with roving tabindex over currently-visible items only \u2014 collapsed subtrees are unmounted, not merely hidden, so they are naturally excluded (under disabledBehavior="selection" the disabled ones stay in). The stop is seeded from the first rendered id present in selectedIds, falling back to the first rendered id \u2014 APG: "If a node is selected before the tree receives focus, focus is set on the selected node", and for a multi-select tree "focus is set on the first selected node". It is re-seeded by the same rule whenever the item holding it is removed, so collapsing or unmounting the focused branch cannot leave the tree with no tabbable item. Only the innermost treeitem under the pointer acts on a click: items nest, so a click on a leaf also reaches every ancestor handler, which would otherwise select and collapse the whole branch above it.'},styling:{cssParts:["root","item","group","item-indicator"],dataAttributes:[...e,"data-state","data-disabled","data-loading","data-checked","data-text-value","data-skdx-tree-node-id","data-skdx-tree-parent-id"],cssCustomProperties:["--skdx-tree-node-depth"]},publicMethods:[{name:"invalidate",signature:"(nodeId?: string): void",description:"Clears the loaded marker on a node so the next expansion fetches again. With nodeId, clears that node and every child it has ever rendered; omitted, clears the whole tree. The consumer owns fetching and caching."}],frameworkExtensions:[{framework:"angular",name:"ControlValueAccessor",type:"ControlValueAccessor",description:"Registers the tree as a Reactive Forms control so [(ngModel)] and formControlName carry the selection. It adds one behaviour no other package has: setDisabledState() disables the whole tree, emitting aria-disabled and data-disabled on the root and refusing selection changes, select-many and select-all. Angular-only because Reactive Forms exists nowhere else \u2014 the other four reach the same place through the controlled `selectedIds` prop and its change event, which Tree already declares."}]};export{a as treeContract};
|