@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{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var r={name:"SignUpPage",purpose:"A registration block composing Heading, Alert, Button, Divider, Form, Field, TextField, PasswordInput and Checkbox. Every provider renders a button and the credentials form always renders, so the block reports either a chosen provider or the submitted account details through one sign-up event. Ships in the blocks package of each framework, not the core package.",props:[{name:"title",type:"string",defaultValue:"'Create account'",required:!1,description:"Heading text, rendered into a derived <h1> that names the section."},{name:"providers",type:"ReadonlyArray<{ id: string; name: string }>",required:!1,description:"Third-party providers, in render order, each rendering one button above the credentials form. No provider region and no divider render when omitted."},{name:"error",type:"string",required:!1,description:"Message rendered into a derived error Alert above the form. The block never clears it: set it from the sign-up handler and reset it when the next attempt starts."},{name:"pending",type:"boolean",defaultValue:"false",required:!1,description:"Marks the request in flight, making the submit button busy and unusable while every field stays editable, so the user can still correct a typo."},{name:"nameLabel",type:"string",required:!1,description:"Label of the name field; supplying it is what makes that field render at all, and what adds name to the event detail."},{name:"emailLabel",type:"string",defaultValue:"'Email'",required:!1,description:"Label of the email field in the credentials form."},{name:"passwordLabel",type:"string",defaultValue:"'Password'",required:!1,description:"Label of the password field in the credentials form."},{name:"confirmPasswordLabel",type:"string",required:!1,description:"Label of the confirmation field; supplying it is what makes that field render and what turns on password matching."},{name:"passwordMismatchMessage",type:"string",defaultValue:"'Passwords do not match'",required:!1,description:"Validation message pushed onto the confirmation field as a custom validity when the two passwords differ."},{name:"terms",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot rather than a prop \u2014 Vue because a renderable region is a slot in Vue's own idiom, Web Components because a custom element attribute carries a string and cannot carry a node. Both slot spellings are declared under `slots`.",description:"Terms copy and links, rendered as the label of a required checkbox before the submit button. No terms field renders when omitted. A prop in React, Svelte, and Angular; Vue and Web Components use the `terms` slot."},{name:"submitLabel",type:"string",defaultValue:"'Create account'",required:!1,description:"Text of the credentials form submit button."},{name:"getProviderLabel",type:"(provider: { id: string; name: string }) => string",defaultValue:"defaultProviderLabel",required:!1,description:`Formats a provider button's text from its entry. The default reads "Sign in with Google".`},{name:"footer",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot rather than a prop \u2014 Vue because a renderable region is a slot in Vue's own idiom, Web Components because a custom element attribute carries a string and cannot carry a node. Both slot spellings are declared under `slots`.",description:"Navigation rendered below the form, such as a link back to the sign-in page. No footer region renders when omitted. A prop in React, Svelte, and Angular; Vue and Web Components use the `footer` slot."}],events:[{name:"sign-up",detail:"{ providerId: string; name?: string; email?: string; password?: string; termsAccepted?: boolean }",description:"Fires when a provider button is activated or the form is submitted with matching, valid fields. A button carries only providerId; the form carries 'credentials' plus the values of the fields that rendered. The native submit is prevented, so the consumer performs the request and sets error on failure."}],slots:[{name:"default",description:"Extra fields rendered inside the form, above the terms and the submit button."},{name:"terms",description:"Terms copy and links used as the label of the required terms checkbox; nothing renders without it."},{name:"footer",description:"Navigation below the form, such as a link back to the sign-in page."}],states:["default"],controlledUncontrolled:"Stateless apart from the field values the native inputs hold; error, pending and success wording are always controlled by the consumer.",formBehavior:"The credentials form is a core Form root with required, natively validated fields; an invalid form reports through constraint validation and emits nothing. The submit button is disabled while pending, and the fields stay editable.",validationBehavior:'Fields are required, the email field is type="email", and the terms checkbox must be ticked. When a confirmation field renders, a mismatch is pushed onto it as a custom validity, reported through the form, and cleared on the next edit of that field.',accessibility:{role:"region (native <section> named by its heading through aria-labelledby)",keyboard:[{key:"Enter",behavior:"Submits the form whose field has focus (native form submission)."},{key:"Enter/Space",behavior:"Activates a focused provider button (native button activation)."},{key:"Space",behavior:"Toggles the terms checkbox when it has focus."}],ariaAttributes:["aria-labelledby on the <section> points at the derived heading","the derived error Alert is a live region, so a new error is announced without moving focus","each field is labelled through the core Field, which wires aria-describedby and aria-invalid"],focusManagement:"Focus stays where the user put it, except that a reported password mismatch moves focus to the confirmation field the way constraint validation does."},styling:{cssParts:["sign-up-page","panel","title","error","providers","provider","divider","form","field","terms","submit","footer"],dataAttributes:[...e,"data-provider",{name:"data-skdx-sign-up-page-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.'},{name:"data-skdx-sign-up-page-content",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{r as signUpPageContract};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var a={name:"Skeleton",purpose:'A loading placeholder block, hidden from assistive tech via aria-hidden="true". Shape and animation are set via the matching props, written to data-shape and data-animation for the brand-layer skin to style; either attribute may be set directly instead.',props:[{name:"animation",type:"'none' | (string & {})",required:!1,description:"Disables the shimmer animation, written to data-animation on the root; the data-animation attribute may be set directly instead."},{name:"shape",type:"'line' | 'circle' | (string & {})",required:!1,description:"Placeholder outline rung, written to data-shape on the root; the data-shape attribute may be set directly instead."}],events:[],slots:[],appearance:[{attribute:"data-animation",values:["none"],stylesheet:"skeleton.css"},{attribute:"data-shape",values:["line","circle"],stylesheet:"skeleton.css"}],states:["default"],controlledUncontrolled:"Stateless \u2014 Skeleton holds no internal state.",formBehavior:"Not applicable \u2014 Skeleton does not participate in forms.",validationBehavior:"Not applicable \u2014 Skeleton carries no value and participates in no validation.",accessibility:{role:"generic (native <div>, removed from the accessibility tree via aria-hidden)",keyboard:[],ariaAttributes:['aria-hidden is always "true"','The container must carry aria-busy="true" while Skeletons are mounted, and drop it when real content renders. Skeleton cannot do this itself \u2014 it is aria-hidden.'],focusManagement:"Not focusable; not part of the tab order.",namingRequirement:"None, and none is possible: the element is aria-hidden. The loading state is announced by the aria-busy region containing the Skeletons, and that region is what carries the name."},styling:{cssParts:["skeleton"],dataAttributes:[...e,"data-animation","data-shape"],cssCustomProperties:["--skdx-skeleton-color","--skdx-skeleton-radius"]},publicMethods:[]};export{a as skeletonContract};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ComponentContract } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The Slider contract every framework package implements: a multi-thumb
|
|
4
|
+
* slider whose `value` is always an array — one element for a simple
|
|
5
|
+
* slider, two for a range slider.
|
|
6
|
+
*/
|
|
7
|
+
export declare const sliderContract: ComponentContract;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{changeDescription as t,changeDetail as e}from"./change-reason.js";import{webComponentsValidationMethods as a}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as r}from"./styling-hooks.js";var o={name:"Slider",purpose:"A multi-thumb slider. Clicking or dragging anywhere in the track moves the thumb closest to the pointer; onValueCommit fires once, on pointer up. Each thumb is independently keyboard-operable.",props:[{name:"value",type:"number[]",required:!1,description:"Selected values, one per thumb, for controlled usage."},{name:"defaultValue",type:"number[]",defaultValue:"[0]",required:!1,description:"Initial values, one per thumb, for uncontrolled usage.",frameworks:["react","vue","svelte","angular"],exception:"wc-default",frameworksReason:"Web Components has no defaultValue member and will not grow one: the authored value attribute is the default, exactly as <input value> is a native input's. <skdx-slider> snapshots it on connect and formResetCallback() restores that snapshot."},{name:"min",type:"number",defaultValue:"0",required:!1,description:"Minimum value of the range."},{name:"max",type:"number",defaultValue:"100",required:!1,description:"Maximum value of the range."},{name:"step",type:"number",defaultValue:"1",required:!1,description:"Increment values are rounded to, for both pointer and keyboard interaction."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables pointer and keyboard interaction on all thumbs."},{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Layout axis, used to map pointer position and Arrow keys to a value."},{name:"largeStep",type:"number",defaultValue:"Math.max((max - min) / 10, step)",required:!1,description:"Increment for PageUp/PageDown and Shift+Arrow on the focused thumb. Defaults to one-tenth of the range (floored at one step) \u2014 the increment these keys already used, so the property changes no shipped slider. Base UI defaults to flat 10, which jumps a 0\u20131 range ten times over; deriving it from min/max keeps the coarse gear proportional to what the slider measures."},{name:"minStepsBetweenValues",type:"number",defaultValue:"0",required:!1,description:"Minimum gap in steps that adjacent values must keep. At default 0, two thumbs may be dragged onto the same value (they clamp but never separate); at 1, the neighbouring thumb is pushed one step away, so a range slider never reports an empty range. Counted in steps, not value units, so it stays meaningful when step changes. Named for values, not thumbs, because array entries are values \u2014 a thumb is what renders one."},{name:"name",type:"string",required:!1,description:"Form field name. A multi-thumb slider submits one name[i] entry per thumb. Without it the slider submits nothing."},{name:"form",type:"string | undefined",required:!1,defaultValue:"undefined",description:"Id of the <form> the slider submits into, forwarded to each thumb's hidden input, so a slider can live outside its form (filter bar, portal, sticky footer). Needs name to mean anything. **Property is `formId`, not `form`, in Web Components** \u2014 form-associated elements already publish `form` as readonly HTMLFormElement; shadowing it with writable string would break `slider.form`. The browser's form-owner algorithm honours the form attribute on form-associated custom elements, so `formId` is declared for API consistency."},{name:"marks",type:"ReadonlyArray<{ value: number; label?: string }>",required:!1,description:"Marks the slider derives along its track \u2014 one per entry at its value, captioned by label. Hand composition stays default and wins when the consumer writes their own."},{name:"showTooltip",type:"boolean",defaultValue:"false",required:!1,description:"Renders the thumb's current value in a tooltip the skin positions; no floating behaviour added."},{name:"thumbLabels",type:"readonly string[]",required:!1,description:`Accessible names for derived thumbs, one per value entry in order (e.g., ["Minimum price", "Maximum price"]). Multi-thumb sliders need these: role="slider" takes no content name, so unnamed thumbs announce identically and users can't tell which end they're moving (see accessibility.namingRequirement). Single-thumb sliders need none. Ignored under hand composition, where each Thumb carries its own aria-label. Deriving a multi-thumb slider without them warns in development.`},{name:"size",type:"'md' | '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:t("the slider values"),detail:e("number[]")},{name:"value-change-detail",frameworks:["angular"],exception:"event-shape",frameworksReason:"Angular's `valueChange` emits the scalar so `[(value)]` round-trips the value itself; this second output carries the detail object the other four hand to `value-change`.",description:"Fires with valueChange, carrying the previous values and the reason for the change.",detail:e("number[]")},{name:"value-commit",detail:"number[]",description:"Fires once with final values when a drag ends (pointer up). Suppressed when values at pointer up match pointer down \u2014 a bare click without drag commits nothing, preventing unwanted writes."}],parts:[{name:"Track",description:"The full-length bar the thumbs move along. Purely presentational."},{name:"Range",description:"The filled band between the lowest and highest value (from the start of the track for a single-thumb slider). Purely presentational."},{name:"Thumb",description:'One draggable handle, the role="slider" that reports a value. One per entry in the values array.',props:[{name:"index",type:"number",required:!1,description:"Which entry of the values array this thumb controls. Omitting it resolves the index from DOM order among sibling thumbs, which is what a single-thumb slider wants and what a statically-rendered range slider gets right too. A server-rendered range slider must pass it explicitly: the resolution runs in a layout effect (or its framework's equivalent) that never runs on the server, so every thumb serialises as index 0 and the markup sent to the client reports the first value on both handles until hydration corrects it. Angular is the exception \u2014 its thumb takes an explicit index defaulting to 0 and does no DOM resolution."},{name:"valueText",type:"string",required:!1,description:`Human-readable announcement of this thumb's value, written to aria-valuetext. Supply it when the raw number is not what the user is choosing \u2014 "Medium" for a size scale, "\xA320" for a price, "Tuesday" for a day index \u2014 and a screen reader announces that instead of the bare aria-valuenow. Left unset the attribute is absent, which is correct for a slider whose value really is a number.`}]},{name:"Mark",description:`An optional tick at a declared value along the track, positioned by the same logical inline offset the Thumb uses so it mirrors correctly under dir="rtl". Renders its own children as the label and publishes the value as data-value; the tick itself is drawn by the skin. aria-hidden, like AngleSlider's Mark: a mark redraws the scale the thumb already reports through aria-valuemin/aria-valuemax, and unhidden its labels are announced as loose text inside the slider.`,props:[{name:"value",type:"number",required:!0,description:"The value on the track this mark sits at."}]}],slots:[{name:"default",description:"SliderTrack (containing SliderRange) plus one SliderThumb per value."},{name:"thumb",description:"A single thumb's optional custom content."},{name:"mark",description:"A single mark's label content."}],appearance:[{attribute:"data-size",values:["md","sm","lg"],stylesheet:"slider.css"}],states:["default","dragging","disabled"],controlledUncontrolled:"Supports both: value + onValueChange (controlled) or defaultValue (uncontrolled). Web Components expresses the uncontrolled seed as the authored `value` attribute rather than a separate `default-value`, the way `<input value>` seeds a native input; that attribute is snapshotted on connect and is what a form reset restores. In Angular the pair is split: `valueChange` emits the scalar for `[(value)]`, `valueChangeDetail` carries the detail.",formBehavior:"Form-associated: with a name, single-thumb submits one name entry; multi-thumb submits one name[i] entry per thumb. A slider always has a value, so checkValidity() always passes. Form reset restores initial values. (Web Components publish through ElementInternals on root; other frameworks render hidden number input per thumb.) form associates hidden inputs with forms the slider doesn't sit inside; Web Components honours form attribute on the form-associated host.",validationBehavior:"Not applicable at the component level.",accessibility:{role:"slider (each thumb)",keyboard:[{key:"ArrowRight/ArrowUp",behavior:"Increases the focused thumb by one step under dir='ltr'. The vertical arrow is unaffected by writing direction; ArrowRight decreases under dir='rtl', where the start of the track is its right edge."},{key:"ArrowLeft/ArrowDown",behavior:"Decreases the focused thumb by one step under dir='ltr'; ArrowLeft increases under dir='rtl'. ArrowDown always decreases."},{key:"PageUp/PageDown",behavior:"Changes the focused thumb by largeStep \u2014 a tenth of the range unless the property overrides it. Not mirrored: these keys name a magnitude, not a direction on the inline axis."},{key:"Shift+Arrow keys",behavior:"Move by largeStep instead of step, in the direction that arrow moves (mirrored under RTL like the unmodified arrows) \u2014 the same coarse gear as PageUp/PageDown, on the keys a laptop keyboard actually has. AngleSlider binds Shift+Arrow the same way."},{key:"Home/End",behavior:"Jumps the focused thumb to the slider's min/max."}],ariaAttributes:["aria-valuemin/aria-valuemax/aria-valuenow/aria-orientation on each thumb","aria-valuetext on a thumb given a valueText, so a value that is not a plain number ('Medium', '\xA320') is announced as what it means","aria-label or aria-labelledby on each thumb of a multi-thumb slider","aria-hidden on each Mark, which redraws a scale the thumb already reports"],focusManagement:"Each SliderThumb is independently focusable and keyboard-operable.",namingRequirement:'A slider with more than one thumb must name each thumb distinctly with aria-label or aria-labelledby (for example "Minimum price" / "Maximum price"). role="slider" takes no name from content and a thumb renders none, so two unnamed thumbs announce identically and the user cannot tell which end of the range they are moving. A single-thumb slider needs no thumb name \u2014 the surrounding field names it and there is nothing to tell apart.'},styling:{cssParts:["slider","track","range","thumb","mark","tooltip"],dataAttributes:[...r,"data-orientation","data-disabled","data-dragging","data-value","data-size",{name:"data-skdx-slider-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:[...a],frameworkExtensions:[{framework:"webComponents",part:"Thumb",name:"showTooltip",type:"boolean",description:"Per-thumb version of the root's `showTooltip`, written from markup as show-tooltip. <skdx-slider-thumb> renders its own value readout inside a shadow root, so the switch has to reach the element that draws it; React, Vue, Svelte and Angular compose the readout as their own children of Thumb and decide per thumb by writing different children."},{framework:"webComponents",name:"updateValue",type:"(index: number, rawValue: number, reason?: 'pointer' | 'keyboard' | 'programmatic') => void",description:"Commits one thumb's value after clamping it to the step grid, the range and its neighbouring thumbs, then dispatches value-change with the given reason. Web Components only: it is how the element's own pointer and keyboard handlers write a value, and an element has no other channel for a caller to enter that path. React, Vue, Svelte and Angular set the controlled `value` prop instead, which runs the same clamping before it renders."}]};export{o as sliderContract};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ComponentContract } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* A floating action button that fans a short list of actions along one axis,
|
|
4
|
+
* positioned via the shared popper layer and navigated as a WAI-ARIA menu.
|
|
5
|
+
*/
|
|
6
|
+
export declare const speedDialContract: ComponentContract;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{dismissalEvents as t,forceMountProp as a,openChangeCompleteEvent as n,popperContentProps as o,popperMeasurementProperties as i,portalPart as r}from"./overlay-parts.js";import{PART_DATA_ATTRIBUTES as s}from"./styling-hooks.js";var d={name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Whether arrow-key navigation wraps from the last action back to the first, and vice versa."},c={name:"SpeedDial",purpose:"A floating action button revealing a short fan of related actions along one axis, positioned via the shared popper layer and navigated as a WAI-ARIA menu. Each action is stamped with its ordinal for a staggered CSS reveal. Composed of a root plus Trigger, Portal, Content, Item, and ItemLabel parts, and an optional Overlay.",props:[{name:"open",type:"boolean",required:!1,description:"Controlled open state \u2014 whether the actions are revealed. Pair with the open-change event."},{name:"defaultOpen",type:"boolean",defaultValue:"false",required:!1,description:"Initial open state, for uncontrolled usage. The dial starts collapsed to just its trigger."},{name:"direction",type:"'up' | 'down' | 'left' | 'right'",defaultValue:"'up'",required:!1,description:'Which way the actions fan out from the trigger. Decides the side Content is positioned on, the axis the arrow keys walk, and the data-direction attribute the stagger CSS reads. Physical rather than logical: the viewport corner a speed dial is anchored to does not move under dir="rtl".'},{name:"openOnHover",type:"boolean",defaultValue:"false",required:!1,description:"Also open on pointer-enter of the trigger, not only on click. The click and keyboard paths work either way; this only adds the hover path, which touch pointers never take."},{name:"hoverCloseDelay",type:"number",defaultValue:"300",required:!1,description:"Milliseconds the dial stays open after the pointer leaves the trigger or the content. The gap between the two is dead space the pointer must cross, so closing on the first pointer-leave would snap the fan shut mid-travel; re-entering either element within the window cancels the pending close. Only consulted when openOnHover is set."},{name:"hoverOpenDelay",type:"number",defaultValue:"0",required:!1,description:"Milliseconds the pointer must rest on the trigger before the fan opens, only consulted when openOnHover is set. Prevents a pointer passing over the button from opening the fan. A value of 0 opens synchronously."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Blocks the dial from opening by any route \u2014 click, hover, or keyboard \u2014 and marks the trigger natively disabled. Setting it while open also closes the fan, firing open-change with false. Focus returns to the trigger only if it was inside Content."},{name:"trigger",type:"ReactElement | Snippet | TemplateRef<unknown>",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:`React, Svelte and Angular take this as a typed prop. Vue uses the #trigger slot and Web Components use light-DOM children marked slot="trigger". Only React's derived trigger is a whole interactive element merged via asChild; the others render their own button around this prop's content.`,description:`The floating action button for the derived anatomy. Its content model differs per framework: React merges a whole element via asChild, while Svelte and Angular take only the button's inner content. The button must carry an accessible name \u2014 an icon-only floating action button announces as "button" and says nothing about what it opens. The triggerLabel prop names the derived button in the frameworks whose trigger content model has no other way to reach it.`},{name:"triggerLabel",type:"string",required:!1,description:"Accessible name applied to the derived trigger's aria-label, for the frameworks where trigger only supplies the button's content rather than a whole element carrying its own name."},{name:"actions",type:"SpeedDialAction[]",required:!1,description:"The entries the derived fan renders \u2014 one Item per entry with its ItemLabel. Supplying it renders the whole anatomy from data; hand composition uses each framework's primitives/speed-dial subpath. An entry is { label, icon?, onSelect?, disabled? }. A disabled entry still occupies its place in the fan and counts towards the positional custom properties the stagger CSS reads. `icon` differs per framework (ReactNode in React, Component in Vue, Snippet in Svelte, TemplateRef in Angular, slotted light-DOM in Web Components)."},{name:"overlay",type:"boolean",defaultValue:"false",required:!1,description:"Paint the scrim behind the derived Content. On the hand-composed path the Overlay part is opt-in; on the derived path this boolean enables it. It does not make the dial modal: focus is not trapped and the page behind stays live."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Size rung forwarded to the Trigger's and every derived Item's data-size; either attribute may be written directly instead."}],events:[{name:"open-change",detail:"boolean",description:"Fired with the new open state whenever the dial opens or closes, controlled or not."},n("speed dial"),...t("speed dial"),{name:"select",detail:"{ action: SpeedDialAction; index: number } | null",description:"Fired by an Item when it is activated by click, Enter, or Space. Preventing default keeps the dial open \u2014 on the hand-composed path, which is the only one where a cancelable Item event is in reach. One event, not two: on the derived path it additionally carries the actions entry that was activated and its index, so a consumer reading the recipe gets the data back without a second same-named event on the same node \u2014 the ambiguity Menu had to rename its way out of. Hand-composed Items carry no entry, because on that path there is none. The derived payload is the entry and the index and nothing else: the recipe reports what was selected, it does not gate it."}],parts:[{name:"Trigger",description:`The floating action button that reveals the actions and anchors their position. Carries aria-haspopup="menu", aria-expanded, aria-controls, and an id that Content points its aria-labelledby at, so the menu inherits the floating button's name without a second prop to keep in sync.`,props:[{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the trigger; the data-size attribute may be set directly instead."}]},r,{name:"Overlay",description:"An optional scrim painted behind Content, dimming the page so a fan opened over dense content is separated from it. Rendered only when the consumer includes it \u2014 there is no prop and no default, and a dial without one is unchanged. A real element rather than a style prop, so it carries data-state of its own and can fade on a different timeline from the staggered actions. It does not make the dial modal: the fan keeps its own dismissal, and a pointer-down on the scrim is an outside interaction that closes it."},{name:"Content",description:`The fanned-out action list (role="menu"). Owns positioning and roving focus. Sets each Item's ordinal custom properties for the staggered reveal. Takes the shared popper positioning props except side, which the root's direction owns.`,props:[...o({sideOffset:"8"}).filter(e=>e.name!=="side"),a,d]},{name:"Item",description:'One action in the fan (role="menuitem"), a roving tab stop activated by click, Enter, or Space. Carries --skdx-speed-dial-index and --skdx-speed-dial-offset for the stagger.',props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Excludes the action from arrow-key navigation and blocks selection. It keeps its slot in the fan, so the actions around it do not shuffle."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the item; the data-size attribute may be set directly instead."}]},{name:"ItemLabel",description:"The visible text naming its Item. Registers its id as the Item's aria-labelledby, so an icon-only action is named by the label beside it rather than needing the name repeated in an aria-label."}],slots:[{name:"trigger",description:"The floating button's content: typically one icon. The button must carry an accessible name whenever content is icon-only \u2014 an unnamed floating action button says nothing about what it opens."},{name:"default",description:"Content's body \u2014 Item entries, each optionally with an ItemLabel."}],appearance:[{attribute:"data-size",values:["sm","md","lg"],stylesheet:"speed-dial.css"}],states:["closed","open","disabled"],controlledUncontrolled:"Stateless by default (uncontrolled): starts at defaultOpen and manages its own open state internally. Passing open switches to controlled.",formBehavior:'Not applicable \u2014 SpeedDial participates in no form; Trigger is type="button".',validationBehavior:"Not applicable \u2014 SpeedDial invokes actions, it collects no value.",accessibility:{role:"menu (Content), menuitem (Item)",keyboard:[{key:"Enter / Space",behavior:"Opens the dial from the trigger and moves focus to the first enabled action."},{key:"Arrow keys along the direction axis",behavior:"Open the dial from the trigger: Up/Down when direction is up or down, Left/Right when it is left or right. Focus lands on the first enabled action."},{key:"Arrow keys (inside the fan)",behavior:'Move focus between enabled actions in DOM order along the direction axis, wrapping unless loop is false. A disabled action is skipped rather than focused. Mirrored under dir="rtl" for the horizontal directions.'},{key:"Home / End",behavior:"Jump focus to the first/last enabled action, skipping disabled ones."},{key:"Printable characters",behavior:'Move focus to the next enabled action whose accessible name starts with the typed string, searching forward from the focused one and wrapping. Disabled actions never match. The buffer resets after one second of inactivity, so typing "s", pausing, then "h" looks for two different actions while "sh" typed quickly looks for one.'},{key:"Enter / Space (on an action)",behavior:"Selects the focused action and closes the dial unless the select event is prevented."},{key:"Escape",behavior:"Requests close (cancelable via escape-key-down) and returns focus to Trigger."},{key:"Tab",behavior:"Closes the dial and returns focus to Trigger, per the WAI-ARIA menu pattern."}],ariaAttributes:['aria-haspopup="menu", aria-expanded, and aria-controls on Trigger',"Content's id matches Trigger's aria-controls",'aria-labelledby on Content pointing at Trigger \u2014 role="menu" is not name-from-content, so a fan of perfectly named actions still announces as an unnamed "menu" without it. One name in one place rather than a second prop to keep in sync; where Trigger is a host element the reference resolves to that host, because that is the element the author writes the name on and the only one an IDREF can reach across a shadow boundary',"aria-orientation on Content reflecting the axis direction implies \u2014 vertical for up/down, horizontal for left/right","aria-labelledby on an Item pointing at its ItemLabel when one is rendered","aria-disabled and data-disabled on a disabled Item, which is skipped by navigation and cannot be selected"],focusManagement:"Opening moves focus to the first action, by every route except hover: keyboard, click, and a programmatic or defaultOpen open all land on it, and the fan is then a single roving tab stop, so only one action is tabbable at a time. Escape, Tab, or selecting an action returns focus to Trigger. Hover-opening moves no focus, which is what keeps the hover path from stealing the caret out from under a keyboard user \u2014 the route is tracked internally rather than being carried on open-change, because contracts/change-reason.ts keeps an enumerated roster of the events that carry a reason and this is not one of them. A click is deliberately not treated as the hover case: pressing a menu button is a request for the menu, and every other menu button in this system focuses its first item for it.",namingRequirement:"Trigger must carry an accessible name (aria-label or visible text) \u2014 it is normally icon-only, and an unnamed floating button announces nothing about what it opens. Each Item is named by its ItemLabel, or by aria-label when it renders an icon alone."},styling:{cssParts:["trigger","overlay","content","item","item-label"],dataAttributes:[...s,"data-state","data-side","data-align","data-direction","data-disabled","data-size",{name:"data-skdx-speed-dial-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:[...i("speed-dial"),"--skdx-speed-dial-index","--skdx-speed-dial-offset"]},publicMethods:[]};export{c as speedDialContract};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var a={name:"Spinner",purpose:'A loading indicator for work of unknown duration (see Progress for measurable work). Renders role="status" with aria-live="polite" and visually hidden text inside the region so mounting the spinner produces an announcement.',props:[{name:"label",type:"string",defaultValue:"'Loading'",required:!1,description:"Accessible label announced while loading. The English default is a fallback so a Spinner is never unnamed \u2014 it is not the contract. What the contract requires is a non-empty, author-supplied name, which is what the shared assertion checks; pass a translated string to replace the default."},{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:[],slots:[{name:"default",description:"Optional custom spinner graphic; omit to style via CSS only."}],appearance:[{attribute:"data-size",values:["sm","lg"],stylesheet:"spinner.css"}],states:["default"],controlledUncontrolled:"Stateless \u2014 Spinner holds no internal state.",formBehavior:"Not applicable \u2014 Spinner does not participate in forms.",validationBehavior:"Not applicable \u2014 Spinner carries no value and participates in no validation.",accessibility:{role:"status",keyboard:[],ariaAttributes:[`role is always "status" and aria-live always "polite" \u2014 both are written after the consumer's props in every package, so neither can be replaced from markup`,"aria-label reflects the label prop, unless the consumer supplied their own aria-label (which wins) or an aria-labelledby (which suppresses the default, so a reference to visible text is not overridden by the English fallback)"],focusManagement:"Not focusable; not part of the tab order.",namingRequirement:'The label prop is the sole accessible name \u2014 always provide a meaningful one. role="status" is not name-from-content, so text rendered inside the spinner names nothing; the name must come from aria-label (which label writes) or a resolving aria-labelledby. The guarantee is "never unnamed", not "named Loading".'},styling:{cssParts:["root","spinner","label"],dataAttributes:[...e,"data-size"],cssCustomProperties:["--skdx-spinner-track-color","--skdx-spinner-indicator-color","--skdx-spinner-track-width","--skdx-spinner-speed"]},publicMethods:[]};export{a as spinnerContract};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ComponentContract } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* A group pairing a primary action with a trigger for a menu of related
|
|
4
|
+
* actions; deliberately stateless, owning no open/menu state of its own.
|
|
5
|
+
*/
|
|
6
|
+
export declare const splitButtonContract: ComponentContract;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var n={name:"SplitButton",purpose:"Groups a primary action button with a small trigger that opens a menu of related actions. Renders a group container plus Action and Trigger parts, derived from label/items or hand-composed; owns no open/menu state of its own.",props:[{name:"label",type:"string",required:!1,description:"Text of the derived primary Action. Absent prop, absent element. Hand-composed children take precedence."},{name:"items",type:"ReadonlyArray<{ value: string; label: string; disabled?: boolean }>",required:!1,description:"The menu entries behind the derived trigger, rendered into a Menu. Absent prop, absent menu. An entry's value is what the select event reports; disabled marks it aria-disabled and blocks selection. Flat only \u2014 no submenus."},{name:"menuLabel",type:"string",defaultValue:"'More options'",required:!1,description:"Accessible name of the derived trigger (bare chevron with no text of its own). Must be distinct from `label` to tell the two halves apart. Web Components renders as visually-hidden text."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the root; the data-size attribute may be set directly instead."},{name:"variant",type:"'secondary' | 'primary' | 'danger' | 'outline' | 'ghost' | (string & {})",required:!1,description:"Fill style rung, written to data-variant on the root; the data-variant attribute may be set directly instead."}],events:[{name:"action-click",description:"Fires when the derived primary Action is pressed, carrying the pointer event. Nothing fires for a hand-composed Action.",detail:"MouseEvent",frameworks:["react","vue","svelte","angular"],exception:"event-shape",frameworksReason:"Web Components derives a real `<button>` in the light DOM, so platform's native `click` is the only event. Re-dispatching would fire twice."},{name:"select",description:"Fires with the activated menu entry. Never fires for disabled entries or hand-composed menus.",detail:"{ value: string; label: string; disabled?: boolean }",frameworks:["react","vue","svelte","angular"],exception:"event-shape",frameworksReason:"Web Components derives a real `<skdx-menu>` as the second half, so its own `item-select` already bubbles out."}],parts:[{name:"Action",description:'The primary action button (type="button"). Clicking it must never open the menu. Note: `Action` is the labelled half; `Trigger` is the disclosure beside it.',props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the primary action independently of Trigger. No root-level equivalent: SplitButton renders no buttons. Disable both halves by composition."}]},{name:"Trigger",description:'The disclosure button (type="button", aria-haspopup="menu"). Owns no open state; meant to *be* the menu\'s trigger element so the menu supplies aria-expanded/aria-controls. React: `MenuTrigger asChild` composes behavior onto this part. Vue/Svelte/Angular/Web Components: nesting this inside the menu\'s trigger creates nested `<button>` elements (invalid). Use the menu\'s own trigger instead.',props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables opening the menu independently of Action."},{name:"aria-label",type:"string",required:!1,description:"Accessible name for the trigger (usually an unlabelled glyph). In Web Components and Angular, must reach the inner `<button>`, not the host."}]}],slots:[{name:"default",description:"SplitButton body \u2014 typically an Action part and a Trigger part."},{name:"action",description:"Action's content \u2014 the primary button's label."}],appearance:[{attribute:"data-size",values:["sm","md","lg"],stylesheet:"split-button.css"},{attribute:"data-variant",values:["secondary","primary","danger","outline","ghost"],stylesheet:"split-button.css"}],states:["default"],controlledUncontrolled:"Stateless \u2014 SplitButton holds no internal state; any menu it pairs with owns its own.",formBehavior:'Not applicable at the group level \u2014 Action and Trigger are both type="button", so neither submits an enclosing form by default.',validationBehavior:"Not applicable \u2014 SplitButton carries no value and participates in no validation.",accessibility:{role:"group",keyboard:[{key:"Enter / Space (on Trigger)",behavior:"Opens the attached menu and moves focus to its first item."},{key:"ArrowDown (on Trigger)",behavior:"Opens the menu and moves focus to its first item (without prior click)."},{key:"ArrowUp (on Trigger)",behavior:"Opens the menu and moves focus to its *last* item (one keystroke to the bottom)."},{key:"Alt+ArrowUp (inside the open menu)",behavior:"Closes the menu and returns focus to Trigger, the mirror of the ArrowDown that opened it."},{key:"Escape (inside the open menu)",behavior:"Closes the menu and returns focus to Trigger."}],ariaAttributes:['aria-haspopup="menu" on Trigger',"aria-expanded and aria-controls on Trigger \u2014 supplied by the menu it is composed into, not by SplitButton"],focusManagement:"Action and Trigger are independently focusable buttons. Composed menu moves focus into its panel on open and **returns it to Trigger when it closes**: Escape, Alt+ArrowUp, pointer outside, or item selection. Menu performs this return; SplitButton does not intercept. Except: pointer dismissal does not return focus.",namingRequirement:`The root must carry aria-label or aria-labelledby (role="group" is not name-from-content). Action is named by its own text. Trigger must have an explicit name distinct from Action's.`},styling:{cssParts:["split-button","action","trigger"],dataAttributes:[...e,"data-size","data-variant",{name:"data-skdx-split-button-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 splitButtonContract};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var a={name:"StatCard",purpose:"A KPI / metric tile block composing Text, Progress, Skeleton and VisuallyHidden. Renders a labelled group holding a value, an optional trend with sentiment colouring, a description, a derived progress bar and a visual region, with no coupling to any chart library. Ships in the blocks package of each framework, not the core package.",props:[{name:"label",type:"string",required:!0,description:"Name of the metric, rendered into the label that names the group through aria-labelledby."},{name:"value",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot rather than a prop \u2014 Vue because a renderable region is a slot in Vue's own idiom, Web Components because a custom element attribute carries a string and cannot carry a node. Both slot spellings are declared under `slots`.",description:"The metric's current reading, already formatted by the consumer, rendered into the value region. A prop in React, Svelte, and Angular; Vue and Web Components use the `value` slot."},{name:"change",type:"string",required:!1,description:'Already-formatted delta text such as "+12.4%", rendered inside the trend region beside the trend icon.'},{name:"trend",type:"'up' | 'down' | 'neutral'",required:!1,description:"Direction of the change only, mirrored to data-trend on the root and the trend part. No trend region renders without change."},{name:"sentiment",type:"'positive' | 'negative' | 'neutral'",required:!1,description:"Whether the change is good or bad, independent of trend, mirrored to data-sentiment for the colour the skin applies."},{name:"changeLabel",type:"string",required:!1,description:'Visually hidden text read before the change, such as "Increased by", so the direction is spoken.'},{name:"trendIcon",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot rather than a prop \u2014 Vue because a renderable region is a slot in Vue's own idiom, Web Components because a custom element attribute carries a string and cannot carry a node. Both slot spellings are declared under `slots`.",description:"Decorative glyph rendered beside the change text inside the trend region. A prop in React, Svelte, and Angular; Vue and Web Components use the `trend-icon` slot."},{name:"icon",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot rather than a prop \u2014 Vue because a renderable region is a slot in Vue's own idiom, Web Components because a custom element attribute carries a string and cannot carry a node. Both slot spellings are declared under `slots`.",description:"Decorative glyph rendered beside the label in the card header. A prop in React, Svelte, and Angular; Vue and Web Components use the `icon` slot."},{name:"description",type:"string",required:!1,description:"Supporting text rendered below the value, in the skin's muted tone."},{name:"progress",type:"number",required:!1,description:"Percentage from 0 to 100, rendered into a derived Progress named by the label. No progress bar renders without a number."},{name:"visual",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot rather than a prop \u2014 Vue because a renderable region is a slot in Vue's own idiom, Web Components because a custom element attribute carries a string and cannot carry a node. Both slot spellings are declared under `slots`.",description:"A chart or sparkline region the card sizes; the consumer draws its contents. A prop in React, Svelte, and Angular; Vue and Web Components use the `visual` slot."},{name:"footer",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot rather than a prop \u2014 Vue because a renderable region is a slot in Vue's own idiom, Web Components because a custom element attribute carries a string and cannot carry a node. Both slot spellings are declared under `slots`.",description:"Content rendered in a footer region below the card. A prop in React, Svelte, and Angular; Vue and Web Components use the `footer` slot."},{name:"actions",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot rather than a prop \u2014 Vue because a renderable region is a slot in Vue's own idiom, Web Components because a custom element attribute carries a string and cannot carry a node. Both slot spellings are declared under `slots`.",description:"Controls rendered at the end of the header, such as a menu button. A prop in React, Svelte, and Angular; Vue and Web Components use the `actions` slot."},{name:"loading",type:"boolean",defaultValue:"false",required:!1,description:'Shows a skeleton in the value region, withholds the trend, and marks the root aria-busy and data-state="loading".'}],events:[],slots:[{name:"value",description:"The metric's current reading, already formatted by the consumer."},{name:"icon",description:"Decorative glyph beside the label in the card header."},{name:"trend-icon",description:"Decorative glyph beside the change text in the trend region."},{name:"visual",description:"A chart or sparkline region the card sizes for the consumer to draw into."},{name:"footer",description:"Content placed in a footer region below the card."},{name:"actions",description:"Controls placed at the end of the header."}],states:["default","loading"],controlledUncontrolled:"Stateless \u2014 StatCard holds no internal state.",formBehavior:"Not applicable \u2014 StatCard participates in no form.",validationBehavior:"Not applicable \u2014 StatCard carries no value and participates in no validation.",accessibility:{role:'group (native <div role="group"> named by its label through aria-labelledby)',keyboard:[],ariaAttributes:["aria-labelledby on the group points at the label, so the tile is announced by its metric name",'aria-busy="true" on the group while loading is true',"the icon and trend icon are aria-hidden, decorative only","changeLabel renders into a visually hidden span before the change, so the direction is spoken"],focusManagement:"Nothing inside the block is focusable except the controls the consumer supplies through actions and footer."},styling:{cssParts:["stat-card","header","icon","label","actions","body","value","trend","trend-icon","description","progress","visual","footer"],dataAttributes:[...e,"data-trend","data-sentiment","data-state",{name:"data-skdx-stat-card-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{a as statCardContract};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{changeDetail as e}from"./change-reason.js";import{ROOT_DATA_ATTRIBUTES as t}from"./styling-hooks.js";var i={name:"Stepper",purpose:'An ordered list of steps in a multi-step task. Renders an <ol>; the current step carries aria-current="step" and visually-hidden status text (completed/current/error/incomplete/disabled). Optionally interactive via per-step Trigger, in linear or non-linear navigation mode.',props:[{name:"value",type:"string",required:!1,description:"Current step's value, for controlled usage. Pair with the value-change event."},{name:"defaultValue",type:"string",required:!1,description:"Initially current step's value, for uncontrolled usage."},{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Layout axis, exposed as data-orientation styling hook. No ARIA orientation or arrow-key handling (each Trigger is an ordinary tab stop)."},{name:"navigationMode",type:"'linear' | 'non-linear'",defaultValue:"'linear'",required:!1,description:"'linear' restricts trigger-driven navigation to completed, current, and first incomplete step. 'non-linear' allows any non-disabled step. Neither restricts programmatic changes to value."},{name:"completedLabel",type:"string",defaultValue:"'Completed'",required:!1,description:"Visually-hidden status text rendered inside a step whose status is completed."},{name:"currentLabel",type:"string",defaultValue:"'Current step'",required:!1,description:"Visually-hidden status text rendered inside the step whose status is current."},{name:"incompleteLabel",type:"string",defaultValue:"'Not completed'",required:!1,description:"Visually-hidden status text rendered inside a step whose status is incomplete."},{name:"disabledLabel",type:"string",defaultValue:"'Disabled'",required:!1,description:"Visually-hidden status text rendered inside a step whose status is disabled."},{name:"errorLabel",type:"string",defaultValue:"'Error'",required:!1,description:"Visually-hidden status text rendered inside a step whose status is error."},{name:"items",type:"ReadonlyArray<{ label: string; description?: string }>",required:!1,description:"The steps the list derives (one Item per entry with its Trigger). Label titles the step; description sits under it. Hand composition takes precedence."},{name:"current",type:"number",required:!1,description:"Which derived step is current, as a **positional index**. The string model (`value`/`defaultValue`/`value-change`) still works and wins when both are set."}],events:[{name:"value-change",description:"Fired when the current step changes, controlled or not. Never fires for a blocked activation (linear mode or disabled step), and never for the step that is already current.",detail:e("string")}],parts:[{name:"Item",description:'One step: an <li> carrying data-state and aria-current="step" (when current) plus visually-hidden status label.',props:[{name:"value",type:"string",required:!0,description:"Unique identifier matched against the root's value and against a Trigger's value."},{name:"completed",type:"boolean",defaultValue:"false",required:!1,description:"Whether this step has been completed. Drives data-state and, in linear mode, which steps a Trigger may activate."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Whether this step can be activated. A disabled step is skipped in tab order and refuses activation, but does not move the linear frontier."},{name:"error",type:"boolean",defaultValue:"false",required:!1,description:"Whether this step is in an error state (form failed, upload rejected). Drives data-state='error' and errorLabel status text (announced, not only painted red). Still navigable and counts as incomplete unless also completed. Ranks below current in precedence."}]},{name:"Trigger",description:"The optional interactive control inside an Item that makes the step navigable. Omit it for a read-only progress indicator.",props:[{name:"value",type:"string",required:!0,description:"The owning Item's value \u2014 the step this trigger activates."}]}],slots:[{name:"default",description:"One Item per step, in order."},{name:"item",description:"A single step's content: its label, marker, and optional Trigger."},{name:"trigger",description:"A single step's interactive control."}],states:["completed","current","error","incomplete","disabled"],controlledUncontrolled:"Stateless by default (uncontrolled): starts at defaultValue and manages the current step internally. Passing value switches to controlled \u2014 the consumer owns state and must update it from value-change, or the DOM will not change. Completion is always consumer-owned: Stepper never marks a step completed by itself.",formBehavior:"Not applicable \u2014 Stepper carries no value that participates in form submission. In a wizard, each step owns its own Form/Field controls.",validationBehavior:"Not applicable \u2014 Stepper runs no validation. A wizard gates forward progress by keeping the next step incomplete until its own form validates.",accessibility:{role:"list (native <ol>) / listitem (native <li>) / button (Trigger)",keyboard:[{key:"Tab / Shift+Tab",behavior:"Moves between step triggers (ordinary tab stops; no roving tabindex)."},{key:"Enter / Space",behavior:"Activates the focused trigger (subject to navigation mode and enabled state), via native button behavior."}],ariaAttributes:['aria-current="step" on the current Item',"aria-disabled on a Trigger that the navigation mode blocks","aria-controls on a Trigger that reveals content (consumer supplies the region id)."],focusManagement:"Each enabled step's Trigger is its own tab stop; disabled step's Trigger is removed from tab order. Activating a step does not move focus.",namingRequirement:'The root should carry aria-label or aria-labelledby (e.g. "Checkout progress").'},styling:{cssParts:["stepper","item","trigger","indicator","title","description","separator"],dataAttributes:[...t,"data-state","data-orientation","data-disabled","data-value","data-state-text",{name:"data-skdx-stepper-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:"getCurrentValue",signature:"(): string | undefined",description:"Reads the value of the step that is current, or undefined while none is.",frameworks:["webComponents"],exception:"imperative",frameworksReason:"The other four publish the same reading through context under a different name \u2014 React as `value` on StepperContextValue, Vue, Svelte and Angular as `currentValue()` \u2014 so listing it here unscoped would read as four packages missing a member they all have. Only the custom element, which has no context to hand it through, spells it as a method."}],contextApi:[{name:"canActivate",signature:"(value: string) => boolean",description:"Whether a trigger for value may activate its step under the current navigationMode. False for a disabled step, and for any step the mode puts out of reach \u2014 the same predicate a Trigger disables itself on.",accessors:{react:"useStepperContext('MyComponent').canActivate",vue:"inject(STEPPER_CONTEXT).canActivate",svelte:"requireContext(STEPPER_CONTEXT).canActivate",angular:"inject(SKDX_STEPPER_CONTEXT).canActivate",webComponents:"document.querySelector('skdx-stepper').canActivate"}},{name:"activate",signature:"(value: string) => void",description:"Makes value the current step and fires value-change, when canActivate allows it. A no-op otherwise \u2014 it never throws, so a blocked target is refused rather than reported.",accessors:{react:"useStepperContext('MyComponent').activate",vue:"inject(STEPPER_CONTEXT).activate",svelte:"requireContext(STEPPER_CONTEXT).activate",angular:"inject(SKDX_STEPPER_CONTEXT).activate",webComponents:"document.querySelector('skdx-stepper').activate"}}]};export{i as stepperContract};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two `data-*` hooks every family publishes by construction, spread into contracts to prevent drift.
|
|
3
|
+
*/
|
|
4
|
+
import type { DataAttr } from './types.js';
|
|
5
|
+
/** Published on every element the part helpers render, in all five frameworks. */
|
|
6
|
+
export declare const PART_DATA_ATTRIBUTES: readonly DataAttr[];
|
|
7
|
+
/** For families whose root renders a real element: the part hook plus the family marker the root alone carries. */
|
|
8
|
+
export declare const ROOT_DATA_ATTRIBUTES: readonly DataAttr[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var t=["data-part"],a=["data-part","data-skdx-component"];export{t as PART_DATA_ATTRIBUTES,a as ROOT_DATA_ATTRIBUTES};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{constraintValidationMethods as e,setCustomValidityMethod as t}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as a}from"./styling-hooks.js";var o={name:"Switch",purpose:'Boolean on/off switch with `role="switch"` and optional native form participation.',props:[{name:"checked",type:"boolean",required:!1,description:"Checked state for controlled usage; pair with checked-change."},{name:"defaultChecked",type:"boolean",defaultValue:"false",required:!1,description:"Initial checked state for uncontrolled usage."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disable switch and exclude from form submission."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Mark hidden input required for form validation."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:'Freeze state without freezing control. Keeps role="switch", tab stop, aria-readonly="true", and still submits.'},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Mark switch invalid (aria-invalid/data-invalid); presentational only."},{name:"name",type:"string",required:!1,description:"Name for form submission via hidden checkbox input."},{name:"value",type:"string",defaultValue:"'on'",required:!1,description:"Value to submit when checked."},{name:"form",type:"string",required:!1,description:"Form id when switch is rendered outside the form."},{name:"label",type:"string",required:!1,description:"Label text; omit to skip the label element."},{name:"labelPosition",type:"'start' | 'end'",defaultValue:"'end'",required:!1,description:"Which side of control the label sits on."},{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:"checked-change",description:"Fires with the new checked state whenever it changes, controlled or not.",detail:"boolean"}],slots:[{name:"default",description:"Switch button content: Label, Thumb, or both."}],parts:[{name:"Label",description:"Switch's visible text; names the control."},{name:"Thumb",description:"Sliding knob; decorative."}],appearance:[{attribute:"data-size",values:["sm","lg"],stylesheet:"switch.css"}],states:["default","checked","unchecked","hover","focus","disabled","readonly","invalid"],controlledUncontrolled:"Supports both: pass checked + listen for checked-change for controlled usage, or defaultChecked to let the component own its own state uncontrolled.",formBehavior:'When name is set, renders a hidden native `<input type="checkbox">` for form submission. An off switch contributes no FormData entry at all.',validationBehavior:"Native: hidden checkbox carries required; form submission blocks on it. invalid is presentational only. setCustomValidity() blocks submission for browser-opaque errors. readOnly still submits.",accessibility:{role:"switch",keyboard:[{key:"Space",behavior:"Toggle checked; required by APG."},{key:"Enter",behavior:"Also toggle checked. Optional per APG (native button activation)."}],ariaAttributes:["aria-checked","aria-required when required","aria-invalid when invalid",'aria-readonly="true" when readOnly'],focusManagement:"Native tab order; disabled removes it. readOnly keeps tab stop and focus ring.",namingRequirement:"Name via Label child, <label>, or aria-label."},styling:{cssParts:["switch","thumb","label"],dataAttributes:[...a,"data-state","data-disabled","data-readonly","data-invalid","data-size",{name:"data-skdx-switch-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:[...e,t],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{o as switchContract};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ComponentContract } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The Table contract, implemented by every framework package's Table: a
|
|
4
|
+
* structural data-table primitive owning only sort and
|
|
5
|
+
* row-selection state — no pagination, filtering, or data model.
|
|
6
|
+
*/
|
|
7
|
+
export declare const tableContract: ComponentContract;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{constraintValidationMethods as e,setCustomValidityMethod as t}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as r}from"./styling-hooks.js";var o={name:"Table",purpose:"A structural data-table primitive. Owns only sort and row-selection state; consumers map over their own row data to render rows and cells. Renders a plain <table>.",props:[{name:"sort",type:"TableSortState[]",required:!1,description:"Sorted columns, most significant first, for controlled usage. Always an array, whatever multiSort is set to; [] means nothing is sorted. The shape does not change when multiSort is toggled at runtime \u2014 multiSort governs only whether the array may hold more than one entry."},{name:"defaultSort",type:"TableSortState[]",defaultValue:"[]",required:!1,description:"Initially sorted columns, most significant first, for uncontrolled usage."},{name:"filter",type:"TableFilterState",required:!1,description:"Active column filters for controlled usage: a map from columnKey to the text that column's cells must contain. A column with no entry is unfiltered; {} means nothing is filtered."},{name:"defaultFilter",type:"TableFilterState",defaultValue:"{}",required:!1,description:"Initial column filters, for uncontrolled usage."},{name:"multiSort",type:"boolean",defaultValue:"false",required:!1,description:`Whether activating a second column appends it to the sort instead of replacing the first. It governs the array's length, never its type: off, sort holds at most one entry and at most one header can report aria-sort="ascending" | "descending"; on, it holds as many as the user has activated, most significant first.`},{name:"selected",type:"Set<string> | string[]",required:!1,description:"Selected row ids, for controlled usage."},{name:"defaultSelected",type:"Set<string> | string[]",required:!1,description:"Initially selected row ids, for uncontrolled usage."},{name:"selectionMode",type:"'single' | 'multiple' | 'none'",defaultValue:"'none'",required:!1,description:"Whether rows can be selected at all, and if so, one or many at once."},{name:"getSortLabel",type:"(column: string, direction: 'asc' | 'desc' | null) => string",defaultValue:"defaultGetSortLabel",required:!1,description:'Formats the message announced through the LiveAnnouncer when a sortable header is activated. `column` is the header cell\'s own text. Return an empty string to announce nothing. The default names the column and new direction \u2014 "Amount sorted ascending" / "Amount sorted descending", and "Amount not sorted" once cleared.'},{name:"expandedRowIds",type:"string[]",required:!1,description:"Row ids whose ExpandedRow detail row is open, for controlled usage."},{name:"defaultExpandedRowIds",type:"string[]",defaultValue:"[]",required:!1,description:"Initially expanded detail rows, for uncontrolled usage."},{name:"columnWidths",type:"Record<string, number>",required:!1,description:"Per-column pixel widths keyed by a header cell's columnKey, for controlled usage."},{name:"defaultColumnWidths",type:"Record<string, number>",defaultValue:"{}",required:!1,description:"Initial per-column pixel widths, for uncontrolled usage. Columns left out size themselves until resized."},{name:"columnOrder",type:"string[]",required:!1,description:"Display order of column keys, for controlled usage. Keys not listed follow in source order; [] means source order. The primitive never reorders your cells \u2014 only the derived columns/data view renders in this order."},{name:"defaultColumnOrder",type:"string[]",defaultValue:"[]",required:!1,description:"Initial column order, for uncontrolled usage."},{name:"columnPins",type:"TableColumnPins",required:!1,description:"Pinned columns for controlled usage: a map from columnKey to 'start' or 'end'. An unpinned column is absent; {} means nothing is pinned. Pinned cells become sticky and receive --skdx-table-pin-offset."},{name:"defaultColumnPins",type:"TableColumnPins",defaultValue:"{}",required:!1,description:"Initially pinned columns, for uncontrolled usage."},{name:"getMoveLabel",type:"(column: string, position: number, count: number) => string",defaultValue:"defaultGetMoveLabel",required:!1,description:'Formats the message announced through the LiveAnnouncer after a column is moved by keyboard or dropped. `column` is the header cell\'s own text, `position` is 1-based. Return an empty string to announce nothing. The default reads "Amount moved to position 2 of 5".'},{name:"collapsedGroups",type:"string[]",required:!1,description:"Group keys whose rows are hidden, for controlled usage. Groups start expanded, so [] shows every group."},{name:"defaultCollapsedGroups",type:"string[]",defaultValue:"[]",required:!1,description:"Initially collapsed groups, for uncontrolled usage."},{name:"expandedNodeIds",type:"string[]",required:!1,description:"Tree parents whose child rows are rendered, for controlled usage. Distinct from expandedRowIds, which opens detail rows."},{name:"defaultExpandedNodeIds",type:"string[]",defaultValue:"[]",required:!1,description:"Initially expanded tree parents, for uncontrolled usage."},{name:"rowCount",type:"number",required:!1,description:"The total number of rows in the full dataset, reflected as aria-rowcount on the <table>. Set it when rows in the DOM are not all rows there are (pagination, virtualization, infinite scroll), else assistive tech counts rendered rows and reports wrong position. Use -1 when the total is unknown \u2014 what ARIA reserves it for. Omitted when unset, so a table rendering all rows says nothing. Per-row aria-rowindex stays the consumer's: Table renders no rows and cannot number them."},{name:"columnCount",type:"number",required:!1,description:"The total number of columns in the full dataset, reflected as aria-colcount on the <table>. Column counterpart of rowCount for tables showing a horizontal window. Use -1 when unknown. Omitted when unset. Per-cell aria-colindex, like aria-rowindex, is consumer-supplied."},{name:"columns",type:"TableColumn<T>[]",required:!1,description:"The columns the derived <thead>/<tbody> draws from \u2014 one HeaderCell and one Cell per row. Each is { key, header?, cell?, sortable?, resizable?, minWidth?, maxWidth? }: key is the columnKey, header defaults to key, and column settings override root defaults. Required together with data to derive the whole table; omit both and compose the body by hand from Row and Cell instead. React alone enforces the pair in its types, because only there is the deriving recipe a separate component from the root."},{name:"data",type:"T[]",required:!1,description:"The rows to render, one derived Row per entry. columns' datum type is inferred from this, so a consumer annotates neither columns nor renderCell. Required together with columns to derive the whole table; omit both and compose the body by hand."},{name:"rowId",type:"(row: T, index: number) => string",defaultValue:"(row, index) => String(row.id ?? index)",required:!1,description:"Derives each row's identity for selection, expansion, and list keys. Defaults to the row's id if it's a string/number, otherwise its index. Index-only identity breaks selection when data reorders, since a selected id silently points to a different row."},{name:"getRowLabel",type:"(row: T, index: number) => string",required:!1,description:`Names each row for the derived RowSelectCheckbox and ExpandTrigger, which speak it as "Select <label>" and "Details for <label>". Return the row's own human-readable text \u2014 a person's name, an invoice number \u2014 because without it a control is named from bookkeeping: the rowId or the row's position, neither of which identifies anything to a screen reader, and the position goes stale the moment a sort reorders the rows.`},{name:"sortable",type:"boolean",defaultValue:"false",required:!1,description:"Default sortable for columns with no own setting. Makes the derived view render rows in live sort order \u2014 a copy of data sorted by most-significant column first, never data itself. The primitive never reorders your rows; this recipe sorts its own copy on top of the sort state."},{name:"filterable",type:"boolean",defaultValue:"false",required:!1,description:"Default filterable for columns with no own setting. A filterable column derives a ColumnHeaderFilterInput under its header, and the derived view renders only the rows whose stringified cell contains every active filter's text, case-insensitively \u2014 a filtered copy, applied before the sort, never data itself."},{name:"selectable",type:"boolean",defaultValue:"false",required:!1,description:"Derives a leading SelectAllCheckbox/RowSelectCheckbox column. Sugar over selectionMode: raises 'none' to 'multiple' once; explicit selectionMode always wins for a single source of truth."},{name:"expandable",type:"boolean",defaultValue:"false",required:!1,description:"Derives a leading ExpandTrigger column and an ExpandedRow per row. A boolean, not the content itself \u2014 renderExpanded supplies the detail row's content, and without it the derived detail row is empty."},{name:"renderExpanded",type:"(row: T) => React.ReactNode",required:!1,description:"Renders a derived ExpandedRow's detail content for one row. Ignored while expandable is false."},{name:"resizable",type:"boolean",defaultValue:"false",required:!1,description:"Default resizable for every column that doesn't set its own."},{name:"reorderable",type:"boolean",defaultValue:"false",required:!1,description:"Default reorderable for every column that doesn't set its own. A reorderable column derives a ColumnReorderTrigger, and the derived view renders columns in columnOrder."},{name:"pinnable",type:"boolean",defaultValue:"false",required:!1,description:"Default pinnable for every column that doesn't set its own. A pinnable column derives a ColumnPinTrigger, and the derived view renders pinned-start columns first and pinned-end columns last."},{name:"groupBy",type:"string",required:!1,description:"A column key to group rows by. The derived view emits a GroupRow per distinct String(row[groupBy]) after filter and sort, groups ordered by first appearance, and hides a group's rows while its key is in collapsedGroups."},{name:"renderGroupHeader",type:"(groupKey: string, rows: T[]) => React.ReactNode",required:!1,description:`Renders a derived GroupRow's label for one group. Ignored without groupBy. Defaults to the key and the row count, as in "EMEA (12)".`},{name:"getSubRows",type:"(row: T) => T[] | undefined",required:!1,description:"Returns a row's child rows to render it as a tree parent. Children render under the parent while its id is in expandedNodeIds, sorted per level, one level deeper each time; the filter applies to top-level rows only. A parent derives a TreeTrigger in its first data cell."},{name:"empty",type:"React.ReactNode",required:!1,description:"Content for the derived Empty row, shown in place of body rows while data is empty. No default text: with no empty supplied, no empty row is derived \u2014 avoiding an i18n leak."},{name:"caption",type:"React.ReactNode",required:!1,description:"Content for a derived Caption, rendered before the header. No caption is derived when omitted."},{name:"renderCell",type:"(row: T, column: TableColumn<T>) => React.ReactNode",required:!1,description:"Fallback cell renderer for a column with no cell of its own. With neither, a cell renders String(row[column.key])."},{name:"density",type:"'compact' | (string & {})",required:!1,description:"Vertical rhythm rung, written to data-density on the root; the data-density attribute may be set directly instead."},{name:"stickyHeader",type:"boolean",required:!1,description:"Pins the header row while the body scrolls, written to data-sticky-header on the root; the data-sticky-header attribute may be set directly instead."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Size rung forwarded to RowSelectCheckbox's and SelectAllCheckbox's data-size; either attribute may be written directly instead."}],events:[{name:"sort-change",description:"Fires with the new sort state whenever a sortable header is activated. The payload is always a TableSortState[], most significant first \u2014 [] once the last sorted column has cycled back to unsorted \u2014 regardless of multiSort.",detail:"TableSortState[]"},{name:"filter-change",detail:"TableFilterState",description:"Fires with the new filter map whenever a column's filter text changes; a cleared column leaves the map, so {} means nothing is filtered."},{name:"selected-change",detail:"string[]",description:"Fires with the new selected row ids whenever selection changes."},{name:"expanded-row-ids-change",detail:"string[]",description:"Fires with the new set of expanded row ids whenever an ExpandTrigger is activated."},{name:"column-widths-change",description:"Fires with the full width map whenever a resizable column is dragged or keyboard-resized \u2014 continuously, on every drag frame and every arrow-key nudge, because the column must follow the pointer. Persist from column-widths-commit instead.",detail:"Record<string, number>"},{name:"column-widths-commit",description:'The settled counterpart of column-widths-change, carrying the same width map: fired once per gesture rather than per frame, so persisting writes once instead of dozens. Fires on pointerup, pointercancel at drag end, Escape (reverting the width), and keyup after Arrow/Home/End resize. Never fires for unchanged gestures (movement-less pointerdown or clamped arrow), so it means "this is the width to store".',detail:"Record<string, number>"},{name:"column-order-change",detail:"string[]",description:"Fires with the full column order whenever a ColumnReorderTrigger moves its column by keyboard or drop."},{name:"column-pins-change",detail:"TableColumnPins",description:"Fires with the full pin map whenever a ColumnPinTrigger is activated."},{name:"collapsed-groups-change",detail:"string[]",description:"Fires with the collapsed group keys whenever a GroupRow is toggled."},{name:"expanded-node-ids-change",detail:"string[]",description:"Fires with the expanded tree parents whenever a TreeTrigger is activated."}],parts:[{name:"Row",description:`A <tr>. Given a rowId and while selectionMode is not 'none', publishes data-row-id, reports selection as data-state="selected", and toggles selection when clicked. The click is pointer sugar, not the affordance: the row is never focusable and never carries a tabindex, so every selectable Row MUST contain a RowSelectCheckbox \u2014 the keyboard path to selecting.`,props:[{name:"rowId",type:"string",required:!1,description:"This row's identifier within the table's selection state. Required for the row to be selectable; a row without one is never selected and never clickable-to-select."},{name:"level",type:"number",required:!1,description:"Tree depth, 0 for a top-level row. Written to data-level and --skdx-table-row-level so the skin indents the first cell; the derived view sets it for every tree row."}]},{name:"Cell",description:"A <td>. Given a columnKey it reflects that column's pin as data-pinned and --skdx-table-pin-offset.",props:[{name:"columnKey",type:"string",required:!1,description:"The column this cell belongs to, so it can follow a pinned header. Set by the derived view; optional when composing by hand."}]},{name:"RowSelectCheckbox",description:"One row's selection checkbox, driven by the table's selection state, rendered inside a Cell of its row. Required in every selectable row: it's the only focusable control that selects one, so omitting it makes the table pointer-only. Space toggles it, Shift-activation extends selection to a range. Needs a row-specific accessible name \u2014 no default because only the consumer knows what names the row. Being a Checkbox, it inherits form participation: name and value submit as a pair from inside a <form> (see formBehavior).",props:[{name:"checked",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 row is currently selected. Read-only: toggle it through the table's selected row ids."},{name:"rowId",type:"string",required:!0,description:"The row this checkbox selects. Must match the rowId on the enclosing Row."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the checkbox; the data-size attribute may be set directly instead."}],methods:[...e,t]},{name:"SelectAllCheckbox",description:'The header checkbox that selects or clears a whole set of rows at once. Tri-state: checked when every id in rowIds is selected, indeterminate when only some are, unchecked otherwise \u2014 including over an empty list, where a select-all above no rows reads unchecked rather than vacuously checked. Meaningful only with selectionMode="multiple".',props:[{name:"checked",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 every row in rowIds is currently selected. Read-only: toggle it through the table's selected row ids."},{name:"rowIds",type:"string[]",required:!0,description:'Exactly the rows this checkbox covers. Required because Table keeps no row registry: "select all" means the ids you hand it and nothing else, so under pagination or virtualization it is either the rendered page or the whole dataset, and only the consumer knows which.'},{name:"scope",type:"'page' | 'all'",required:!0,description:"Which set rowIds is \u2014 the rendered page or the entire dataset. Required and undefaulted: the two behave identically until the table is paginated or virtualized, at which point a select-all that silently covered only the visible window is a bug found in production. It is also published as data-scope and spoken in the default accessible name."},{name:"getSelectAllLabel",type:"(scope: 'page' | 'all', count: number) => string",defaultValue:"defaultSelectAllLabel \u2014 `Select all N rows on this page` / `Select all N rows`",required:!1,description:`Formats the checkbox's own accessible name. The default names the count and the scope rather than a bare "Select all", because "select all 40 rows on this page" and "select all 1,204 rows" are different promises and the user has to hear which one is on offer.`},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the checkbox; the data-size attribute may be set directly instead."}],methods:[...e,t]},{name:"HeaderCell",description:"A <th>. A column has one identifier, columnKey, and sorting, filtering and resizing all key off it. Sortable when given `sortable`; filterable when given `filterable`; resizable when given `resizable`. Any affordance needs a columnKey \u2014 a column with no identifier has nowhere to read its sort or filter from or store its width in, so all are suppressed however the booleans are set. Carries data-filterable, and data-filtered while its filter text is non-empty.",props:[{name:"columnKey",type:"string",required:!1,description:"This column's single identifier, used by both sorting and resizing. Required for a column that does either. It is the key that appears in a TableSortState and in the columnWidths map."},{name:"sortable",type:"boolean",defaultValue:"false",required:!1,description:"Whether this column can be sorted. A sortable cell sets aria-sort and data-sort-direction and wraps its children in a ColumnHeaderSortTrigger unless the consumer rendered one."},{name:"filterable",type:"boolean",defaultValue:"false",required:!1,description:"Whether this column can be filtered. A filterable cell renders a ColumnHeaderFilterInput after its label unless the consumer rendered one."},{name:"filterLabel",type:"string",defaultValue:"Filter ${columnKey}",required:!1,description:'Accessible name for the derived filter input, which needs one of its own; the deriving recipe passes "Filter <header text>".'},{name:"resizable",type:"boolean",defaultValue:"false",required:!1,description:`Renders a focusable role="separator" resize handle at the cell's inline end, driven by pointer drag or Arrow Left/Right (Home/End for the bounds).`},{name:"minWidth",type:"number",defaultValue:"40",required:!1,description:"Smallest width in pixels the column can be resized to."},{name:"maxWidth",type:"number",defaultValue:"1000",required:!1,description:"Largest width in pixels the column can be resized to."},{name:"resizeStep",type:"number",defaultValue:"8",required:!1,description:"Pixels one Arrow Left/Right press moves the edge, handed down to this cell's ColumnResizeTrigger."},{name:"resizeLabel",type:"string",defaultValue:"'Resize column'",required:!1,description:"Accessible name for the resize handle, which needs one of its own."},{name:"reorderable",type:"boolean",defaultValue:"false",required:!1,description:"Renders a ColumnReorderTrigger after the label unless the consumer rendered one. Needs a columnKey. Carries data-reorderable."},{name:"pinnable",type:"boolean",defaultValue:"false",required:!1,description:"Renders a ColumnPinTrigger after the label unless the consumer rendered one. Needs a columnKey. Carries data-pinnable, and data-pinned plus --skdx-table-pin-offset while pinned."},{name:"reorderLabel",type:"string",defaultValue:"'Move column'",required:!1,description:"Accessible name for the derived reorder trigger."},{name:"pinLabel",type:"string",defaultValue:"'Pin column'",required:!1,description:"Accessible name for the derived pin trigger."}]},{name:"ColumnHeaderFilterInput",description:`The <input type="search"> inside a filterable HeaderCell, bound to that column's entry in the filter map: typing writes it, clearing removes it. A filterable HeaderCell renders one after its label automatically, standing down when it finds one, so exactly one exists per column. Marked data-skdx-table-filter-input, and data-filtered while non-empty. Renders nothing when it can't find a column to filter.`,props:[{name:"columnKey",type:"string",required:!1,description:"The column this input filters. Normally omitted: inside a filterable HeaderCell it inherits the cell's columnKey. Pass it when the input sits outside a header cell or inside one left non-filterable \u2014 an explicit key is itself the opt-in."}]},{name:"ColumnHeaderSortTrigger",description:"The <button> inside a sortable HeaderCell that cycles ascending \u2192 descending \u2192 unsorted (APG sortable-table pattern). The control is a button inside the <th>, announcing as a button, activating on Enter/Space with no library key handling, and leaving the header out of the tab order. A sortable HeaderCell renders one around its children automatically, standing down when it finds one, so exactly one exists per column whether or not the consumer wrote it. Writing one is how to add an indicator, icon, or count inside the button. Carries data-sort-direction and, under multiSort, data-sort-index (the 0-based position for multi-sorted badges). Renders nothing when it can't find a column to sort, because a button that does nothing is worse than no button.",props:[{name:"columnKey",type:"string",required:!1,description:"The column this trigger sorts. Normally omitted: inside a sortable HeaderCell it inherits the cell's columnKey, which is the whole point of the cell owning one identifier for sorting and resizing alike. Pass it when the trigger sits outside a header cell, or inside one deliberately left non-sortable \u2014 an explicit key here is itself the opt-in, so the trigger sorts without the cell having to declare sortable and light up its own aria-sort wiring."}]},{name:"ColumnResizeTrigger",description:'The role="separator" handle a HeaderCell\'s `resizable` renders \u2014 or that a consumer renders directly to place it elsewhere or to give one column a different step. Drag, or focus and use Arrow Left/Right/Home/End, to resize the column.',props:[{name:"columnKey",type:"string",required:!1,description:"Which column this handle resizes. Normally omitted: inside a HeaderCell it inherits the cell's columnKey."},{name:"minWidth",type:"number",required:!1,description:"Lower clamp for the drag and for the Home key. Falls back to the enclosing HeaderCell's minWidth, then to a component default of 40."},{name:"maxWidth",type:"number",required:!1,description:"Upper clamp for the drag and for the End key. Falls back to the enclosing HeaderCell's maxWidth, then to a component default of 1000."},{name:"step",type:"number",required:!1,description:"Pixels one Arrow Left/Right press moves the edge. Falls back to the enclosing HeaderCell's resizeStep, then to a component default of 8. Keyboard only \u2014 a pointer drag follows the pointer."}]},{name:"ColumnReorderTrigger",description:'The <button> a HeaderCell\'s `reorderable` renders, or a consumer places, to move the column. Focus it and press Arrow Left/Right to move one position (mirrored under dir="rtl") or Home/End to move to the ends; drag it over another header cell to drop the column there. Every move publishes the full order and is announced through getMoveLabel. Carries data-dragging during a drag. Renders nothing without a column key.',props:[{name:"columnKey",type:"string",required:!1,description:"Which column this trigger moves. Normally omitted: inside a HeaderCell it inherits the cell's columnKey."},{name:"label",type:"string",required:!1,description:"Accessible name for the trigger. Falls back to the enclosing HeaderCell's reorderLabel, then to 'Move column'."}]},{name:"ColumnPinTrigger",description:"The <button aria-pressed> a HeaderCell's `pinnable` renders, or a consumer places, to pin the column to one side. Pressed while the column is pinned to `side`; activating it unpins, otherwise pins to `side`. Carries data-pinned mirroring the column. Renders nothing without a column key.",props:[{name:"columnKey",type:"string",required:!1,description:"Which column this trigger pins. Normally omitted: inside a HeaderCell it inherits the cell's columnKey."},{name:"side",type:"'start' | 'end'",defaultValue:"'start'",required:!1,description:"Which edge the column pins to."},{name:"label",type:"string",required:!1,description:"Accessible name for the trigger. Falls back to the enclosing HeaderCell's pinLabel, then to 'Pin column'."}]},{name:"GroupRow",description:'The row that heads a group of rows: a <tr> holding one <th scope="rowgroup" colspan> whose <button aria-expanded> wraps the children and toggles the group. Carries data-state="expanded" | "collapsed".',props:[{name:"groupKey",type:"string",required:!0,description:"The group this row heads; the key that appears in collapsedGroups."},{name:"colSpan",type:"number",defaultValue:"1",required:!1,description:"How many columns the group cell spans \u2014 the table's column count."}]},{name:"TreeTrigger",lightDom:!0,description:"Disclosure button inside a tree parent's first cell, carrying aria-expanded for that row's child rows. No aria-controls: the children are sibling rows, not one element.",props:[{name:"rowId",type:"string",required:!0,description:"Id of the parent row this trigger expands; the id that appears in expandedNodeIds."},{name:"label",type:"string",required:!1,frameworks:["webComponents"],exception:"attribute-passthrough",frameworksReason:"React, Vue, Svelte and Angular take `aria-label` on the element through attribute passthrough.",description:"Accessible name for the disclosure button, since its content is usually an icon."}]},{name:"SortIndicator",description:'The arrow, caret, or badge showing how a column is sorted: a <span aria-hidden="true"> with data-sort-direction ("asc"/"desc"/"none") and, under multiSort, data-sort-index. The aria-hidden is fixed \u2014 the HeaderCell publishes aria-sort and the sort trigger announces through the live announcer, so an indicator that also spoke would triple-announce the sort. It renders children and stays mounted in all three states, not swapping in/out, so a CSS arrow can rotate between them and an unsorted column reserves space.',props:[{name:"columnKey",type:"string",required:!1,description:"The column whose direction this indicator reflects. Normally omitted: it inherits the enclosing HeaderCell's columnKey, so an indicator dropped inside a header needs no wiring. Unlike the sort trigger it inherits from any header cell rather than only a sortable one, because reflecting a direction is not the same act as offering to change it \u2014 an indicator is free to sit in a column sorted from outside the header."}]},{name:"ExpandTrigger",lightDom:!0,description:"Disclosure button placed inside a row's cell, carrying aria-expanded and aria-controls pointing at that row's ExpandedRow.",props:[{name:"rowId",type:"string",required:!0,description:"Id of the row this trigger expands; must match the paired ExpandedRow."},{name:"label",type:"string",required:!1,frameworks:["webComponents"],exception:"attribute-passthrough",frameworksReason:"React, Vue, Svelte and Angular take `aria-label` on the element through attribute passthrough.",description:"Accessible name for the disclosure button, since its content is usually an icon."}]},{name:"ExpandedRow",description:"The full-width detail row an ExpandTrigger reveals: a <tr> with a single <td colspan> holding the expanded content. Stays mounted while collapsed so aria-controls resolves.",props:[{name:"rowId",type:"string",required:!0,description:"Id of the row this detail row belongs to."},{name:"colSpan",type:"number",defaultValue:"1",required:!1,description:"How many columns the detail cell spans \u2014 the table's column count."}]},{name:"Empty",description:'The row rendered in place of body rows when there is no data: a <tr data-state="empty"> whose single <td colspan> holds the empty-state message.',props:[{name:"colSpan",type:"number",defaultValue:"1",required:!1,description:"How many columns the empty cell spans \u2014 the table's column count."}]}],slots:[{name:"default",description:"Table sections \u2014 Header, Body, Footer, Caption."},{name:"header-cell",description:"A TableHeaderCell \u2014 optionally sortable via `sortable` plus a columnKey, in which case it wraps its label in a sort button."},{name:"cell",description:"A plain TableCell data cell."},{name:"detail",description:"An ExpandedRow's detail content, spanning the full column width."},{name:"empty",description:"The empty-state message shown in place of body rows when there is no data."},{name:"group-header",description:"A derived GroupRow's label, given the group key and its rows."}],appearance:[{attribute:"data-density",values:["compact"],stylesheet:"table.css"},{attribute:"data-sticky-header",values:[],stylesheet:"table.css"}],states:["default","selected","expanded","collapsed","empty"],controlledUncontrolled:"Sort, selection, expanded detail rows, column widths, column order, column pins, collapsed groups and expanded tree nodes each work controlled or uncontrolled, independently of one another.",formBehavior:`The Table root submits nothing (no name, value, or hidden input), so a <form> containing it gains no field. But its two checkbox parts are different: RowSelectCheckbox and SelectAllCheckbox inherit Checkbox's form participation wholly \u2014 name, value, required, invalid all work. A named RowSelectCheckbox submits its pair through a hidden input like any other checkbox. This makes a selection table usable as HTML form: name="rowIds" and value={row.id} means formData.getAll("rowIds") is the selection. Important: checkbox checked state stays owned by table selection, not the form, so form reset doesn't clear selection. Required on a row checkbox blocks submission on that row, not "select at least one row" \u2014 validate selection yourself.`,validationBehavior:"Not applicable \u2014 Table carries no single value and participates in no validation.",accessibility:{role:"table (native <table>)",keyboard:[{key:"Enter/Space",behavior:"Activates a focused sort button, cycling its column's sort, or a focused ExpandTrigger, toggling its detail row (native button activation). Likewise a focused ColumnPinTrigger, GroupRow button, or TreeTrigger."},{key:"Space",behavior:"Toggles a focused RowSelectCheckbox, selecting/deselecting its row, or a focused SelectAllCheckbox (native activation). With Shift on a RowSelectCheckbox it extends selection to a range, like Shift-click. This is the only keyboard path to row selection: the row itself is never focusable, so a Table without RowSelectCheckbox is operable by pointer alone."},{key:"ArrowLeft/ArrowRight",behavior:'Narrows/widens the column while its resize handle has focus, clamped to minWidth/maxWidth; moves the column one position while its reorder trigger has focus. Mirrored under dir="rtl".'},{key:"Home/End",behavior:"Jumps the focused resize handle's column to minWidth/maxWidth; moves the focused reorder trigger's column to the first/last position."}],ariaAttributes:["aria-sort on a sortable TableHeaderCell reflects its current sort direction","activating a sort button announces the new sort through the shared LiveAnnouncer polite region, formatted by getSortLabel \u2014 a changed aria-sort is not itself re-announced","aria-expanded on an ExpandTrigger, with aria-controls pointing at its row's ExpandedRow id","aria-pressed on a ColumnPinTrigger while its column is pinned to its side","aria-expanded on a GroupRow's button and on a TreeTrigger; neither carries aria-controls because the rows they reveal are siblings, not one element","a keyboard move or a drop announces the new position through the shared LiveAnnouncer, formatted by getMoveLabel",'role="separator" with aria-orientation="vertical", aria-valuenow/valuemin/valuemax and its own aria-label on a resize handle',`role="checkbox" with aria-checked on each row's RowSelectCheckbox, which is what exposes that row's selection as an operable control rather than as state alone`,"aria-rowcount/aria-colcount on the <table> when rendered rows/columns are a window onto a larger set; omitted unless set. Per-row aria-rowindex on <tr> and aria-colindex on cells are consumer-supplied \u2014 Table renders no rows and cannot number them. rowCount without per-row aria-rowindex is incomplete.",`no aria-selected on a <tr>, in either mode: it is a grid state, this family is a role="table", and emitting it would promise a grid keyboard contract Table does not implement. data-state="selected" carries the same fact for styling, and the row's RowSelectCheckbox carries it for assistive tech`],focusManagement:`A sortable TableHeaderCell renders a <button data-skdx-table-sort-trigger> around its label (APG pattern) \u2014 the focusable sort control. A resizable one appends a tabbable role="separator" handle. The <th> itself is never focusable. Neither is a <tr>: selection is reached only through the row's own RowSelectCheckbox, so tables where selectionMode is not 'none' MUST render one in every selectable row, and no row gets a tabindex. In role="table" every focusable element joins the tab sequence, so focusable rows would put the entire body in it; one checkbox per row is a single tab stop with the state as aria-checked. Row clicks stay pointer-only shortcuts. assertTableSelectionContract in @skdx/shared/testing enforces this.`},styling:{cssParts:["table","header","body","footer","row","header-cell","sort-trigger","indicator","resizer","cell","checkbox","caption","expand-trigger","detail-row","detail-cell","empty","empty-cell","column-header-sort-trigger","column-header-filter-input","column-resize-trigger","sort-indicator","select-all-checkbox","row-select-checkbox","expanded-row","column-reorder-trigger","column-pin-trigger","group-row","group-cell","group-trigger","tree-trigger"],dataAttributes:[...r,"data-state","data-sort-direction","data-filterable","data-filtered","data-resizable","data-readonly","data-dragging","data-row-id","data-scope","data-skdx-table-detail-row","data-skdx-table-empty","data-skdx-table-expand-trigger","data-skdx-table-filter-input","data-skdx-table-resizer","data-skdx-table-row-select","data-skdx-table-select-all","data-skdx-table-sort-indicator","data-skdx-table-sort-trigger","data-sort-index","data-column-key","data-reorderable","data-pinnable","data-pinned","data-level","data-skdx-table-reorder-trigger","data-skdx-table-pin-trigger","data-skdx-table-group-row","data-skdx-table-tree-trigger","data-disabled","data-density","data-sticky-header","data-size",{name:"data-skdx-table-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-table-column-width","--skdx-table-pin-offset","--skdx-table-row-level","--skdx-table-sticky-header-height","--skdx-table-cell-padding-inline","--skdx-table-cell-padding-block"]},publicMethods:[{name:"toggleAll",frameworks:["angular","webComponents"],exception:"imperative",frameworksReason:"React, Vue and Svelte have no component instance to hang a method off \u2014 Table's root forwards a DOM ref, not an imperative handle \u2014 so `useTableContext` and the two context injections are those frameworks' binding of this member, declared under `contextApi` below. Angular's component and `<skdx-table>` do have instances, and expose it as a method.",signature:"(allIds: string[]) => void",description:'Selects every id in allIds, or deselects all when every one is already selected. A no-op while selectionMode is "none". Table keeps no row registry, so the caller supplies the id list \u2014 under pagination or virtualization that must be the full list, not the rendered page. An element method on <skdx-table>; reached through the table context in other frameworks (see contextApi).'},{name:"isAllSelected",frameworks:["angular","webComponents"],exception:"imperative",frameworksReason:"React, Vue and Svelte have no component instance to hang a method off \u2014 Table's root forwards a DOM ref, not an imperative handle \u2014 so `useTableContext` and the two context injections are those frameworks' binding of this member, declared under `contextApi` below. Angular's component and `<skdx-table>` do have instances, and expose it as a method.",signature:"(allIds: string[]) => boolean",description:"Whether every id in allIds is selected. False for an empty list, so a select-all checkbox over no rows reads unchecked rather than checked. An element method on <skdx-table>; reached through the table context in the other four frameworks (see contextApi)."},{name:"isSomeSelected",frameworks:["angular","webComponents"],exception:"imperative",frameworksReason:"React, Vue and Svelte have no component instance to hang a method off \u2014 Table's root forwards a DOM ref, not an imperative handle \u2014 so `useTableContext` and the two context injections are those frameworks' binding of this member, declared under `contextApi` below. Angular's component and `<skdx-table>` do have instances, and expose it as a method.",signature:"(allIds: string[]) => boolean",description:"Whether some but not all of allIds are selected \u2014 the indeterminate third state of a select-all checkbox. Mutually exclusive with isAllSelected. An element method on <skdx-table>; reached through the table context in the other four frameworks (see contextApi)."}],contextApi:[{name:"toggleAll",signature:"(allIds: string[]) => void",description:`Selects every id in allIds, or deselects all when every one is already selected. A no-op while selectionMode is "none". The id list must be the full dataset under pagination or virtualization, not the rendered page \u2014 this is what SelectAllCheckbox's scope prop expresses. Also an element method on <skdx-table>.`,accessors:{react:"useTableContext('MyComponent').toggleAll",vue:"inject(TABLE_CONTEXT).toggleAll",svelte:"getContext(TABLE_CONTEXT).toggleAll",angular:"inject(SkdxTableState).toggleAll"}},{name:"isAllSelected",signature:"(allIds: string[]) => boolean",description:"Whether every id in allIds is selected. False for an empty list, so a select-all checkbox over no rows reads unchecked rather than checked. Also an element method on <skdx-table>.",accessors:{react:"useTableContext('MyComponent').isAllSelected",vue:"inject(TABLE_CONTEXT).isAllSelected",svelte:"getContext(TABLE_CONTEXT).isAllSelected",angular:"inject(SkdxTableState).isAllSelected"}},{name:"isSomeSelected",signature:"(allIds: string[]) => boolean",description:"Whether some but not all of allIds are selected \u2014 the indeterminate third state of a select-all checkbox. Mutually exclusive with isAllSelected. Also an element method on <skdx-table>.",accessors:{react:"useTableContext('MyComponent').isSomeSelected",vue:"inject(TABLE_CONTEXT).isSomeSelected",svelte:"getContext(TABLE_CONTEXT).isSomeSelected",angular:"inject(SkdxTableState).isSomeSelected"}}]};export{o as tableContract};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{changeDescription as t,changeDetail as e}from"./change-reason.js";import{ROOT_DATA_ATTRIBUTES as a}from"./styling-hooks.js";var r={name:"Tabs",purpose:"A tabbed interface: one composite root owns the selected value and hands it down to a list of tab triggers and a set of tab panels. Behavior and accessibility only \u2014 layout of the list vs. panels is entirely consumer CSS.",props:[{name:"value",type:"string",required:!1,description:"Selected tab's value, for controlled usage. Pair with the value-change event."},{name:"defaultValue",type:"string",required:!1,description:"Initially selected tab's value, for uncontrolled usage."},{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Layout axis, exposed as data-orientation and used to pick Arrow Left/Right vs Arrow Up/Down for keyboard navigation between triggers."},{name:"activationMode",type:"'automatic' | 'manual'",defaultValue:"'automatic'",required:!1,description:"'automatic' selects a tab on arrow-key focus; 'manual' only on Enter/Space. With 'automatic', expensive panels should set forceMount to avoid remounts during navigation. Selection follows focus only from tablist arrow/Home/End or pointer press, not from restoring focus after a dialog."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables every trigger. OR-ed with each Trigger's own disabled (never overridden)."},{name:"items",type:"ReadonlyArray<{ value: string; label: string; content?: unknown; disabled?: boolean }>",required:!1,description:"The tabs the interface derives from \u2014 one Trigger per entry, one Content panel each. Entry label names its trigger, content fills panel, value is the identity. Hand composition wins when the consumer supplies children."},{name:"renderPanel",type:"(item: TabsItem) => unknown",required:!1,frameworks:["react","svelte","angular","webComponents"],exception:"render-prop",frameworksReason:"Vue's equivalent is a scoped slot, `panel`, receiving the same entry. A function returning renderable nodes is not a Vue prop idiom \u2014 template content reaches a component through its slot mechanism \u2014 and the gate matches member names literally, so a scoped slot cannot be reported as the prop it stands in for.",description:"Renders a derived panel body in place of the entry's `content` string. Panel element (role, ids, hidden handling) stays the library's. Ignored without `items`. **Vue:** `panel` scoped slot receiving entry and index. **Angular:** TemplateRef under this name."},{name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Whether arrow-key navigation wraps from last to first trigger. Forwarded to derived List; hand-composed TabsList sets `loop` on the List itself. On the root because deriving from `items` otherwise hides the prop."}],events:[{name:"value-change",description:t("the selected tab"),detail:e("string")},{name:"value-change-detail",frameworks:["angular"],exception:"event-shape",frameworksReason:"Angular's `valueChange` emits the scalar so `[(value)]` round-trips the value itself; this second output carries the detail object the other four hand to `value-change`.",description:"Fires with valueChange, carrying the previously selected tab and the change reason.",detail:e("string")}],parts:[{name:"List",description:'Container for tab triggers (role="tablist"). Owns roving focus: one trigger in tab order at a time, arrows move between them.',props:[{name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Whether Arrow-key navigation wraps from the last trigger back to the first, and vice versa."}]},{name:"Trigger",description:'One tab button (role="tab"), controlling Content with the same value. Selected on click and on focus in automatic activation mode.',props:[{name:"value",type:"string",required:!0,description:"Identifies this tab. Matched against the root's selected value, and against the Content that this trigger reveals."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Excludes from selection and arrow navigation, keeps out of tab order (tabindex -1). OR-ed with root disabled (never overridden)."}]},{name:"Content",description:"One tab panel (role=tabpanel), labelled by its trigger and shown when its value matches selected tab. Focusable landmark (tabindex 0 by default) for keyboard navigation into panel content.",props:[{name:"value",type:"string",required:!0,description:"Matched against the root's selected value to decide whether this panel is shown."},{name:"forceMount",type:"boolean",defaultValue:"false",required:!1,frameworks:["react","vue","svelte","angular"],exception:"force-mount",frameworksReason:"Web Components never unmounts a closed overlay \u2014 the part hosts the consumer's own adopted light-DOM children and only hides them, so there is no unmount for forceMount to prevent and no exit animation it could rescue.",description:'Keep this panel mounted while inactive ("keepMounted"), hidden via hidden="". For exit animations or to preserve panel state. Not in Web Components \u2014 authored panels are never unmounted.'},{name:"tabIndex",type:"0 | -1",defaultValue:"0",required:!1,description:'Whether the panel itself is a tab stop. APG requires tabindex="0" only when the panel contains no focusable elements. Pass -1 for a panel with focusable content. In Web Components, the native tabindex attribute is the canonical spelling.'}]}],slots:[{name:"default",description:"Root content \u2014 the list and content parts."},{name:"list",description:"Container for the tab triggers (TabsList)."},{name:"trigger",description:"A single tab button, one per TabsTrigger."},{name:"content",description:"A single tab panel, one per TabsContent."}],states:["active","inactive","disabled","focus"],controlledUncontrolled:"Stateless by default (uncontrolled): starts at defaultValue and manages its own state internally. Passing value switches to controlled \u2014 the consumer owns state and must update it from value-change, or the DOM will not change. In Angular the pair is split: `valueChange` emits the scalar for `[(value)]`, `valueChangeDetail` carries the detail.",formBehavior:"Not applicable \u2014 Tabs carries no value that participates in form submission.",validationBehavior:"Not applicable \u2014 Tabs carries no value that participates in validation.",accessibility:{role:"tablist (TabsList) / tab (TabsTrigger) / tabpanel (TabsContent)",keyboard:[{key:"ArrowRight / ArrowLeft",behavior:"Moves focus to the next/previous trigger when orientation is 'horizontal', wrapping if loop is true."},{key:"ArrowDown / ArrowUp",behavior:"Moves focus to the next/previous trigger when orientation is 'vertical', wrapping if loop is true."},{key:"Home / End",behavior:"Moves focus to the first/last enabled trigger."},{key:"Enter / Space",behavior:"Selects the focused trigger. Always active; the only way to select in activationMode='manual'."}],ariaAttributes:["aria-selected on the active TabsTrigger","aria-controls on TabsTrigger to Content (only when panel is in DOM; inactive panels are unmounted by default)","aria-labelledby on TabsContent back to TabsTrigger","aria-orientation on TabsList"],focusManagement:"Roving tabindex in TabsList \u2014 selected trigger (or first enabled if none) is tab stop (tabIndex 0), others -1 via arrows. Disabled triggers always -1. Arrow/Home/End scroll newly focused trigger into view. Each TabsContent is a tab stop (tabIndex 0) for keyboard entry.",namingRequirement:"TabsList should carry an accessible name via aria-label or aria-labelledby."},styling:{cssParts:["list","trigger","content","root"],dataAttributes:[...a,"data-state","data-orientation","data-disabled","data-value",{name:"data-skdx-tabs-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:"setValue",signature:"(value: string, reason?: TabsChangeReason) => void",frameworks:["webComponents"],exception:"imperative",frameworksReason:"Only the custom element publishes it. The other four re-render with a new value 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:"Activates the tab named by value and emits value-change carrying reason."}]};export{r as tabsContract};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ComponentContract } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* A `role="list"` of removable {@link badgeContract} badges with one Tab stop and managed removal focus.
|
|
4
|
+
*/
|
|
5
|
+
export declare const tagGroupContract: ComponentContract;
|
|
6
|
+
/** Decision record: TagGroup does not adopt a `disabledKeys` set. */
|
|
7
|
+
export declare const TAG_GROUP_DISABLED_KEYS_DECISION = "Not adopted: a key set would require the group to know each badge's identity, which the contract deliberately refuses, and per-badge `disabled` already expresses the same subset in a composition model.";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var a={name:"TagGroup",purpose:'A keyboard-navigable list of Badges. Renders role="list" and gives the whole group a single Tab stop, with the arrow keys plus Home/End moving between badges (roving tabindex). On removal it moves focus to the following badge, or the preceding one when the removed badge was last, or the group itself when it was the only one \u2014 never the document body. That holds for every route to a removal, not only the ones a Badge initiates: a badge unmounted by a clear-all button, a filter reset or a list replaced from the server hands focus back into the group the same way. It holds no entry data: each Badge owns its own removal.',props:[{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:'Layout axis for arrow-key navigation between badges, exposed as data-orientation. Mirrored under dir="rtl".'},{name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Whether arrow-key navigation wraps from the last badge back to the first, and vice versa."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables every Badge in the group: none can be removed, each mirrors data-disabled, and arrow-key navigation skips them all."},{name:"tags",type:"ReadonlyArray<{ value: string; label: string; disabled?: boolean }>",required:!1,description:"Optional entries the group renders a Badge from \u2014 one per entry, keyed by value so removed elements hold their place in the tab order. Omitting this prop renders the provided children instead, so recipes and hand-composed anatomy do not collide. The group holds no entry data between renders; remove reports what left rather than mutating the array."},{name:"removable",type:"boolean",defaultValue:"false",required:!1,frameworks:["webComponents"],exception:"wc-internals",frameworksReason:"React, Vue, Svelte and Angular derive this from the onRemove callback presence. Web Components cannot inspect event listeners, so it must be explicit.",description:"Whether each derived Badge gets a delete button. Web Components only, because event listeners are not inspectable there. Only affects badges from the tags prop; hand-composed badges control their own delete."},{name:"density",type:"'comfortable' | 'compact' | (string & {})",required:!1,description:"Vertical rhythm rung, written to data-density on the root; the data-density attribute may be set directly instead."}],events:[{name:"remove",description:"Fired when a Badge is removed without veto. Carries { label, index } \u2014 the removed badge's text and position \u2014 so group-level undo, counters, or announcements use one listener instead of N per-badge callbacks. Fires when focus moves to the neighbour.",detail:"{ label: string; index: number }"}],parts:[{name:"Label",description:"A visible heading for the group. Generates an id and points the list's aria-labelledby at it so the group name stays in sync with the visible text. Rendering it switches the root to wrap [Label, List]."},{name:"List",description:'The <ul role="list"> that holds the badges in labelled compositions. It exists so a heading is not announced as a list item. Rendering a List moves role="list" and the accessible name off the root to it. Optional \u2014 groups without a visible heading keep role="list" on the root.'},{name:"Empty",description:"Content rendered while the group holds no badges, so empty filters say so rather than collapsing. Appears and disappears with badge count, not a separate flag."}],slots:[{name:"default",description:"The group's Badge children, or its Label / List / Empty parts."},{name:"label",description:"The Label part's content \u2014 the group's visible heading."},{name:"list",description:"The List part's content \u2014 the group's Badge children."},{name:"empty",description:"The Empty part's content \u2014 shown only while the group has no badges."}],appearance:[{attribute:"data-density",values:["comfortable","compact"],stylesheet:"tag-group.css"}],states:["default","disabled","empty"],controlledUncontrolled:"Stateless \u2014 the group tracks only which badge holds the Tab stop. The consumer owns the list of entries.",formBehavior:"Not applicable \u2014 TagGroup participates in no form. For a badge list that submits, use TagsInput.",validationBehavior:"Not applicable.",accessibility:{role:"list",keyboard:[{key:"ArrowRight / ArrowDown",behavior:"Moves focus to the next badge, wrapping when loop is set."},{key:"ArrowLeft / ArrowUp",behavior:"Moves focus to the previous badge, wrapping when loop is set."},{key:"Home",behavior:"Moves focus to the first badge."},{key:"End",behavior:"Moves focus to the last badge."},{key:"Tab",behavior:"One tab stop per group: only one badge is in the tab order at a time."}],ariaAttributes:['aria-label or aria-labelledby names the list. role="list" has no implicit name and derives none from contents.'],focusManagement:'Roving tabindex over badges: exactly one carries tabindex="0", the rest "-1". Disabled badges are skipped. The root is tabindex="-1" \u2014 not a tab stop but programmatically focusable so the last removal has somewhere to land rather than the document body. When a badge is removed, focus moves to the next badge, or the previous if it was last, or the root if it was only. This holds for removals from any source \u2014 never pulling focus if the user is elsewhere.',namingRequirement:'The element with role="list" must have an accessible name via aria-label or aria-labelledby. Author-supplied: role="list" has no implicit name. Rendering a Label part generates the id and aria-labelledby for you.'},styling:{cssParts:["root","label","list","empty"],dataAttributes:[...e,"data-orientation","data-disabled","data-density","data-skdx-tag-group","data-skdx-tag",{name:"data-skdx-tag-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:[]},publicMethods:[]},o="Not adopted: a key set would require the group to know each badge's identity, which the contract deliberately refuses, and per-badge `disabled` already expresses the same subset in a composition model.";export{o as TAG_GROUP_DISABLED_KEYS_DECISION,a as tagGroupContract};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ComponentContract } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The TagsInput contract. Every framework package's TagsInput implements
|
|
4
|
+
* exactly this: a controllable string[] of tags, committed via delimiter-driven
|
|
5
|
+
* text field. Not Select: TagsInput has open vocabulary (user-typed); Select
|
|
6
|
+
* has closed vocabulary (pre-defined options).
|
|
7
|
+
*/
|
|
8
|
+
export declare const tagsInputContract: ComponentContract;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{changeDetail as e}from"./change-reason.js";import{constraintValidationMethods as t,setCustomValidityMethod as a}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as i}from"./styling-hooks.js";var o={name:"TagsInput",purpose:"A controllable string[] of tags. Delimiter or Enter commits draft; Backspace on empty removes last tag. Pasted text splits and commits in batch. Validator callback gates additions.",props:[{name:"value",type:"string[]",required:!1,description:"Current tags, for controlled usage."},{name:"defaultValue",type:"string[]",defaultValue:"[]",required:!1,description:"Initial tags, for uncontrolled usage."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables adding/removing tags."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Marks the field as invalid."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:"Makes the text field read-only."},{name:"max",type:"number",required:!1,description:"Maximum number of tags; further additions are no-ops once reached."},{name:"name",type:"string",required:!1,description:"Form field name. Every tag is submitted as its own entry under it; without it the field submits nothing."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Marks the field required. valueMissing while there are no tags."},{name:"form",type:"string",required:!1,description:"Id of the <form> this field submits to when it is not nested inside one, exactly like the native form attribute."},{name:"delimiter",type:"string | string[]",defaultValue:"[',', '\\n']",required:!1,description:"Characters that commit draft or split pastes. Array default: paste splits on all entries, typed commit on single-char only (vs KeyboardEvent.key). RegExp not accepted. **Web Components**: array is property-only (attribute is string)."},{name:"blurBehavior",type:"'keep' | 'clear' | 'commit'",defaultValue:"'keep'",required:!1,description:"On blur: keep (leave draft), clear (discard), or commit (as tag via refusal rules)."},{name:"editable",type:"boolean",defaultValue:"false",required:!1,description:"Whether a committed tag can be edited in place. Enter opens ItemInput, Enter commits, Escape cancels. Default false."},{name:"addOnPaste",type:"boolean",defaultValue:"true",required:!1,description:"Commit pasted text as tags (split on delimiter) instead of dropping it into the draft field."},{name:"validator",type:"(tag: string, tags: string[]) => boolean",required:!1,description:"Decides whether a candidate may be added (given trimmed tag and tags earlier in the same paste). Return false=reject, true=accept over built-in duplicate, undefined=built-in rules. Must be pure. **Property-only**: function has no attribute form."},{name:"allowDuplicates",type:"boolean",defaultValue:"false",required:!1,description:"Whether same tag may appear more than once (exact match on trimmed). validator overrides."},{name:"inputValue",type:"string",required:!1,description:"Current draft text in the text field, for controlled usage."},{name:"defaultInputValue",type:"string",defaultValue:"''",required:!1,description:"Initial draft text, for uncontrolled usage."},{name:"placeholder",type:"string",required:!1,description:"Placeholder on draft field. Not a label; use inputLabel for accessible name."},{name:"clearable",type:"boolean",defaultValue:"false",required:!1,description:"Whether to render Clear button. Default false. Disabled while root is disabled or readOnly."},{name:"inputLabel",type:"string",defaultValue:"'Add a tag'",required:!1,description:'Accessible name for draft input (default: "Add a tag"). No visible label; placeholder is not a name.'},{name:"size",type:"'md' | '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",detail:e("string[]"),description:"Fires with the new tag list whenever it changes (add or remove)."},{name:"input-value-change",description:"Fires with the new draft text whenever it changes \u2014 typing, or the reset to empty after a tag is committed.",detail:"string"},{name:"value-invalid",description:"Fires once for every candidate tag the field refuses, carrying the trimmed candidate and which of the four contracted rules refused it. Without it a refused tag simply vanished: the field looked broken to the user, the application could not tell a rejected paste from an accepted one, and nothing could be announced. Fired once per candidate rather than once per commit, so a pasted batch reports every entry it dropped; a batch that refuses nothing fires nothing. The reasons are exactly the four refusal sites, in the order validationBehavior fixes them in: empty (blank after trimming), max (the list is already full), validator (the consumer predicate returned false) and duplicate (the built-in rule, which allowDuplicates switches off and a validator returning true overrides).",detail:"{ tag: string; reason: 'empty' | 'max' | 'validator' | 'duplicate' }"}],parts:[{name:"Input",description:"The draft field new tags are typed into, sitting after the committed items. Commits on the delimiter or Enter; Backspace while empty reaches back to the last item.",props:[{name:"list",type:"string",required:!1,frameworks:["angular","webComponents"],exception:"attribute-passthrough",frameworksReason:"React, Vue and Svelte forward `list` to the native <input> through attribute passthrough. Angular and the custom element render the <input> inside their own element, so they declare it to carry it across.",description:"Id of a <datalist> backing the draft field with browser-native suggestions, forwarded to the native input's list attribute."}]},{name:"Item",description:"One committed tag, identified **positionally** (not by value). Allows duplicate text and unambiguous removal.",props:[{name:"index",type:"number",required:!0,description:"This tag's 0-based position in `value`. Required in every package. It is what the roving Tab stop compares against and what the delete button removes, so it must match the index the tag was rendered from \u2014 deriving it from the tag's text would break the moment two tags share text."}]},{name:"ItemDelete",description:'Button to remove one tag. Not a Tab stop (tabindex="-1"): Delete/Backspace on focused tag is keyboard route.',props:[{name:"index",type:"number",required:!0,description:"The position of the tag this button removes \u2014 the same positional identity `Item` carries, and required for the same reason. `removeTag` takes an index."},{name:"getLabel",type:"(tag: string) => string",required:!1,frameworks:["angular"],exception:"attribute-passthrough",frameworksReason:"Angular binds aria-label in template where host attribute cannot beat it. React/Vue/Svelte spread attributes. Web Components: see label below.",description:"Function to build delete button's accessible name from tag (e.g., 'Remove Ruby'). Must name the tag."},{name:"label",type:"string",required:!1,frameworks:["webComponents"],exception:"attribute-passthrough",frameworksReason:"Button is in shadow root; aria-label on host does not reach it. Whole string, per tag.",description:'Accessible name for delete <button> (full string, per tag, e.g., "Remove Ruby").'}]},{name:"ItemInput",lightDom:!0,description:"Text field for editing a tag. Renders nothing unless editable and tag is open. Seeded with tag text, selected on open. Enter commits (refusal rules apply), Escape cancels, blur abandons. Focus returns to tag before editor unmounts.",props:[{name:"index",type:"number",required:!0,description:"The position of the tag this editor edits \u2014 the same positional identity `Item` and `ItemDelete` carry, and required for the same reason: it is what decides whether this editor is the open one, and what the commit writes back to."},{name:"label",type:"string",required:!1,frameworks:["angular","webComponents"],exception:"attribute-passthrough",frameworksReason:"React, Vue and Svelte let an aria-label written on the editor through by attribute passthrough, so it beats the default without a declared member. Angular binds aria-label in its own template, where a host attribute cannot beat it, and Web Components renders the <input> itself, so both have to take the override as a declared property.",description:'Accessible name for the editing input, replacing the default "Edit <tag>" (full string, per tag).'}]},{name:"Clear",description:'Button to empty whole list in one press (vs. twenty presses). Default aria-label "Clear tags", overridable per port. Disabled while root disabled/readOnly. Carries data-empty while nothing to clear. Focus goes to draft field after clear.'}],slots:[{name:"default",description:"TagsInputItem children plus a TagsInputInput, and optionally a TagsInputClear. Under editable, each TagsInputItem also holds a TagsInputItemInput."},{name:"delete",description:"A TagsInputItem's delete button."}],appearance:[{attribute:"data-size",values:["md","sm","lg"],stylesheet:"tags-input.css"}],states:["default","disabled","invalid","readonly"],controlledUncontrolled:"Supports both: value + onValueChange (controlled) or defaultValue (uncontrolled). The draft text is a second, independent controllable value: inputValue + input-value-change, or defaultInputValue.",formBehavior:'Form-associated: with name, each tag submits as own entry (formData.getAll(name) returns tags). Empty field: submits nothing unless required, where one empty-valued control remains. Four frameworks use visually-hidden native inputs \u2014 never type="hidden" and never readonly. Web Components uses ElementInternals.',validationBehavior:"invalid is presentational; required validators via checkValidity()/reportValidity(). Refusal order (fixed, API): **blank**, **max**, `validator`, **duplicate** \u2014 `allowDuplicates` switches off duplicate; `validator` returning true overrides. Every refusal fires value-invalid (trimmed candidate + reason). Editing uses list without that tag.",accessibility:{role:"generic (root and each tag); the text field is a native <input>",keyboard:[{key:"Enter or a delimiter",behavior:"In draft field: commits as new tag. Single-char delimiter commits; multi-char only splits pastes."},{key:"Backspace",behavior:"On an empty draft, removes the last committed tag."},{key:"ArrowLeft/ArrowRight",behavior:'On focused tag: moves roving Tab stop to previous/next tag; past last tag moves to draft field. Mirrored under dir="rtl".'},{key:"Delete or Backspace",behavior:"On focused tag: removes it (keyboard counterpart of delete button)."},{key:"Enter",behavior:"On focused tag (if editable): opens ItemInput with text selected. Does nothing if root disabled/readOnly."},{key:"Enter (editing)",behavior:"Commits edited text via refusal rules (blank/duplicate refused, reported via value-invalid)."},{key:"Escape (editing)",behavior:"Abandons edit, leaves tag as is. Both Enter/Escape return focus to tag before editor unmounts."}],ariaAttributes:["aria-invalid/aria-readonly on text field",'aria-label on draft field (default: inputLabel "Add a tag")','aria-label on ItemInput (default: "Edit <tag>")','aria-label on Clear button (default: "Clear tags")'],focusManagement:'Draft text on root (inputValue controllable), cleared after commit. Tags navigated by roving DOM focus: one tab stop (tabindex="0"), every delete button is tabindex="-1". Delete hands focus to next tag, else previous, else draft field. Editing: focus moves into ItemInput, returns to tag before editor unmounts. Clear: focus to draft field.'},styling:{cssParts:["tags-input","item","delete","input","item-delete","item-input","clear"],dataAttributes:[...i,"data-disabled","data-invalid","data-readonly","data-editing","data-empty","data-size","data-skdx-tags-input","data-skdx-tags-input-item","data-skdx-tags-input-delete","data-skdx-tags-input-field","data-skdx-tags-input-clear","data-skdx-tags-input-item-input",{name:"data-skdx-tags-input-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:[...t,a]};export{o as tagsInputContract};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{changeDetail as e}from"./change-reason.js";import{constraintValidationMethods as t,setCustomValidityMethod as a}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as i}from"./styling-hooks.js";var s={name:"TextField",purpose:"A single-line text input with root-owned value and state, plus input and optional slot/clear-button parts. Behavior only \u2014 no visual style.",props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the field and the wrapped input."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Marks the field invalid; sets data-invalid on the root and aria-invalid/data-invalid on the input."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Marks the wrapped input required for native form validation."},{name:"value",type:"string",defaultValue:"''",required:!1,description:"Current value. Root owns this state internally, so binding it (via each framework's native two-way-binding mechanism) makes usage controlled; leaving it unbound is uncontrolled."},{name:"defaultValue",type:"string",defaultValue:"''",required:!1,description:"Initial value for uncontrolled usage, and \u2014 in every package \u2014 the single value a form reset restores, the same role a native input's defaultValue plays. Ignored while value is bound."},{name:"name",type:"string",required:!1,description:"Form field name. Without it the field submits nothing, exactly like a nameless native input."},{name:"form",type:"string",required:!1,description:"Id of the <form> this field submits with, for fields outside the form's DOM tree. React/Vue/Svelte/Angular put it on the <input>; Web Components uses ElementInternals.form."},{name:"clearable",type:"boolean",defaultValue:"false",required:!1,description:"Renders a button that clears the value."},{name:"clearLabel",type:"string",defaultValue:"'Clear'",required:!1,description:"Accessible name for the derived clear button."},{name:"leading",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot (not a prop) \u2014 Vue idiom, Web Components attribute limit. Both slot spellings are under `slots`.",description:"Content rendered before the input, typically an icon or prefix."},{name:"trailing",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot (not a prop) \u2014 Vue idiom, Web Components attribute limit. Both slot spellings are under `slots`.",description:"Content rendered after the input, typically an icon or unit."},{name:"placeholder",type:"string",required:!1,description:"Placeholder text for the derived input. Never a substitute for a label \u2014 the naming requirement below still applies."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:"Makes the derived input read-only while keeping it focusable and submittable."},{name:"type",type:"string",defaultValue:"'text'",required:!1,description:"Native input type for the derived input, such as 'email', 'search' or 'url'; ignored when children are given."},{name:"size",type:"'md' | '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."},{name:"variant",type:"'filled' | 'ghost' | (string & {})",required:!1,description:"Fill style rung, written to data-variant on the root; the data-variant attribute may be set directly instead."}],events:[{name:"value-change",description:"Fired with the new value whenever it changes, controlled or not (typing, or the clear button).",detail:e("string")}],parts:[{name:"Input",lightDom:!0,description:"The native single-line <input>, driven by the root's value/disabled/invalid/required state. Value/defaultValue are root-owned. Native attributes (readonly, pattern, minlength, maxlength, autocomplete, inputmode, aria-describedby) reach the <input>.",props:[{name:"type",type:"string",defaultValue:"'text'",required:!1,description:"The native <input> type, such as 'email', 'search' or 'url'."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:"Reflected as the native readonly attribute on the <input>. Not the same as disabled: a read-only field stays focusable, selectable, and submits its value \u2014 only editing is blocked."},{name:"size",type:"'md' | 'sm' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the input; the data-size attribute may be set directly instead."},{name:"variant",type:"'filled' | 'ghost' | (string & {})",required:!1,description:"Fill style rung, written to data-variant on the input; the data-variant attribute may be set directly instead."}]},{name:"Slot",description:"A decorative container for an icon or adornment beside the input. Not focusable and not part of the tab order \u2014 put interactive adornments in their own button instead.",props:[{name:"side",type:"'start' | 'end'",defaultValue:"'start'",required:!1,description:"Which end of the field this slot sits at, exposed as data-side."}]},{name:"ClearButton",description:"A button that resets the root's value to empty. Rendered only while the field has a value, unless forceMount says otherwise.",props:[{name:"label",type:"string",defaultValue:"'Clear'",required:!1,description:"Accessible name for the clear button (no text content). Must be translated."},{name:"forceMount",type:"boolean",defaultValue:"false",required:!1,description:"Keep the button mounted while the field is empty instead of unmounting it, so an animation library can play an exit transition."}]}],slots:[{name:"default",description:"The root's children: a TextFieldInput plus optional TextFieldSlot/TextFieldClearButton parts."},{name:"leading",description:"Content rendered before the input, typically an icon or prefix."},{name:"trailing",description:"Content rendered after the input, typically an icon or unit."}],appearance:[{attribute:"data-size",values:["md","sm","lg"],stylesheet:"text-field.css"},{attribute:"data-variant",values:["filled","ghost"],stylesheet:"text-field.css"}],states:["default","hover","focus","disabled","invalid","readonly"],controlledUncontrolled:"Root owns value internally; binding it (controlled) syncs an external source; leaving it unbound (uncontrolled) works via root's own state.",formBehavior:"Form-associated: with a name, submits its value and mirrors the input's ValidityState (including required). checkValidity()/reportValidity() behave as on a native <input>. A form reset restores `defaultValue` (empty string fallback) in all packages.",validationBehavior:"invalid is a purely presentational flag (aria-invalid/data-invalid) the consumer sets from its own validation result. required marks the input for native constraint validation.",accessibility:{role:"textbox (native <input> element, implicit)",keyboard:[{key:"Standard text-editing keys",behavior:"Arrow keys, selection, and editing behave exactly like a native <input> \u2014 no custom key handling."}],ariaAttributes:["aria-invalid on the input when invalid"],focusManagement:"Focus lands on the native input; the root is not itself focusable.",namingRequirement:"Pair with a Label (pointing at input's id) \u2014 don't rely on placeholder alone. For description or error text, wrap in Field. TextField generates no ids and merges nothing into aria-describedby; Field does that wiring."},styling:{cssParts:["root","input","slot","clear-button"],dataAttributes:[...i,"data-disabled","data-invalid","data-side","data-size","data-variant",{name:"data-skdx-text-field-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:[...t,a],contextApi:[{name:"validity",signature:"(): ValidityState | null",description:"The wrapped input's own ValidityState, live. null before the input mounts.",accessors:{react:"ref.current.validity \u2014 a getter on the TextFieldHandle",vue:"templateRef.value.validity \u2014 defineExpose, unwrapped",svelte:"instance.validity() \u2014 export function, reached with bind:this",angular:"component.validity \u2014 a getter on the component instance",webComponents:"el.validity \u2014 a getter on <skdx-text-field>"}},{name:"validationMessage",signature:"(): string",description:"The message the browser would show for the current validity (empty when valid). Available to render in your own error slot.",accessors:{react:"ref.current.validationMessage \u2014 a getter on the TextFieldHandle",vue:"templateRef.value.validationMessage \u2014 defineExpose, unwrapped",svelte:"instance.validationMessage() \u2014 export function, reached with bind:this",angular:"component.validationMessage \u2014 a getter on the component instance",webComponents:"el.validationMessage \u2014 a getter on <skdx-text-field>"}}],frameworkExtensions:[{framework:"webComponents",name:"requiredMessage",type:"string",description:"Replaces the English required message (attribute `required-message`). Web Components only \u2014 the other four packages render an <input> the consumer can override with setCustomValidity()."}]};export{s as textFieldContract};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var a={name:"Text",purpose:"A typographic primitive: one element with .skdx-text class, tag chosen by the consumer. Appearance comes from three props\u2014tone, variant and size\u2014each written to a matching data-tone/data-variant/data-size attribute the skin reads (or set directly). The variant axis holds tabular figures, so numbers line up without every component stylesheet inlining font-variant-numeric.",props:[{name:"as",type:"PolymorphicTag",defaultValue:"'span'",required:!1,frameworks:["react","vue","svelte","webComponents"],exception:"as-directive",frameworksReason:"Angular has no `as` input. Its element-choice mechanism is an attribute directive the consumer puts on their own element \u2014 `<p skdx-ng-text>` \u2014 which is the same capability spelled the way Angular's template compiler already reads, and eleven such directives predate this one.",description:"Element name from the closed allowlist in POLYMORPHIC_TAGS. The tag is the semantics\u2014<p> for paragraph, <code> for code span, <strong> for importance\u2014and this component supplies none. A tag name only, never a component: Lit needs a static-html literal per tag and cannot build one at runtime. React additionally reaches this through asChild, which wins when both are set."},{name:"tone",type:"'default' | 'muted' | 'accent' | 'danger' | 'success' | 'warning' | 'info' | (string & {})",required:!1,description:"Colour rung, written to data-tone on the root; the data-tone attribute may be set directly instead."},{name:"variant",type:"'body' | 'numeric' | 'mono' | (string & {})",required:!1,description:"Font-feature rung, written to data-variant on the root; the data-variant attribute may be set directly instead."},{name:"size",type:"'sm' | 'md' | '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:[],slots:[{name:"default",description:"The text content."}],appearance:[{attribute:"data-tone",values:["default","muted","accent","danger","success","warning","info"],stylesheet:"text.css"},{attribute:"data-variant",values:["body","numeric","mono"],stylesheet:"text.css"},{attribute:"data-size",values:["sm","md","lg"],stylesheet:"text.css"}],states:["default"],controlledUncontrolled:"Stateless \u2014 Text holds no internal state.",formBehavior:"Not applicable \u2014 Text participates in no form.",validationBehavior:"Not applicable \u2014 Text carries no value and participates in no validation.",accessibility:{role:"whatever the chosen tag implies \u2014 generic for the default <span>, none of its own",keyboard:[],ariaAttributes:[],focusManagement:"Not focusable itself; not part of the tab order."},styling:{cssParts:["text"],dataAttributes:[...e,"data-tone","data-variant","data-size"],cssCustomProperties:[]},publicMethods:[]};export{a as textContract};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{changeDetail as e}from"./change-reason.js";import{constraintValidationMethods as t,setCustomValidityMethod as a}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as r}from"./styling-hooks.js";var o={name:"Textarea",purpose:"A wrapper around a native <textarea>. With autoResize, grows to fit content instead of scrolling (optionally capped to maxRows). Native attributes (name, required, maxlength, etc.) are forwarded to the control.",lightDom:!0,props:[{name:"value",type:"string",required:!1,description:"Current value, for controlled usage. Bind it with the framework's native two-way mechanism; pair with the value-change event."},{name:"defaultValue",type:"string",required:!1,description:"Initial value, for uncontrolled usage \u2014 seeds the internally-tracked value."},{name:"autoResize",type:"boolean",defaultValue:"false",required:!1,description:"Grow the textarea to fit its content instead of showing a scrollbar."},{name:"maxRows",type:"number",required:!1,description:"Caps auto-resize growth to this many rows, based on computed line-height."},{name:"minRows",type:"number",defaultValue:"2",required:!1,description:"The control's opening size, and the floor auto-resize will not shrink below. Rendered as the native rows attribute when autoResize is off, and applied as a minimum on the measured height when it is on \u2014 so the same number means the same thing either way. Default 2, which is the platform's own rows default, so an unmarked textarea is unchanged. Where minRows and maxRows disagree, maxRows wins: an explicit cap is a stronger statement than the default floor."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Marks the textarea as invalid, exposed as aria-invalid/data-invalid."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the textarea: it leaves the tab order, submits nothing, and is announced as unavailable."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:"Makes the textarea read-only, exposed as the native readonly attribute plus aria-readonly/data-readonly."},{name:"name",type:"string",required:!1,description:"Form field name. Without it the textarea submits nothing, exactly like a nameless native <textarea>."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Marks the textarea required for native constraint validation (valueMissing when empty)."},{name:"form",type:"string",required:!1,description:`Id of the <form> this control submits with, so a textarea rendered outside that form's subtree still participates in it \u2014 a native <textarea form="\u2026">. React, Vue, Svelte and Angular put it on the <textarea> they render; <skdx-textarea> is form-associated through ElementInternals, which resolves the same attribute on the host, so the attribute is declared there and ElementInternals.form does the rest.`},{name:"maxLength",type:"number",required:!1,description:"Native maxlength \u2014 the longest value the control accepts, reported as tooLong. Declared because the contract had no length constraint at all, so the attribute reached the control only in the three packages that forward native attributes onto the element they render."},{name:"minLength",type:"number",required:!1,description:"Native minlength \u2014 the shortest value constraint validation will accept, reported as tooShort. It fires only after a user edit, so it is not a stand-in for required."},{name:"inputMode",type:"string",required:!1,frameworks:["svelte","angular","webComponents"],exception:"attribute-passthrough",frameworksReason:"React and Vue pass inputmode through as a native attribute of the rendered textarea rather than a declared prop.",description:"Virtual keyboard hint forwarded as the native inputmode attribute."},{name:"resize",type:"'none' | 'block' | 'auto' | (string & {})",required:!1,description:"Resize handle rung, written to data-resize on the root; the data-resize attribute may be set directly instead."}],events:[{name:"value-change",description:"Fired with the new value whenever it changes, controlled or not.",frameworks:["vue","angular","webComponents","svelte"],exception:"event-shape",frameworksReason:"React has no distinct value-change member to document: it realises the concept as the native onChange passthrough already covered by the element props table, not a second callback prop.",detail:e("string")}],slots:[],appearance:[{attribute:"data-resize",values:["none","block","auto"],stylesheet:"textarea.css"}],states:["default","invalid","readonly","disabled"],controlledUncontrolled:"Controlled via value + value-change, or uncontrolled via defaultValue. The underlying element is a native <textarea>, so the platform still handles editing \u2014 value/defaultValue only decide who owns the value.",formBehavior:"Form-associated: with a name, submits its text and mirrors the inner <textarea>'s own ValidityState, including required. A form reset restores `defaultValue` (falling back to the empty string) in all five packages \u2014 never the text the control happened to be mounted or last bound with. `form` associates the control with a <form> it is not nested inside, by id.",validationBehavior:"invalid is a purely presentational flag (aria-invalid/data-invalid) \u2014 pair with native constraint validation (required, minlength, maxlength) or a Form component. `invalid` on its own tells a screen-reader user *that* the field is wrong and never *why*, so a textarea marked invalid must also be pointed at the text that explains it. The association is `aria-describedby`, not `aria-errormessage`: see the Field contract's `accessibility.ariaAttributes`, which records the system-wide ruling against `aria-errormessage` and the three reasons behind it. Wrap the Textarea in a Field and that wiring is automatic \u2014 the Field emits an `error` part with a stable id, discovers the control it wraps, and merges that id into the control's `aria-describedby`. Outside a Field it is the consumer's obligation, and the contract states it here so it is not silently no one's.",accessibility:{role:"generic (native <textarea>)",keyboard:[],ariaAttributes:["aria-invalid reflects invalid","aria-readonly reflects readOnly","aria-describedby carries the error text whenever invalid is set \u2014 merged in by a wrapping Field, or set by the consumer outside one. Deliberately not aria-errormessage; the Field contract records why that attribute is unused system-wide"],focusManagement:"Native textarea focus behavior.",namingRequirement:"A <textarea> has role textbox and permits no other role, so its accessible name can only come from an associated <label>, an aria-label, or an aria-labelledby \u2014 a placeholder is not a name, it disappears as soon as the field has content."},styling:{cssParts:["textarea"],dataAttributes:[...r,"data-invalid","data-readonly","data-disabled","data-resize"],cssCustomProperties:[]},publicMethods:[...t,a]};export{o as textareaContract};
|