@skdx/docs-kit 0.38.0 → 0.40.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.
Files changed (147) hide show
  1. package/dist/data/angular-inputs.json +1 -1
  2. package/dist/data/api-manifest.json +1 -1
  3. package/dist/shared/contracts/accordion.js +1 -1
  4. package/dist/shared/contracts/alert.js +1 -1
  5. package/dist/shared/contracts/autocomplete.d.ts +1 -1
  6. package/dist/shared/contracts/autocomplete.js +1 -1
  7. package/dist/shared/contracts/avatar.js +1 -1
  8. package/dist/shared/contracts/breadcrumb.js +1 -1
  9. package/dist/shared/contracts/button.js +1 -1
  10. package/dist/shared/contracts/calendar.js +1 -1
  11. package/dist/shared/contracts/card.js +1 -1
  12. package/dist/shared/contracts/carousel.js +1 -1
  13. package/dist/shared/contracts/checkbox-card.js +1 -1
  14. package/dist/shared/contracts/checkbox-group.js +1 -1
  15. package/dist/shared/contracts/collapsible.js +1 -1
  16. package/dist/shared/contracts/combobox.js +1 -1
  17. package/dist/shared/contracts/command.js +1 -1
  18. package/dist/shared/contracts/dashboard-layout.js +1 -1
  19. package/dist/shared/contracts/date-picker.js +1 -1
  20. package/dist/shared/contracts/dialog.d.ts +1 -1
  21. package/dist/shared/contracts/dialog.js +1 -1
  22. package/dist/shared/contracts/drawer.d.ts +1 -1
  23. package/dist/shared/contracts/drawer.js +1 -1
  24. package/dist/shared/contracts/field.js +1 -1
  25. package/dist/shared/contracts/file-upload.js +1 -1
  26. package/dist/shared/contracts/floating-panel.js +1 -1
  27. package/dist/shared/contracts/form.js +1 -1
  28. package/dist/shared/contracts/image.js +1 -1
  29. package/dist/shared/contracts/listbox.js +1 -1
  30. package/dist/shared/contracts/loading-overlay.js +1 -1
  31. package/dist/shared/contracts/mentions.js +1 -1
  32. package/dist/shared/contracts/menu.js +1 -1
  33. package/dist/shared/contracts/menubar.js +1 -1
  34. package/dist/shared/contracts/navigation-menu.js +1 -1
  35. package/dist/shared/contracts/page-container.js +1 -1
  36. package/dist/shared/contracts/pagination.js +1 -1
  37. package/dist/shared/contracts/password-input.js +1 -1
  38. package/dist/shared/contracts/popover.js +1 -1
  39. package/dist/shared/contracts/progress.js +1 -1
  40. package/dist/shared/contracts/qr-code.js +1 -1
  41. package/dist/shared/contracts/radio-card.js +1 -1
  42. package/dist/shared/contracts/radio-group.js +1 -1
  43. package/dist/shared/contracts/rating.js +1 -1
  44. package/dist/shared/contracts/resizable.js +1 -1
  45. package/dist/shared/contracts/scroll-area.js +1 -1
  46. package/dist/shared/contracts/select.js +1 -1
  47. package/dist/shared/contracts/sign-up-page.js +1 -1
  48. package/dist/shared/contracts/slider.js +1 -1
  49. package/dist/shared/contracts/speed-dial.js +1 -1
  50. package/dist/shared/contracts/split-button.js +1 -1
  51. package/dist/shared/contracts/stepper.js +1 -1
  52. package/dist/shared/contracts/switch.js +1 -1
  53. package/dist/shared/contracts/table.js +3 -1
  54. package/dist/shared/contracts/tabs.js +1 -1
  55. package/dist/shared/contracts/tag-group.js +1 -1
  56. package/dist/shared/contracts/tags-input.js +1 -1
  57. package/dist/shared/contracts/text-field.js +1 -1
  58. package/dist/shared/contracts/textarea.js +1 -1
  59. package/dist/shared/contracts/timeline.js +1 -1
  60. package/dist/shared/contracts/toast.js +9 -1
  61. package/dist/shared/contracts/toolbar.js +1 -1
  62. package/dist/shared/contracts/tour.js +1 -1
  63. package/dist/shared/contracts/transfer.js +1 -1
  64. package/dist/shared/contracts/tree-select.js +1 -1
  65. package/dist/shared/contracts/tree.js +1 -1
  66. package/dist/shared/contracts/types.d.ts +2 -0
  67. package/dist/shared/contracts/verification-page.js +1 -1
  68. package/dist/shared/contracts/workspace-switcher.js +1 -1
  69. package/dist/shared/core/field-core.d.ts +2 -0
  70. package/dist/shared/core/field-core.js +1 -1
  71. package/dist/shared/core/focus-targets.js +1 -1
  72. package/dist/shared/core/label-activation.js +1 -1
  73. package/dist/skins-src/_foundation-fallback.css +2 -1
  74. package/dist/skins-src/components/_actuator.css +1 -1
  75. package/dist/skins-src/components/_card-control.css +1 -1
  76. package/dist/skins-src/components/_collection.css +2 -2
  77. package/dist/skins-src/components/_overlay.css +1 -1
  78. package/dist/skins-src/components/_trigger.css +1 -1
  79. package/dist/skins-src/components/accordion.css +1 -1
  80. package/dist/skins-src/components/alert.css +3 -2
  81. package/dist/skins-src/components/autocomplete.css +1 -1
  82. package/dist/skins-src/components/avatar.css +1 -1
  83. package/dist/skins-src/components/badge.css +1 -1
  84. package/dist/skins-src/components/button.css +1 -1
  85. package/dist/skins-src/components/calendar.css +8 -6
  86. package/dist/skins-src/components/card.css +1 -1
  87. package/dist/skins-src/components/carousel.css +11 -1
  88. package/dist/skins-src/components/chat-composer.css +1 -1
  89. package/dist/skins-src/components/chat-message.css +1 -1
  90. package/dist/skins-src/components/checkbox-card.css +2 -2
  91. package/dist/skins-src/components/checkbox.css +1 -1
  92. package/dist/skins-src/components/clipboard.css +2 -2
  93. package/dist/skins-src/components/color-picker.css +4 -4
  94. package/dist/skins-src/components/combobox.css +2 -2
  95. package/dist/skins-src/components/command.css +1 -1
  96. package/dist/skins-src/components/dashboard-layout.css +21 -1
  97. package/dist/skins-src/components/date-field.css +2 -2
  98. package/dist/skins-src/components/dialog.css +4 -4
  99. package/dist/skins-src/components/drawer.css +9 -9
  100. package/dist/skins-src/components/editable.css +3 -3
  101. package/dist/skins-src/components/file-upload.css +4 -4
  102. package/dist/skins-src/components/floating-panel.css +1 -1
  103. package/dist/skins-src/components/forgot-password-page.css +1 -1
  104. package/dist/skins-src/components/form-section.css +1 -1
  105. package/dist/skins-src/components/form.css +12 -2
  106. package/dist/skins-src/components/image.css +1 -1
  107. package/dist/skins-src/components/kbd.css +1 -1
  108. package/dist/skins-src/components/link.css +1 -1
  109. package/dist/skins-src/components/listbox.css +1 -1
  110. package/dist/skins-src/components/mentions.css +1 -1
  111. package/dist/skins-src/components/menubar.css +2 -2
  112. package/dist/skins-src/components/navigation-menu.css +1 -1
  113. package/dist/skins-src/components/number-field.css +1 -1
  114. package/dist/skins-src/components/onboarding-checklist.css +1 -1
  115. package/dist/skins-src/components/pagination.css +2 -2
  116. package/dist/skins-src/components/password-input.css +80 -16
  117. package/dist/skins-src/components/pin-input.css +2 -2
  118. package/dist/skins-src/components/popover.css +1 -1
  119. package/dist/skins-src/components/qr-code.css +2 -2
  120. package/dist/skins-src/components/radio-card.css +1 -1
  121. package/dist/skins-src/components/reset-password-page.css +1 -1
  122. package/dist/skins-src/components/select.css +3 -3
  123. package/dist/skins-src/components/sign-in-page.css +1 -1
  124. package/dist/skins-src/components/sign-up-page.css +1 -1
  125. package/dist/skins-src/components/skeleton.css +1 -1
  126. package/dist/skins-src/components/skip-link.css +1 -1
  127. package/dist/skins-src/components/speed-dial.css +3 -3
  128. package/dist/skins-src/components/stat-card.css +6 -1
  129. package/dist/skins-src/components/stepper.css +3 -1
  130. package/dist/skins-src/components/switch.css +21 -1
  131. package/dist/skins-src/components/table.css +4 -4
  132. package/dist/skins-src/components/tags-input.css +2 -2
  133. package/dist/skins-src/components/text-field.css +26 -21
  134. package/dist/skins-src/components/text.css +1 -1
  135. package/dist/skins-src/components/textarea.css +1 -1
  136. package/dist/skins-src/components/time-field.css +2 -2
  137. package/dist/skins-src/components/toast.css +2 -2
  138. package/dist/skins-src/components/toggle-group.css +3 -3
  139. package/dist/skins-src/components/toggle.css +1 -1
  140. package/dist/skins-src/components/toolbar.css +2 -2
  141. package/dist/skins-src/components/tree-select.css +2 -2
  142. package/dist/skins-src/components/tree.css +7 -1
  143. package/dist/skins-src/components/usage-card.css +1 -1
  144. package/dist/skins-src/components/user-menu.css +1 -1
  145. package/dist/skins-src/components/verification-page.css +1 -1
  146. package/dist/skins-src/components/workspace-switcher.css +2 -2
  147. package/package.json +14 -14
@@ -1 +1 @@
1
- import{changeDetail as e}from"./change-reason.js";import{ROOT_DATA_ATTRIBUTES as t}from"./styling-hooks.js";var r={name:"Carousel",purpose:"A single-slide-at-a-time carousel: the active slide index is owned by the root and driven by keyboard, Previous/Next buttons, or direct control. Slide order comes from CarouselItem mount order, not an explicit per-item index. Composed of a root plus Content, Item, Previous, and Next parts.",props:[{name:"value",type:"number",required:!1,description:"Controlled index of first active slide; pair with value-change event. With slidesPerPage > 1, names the first of several (convention across all families)."},{name:"defaultValue",type:"number",defaultValue:"0",required:!1,description:"Initial index of the first slide in the active window, 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."},{name:"loop",type:"boolean",defaultValue:"false",required:!1,description:"Wrap past last slide to first; false disables Previous/Next at ends."},{name:"slidesPerPage",type:"number",defaultValue:"1",required:!1,description:"Visible slides at once (value to value + slidesPerPage - 1 are active). Highest index is max(0, count - slidesPerPage), keeping the last page full."},{name:"slidesPerMove",type:"number",defaultValue:"1",required:!1,description:"Slides per Previous/Next step or Arrow key. Set equal to slidesPerPage for page-at-a-time paging."},{name:"spacing",type:"number | string",required:!1,description:"Gap between slides (--skdx-carousel-spacing). Numbers are pixels; strings used verbatim."},{name:"autoplay",type:"boolean",defaultValue:"false",required:!1,description:"Advances on timer (off by default, WCAG 2.2.2). Never starts under prefers-reduced-motion: reduce. Hover and page-visibility suspend the timer and resume it when they end; focus entering the carousel stops it for good\u2014only PlayPause restarts (APG requires no auto-resume)."},{name:"autoplayInterval",type:"number",defaultValue:"5000",required:!1,description:"Milliseconds between automatic advances."},{name:"items",type:"T[]",required:!1,description:"Data to render as Item slides, instead of hand-written children."},{name:"renderItem",type:"(item: T, index: number) => React.ReactNode",required:!1,description:"Renders one derived slide's content, in place of its String(item) fallback."},{name:"showIndicators",type:"boolean",defaultValue:"false",required:!1,description:"Render an Indicators strip (one dot per item)."},{name:"showControls",type:"boolean",defaultValue:"true",required:!1,description:"Render Previous/Next around Content, independent of PlayPause (which auto-derives with autoplay)."},{name:"indicatorLabels",type:"readonly string[]",required:!1,description:"Accessible names for Indicator dots (one per item, same order). Dots default to positional announcements; partial lists allowed. Ignored under hand composition (each Indicator carries its own aria-label)."}],events:[{name:"value-change",detail:e("number"),description:"Fires with the new active index whenever the slide changes, controlled or not."}],parts:[{name:"Content",description:`Wrapper around Items and the carousel's live region (aria-atomic="false"). aria-live="off" while playing, "polite" while paused, to avoid interrupting user reading on timer advances.`},{name:"PlayPause",description:'Pause/resume control WCAG 2.2.2 requires (toggles timer, data-state="playing"/"paused"). Works when autoplay is false. Must be FIRST in tab sequence, before Content and Previous/Next (APG requirement).',props:[{name:"playLabel",type:"string",defaultValue:"'Play slideshow'",required:!1,frameworks:["angular","webComponents"],exception:"attribute-passthrough",frameworksReason:"React, Vue and Svelte take `aria-label` on the element through attribute passthrough.",description:"Accessible name while paused, announcing that activation resumes autoplay."},{name:"pauseLabel",type:"string",defaultValue:"'Pause slideshow'",required:!1,frameworks:["angular","webComponents"],exception:"attribute-passthrough",frameworksReason:"React, Vue and Svelte take `aria-label` on the element through attribute passthrough.",description:"Accessible name while playing, announcing that activation pauses autoplay."}]},{name:"Indicators",description:'Strip of slide dots (role="group", data-orientation). Group, not tablist\u2014dots jump rather than tab. Composed by consumer, mapping items to Indicators.'},{name:"Indicator",description:'Slide dot button (calls scrollToIndex, data-state="active"/"inactive"). Uses aria-disabled="true" (not disabled) to stay focusable for keyboard counting. Defaults to aria-label "Go to slide N".',props:[{name:"index",type:"number",required:!0,description:"Zero-based slide index this dot jumps to when pressed."},{name:"label",type:"string",required:!1,description:"Accessible name for this dot, in place of the positional default, and what the root's indicatorLabels hands each derived dot. A named prop rather than an aria-label passthrough because Angular and Web Components both render the dot as an inner button a host aria-label cannot reach \u2014 a prop is the one spelling that works in all five. A consumer's own aria-label on the part still wins over both."}]},{name:"Progress",description:'Slide position readout ("Slide 2 of 5"). Format callback controls the text; translatable by consumer. No aria-live (Content is the live region). Natural aria-labelledby target for root.',props:[{name:"format",type:"(current: number, total: number) => string",defaultValue:"(current, total) => `Slide ${current} of ${total}`",required:!1,description:"Builds the readout text from the 1-based position of the first visible slide and the total slide count. An empty carousel reports current as 0 rather than 1, because there is no first slide to be on."}]}],slots:[{name:"default",description:"Root content \u2014 an optional PlayPause first (APG puts the rotation control first in the tab sequence), then Content (wrapping Items), Previous/Next, and optionally Indicators (wrapping one Indicator per slide) and Progress."}],states:["active","inactive","disabled","playing","paused","suspended"],controlledUncontrolled:"value: controlled or uncontrolled (defaultValue). Autoplay play/pause is internal state (not controlled). PlayPause and keyboard focus (entering carousel) write it; hover/page-visibility suspend timer only.",formBehavior:"Not applicable \u2014 Carousel does not participate in forms.",validationBehavior:"Not applicable \u2014 Carousel carries no value and participates in no validation.",accessibility:{role:"region (root); group (Item)",keyboard:[{key:"ArrowLeft/ArrowRight (horizontal) or ArrowUp/ArrowDown (vertical)",behavior:'Stepper by slidesPerMove when root focused (wraps if loop set). Mirrored under dir="rtl". Root ignores arrows from form controls, contenteditable, or roles with own arrow behavior (textbox, listbox, slider, menu, grid, etc.). Buttons excluded to keep arrows working on Previous/Next/PlayPause.'}],ariaAttributes:["aria-label or aria-labelledby on the root, which is required rather than optional (see namingRequirement)",'aria-roledescription="carousel" on the root','aria-roledescription="slide" and data-state ("active"/"inactive") on each Item',"data-disabled on Previous/Next when stepping further is not possible",'data-state ("playing"/"paused") on the root and on PlayPause, reflecting the autoplay setting',"data-suspended on the root while hover or a hidden page is holding the timer \u2014 the live-timer fact data-state deliberately does not report",'aria-disabled="true" on the Indicator for a slide already on screen (not the native disabled attribute, so the dot keeps its tab stop)','aria-atomic="false" on Content, plus aria-live="off" while the root is playing and aria-live="polite" once it is not \u2014 the slide region is a live region, and its politeness is the one thing the playing/paused state has to drive'],focusManagement:'Root is keyboard target (tabIndex 0). "Stepper when root focused" requires tab stop; pairs with mandatory name. Only active Items exposed (no roving tabindex). PlayPause first in tab sequence (APG).',namingRequirement:'Root must have aria-label or aria-labelledby (e.g., "Featured products"). role="region" takes no name from contents; without one, carousel is not exposed as landmark, aria-roledescription="carousel" is inert.'},styling:{cssParts:["content","item","previous","next","play-pause","indicators","indicator","progress","root"],dataAttributes:[...t,"data-state","data-orientation","data-disabled","data-suspended",{name:"data-skdx-carousel-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-carousel-spacing","--skdx-carousel-slides-per-page"]},publicMethods:[{name:"scrollToIndex",frameworks:["vue","svelte","angular","webComponents"],exception:"imperative",frameworksReason:"React's root forwards a DOM ref rather than an imperative handle, so there is no component instance to hang a method off \u2014 `useCarouselContext` is React's binding of this member and it is declared under `contextApi` below. Listing it here unscoped would read as React missing a method the family has.",signature:"(index: number) => void",description:"Moves to index, clamped into [0, max(0, count - slidesPerPage)]. Exposed on the carousel context, and additionally as an instance or element method where one exists."},{name:"next",frameworks:["vue","svelte","angular","webComponents"],exception:"imperative",frameworksReason:"React's root forwards a DOM ref rather than an imperative handle, so there is no component instance to hang a method off \u2014 `useCarouselContext` is React's binding of this member and it is declared under `contextApi` below. Listing it here unscoped would read as React missing a method the family has.",signature:"() => void",description:"Stepper forward by slidesPerMove, wrapping to the first slide when loop is set and resting on the last full page otherwise. What CarouselNext and the forward Arrow key both call \u2014 declared because binding your own control to it is the point of the context surface."},{name:"previous",frameworks:["vue","svelte","angular","webComponents"],exception:"imperative",frameworksReason:"React's root forwards a DOM ref rather than an imperative handle, so there is no component instance to hang a method off \u2014 `useCarouselContext` is React's binding of this member and it is declared under `contextApi` below. Listing it here unscoped would read as React missing a method the family has.",signature:"() => void",description:"Stepper back by slidesPerMove, wrapping to the last page when loop is set and resting on the first slide otherwise. What CarouselPrevious and the back Arrow key both call."}],contextApi:[{name:"scrollToIndex",signature:"(index: number) => void",description:"Moves to index, clamped into [0, max(0, count - slidesPerPage)]. Also an instance/element method on every framework that has one.",accessors:{react:"useCarouselContext('MyComponent').scrollToIndex",vue:"inject(CAROUSEL_CONTEXT).scrollToIndex",svelte:"getContext(CAROUSEL_CONTEXT).scrollToIndex",angular:"inject(SkdxCarouselState).scrollToIndex",webComponents:"document.querySelector('skdx-carousel').scrollToIndex"}},{name:"next",signature:"() => void",description:"Stepper forward by slidesPerMove, wrapping to the first slide when loop is set. What CarouselNext and the forward Arrow key both call.",accessors:{react:"useCarouselContext('MyComponent').next",vue:"inject(CAROUSEL_CONTEXT).next",svelte:"getContext(CAROUSEL_CONTEXT).next",angular:"inject(SkdxCarouselState).next",webComponents:"document.querySelector('skdx-carousel').next"}},{name:"previous",signature:"() => void",description:"Stepper back by slidesPerMove, wrapping to the last page when loop is set. What CarouselPrevious and the back Arrow key both call.",accessors:{react:"useCarouselContext('MyComponent').previous",vue:"inject(CAROUSEL_CONTEXT).previous",svelte:"getContext(CAROUSEL_CONTEXT).previous",angular:"inject(SkdxCarouselState).previous",webComponents:"document.querySelector('skdx-carousel').previous"}},{name:"canScrollNext",signature:"boolean",description:"Read-only: whether next() has somewhere to go. False at the last page of a non-looping carousel and whenever there are no slides \u2014 the same predicate CarouselNext disables itself on.",accessors:{react:"useCarouselContext('MyComponent').canScrollNext",vue:"inject(CAROUSEL_CONTEXT).canScrollNext",svelte:"getContext(CAROUSEL_CONTEXT).canScrollNext",angular:"inject(SkdxCarouselState).canScrollNext()",webComponents:"document.querySelector('skdx-carousel').canScrollNext"}},{name:"canScrollPrev",signature:"boolean",description:"Read-only: whether previous() has somewhere to go. False at the first slide of a non-looping carousel and whenever there are no slides.",accessors:{react:"useCarouselContext('MyComponent').canScrollPrev",vue:"inject(CAROUSEL_CONTEXT).canScrollPrev",svelte:"getContext(CAROUSEL_CONTEXT).canScrollPrev",angular:"inject(SkdxCarouselState).canScrollPrev()",webComponents:"document.querySelector('skdx-carousel').canScrollPrev"}},{name:"itemIds",signature:"string[]",description:"Read-only: the generated id of every slide, in DOM order. Its length is the slide count the movement API clamps against, and its entries are what an Indicator points at with aria-controls.",accessors:{react:"useCarouselContext('MyComponent').itemIds",vue:"inject(CAROUSEL_CONTEXT).itemIds",svelte:"getContext(CAROUSEL_CONTEXT).itemIds",angular:"inject(SkdxCarouselState).itemIds()",webComponents:"document.querySelector('skdx-carousel').itemIds"}}],frameworkExtensions:[{framework:"webComponents",part:"PlayPause",name:"playLabel",type:"string",description:'Accessible name for the play/pause control while autoplay is off, i.e. the action pressing it performs. `<skdx-carousel-play-pause>` renders its <button> into a shadow root, so an aria-label written on the host names the host and not the button the user activates. React, Vue and Svelte render the button in the consumer\'s own tree, where the consumer sets aria-label directly and there is nothing to be missing; Angular has the same gap for a different structural reason and takes the same input. Same reason `<skdx-toast-close>` takes a `label`. Default: "Play slideshow".'},{framework:"webComponents",part:"PlayPause",name:"pauseLabel",type:"string",description:'Accessible name for the play/pause control while autoplay is on \u2014 the other half of the pair playLabel documents, for the same shadow-root reason. Default: "Pause slideshow".'},{framework:"angular",part:"PlayPause",name:"playLabel",type:"string",description:'Accessible name for the play/pause control while autoplay is off. `SkdxCarouselPlayPauseComponent` is boxless (`display: contents`) and renders the <button> in its own template, so an aria-label written on `<skdx-carousel-play-pause>` names the boxless host rather than the button the user activates \u2014 the same gap Web Components has, reached by a different route. React, Vue and Svelte render the button in the consumer\'s own tree and need no input. Default: "Play slideshow".'},{framework:"angular",part:"PlayPause",name:"pauseLabel",type:"string",description:`Accessible name for the play/pause control while autoplay is on \u2014 the other half of the pair Angular's playLabel documents, for the same boxless-host reason. Default: "Pause slideshow".`}]};export{r as carouselContract};
1
+ import{changeDetail as e}from"./change-reason.js";import{ROOT_DATA_ATTRIBUTES as t}from"./styling-hooks.js";var r={name:"Carousel",purpose:"A single-slide-at-a-time carousel: the active slide index is owned by the root and driven by keyboard, Previous/Next buttons, or direct control. Slide order comes from CarouselItem mount order, not an explicit per-item index. Composed of a root plus Content, Item, Previous, and Next parts.",props:[{name:"value",type:"number",required:!1,description:"Controlled index of first active slide; pair with value-change event. With slidesPerPage > 1, names the first of several (convention across all families)."},{name:"defaultValue",type:"number",defaultValue:"0",required:!1,description:"Initial index of the first slide in the active window, 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."},{name:"loop",type:"boolean",defaultValue:"false",required:!1,description:"Wrap past last slide to first; false disables Previous/Next at ends."},{name:"slidesPerPage",type:"number",defaultValue:"1",required:!1,description:"Visible slides at once (value to value + slidesPerPage - 1 are active). Highest index is max(0, count - slidesPerPage), keeping the last page full."},{name:"slidesPerMove",type:"number",defaultValue:"1",required:!1,description:"Slides per Previous/Next step or Arrow key. Set equal to slidesPerPage for page-at-a-time paging."},{name:"spacing",type:"number | string",required:!1,description:"Gap between slides (--skdx-carousel-spacing). Numbers are pixels; strings used verbatim."},{name:"autoplay",type:"boolean",defaultValue:"false",required:!1,description:"Advances on timer (off by default, WCAG 2.2.2). Never starts under prefers-reduced-motion: reduce. Hover and page-visibility suspend the timer and resume it when they end; focus entering the carousel stops it for good\u2014only PlayPause restarts (APG requires no auto-resume)."},{name:"autoplayInterval",type:"number",defaultValue:"5000",required:!1,description:"Milliseconds between automatic advances."},{name:"items",type:"T[]",required:!1,description:"Data to render as Item slides, instead of hand-written children."},{name:"renderItem",type:"(item: T, index: number) => React.ReactNode",required:!1,description:"Renders one derived slide's content, in place of its String(item) fallback."},{name:"showIndicators",type:"boolean",defaultValue:"false",required:!1,description:"Render an Indicators strip (one dot per item)."},{name:"showControls",type:"boolean",defaultValue:"true",required:!1,description:"Render Previous/Next around Content, independent of PlayPause (which auto-derives with autoplay)."},{name:"indicatorLabels",type:"readonly string[]",required:!1,description:"Accessible names for Indicator dots (one per item, same order). Dots default to positional announcements; partial lists allowed. Ignored under hand composition (each Indicator carries its own aria-label)."}],events:[{name:"value-change",detail:e("number"),description:"Fires with the new active index whenever the slide changes, controlled or not."}],parts:[{name:"Content",description:`Wrapper around Items and the carousel's live region (aria-atomic="false"). aria-live="off" while playing, "polite" while paused, to avoid interrupting user reading on timer advances.`},{name:"PlayPause",description:'Pause/resume control WCAG 2.2.2 requires (toggles timer, data-state="playing"/"paused"). Works when autoplay is false. Must be FIRST in tab sequence, before Content and Previous/Next (APG requirement).',props:[{name:"playLabel",type:"string",defaultValue:"'Play slideshow'",required:!1,frameworks:["angular","webComponents"],exception:"attribute-passthrough",frameworksReason:"React, Vue and Svelte take `aria-label` on the element through attribute passthrough.",description:"Accessible name while paused, announcing that activation resumes autoplay."},{name:"pauseLabel",type:"string",defaultValue:"'Pause slideshow'",required:!1,frameworks:["angular","webComponents"],exception:"attribute-passthrough",frameworksReason:"React, Vue and Svelte take `aria-label` on the element through attribute passthrough.",description:"Accessible name while playing, announcing that activation pauses autoplay."}]},{name:"Indicators",description:'Strip of slide dots (role="group", data-orientation). Group, not tablist\u2014dots jump rather than tab. Composed by consumer, mapping items to Indicators.'},{name:"Indicator",description:'Slide dot button (calls scrollToIndex, data-state="active"/"inactive"). Uses aria-disabled="true" (not disabled) to stay focusable for keyboard counting. Defaults to aria-label "Go to slide N".',props:[{name:"index",type:"number",required:!0,description:"Zero-based slide index this dot jumps to when pressed."},{name:"label",type:"string",required:!1,description:"Accessible name for this dot, in place of the positional default, and what the root's indicatorLabels hands each derived dot. A named prop rather than an aria-label passthrough because Angular and Web Components both render the dot as an inner button a host aria-label cannot reach \u2014 a prop is the one spelling that works in all five. A consumer's own aria-label on the part still wins over both."}]},{name:"Progress",description:'Slide position readout ("Slide 2 of 5"). Format callback controls the text; translatable by consumer. No aria-live (Content is the live region). Natural aria-labelledby target for root.',props:[{name:"format",type:"(current: number, total: number) => string",defaultValue:"(current, total) => `Slide ${current} of ${total}`",required:!1,description:"Builds the readout text from the 1-based position of the first visible slide and the total slide count. An empty carousel reports current as 0 rather than 1, because there is no first slide to be on."}]}],slots:[{name:"default",description:"Root content \u2014 an optional PlayPause first (APG puts the rotation control first in the tab sequence), then Content (wrapping Items), Previous/Next, and optionally Indicators (wrapping one Indicator per slide) and Progress."},{name:"render-item",frameworks:["svelte"],exception:"render-prop",frameworksReason:"svelte expose render-item as native content projection for the renderItem rendering capability. Other frameworks pass the documented renderItem render prop or template instead of a named slot with this spelling.",description:"Renders one derived slide's content, in place of its String(item) fallback."}],states:["active","inactive","disabled","playing","paused","suspended"],controlledUncontrolled:"value: controlled or uncontrolled (defaultValue). Autoplay play/pause is internal state (not controlled). PlayPause and keyboard focus (entering carousel) write it; hover/page-visibility suspend timer only.",formBehavior:"Not applicable \u2014 Carousel does not participate in forms.",validationBehavior:"Not applicable \u2014 Carousel carries no value and participates in no validation.",accessibility:{role:"region (root); group (Item)",keyboard:[{key:"ArrowLeft/ArrowRight (horizontal) or ArrowUp/ArrowDown (vertical)",behavior:'Stepper by slidesPerMove when root focused (wraps if loop set). Mirrored under dir="rtl". Root ignores arrows from form controls, contenteditable, or roles with own arrow behavior (textbox, listbox, slider, menu, grid, etc.). Buttons excluded to keep arrows working on Previous/Next/PlayPause.'}],ariaAttributes:["aria-label or aria-labelledby on the root, which is required rather than optional (see namingRequirement)",'aria-roledescription="carousel" on the root','aria-roledescription="slide" and data-state ("active"/"inactive") on each Item',"data-disabled on Previous/Next when stepping further is not possible",'data-state ("playing"/"paused") on the root and on PlayPause, reflecting the autoplay setting',"data-suspended on the root while hover or a hidden page is holding the timer \u2014 the live-timer fact data-state deliberately does not report",'aria-disabled="true" on the Indicator for a slide already on screen (not the native disabled attribute, so the dot keeps its tab stop)','aria-atomic="false" on Content, plus aria-live="off" while the root is playing and aria-live="polite" once it is not \u2014 the slide region is a live region, and its politeness is the one thing the playing/paused state has to drive'],focusManagement:'Root is keyboard target (tabIndex 0). "Stepper when root focused" requires tab stop; pairs with mandatory name. Only active Items exposed (no roving tabindex). PlayPause first in tab sequence (APG).',namingRequirement:'Root must have aria-label or aria-labelledby (e.g., "Featured products"). role="region" takes no name from contents; without one, carousel is not exposed as landmark, aria-roledescription="carousel" is inert.'},styling:{cssParts:["content","item","previous","next","play-pause","indicators","indicator","progress","root"],dataAttributes:[...t,"data-state","data-orientation","data-disabled","data-suspended",{name:"data-skdx-carousel-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-carousel-spacing","--skdx-carousel-slides-per-page"]},publicMethods:[{name:"scrollToIndex",frameworks:["vue","svelte","angular","webComponents"],exception:"imperative",frameworksReason:"React's root forwards a DOM ref rather than an imperative handle, so there is no component instance to hang a method off \u2014 `useCarouselContext` is React's binding of this member and it is declared under `contextApi` below. Listing it here unscoped would read as React missing a method the family has.",signature:"(index: number) => void",description:"Moves to index, clamped into [0, max(0, count - slidesPerPage)]. Exposed on the carousel context, and additionally as an instance or element method where one exists."},{name:"next",frameworks:["vue","svelte","angular","webComponents"],exception:"imperative",frameworksReason:"React's root forwards a DOM ref rather than an imperative handle, so there is no component instance to hang a method off \u2014 `useCarouselContext` is React's binding of this member and it is declared under `contextApi` below. Listing it here unscoped would read as React missing a method the family has.",signature:"() => void",description:"Stepper forward by slidesPerMove, wrapping to the first slide when loop is set and resting on the last full page otherwise. What CarouselNext and the forward Arrow key both call \u2014 declared because binding your own control to it is the point of the context surface."},{name:"previous",frameworks:["vue","svelte","angular","webComponents"],exception:"imperative",frameworksReason:"React's root forwards a DOM ref rather than an imperative handle, so there is no component instance to hang a method off \u2014 `useCarouselContext` is React's binding of this member and it is declared under `contextApi` below. Listing it here unscoped would read as React missing a method the family has.",signature:"() => void",description:"Stepper back by slidesPerMove, wrapping to the last page when loop is set and resting on the first slide otherwise. What CarouselPrevious and the back Arrow key both call."}],contextApi:[{name:"scrollToIndex",signature:"(index: number) => void",description:"Moves to index, clamped into [0, max(0, count - slidesPerPage)]. Also an instance/element method on every framework that has one.",accessors:{react:"useCarouselContext('MyComponent').scrollToIndex",vue:"inject(CAROUSEL_CONTEXT).scrollToIndex",svelte:"getContext(CAROUSEL_CONTEXT).scrollToIndex",angular:"inject(SkdxCarouselState).scrollToIndex",webComponents:"document.querySelector('skdx-carousel').scrollToIndex"}},{name:"next",signature:"() => void",description:"Stepper forward by slidesPerMove, wrapping to the first slide when loop is set. What CarouselNext and the forward Arrow key both call.",accessors:{react:"useCarouselContext('MyComponent').next",vue:"inject(CAROUSEL_CONTEXT).next",svelte:"getContext(CAROUSEL_CONTEXT).next",angular:"inject(SkdxCarouselState).next",webComponents:"document.querySelector('skdx-carousel').next"}},{name:"previous",signature:"() => void",description:"Stepper back by slidesPerMove, wrapping to the last page when loop is set. What CarouselPrevious and the back Arrow key both call.",accessors:{react:"useCarouselContext('MyComponent').previous",vue:"inject(CAROUSEL_CONTEXT).previous",svelte:"getContext(CAROUSEL_CONTEXT).previous",angular:"inject(SkdxCarouselState).previous",webComponents:"document.querySelector('skdx-carousel').previous"}},{name:"canScrollNext",signature:"boolean",description:"Read-only: whether next() has somewhere to go. False at the last page of a non-looping carousel and whenever there are no slides \u2014 the same predicate CarouselNext disables itself on.",accessors:{react:"useCarouselContext('MyComponent').canScrollNext",vue:"inject(CAROUSEL_CONTEXT).canScrollNext",svelte:"getContext(CAROUSEL_CONTEXT).canScrollNext",angular:"inject(SkdxCarouselState).canScrollNext()",webComponents:"document.querySelector('skdx-carousel').canScrollNext"}},{name:"canScrollPrev",signature:"boolean",description:"Read-only: whether previous() has somewhere to go. False at the first slide of a non-looping carousel and whenever there are no slides.",accessors:{react:"useCarouselContext('MyComponent').canScrollPrev",vue:"inject(CAROUSEL_CONTEXT).canScrollPrev",svelte:"getContext(CAROUSEL_CONTEXT).canScrollPrev",angular:"inject(SkdxCarouselState).canScrollPrev()",webComponents:"document.querySelector('skdx-carousel').canScrollPrev"}},{name:"itemIds",signature:"string[]",description:"Read-only: the generated id of every slide, in DOM order. Its length is the slide count the movement API clamps against, and its entries are what an Indicator points at with aria-controls.",accessors:{react:"useCarouselContext('MyComponent').itemIds",vue:"inject(CAROUSEL_CONTEXT).itemIds",svelte:"getContext(CAROUSEL_CONTEXT).itemIds",angular:"inject(SkdxCarouselState).itemIds()",webComponents:"document.querySelector('skdx-carousel').itemIds"}}],frameworkExtensions:[{framework:"webComponents",part:"PlayPause",name:"playLabel",type:"string",description:'Accessible name for the play/pause control while autoplay is off, i.e. the action pressing it performs. `<skdx-carousel-play-pause>` renders its <button> into a shadow root, so an aria-label written on the host names the host and not the button the user activates. React, Vue and Svelte render the button in the consumer\'s own tree, where the consumer sets aria-label directly and there is nothing to be missing; Angular has the same gap for a different structural reason and takes the same input. Same reason `<skdx-toast-close>` takes a `label`. Default: "Play slideshow".'},{framework:"webComponents",part:"PlayPause",name:"pauseLabel",type:"string",description:'Accessible name for the play/pause control while autoplay is on \u2014 the other half of the pair playLabel documents, for the same shadow-root reason. Default: "Pause slideshow".'},{framework:"angular",part:"PlayPause",name:"playLabel",type:"string",description:'Accessible name for the play/pause control while autoplay is off. `SkdxCarouselPlayPauseComponent` is boxless (`display: contents`) and renders the <button> in its own template, so an aria-label written on `<skdx-carousel-play-pause>` names the boxless host rather than the button the user activates \u2014 the same gap Web Components has, reached by a different route. React, Vue and Svelte render the button in the consumer\'s own tree and need no input. Default: "Play slideshow".'},{framework:"angular",part:"PlayPause",name:"pauseLabel",type:"string",description:`Accessible name for the play/pause control while autoplay is on \u2014 the other half of the pair Angular's playLabel documents, for the same boxless-host reason. Default: "Pause slideshow".`},{framework:"vue",kind:"method",name:"canScrollNext",type:"Content projection",description:"Whether `next()` has somewhere to go, given the current page and `loop`. This framework exposes the documented state accessor through its component instance. Other wrappers expose the state as properties/context rather than requiring this callable instance spelling."},{framework:"svelte",kind:"method",name:"canScrollNext",type:"() => boolean",description:"Whether `next()` has somewhere to go, given the current page and `loop`; a\nfunction because Svelte cannot export derived state, and reactive at the call\nsite because it reads the same state the controls do. This framework exposes the documented state accessor through its component instance. Other wrappers expose the state as properties/context rather than requiring this callable instance spelling."},{framework:"angular",kind:"method",name:"canScrollNext",type:"Content projection",description:"Whether `next()` has somewhere to go; same predicate `skdx-carousel-next` uses. This framework exposes the documented state accessor through its component instance. Other wrappers expose the state as properties/context rather than requiring this callable instance spelling."},{framework:"vue",kind:"method",name:"canScrollPrev",type:"Content projection",description:"Whether `previous()` has somewhere to go, given the current page and `loop`. This framework exposes the documented state accessor through its component instance. Other wrappers expose the state as properties/context rather than requiring this callable instance spelling."},{framework:"svelte",kind:"method",name:"canScrollPrev",type:"() => boolean",description:"Whether `previous()` has somewhere to go, given the current page and `loop`. This framework exposes the documented state accessor through its component instance. Other wrappers expose the state as properties/context rather than requiring this callable instance spelling."},{framework:"angular",kind:"method",name:"canScrollPrev",type:"Content projection",description:"Whether `previous()` has somewhere to go. This framework exposes the documented state accessor through its component instance. Other wrappers expose the state as properties/context rather than requiring this callable instance spelling."},{framework:"webComponents",kind:"method",name:"setPlaying",type:"(playing: boolean) => void",description:"Switches autoplay on or off, doubling as a play button even when `autoplay`\nis false, and never starts under `prefers-reduced-motion: reduce`. Web Components exposes this documented state/action on its element for native JavaScript and composed elements. Other wrappers coordinate their parts through context, injected state or callback props; this instance helper is separate from the common interaction contract."},{framework:"webComponents",kind:"method",name:"setValue",type:"(next: number) => void",description:"Sets the active index (updates internal state when uncontrolled) and dispatches `value-change`. Web Components exposes this documented state/action on its element for native JavaScript and composed elements. Other wrappers coordinate their parts through context, injected state or callback props; this instance helper is separate from the common interaction contract."},{framework:"webComponents",name:"canScrollNext",type:"boolean",description:"Whether `next()` has somewhere to go \u2014 false at the last page of a non-looping carousel or with no slides. This documented getter exposes the native element\u2019s derived live state. Other wrappers expose their state through context or framework refs; the shared component contract does not require identical getter spellings.",kind:"prop"},{framework:"webComponents",name:"canScrollPrev",type:"boolean",description:"Whether `previous()` has somewhere to go \u2014 false at the first slide of a non-looping carousel. This documented getter exposes the native element\u2019s derived live state. Other wrappers expose their state through context or framework refs; the shared component contract does not require identical getter spellings.",kind:"prop"},{framework:"webComponents",name:"maxIndex",type:"number",description:"The last reachable index: the last page stays full rather than scrolling past the final slide. This documented getter exposes the native element\u2019s derived live state. Other wrappers expose their state through context or framework refs; the shared component contract does not require identical getter spellings.",kind:"prop"},{framework:"webComponents",name:"playing",type:"boolean",description:"Whether autoplay is switched on \u2014 the user's setting, not the possibly-suspended timer. This documented getter exposes the native element\u2019s derived live state. Other wrappers expose their state through context or framework refs; the shared component contract does not require identical getter spellings.",kind:"prop"},{framework:"vue",kind:"method",name:"canScrollNext",type:"Content projection",description:"Whether `next()` has somewhere to go, given the current page and `loop`. This framework exposes the documented state accessor through its component instance. Other wrappers expose the state as properties/context rather than requiring this callable instance spelling."},{framework:"svelte",kind:"method",name:"canScrollNext",type:"() => boolean",description:"Whether `next()` has somewhere to go, given the current page and `loop`; a\nfunction because Svelte cannot export derived state, and reactive at the call\nsite because it reads the same state the controls do. This framework exposes the documented state accessor through its component instance. Other wrappers expose the state as properties/context rather than requiring this callable instance spelling."},{framework:"angular",kind:"method",name:"canScrollNext",type:"Content projection",description:"Whether `next()` has somewhere to go; same predicate `skdx-carousel-next` uses. This framework exposes the documented state accessor through its component instance. Other wrappers expose the state as properties/context rather than requiring this callable instance spelling."},{framework:"vue",kind:"method",name:"canScrollPrev",type:"Content projection",description:"Whether `previous()` has somewhere to go, given the current page and `loop`. This framework exposes the documented state accessor through its component instance. Other wrappers expose the state as properties/context rather than requiring this callable instance spelling."},{framework:"svelte",kind:"method",name:"canScrollPrev",type:"() => boolean",description:"Whether `previous()` has somewhere to go, given the current page and `loop`. This framework exposes the documented state accessor through its component instance. Other wrappers expose the state as properties/context rather than requiring this callable instance spelling."},{framework:"angular",kind:"method",name:"canScrollPrev",type:"Content projection",description:"Whether `previous()` has somewhere to go. This framework exposes the documented state accessor through its component instance. Other wrappers expose the state as properties/context rather than requiring this callable instance spelling."},{framework:"webComponents",kind:"method",name:"setPlaying",type:"(playing: boolean) => void",description:"Switches autoplay on or off, doubling as a play button even when `autoplay`\nis false, and never starts under `prefers-reduced-motion: reduce`. Web Components exposes this documented state/action on its element for native JavaScript and composed elements. Other wrappers coordinate their parts through context, injected state or callback props; this instance helper is separate from the common interaction contract."},{framework:"webComponents",kind:"method",name:"setValue",type:"(next: number) => void",description:"Sets the active index (updates internal state when uncontrolled) and dispatches `value-change`. Web Components exposes this documented state/action on its element for native JavaScript and composed elements. Other wrappers coordinate their parts through context, injected state or callback props; this instance helper is separate from the common interaction contract."},{framework:"webComponents",name:"canScrollNext",type:"boolean",description:"Whether `next()` has somewhere to go \u2014 false at the last page of a non-looping carousel or with no slides. This documented getter exposes the native element\u2019s derived live state. Other wrappers expose their state through context or framework refs; the shared component contract does not require identical getter spellings."},{framework:"webComponents",name:"canScrollPrev",type:"boolean",description:"Whether `previous()` has somewhere to go \u2014 false at the first slide of a non-looping carousel. This documented getter exposes the native element\u2019s derived live state. Other wrappers expose their state through context or framework refs; the shared component contract does not require identical getter spellings."},{framework:"webComponents",name:"maxIndex",type:"number",description:"The last reachable index: the last page stays full rather than scrolling past the final slide. This documented getter exposes the native element\u2019s derived live state. Other wrappers expose their state through context or framework refs; the shared component contract does not require identical getter spellings."},{framework:"webComponents",name:"playing",type:"boolean",description:"Whether autoplay is switched on \u2014 the user's setting, not the possibly-suspended timer. This documented getter exposes the native element\u2019s derived live state. Other wrappers expose their state through context or framework refs; the shared component contract does not require identical getter spellings."}]};export{r as carouselContract};
@@ -1 +1 @@
1
- import{constraintValidationMethods as e,setCustomValidityMethod as t}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as a}from"./styling-hooks.js";var r={name:"CheckboxCard",purpose:'A checkbox with a card-sized hit target: a <label> root wrapping a real <input type="checkbox">, plus Control, Indicator, Label, and Description parts.',props:[{name:"checked",type:"boolean",required:!1,description:"Controlled checked state. Boolean only, not indeterminate: a card is one titled choice, and the mixed state belongs to a parent summarising a set."},{name:"defaultChecked",type:"boolean",defaultValue:"false",required:!1,description:"Initial checked state, for uncontrolled usage. The card starts unselected."},{name:"name",type:"string",required:!1,description:"Name put on the underlying native input for form submission. Unlike Checkbox the input always exists here \u2014 it is what makes the card clickable \u2014 so omitting name only means the value is not submitted."},{name:"value",type:"string",defaultValue:"'on'",required:!1,description:"Value submitted with the control when checked \u2014 the same default the HTML checkbox itself uses."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Marks the control required for form validation; an unchecked card blocks submission with valueMissing."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the control: neither the card surface nor keyboard can change it, and it leaves the tab order."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:'Freezes selection without freezing interaction. The Control keeps its tab stop and stays focusable; gains aria-readonly="true"; clicking and Space do nothing. It does NOT gain aria-disabled, and the Control keeps submitting its value \u2014 the native readonly attribute is deliberately never set on it because that blocks constraint validation. Same model as Checkbox, CheckboxGroup and RadioGroup.'},{name:"form",type:"string",required:!1,description:"Id of the <form> that owns this card when rendered outside it. Set as the form content attribute on <skdx-checkbox-card>; in React, Vue, Svelte and Angular forwarded to the Control input's form attribute."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Marks the card invalid: exposes aria-invalid on the control and data-invalid on the root for error styling."},{name:"hasLabel",type:"boolean",defaultValue:"false",required:!1,description:"Declares a Label is present, so server-rendered markup carries aria-labelledby before hydration. Only affects the first paint; mount registration is authoritative.",frameworks:["svelte"],exception:"snippet-opaque",frameworksReason:"Svelte alone has no render-time signal: children arrive as an opaque Snippet function. React, Vue, and Angular resolve this from their declared children; Web Components queries real DOM."},{name:"hasDescription",type:"boolean",defaultValue:"false",required:!1,description:"Same as hasLabel, for a Description and aria-describedby.",frameworks:["svelte"],exception:"snippet-opaque",frameworksReason:"Same reason as hasLabel: Svelte has no render-time way to detect the part."},{name:"label",type:"string",required:!1,description:"The card's title copy, rendered into the derived Label that the control's aria-labelledby points at. Supplying it derives the whole anatomy (Control, Indicator, Label). Omitting it requires an aria-label on the control. Anatomy derivation is all-or-nothing: a card with any consumer composition derives nothing."},{name:"description",type:"string",required:!1,description:"The supporting copy under the title, which derives a Description part and the control's aria-describedby. The only optional part of the derived anatomy."},{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:[{name:"checked-change",detail:"boolean",description:"Fired with the new checked state whenever it changes, controlled or not."}],parts:[{name:"Control",description:"The real checkbox input, visually hidden but focusable so the browser owns activation, focus, form submission, and validation. Points aria-labelledby and aria-describedby only at the ones actually mounted."},{name:"Indicator",description:"The drawn check mark or box. Decorative and aria-hidden: the control already reports its own checked state, and a second announcement would stutter."},{name:"Label",description:"The card's title line, and its accessible name."},{name:"Description",description:"The supporting copy under the title, announced after the name via aria-describedby rather than folded into it."}],slots:[{name:"default",description:"The card's body \u2014 a Control, an Indicator, a Label, and usually a Description."}],appearance:[{attribute:"data-size",values:["sm","md","lg"],stylesheet:"checkbox-card.css"}],states:["checked","unchecked","focus-visible","invalid","disabled","readonly"],controlledUncontrolled:"Uncontrolled by default: starts at defaultChecked and tracks its own checked state. Passing checked switches to controlled.",formBehavior:`A real <input type="checkbox">: submits value under name when checked, participates in form reset, and is reachable through the form's elements collection. form associates it with a <form> outside its DOM location. readOnly does not affect submission \u2014 the Control never receives the native readonly attribute.`,validationBehavior:"Native constraint validation through required, failing with valueMissing when unchecked. checkValidity()/reportValidity() delegate straight to the Control input; setCustomValidity() writes to it for server or cross-field errors. The invalid prop is presentational and does not itself block submission \u2014 pair with Field for messages.",accessibility:{role:"checkbox \u2014 supplied by the native input, not an ARIA role",keyboard:[{key:"Space",behavior:"Toggles the card, handled natively by the input."},{key:"Tab",behavior:"Moves to the card; each card is its own tab stop, since checkboxes are independent."}],ariaAttributes:["aria-labelledby on the control pointing at the Label when mounted \u2014 a dangling reference is an accessibility bug","aria-describedby on the control pointing at the Description, when mounted","The association must also hold in server-rendered markup, where effects have not yet run: it is resolved from declared children or real DOM before rendering, or seeded by explicit hasLabel/hasDescription props (default false) where no render-time signal exists.","aria-invalid on the control while invalid, with data-invalid on the root for styling","aria-readonly on the control while readOnly, with data-readonly on the root \u2014 never aria-disabled","aria-hidden on the Indicator, which draws a state the control already reports"],focusManagement:"Focus lives on the hidden input, never the card. Pointer activation moves focus natively; data-focus-visible is set only for keyboard focus, so a ring appears when it should and not on every click. readOnly does not affect the tab order. Programmatic focus() sets data-focus-visible even without a preceding pointer event, diverging from some `:focus-visible` implementations.",namingRequirement:"A Label part or aria-label on the control. The Description is deliberately not part of the name; folding a paragraph into the accessible name makes announcements unbearable."},styling:{cssParts:["checkbox-card","control","indicator","label","description"],dataAttributes:[...a,"data-state","data-disabled","data-readonly","data-invalid","data-focus-visible","data-size",{name:"data-skdx-checkbox-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:[...e,t]};export{r as checkboxCardContract};
1
+ import{constraintValidationMethods as e,setCustomValidityMethod as t}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as a}from"./styling-hooks.js";var r={name:"CheckboxCard",purpose:'A checkbox with a card-sized hit target: a <label> root wrapping a real <input type="checkbox">, plus Control, Indicator, Label, and Description parts.',props:[{name:"checked",type:"boolean",required:!1,description:"Controlled checked state. Boolean only, not indeterminate: a card is one titled choice, and the mixed state belongs to a parent summarising a set."},{name:"defaultChecked",type:"boolean",defaultValue:"false",required:!1,description:"Initial checked state, for uncontrolled usage. The card starts unselected."},{name:"name",type:"string",required:!1,description:"Name put on the underlying native input for form submission. Unlike Checkbox the input always exists here \u2014 it is what makes the card clickable \u2014 so omitting name only means the value is not submitted."},{name:"value",type:"string",defaultValue:"'on'",required:!1,description:"Value submitted with the control when checked \u2014 the same default the HTML checkbox itself uses."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Marks the control required for form validation; an unchecked card blocks submission with valueMissing."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the control: neither the card surface nor keyboard can change it, and it leaves the tab order."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:'Freezes selection without freezing interaction. The Control keeps its tab stop and stays focusable; gains aria-readonly="true"; clicking and Space do nothing. It does NOT gain aria-disabled, and the Control keeps submitting its value \u2014 the native readonly attribute is deliberately never set on it because that blocks constraint validation. Same model as Checkbox, CheckboxGroup and RadioGroup.'},{name:"form",type:"string",required:!1,description:"Id of the <form> that owns this card when rendered outside it. Set as the form content attribute on <skdx-checkbox-card>; in React, Vue, Svelte and Angular forwarded to the Control input's form attribute."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Marks the card invalid: exposes aria-invalid on the control and data-invalid on the root for error styling."},{name:"hasLabel",type:"boolean",defaultValue:"false",required:!1,description:"Declares a Label is present, so server-rendered markup carries aria-labelledby before hydration. Only affects the first paint; mount registration is authoritative.",frameworks:["svelte"],exception:"snippet-opaque",frameworksReason:"Svelte alone has no render-time signal: children arrive as an opaque Snippet function. React, Vue, and Angular resolve this from their declared children; Web Components queries real DOM."},{name:"hasDescription",type:"boolean",defaultValue:"false",required:!1,description:"Same as hasLabel, for a Description and aria-describedby.",frameworks:["svelte"],exception:"snippet-opaque",frameworksReason:"Same reason as hasLabel: Svelte has no render-time way to detect the part."},{name:"label",type:"string",required:!1,description:"The card's title copy, rendered into the derived Label that the control's aria-labelledby points at. Supplying it derives the whole anatomy (Control, Indicator, Label). Omitting it requires an aria-label on the control. Anatomy derivation is all-or-nothing: a card with any consumer composition derives nothing."},{name:"description",type:"string",required:!1,description:"The supporting copy under the title, which derives a Description part and the control's aria-describedby. The only optional part of the derived anatomy."},{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:[{name:"checked-change",detail:"boolean",description:"Fired with the new checked state whenever it changes, controlled or not."}],parts:[{name:"Control",description:"The real checkbox input, visually hidden but focusable so the browser owns activation, focus, form submission, and validation. Points aria-labelledby and aria-describedby only at the ones actually mounted."},{name:"Indicator",description:"The drawn check mark or box. Decorative and aria-hidden: the control already reports its own checked state, and a second announcement would stutter."},{name:"Label",description:"The card's title line, and its accessible name."},{name:"Description",description:"The supporting copy under the title, announced after the name via aria-describedby rather than folded into it."}],slots:[{name:"default",description:"The card's body \u2014 a Control, an Indicator, a Label, and usually a Description."}],appearance:[{attribute:"data-size",values:["sm","md","lg"],stylesheet:"checkbox-card.css"}],states:["checked","unchecked","focus-visible","invalid","disabled","readonly"],controlledUncontrolled:"Uncontrolled by default: starts at defaultChecked and tracks its own checked state. Passing checked switches to controlled.",formBehavior:`A real <input type="checkbox">: submits value under name when checked, participates in form reset, and is reachable through the form's elements collection. form associates it with a <form> outside its DOM location. readOnly does not affect submission \u2014 the Control never receives the native readonly attribute.`,validationBehavior:"Native constraint validation through required, failing with valueMissing when unchecked. checkValidity()/reportValidity() delegate straight to the Control input; setCustomValidity() writes to it for server or cross-field errors. The invalid prop is presentational and does not itself block submission \u2014 pair with Field for messages.",accessibility:{role:"checkbox \u2014 supplied by the native input, not an ARIA role",keyboard:[{key:"Space",behavior:"Toggles the card, handled natively by the input."},{key:"Tab",behavior:"Moves to the card; each card is its own tab stop, since checkboxes are independent."}],ariaAttributes:["aria-labelledby on the control pointing at the Label when mounted \u2014 a dangling reference is an accessibility bug","aria-describedby on the control pointing at the Description, when mounted","The association must also hold in server-rendered markup, where effects have not yet run: it is resolved from declared children or real DOM before rendering, or seeded by explicit hasLabel/hasDescription props (default false) where no render-time signal exists.","aria-invalid on the control while invalid, with data-invalid on the root for styling","aria-readonly on the control while readOnly, with data-readonly on the root \u2014 never aria-disabled","aria-hidden on the Indicator, which draws a state the control already reports"],focusManagement:"Focus lives on the hidden input, never the card. Pointer activation moves focus natively; data-focus-visible is set only for keyboard focus, so a ring appears when it should and not on every click. readOnly does not affect the tab order. Programmatic focus() sets data-focus-visible even without a preceding pointer event, diverging from some `:focus-visible` implementations.",namingRequirement:"A Label part or aria-label on the control. The Description is deliberately not part of the name; folding a paragraph into the accessible name makes announcements unbearable."},styling:{cssParts:["checkbox-card","control","indicator","label","description"],dataAttributes:[...a,"data-state","data-disabled","data-readonly","data-invalid","data-focus-visible","data-size",{name:"data-skdx-checkbox-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:[...e,t],frameworkExtensions:[{framework:"webComponents",kind:"method",name:"setChecked",type:"(next: boolean) => void",description:"Sets the checked state, firing `checked-change`, as a no-op while disabled or when `next` already equals the current state. Web Components exposes this documented state/action on its element for native JavaScript and composed elements. Other wrappers coordinate their parts through context, injected state or callback props; this instance helper is separate from the common interaction contract."},{framework:"webComponents",kind:"method",name:"toggle",type:"() => void",description:"Flips the checked state. What the card surface, Space, and the control all do. Web Components exposes this documented state/action on its element for native JavaScript and composed elements. Other wrappers coordinate their parts through context, injected state or callback props; this instance helper is separate from the common interaction contract."},{framework:"webComponents",name:"isChecked",type:"boolean",description:"The current checked state, resolving controlled vs. uncontrolled. This documented getter exposes the native element\u2019s derived live state. Other wrappers expose their state through context or framework refs; the shared component contract does not require identical getter spellings.",kind:"prop"},{framework:"webComponents",kind:"method",name:"setChecked",type:"(next: boolean) => void",description:"Sets the checked state, firing `checked-change`, as a no-op while disabled or when `next` already equals the current state. Web Components exposes this documented state/action on its element for native JavaScript and composed elements. Other wrappers coordinate their parts through context, injected state or callback props; this instance helper is separate from the common interaction contract."},{framework:"webComponents",kind:"method",name:"toggle",type:"() => void",description:"Flips the checked state. What the card surface, Space, and the control all do. Web Components exposes this documented state/action on its element for native JavaScript and composed elements. Other wrappers coordinate their parts through context, injected state or callback props; this instance helper is separate from the common interaction contract."},{framework:"webComponents",name:"isChecked",type:"boolean",description:"The current checked state, resolving controlled vs. uncontrolled. This documented getter exposes the native element\u2019s derived live state. Other wrappers expose their state through context or framework refs; the shared component contract does not require identical getter spellings."}]};export{r as checkboxCardContract};
@@ -1 +1 @@
1
- import{changeDetail as a}from"./change-reason.js";import{constraintValidationMethods as e,setCustomValidityMethod as t}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as r}from"./styling-hooks.js";var s={name:"CheckboxGroup",purpose:"A multi-selection group owning a string[] value, with group-level disabled/required/invalid and optional tri-state select-all parent.",props:[{name:"value",type:"string[]",required:!1,description:"Checked item values, for controlled usage."},{name:"defaultValue",type:"string[]",defaultValue:"[]",required:!1,description:"Initially checked item values, for uncontrolled usage. Vue spells this default as the factory `() => []` rather than the literal, because Vue props with object/array defaults must be factories. The two say the same thing."},{name:"name",type:"string",required:!1,description:"Name under which the checked values are submitted \u2014 one entry per checked value, so formData.getAll(name) returns them all."},{name:"form",type:"string",required:!1,description:"Id of the <form> that owns this group, for a group rendered outside it. Forwarded to every item's hidden input (React/Vue/Svelte/Angular) or set on the element (<skdx-checkbox-group>)."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:'Marks the group as required \u2014 at least one item must be checked. Exposed as aria-required on every item (role="group" does not support it).'},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables every item in the group, and the select-all parent."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:'Freezes the selection. Items and parent stay focusable and tabstoppable; each gains aria-readonly="true". role="group" does not allow it on the root, so the root carries only data-readonly. Space and click change nothing, value-change never fires. Nothing gains aria-disabled. Same model as Checkbox.'},{name:"max",type:"number",required:!1,description:'Caps how many items may be checked. Unchecked items gain aria-disabled="true" and data-max-reached but keeps its tab stop (native disabled attribute is deliberately not used; disabling mid-interaction would steal focus).'},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Marks the group as invalid, exposed as aria-invalid/data-invalid on the group root."},{name:"options",type:"ReadonlyArray<{ value: string; label: string; disabled?: boolean }>",required:!1,description:"The checkboxes the group derives (one Item per entry, keyed by value). Flat only \u2014 no option groups. Hand composition takes precedence."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Size rung forwarded to every derived Item's and the SelectAll control's data-size; either attribute may be written directly instead."}],events:[{name:"value-change",description:"Fires with the new value array whenever an item \u2014 or the select-all parent \u2014 changes the selection.",detail:a("string[]","selectedValue: string | null")}],parts:[{name:"Item",description:'One checkbox in the group. Renders the framework\'s Checkbox with `role="checkbox"`, aria-checked, data-state, data-disabled, plus data-value and the item marker. Toggling adds/removes its value from the group. Each item is its own tab stop.',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 item currently holds one of the group's selected values. Read-only: pick or clear it through the root's value."},{name:"effectiveDisabled",type:"boolean",required:!1,frameworks:["webComponents"],exception:"wc-internals",frameworksReason:"Only the custom element publishes it. The other four hand this derived state down to their parts through context, so a consumer never reads it off a part; here every part is its own element with no such channel, and reading it back is the only way to reflect the state in surrounding markup.",description:"Whether this item is disabled, by its own disabled or by the root's. Read-only: it is the OR of the two."},{name:"value",type:"string",required:!0,description:"Unique identifier added to or removed from the group's value."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables this item alone. A disabled item is excluded from select-all: neither counted in the parent state nor changed when the parent is toggled."},{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."}],methods:[...e,t]},{name:"SelectAll",description:"The tri-state parent. Checked when all enabled items are checked, indeterminate when some are, unchecked when none are. Toggling checks all items or clears them (indeterminate resolves to checked). It carries no value and is never submitted. Carries aria-controls listing every item it governs so it is announced as the parent of the set, not as one more option.",props:[{name:"effectiveDisabled",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 the select-all control is disabled, by its own disabled or by the root's. Read-only: it is the OR of the two."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the parent alone; the group-level disabled also disables it."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the select-all control; the data-size attribute may be set directly instead."}],methods:[...e,t]}],slots:[{name:"default",description:"CheckboxGroupItem children and an optional CheckboxGroupSelectAll."},{name:"select-all",description:"The SelectAll label, for a group derived from `options`; its content becomes the parent's accessible name."}],states:["default","disabled","readonly","invalid"],controlledUncontrolled:"Controlled via value + the value-change event, or uncontrolled via defaultValue. Passing value switches to controlled \u2014 the consumer owns the array and must update it from value-change.",formBehavior:'With a name, submits one entry per checked value (formData.getAll(name) returns every checked value). React/Vue/Svelte/Angular use a hidden <input type="checkbox"> per item; Web Components uses ElementInternals.multiFormValue(). Select-all parent is never submitted.',validationBehavior:`required means "at least one checked", which native constraint validation cannot express. Outside Web Components, required only sets aria-required on items and produces **no browser validation message at all**; Web Components reports valueMissing via ElementInternals. Wrap in Fieldset to get a browser message. This caveat is repeated in every package's own public TSDoc. invalid is a presentational flag.`,accessibility:{role:"group",keyboard:[{key:"Tab",behavior:"Moves to the next checkbox \u2014 every item is its own tab stop, as with native checkboxes."},{key:"Space",behavior:"Toggles the focused item, or the select-all parent."},{key:"Enter",behavior:'Suppressed, matching native <input type="checkbox">.'}],ariaAttributes:['aria-invalid reflects invalid on the root \u2014 it and aria-disabled are the only global ARIA attributes, so they are the only ones role="group" may carry','each item exposes aria-required while the group is required \u2014 role="checkbox" supports it and role="group" does not, the same split a segmented field makes between its group root and its spinbuttons',"each item exposes aria-readonly while the group is readOnly, on the same split and for the same reason; the root carries only data-readonly, and nothing carries aria-disabled","each item exposes aria-checked",'the select-all parent exposes aria-checked="mixed" while only some items are checked',"the select-all parent exposes aria-controls listing every item id it governs \u2014 without it the parent is announced as an indistinguishable fifth option in a four-option group",'while max is reached, every unchecked item exposes aria-disabled="true" without the native disabled attribute, so it can still be focused and heard'],focusManagement:"No roving tabindex. Each item is its own tab stop, unlike a radio group.",namingRequirement:'Requires a group name \u2014 a wrapping Fieldset or aria-label/aria-labelledby on the group root. Every item and the select-all parent need their own name (role="checkbox" takes its name from content).'},styling:{cssParts:["checkbox-group","item","item-label","select-all"],dataAttributes:[...r,"data-disabled","data-readonly","data-invalid","data-value","data-state","data-max-reached","data-size","data-skdx-checkbox-group-item",{name:"data-skdx-checkbox-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.'},{name:"data-skdx-checkbox-group-item-indicator-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.'},"data-skdx-checkbox-group-item-default-indicator"],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{s as checkboxGroupContract};
1
+ import{changeDetail as r}from"./change-reason.js";import{constraintValidationMethods as e,setCustomValidityMethod as t}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as n}from"./styling-hooks.js";var s={name:"CheckboxGroup",purpose:"A multi-selection group owning a string[] value, with group-level disabled/required/invalid and optional tri-state select-all parent.",props:[{name:"value",type:"string[]",required:!1,description:"Checked item values, for controlled usage."},{name:"defaultValue",type:"string[]",defaultValue:"[]",required:!1,description:"Initially checked item values, for uncontrolled usage. Vue spells this default as the factory `() => []` rather than the literal, because Vue props with object/array defaults must be factories. The two say the same thing."},{name:"name",type:"string",required:!1,description:"Name under which the checked values are submitted \u2014 one entry per checked value, so formData.getAll(name) returns them all."},{name:"form",type:"string",required:!1,description:"Id of the <form> that owns this group, for a group rendered outside it. Forwarded to every item's hidden input (React/Vue/Svelte/Angular) or set on the element (<skdx-checkbox-group>)."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:'Marks the group as required \u2014 at least one item must be checked. Exposed as aria-required on every item (role="group" does not support it).'},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables every item in the group, and the select-all parent."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:'Freezes the selection. Items and parent stay focusable and tabstoppable; each gains aria-readonly="true". role="group" does not allow it on the root, so the root carries only data-readonly. Space and click change nothing, value-change never fires. Nothing gains aria-disabled. Same model as Checkbox.'},{name:"max",type:"number",required:!1,description:'Caps how many items may be checked. Unchecked items gain aria-disabled="true" and data-max-reached but keeps its tab stop (native disabled attribute is deliberately not used; disabling mid-interaction would steal focus).'},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Marks the group as invalid, exposed as aria-invalid/data-invalid on the group root."},{name:"options",type:"ReadonlyArray<{ value: string; label: string; disabled?: boolean }>",required:!1,description:"The checkboxes the group derives (one Item per entry, keyed by value). Flat only \u2014 no option groups. Hand composition takes precedence."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Size rung forwarded to every derived Item's and the SelectAll control's data-size; either attribute may be written directly instead."}],events:[{name:"value-change",description:"Fires with the new value array whenever an item \u2014 or the select-all parent \u2014 changes the selection.",detail:r("string[]","selectedValue: string | null")}],parts:[{name:"Item",description:'One checkbox in the group. Renders the framework\'s Checkbox with `role="checkbox"`, aria-checked, data-state, data-disabled, plus data-value and the item marker. Toggling adds/removes its value from the group. Each item is its own tab stop.',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 item currently holds one of the group's selected values. Read-only: pick or clear it through the root's value."},{name:"effectiveDisabled",type:"boolean",required:!1,frameworks:["webComponents"],exception:"wc-internals",frameworksReason:"Only the custom element publishes it. The other four hand this derived state down to their parts through context, so a consumer never reads it off a part; here every part is its own element with no such channel, and reading it back is the only way to reflect the state in surrounding markup.",description:"Whether this item is disabled, by its own disabled or by the root's. Read-only: it is the OR of the two."},{name:"value",type:"string",required:!0,description:"Unique identifier added to or removed from the group's value."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables this item alone. A disabled item is excluded from select-all: neither counted in the parent state nor changed when the parent is toggled."},{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."}],methods:[...e,t]},{name:"SelectAll",description:"The tri-state parent. Checked when all enabled items are checked, indeterminate when some are, unchecked when none are. Toggling checks all items or clears them (indeterminate resolves to checked). It carries no value and is never submitted. Carries aria-controls listing every item it governs so it is announced as the parent of the set, not as one more option.",props:[{name:"effectiveDisabled",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 the select-all control is disabled, by its own disabled or by the root's. Read-only: it is the OR of the two."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the parent alone; the group-level disabled also disables it."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the select-all control; the data-size attribute may be set directly instead."}],methods:[...e,t],slots:[{name:"default",description:"The SelectAll label, for a group derived from `options`; its content becomes the parent's accessible name."}]}],slots:[{name:"default",description:"CheckboxGroupItem children and an optional CheckboxGroupSelectAll."},{name:"select-all",description:"The SelectAll label, for a group derived from `options`; its content becomes the parent's accessible name.",frameworks:["webComponents"],exception:"derived-anatomy",frameworksReason:"The root exposes select-all as content projection in webComponents. Other wrappers project default content into the SelectAll part or use their separately documented rendering property; they do not accept a root named slot with this spelling."}],states:["default","disabled","readonly","invalid"],controlledUncontrolled:"Controlled via value + the value-change event, or uncontrolled via defaultValue. Passing value switches to controlled \u2014 the consumer owns the array and must update it from value-change.",formBehavior:'With a name, submits one entry per checked value (formData.getAll(name) returns every checked value). React/Vue/Svelte/Angular use a hidden <input type="checkbox"> per item; Web Components uses ElementInternals.multiFormValue(). Select-all parent is never submitted.',validationBehavior:`required means "at least one checked", which native constraint validation cannot express. Outside Web Components, required only sets aria-required on items and produces **no browser validation message at all**; Web Components reports valueMissing via ElementInternals. Wrap in Fieldset to get a browser message. This caveat is repeated in every package's own public TSDoc. invalid is a presentational flag.`,accessibility:{role:"group",keyboard:[{key:"Tab",behavior:"Moves to the next checkbox \u2014 every item is its own tab stop, as with native checkboxes."},{key:"Space",behavior:"Toggles the focused item, or the select-all parent."},{key:"Enter",behavior:'Suppressed, matching native <input type="checkbox">.'}],ariaAttributes:['aria-invalid reflects invalid on the root \u2014 it and aria-disabled are the only global ARIA attributes, so they are the only ones role="group" may carry','each item exposes aria-required while the group is required \u2014 role="checkbox" supports it and role="group" does not, the same split a segmented field makes between its group root and its spinbuttons',"each item exposes aria-readonly while the group is readOnly, on the same split and for the same reason; the root carries only data-readonly, and nothing carries aria-disabled","each item exposes aria-checked",'the select-all parent exposes aria-checked="mixed" while only some items are checked',"the select-all parent exposes aria-controls listing every item id it governs \u2014 without it the parent is announced as an indistinguishable fifth option in a four-option group",'while max is reached, every unchecked item exposes aria-disabled="true" without the native disabled attribute, so it can still be focused and heard'],focusManagement:"No roving tabindex. Each item is its own tab stop, unlike a radio group.",namingRequirement:'Requires a group name \u2014 a wrapping Fieldset or aria-label/aria-labelledby on the group root. Every item and the select-all parent need their own name (role="checkbox" takes its name from content).'},styling:{cssParts:["checkbox-group","item","item-label","select-all"],dataAttributes:[...n,"data-disabled","data-readonly","data-invalid","data-value","data-state","data-max-reached","data-size","data-skdx-checkbox-group-item",{name:"data-skdx-checkbox-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.'},{name:"data-skdx-checkbox-group-item-indicator-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.'},"data-skdx-checkbox-group-item-default-indicator"],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."},{framework:"react",part:"Item",name:"indicator",type:"React.ReactNode",description:"Renders a derived `CheckboxIndicator` holding this content in place of the default check glyph, ignored when `children` is given. This wrapper receives projected content as a render prop, Snippet or TemplateRef. Other wrappers supply the matching named slot or default content of the composed part; the property is framework rendering syntax.",kind:"prop"},{framework:"svelte",part:"Item",name:"indicator",type:"Snippet | undefined",description:"Content rendered inside the derived indicator, e.g. a custom check icon,\nignored while `children` is given. This wrapper receives projected content as a render prop, Snippet or TemplateRef. Other wrappers supply the matching named slot or default content of the composed part; the property is framework rendering syntax.",kind:"prop"},{framework:"angular",part:"Item",name:"indicator",type:"TemplateRef<unknown>",description:"Content drawn into a derived Indicator, when deriving from no content. This wrapper receives projected content as a render prop, Snippet or TemplateRef. Other wrappers supply the matching named slot or default content of the composed part; the property is framework rendering syntax.",kind:"prop"},{framework:"vue",part:"Item",kind:"slot",name:"indicator",type:"Content projection",description:"indicator content projected by CheckboxGroupItem. This framework spells the content customization as a native named slot/snippet on this part; consumers of other wrappers compose the corresponding part or use their documented rendering property."},{framework:"svelte",part:"Item",kind:"slot",name:"indicator",type:"Content projection",description:"Content rendered inside the derived indicator, e.g. a custom check icon,\nignored while `children` is given. This framework spells the content customization as a native named slot/snippet on this part; consumers of other wrappers compose the corresponding part or use their documented rendering property."},{framework:"webComponents",kind:"method",name:"getSelectAllChecked",type:"() => SkdxCheckedState",description:"The tri-state the `<skdx-checkbox-group-select-all>` parent renders. Web Components exposes this documented state/action on its element for native JavaScript and composed elements. Other wrappers coordinate their parts through context, injected state or callback props; this instance helper is separate from the common interaction contract."},{framework:"webComponents",kind:"method",name:"getSelectedValues",type:"() => string[]",description:"The currently checked values, resolving controlled vs. uncontrolled. Web Components exposes this documented state/action on its element for native JavaScript and composed elements. Other wrappers coordinate their parts through context, injected state or callback props; this instance helper is separate from the common interaction contract."},{framework:"webComponents",kind:"method",name:"toggleAll",type:"() => void",description:"Checks every enabled item, or clears them all when they already are. Web Components exposes this documented state/action on its element for native JavaScript and composed elements. Other wrappers coordinate their parts through context, injected state or callback props; this instance helper is separate from the common interaction contract."},{framework:"webComponents",kind:"method",name:"toggleItem",type:"(itemValue: string, checked: boolean) => void",description:"Adds or removes one item's value, firing `value-change`, guarded both ways so a no-op selection change fires nothing. Web Components exposes this documented state/action on its element for native JavaScript and composed elements. Other wrappers coordinate their parts through context, injected state or callback props; this instance helper is separate from the common interaction contract."},{framework:"react",part:"SelectAll",name:"indicator",type:"React.ReactNode",description:"Renders a derived `CheckboxIndicator` holding this content in place of the default check glyph, ignored when `children` is given. This wrapper receives projected content as a render prop, Snippet or TemplateRef. Other wrappers supply the matching named slot or default content of the composed part; the property is framework rendering syntax.",kind:"prop"},{framework:"svelte",part:"SelectAll",name:"indicator",type:"Snippet | undefined",description:"Content rendered inside the derived indicator, e.g. a custom check icon,\nignored while `children` is given. This wrapper receives projected content as a render prop, Snippet or TemplateRef. Other wrappers supply the matching named slot or default content of the composed part; the property is framework rendering syntax.",kind:"prop"},{framework:"angular",part:"SelectAll",name:"indicator",type:"TemplateRef<unknown>",description:"Content drawn into a derived Indicator, when deriving from no content. This wrapper receives projected content as a render prop, Snippet or TemplateRef. Other wrappers supply the matching named slot or default content of the composed part; the property is framework rendering syntax.",kind:"prop"},{framework:"vue",part:"SelectAll",kind:"slot",name:"indicator",type:"Content projection",description:"indicator content projected by CheckboxGroupSelectAll. This framework spells the content customization as a native named slot/snippet on this part; consumers of other wrappers compose the corresponding part or use their documented rendering property."},{framework:"svelte",part:"SelectAll",kind:"slot",name:"indicator",type:"Content projection",description:"Content rendered inside the derived indicator, e.g. a custom check icon,\nignored while `children` is given. This framework spells the content customization as a native named slot/snippet on this part; consumers of other wrappers compose the corresponding part or use their documented rendering property."},{framework:"react",part:"Item",name:"indicator",type:"React.ReactNode",description:"Renders a derived `CheckboxIndicator` holding this content in place of the default check glyph, ignored when `children` is given. This wrapper receives projected content as a render prop, Snippet or TemplateRef. Other wrappers supply the matching named slot or default content of the composed part; the property is framework rendering syntax."},{framework:"svelte",part:"Item",name:"indicator",type:"Snippet | undefined",description:"Content rendered inside the derived indicator, e.g. a custom check icon,\nignored while `children` is given. This wrapper receives projected content as a render prop, Snippet or TemplateRef. Other wrappers supply the matching named slot or default content of the composed part; the property is framework rendering syntax."},{framework:"angular",part:"Item",name:"indicator",type:"TemplateRef<unknown>",description:"Content drawn into a derived Indicator, when deriving from no content. This wrapper receives projected content as a render prop, Snippet or TemplateRef. Other wrappers supply the matching named slot or default content of the composed part; the property is framework rendering syntax."},{framework:"vue",part:"Item",kind:"slot",name:"indicator",type:"Content projection",description:"indicator content projected by CheckboxGroupItem. This framework spells the content customization as a native named slot/snippet on this part; consumers of other wrappers compose the corresponding part or use their documented rendering property."},{framework:"svelte",part:"Item",kind:"slot",name:"indicator",type:"Content projection",description:"Content rendered inside the derived indicator, e.g. a custom check icon,\nignored while `children` is given. This framework spells the content customization as a native named slot/snippet on this part; consumers of other wrappers compose the corresponding part or use their documented rendering property."},{framework:"webComponents",kind:"method",name:"getSelectAllChecked",type:"() => SkdxCheckedState",description:"The tri-state the `<skdx-checkbox-group-select-all>` parent renders. Web Components exposes this documented state/action on its element for native JavaScript and composed elements. Other wrappers coordinate their parts through context, injected state or callback props; this instance helper is separate from the common interaction contract."},{framework:"webComponents",kind:"method",name:"getSelectedValues",type:"() => string[]",description:"The currently checked values, resolving controlled vs. uncontrolled. Web Components exposes this documented state/action on its element for native JavaScript and composed elements. Other wrappers coordinate their parts through context, injected state or callback props; this instance helper is separate from the common interaction contract."},{framework:"webComponents",kind:"method",name:"toggleAll",type:"() => void",description:"Checks every enabled item, or clears them all when they already are. Web Components exposes this documented state/action on its element for native JavaScript and composed elements. Other wrappers coordinate their parts through context, injected state or callback props; this instance helper is separate from the common interaction contract."},{framework:"webComponents",kind:"method",name:"toggleItem",type:"(itemValue: string, checked: boolean) => void",description:"Adds or removes one item's value, firing `value-change`, guarded both ways so a no-op selection change fires nothing. Web Components exposes this documented state/action on its element for native JavaScript and composed elements. Other wrappers coordinate their parts through context, injected state or callback props; this instance helper is separate from the common interaction contract."},{framework:"react",part:"SelectAll",name:"indicator",type:"React.ReactNode",description:"Renders a derived `CheckboxIndicator` holding this content in place of the default check glyph, ignored when `children` is given. This wrapper receives projected content as a render prop, Snippet or TemplateRef. Other wrappers supply the matching named slot or default content of the composed part; the property is framework rendering syntax."},{framework:"svelte",part:"SelectAll",name:"indicator",type:"Snippet | undefined",description:"Content rendered inside the derived indicator, e.g. a custom check icon,\nignored while `children` is given. This wrapper receives projected content as a render prop, Snippet or TemplateRef. Other wrappers supply the matching named slot or default content of the composed part; the property is framework rendering syntax."},{framework:"angular",part:"SelectAll",name:"indicator",type:"TemplateRef<unknown>",description:"Content drawn into a derived Indicator, when deriving from no content. This wrapper receives projected content as a render prop, Snippet or TemplateRef. Other wrappers supply the matching named slot or default content of the composed part; the property is framework rendering syntax."},{framework:"vue",part:"SelectAll",kind:"slot",name:"indicator",type:"Content projection",description:"indicator content projected by CheckboxGroupSelectAll. This framework spells the content customization as a native named slot/snippet on this part; consumers of other wrappers compose the corresponding part or use their documented rendering property."},{framework:"svelte",part:"SelectAll",kind:"slot",name:"indicator",type:"Content projection",description:"Content rendered inside the derived indicator, e.g. a custom check icon,\nignored while `children` is given. This framework spells the content customization as a native named slot/snippet on this part; consumers of other wrappers compose the corresponding part or use their documented rendering property."}]};export{s as checkboxGroupContract};
@@ -1 +1 @@
1
- import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var n={name:"Collapsible",purpose:"A show/hide interface. The root owns open state and hands it to a trigger button and content panel via context.",props:[{name:"open",type:"boolean",required:!1,description:"Open state, for controlled usage. Pair with an open-change event."},{name:"defaultOpen",type:"boolean",defaultValue:"false",required:!1,description:"Initial open state, for uncontrolled usage. Not in Web Components \u2014 `open` as a reflected property is the custom-element idiom; a `default-open` attribute would create two sources of truth.",frameworks:["react","vue","svelte","angular"],exception:"wc-default",frameworksReason:"Web Components idiom: `open` is a reflected property, not a `default-open` attribute."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Prevents the trigger from toggling the content."},{name:"title",type:"string",required:!1,description:"The trigger's copy, which derives a Trigger part above the panel. Absent prop, absent element. Consumer-authored Trigger wins the derived one. On Web Components this shadows `HTMLElement.title` (browser tooltip)."}],events:[{name:"open-change",description:"Fires with the new open state whenever it changes.",detail:"boolean"},{name:"open-change-complete",description:"Fires with settled open state once the content panel finishes transitioning \u2014 on transitionend or synchronously when no transition is running.",detail:"{ open: boolean }"}],parts:[{name:"Trigger",description:"The button that toggles the panel. Carries aria-expanded, aria-controls and data-state, and forwards its disabled state from the root.",props:[]},{name:"Content",description:"The panel revealed when open. Unmounted while closed unless forceMount or hiddenUntilFound is set. Always carries measured size custom properties.",props:[{name:"forceMount",type:"boolean",defaultValue:"false",required:!1,frameworks:["react","vue","svelte","angular"],exception:"force-mount",frameworksReason:"Web Components satisfy this vacuously \u2014 markup content is never unmounted, only hidden via the hidden attribute.",description:'Keep the panel mounted while closed, hidden via hidden="". For exit animations or to preserve panel state. Web Components satisfy this vacuously \u2014 markup is never unmounted.'},{name:"hiddenUntilFound",type:"boolean",defaultValue:"false",required:!1,description:'Keep panel mounted as hidden="until-found" for browser find-in-page search. Opens on beforematch event to keep aria-expanded/data-state truthful. Implies forceMount.'}]},{name:"Indicator",description:"The disclosure affordance inside the trigger \u2014 chevron or caret. A <span> carrying data-state so the skin can rotate it. No glyph of its own \u2014 the icon is the consumer's child.",props:[]}],slots:[{name:"default",description:"Root content \u2014 typically a trigger and a content panel."},{name:"trigger",description:"CollapsibleTrigger's content \u2014 the toggle button."},{name:"content",description:"CollapsibleContent's content \u2014 the revealed panel."},{name:"indicator",description:"CollapsibleIndicator's content \u2014 the chevron or caret glyph."}],states:["open","closed"],controlledUncontrolled:"Supports both: `open` for controlled, `defaultOpen` for uncontrolled.",formBehavior:"Not applicable \u2014 Collapsible does not participate in forms.",validationBehavior:"Not applicable \u2014 Collapsible carries no value and participates in no validation.",accessibility:{role:"generic root; trigger is a native button",keyboard:[{key:"Enter",behavior:"Toggles the panel and fires exactly one open-change, via native <button> activation."},{key:"Space",behavior:"Toggles the panel and fires exactly one open-change, identically to Enter. Listed separately because a trigger that is not a native button gets Enter for free and Space only if something implements it."}],ariaAttributes:["trigger's aria-controls points at the content's id (only while content is in DOM; default: unmounted while closed)","trigger's aria-expanded reflects open state"],focusManagement:"Does not move focus on toggle."},styling:{cssParts:["root","trigger","content","indicator"],dataAttributes:[...e,"data-state","data-disabled",{name:"data-skdx-collapsible-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-collapsible-content-height","--skdx-collapsible-content-width"]},publicMethods:[{name:"setOpen",signature:"(next: boolean) => void",description:"Sets open and fires open-change; setting the prop directly is the equivalent declarative path.",frameworks:["webComponents"],exception:"imperative",frameworksReason:"Custom elements have no props; the trigger reaches its root through closest() and needs something to call."}]};export{n as collapsibleContract};
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var o={name:"Collapsible",purpose:"A show/hide interface. The root owns open state and hands it to a trigger button and content panel via context.",props:[{name:"open",type:"boolean",required:!1,description:"Open state, for controlled usage. Pair with an open-change event."},{name:"defaultOpen",type:"boolean",defaultValue:"false",required:!1,description:"Initial open state, for uncontrolled usage. Not in Web Components \u2014 `open` as a reflected property is the custom-element idiom; a `default-open` attribute would create two sources of truth.",frameworks:["react","vue","svelte","angular"],exception:"wc-default",frameworksReason:"Web Components idiom: `open` is a reflected property, not a `default-open` attribute."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Prevents the trigger from toggling the content."},{name:"title",type:"string",required:!1,description:"The trigger's copy, which derives a Trigger part above the panel. Absent prop, absent element. Consumer-authored Trigger wins the derived one. On Web Components this shadows `HTMLElement.title` (browser tooltip)."}],events:[{name:"open-change",description:"Fires with the new open state whenever it changes.",detail:"boolean"},{name:"open-change-complete",description:"Fires with settled open state once the content panel finishes transitioning \u2014 on transitionend or synchronously when no transition is running.",detail:"{ open: boolean }"}],parts:[{name:"Trigger",description:"The button that toggles the panel. Carries aria-expanded, aria-controls and data-state, and forwards its disabled state from the root.",props:[],slots:[{name:"default",description:"CollapsibleTrigger's content \u2014 the toggle button."}]},{name:"Content",description:"The panel revealed when open. Unmounted while closed unless forceMount or hiddenUntilFound is set. Always carries measured size custom properties.",props:[{name:"forceMount",type:"boolean",defaultValue:"false",required:!1,frameworks:["react","vue","svelte","angular"],exception:"force-mount",frameworksReason:"Web Components satisfy this vacuously \u2014 markup content is never unmounted, only hidden via the hidden attribute.",description:'Keep the panel mounted while closed, hidden via hidden="". For exit animations or to preserve panel state. Web Components satisfy this vacuously \u2014 markup is never unmounted.'},{name:"hiddenUntilFound",type:"boolean",defaultValue:"false",required:!1,description:'Keep panel mounted as hidden="until-found" for browser find-in-page search. Opens on beforematch event to keep aria-expanded/data-state truthful. Implies forceMount.'}],slots:[{name:"default",description:"CollapsibleContent's content \u2014 the revealed panel."}]},{name:"Indicator",description:"The disclosure affordance inside the trigger \u2014 chevron or caret. A <span> carrying data-state so the skin can rotate it. No glyph of its own \u2014 the icon is the consumer's child.",props:[],slots:[{name:"default",description:"CollapsibleIndicator's content \u2014 the chevron or caret glyph."}]}],slots:[{name:"default",description:"Root content \u2014 typically a trigger and a content panel."},{name:"trigger",description:"CollapsibleTrigger's content \u2014 the toggle button.",frameworks:["vue"],exception:"derived-anatomy",frameworksReason:"Vue spells this root projection trigger; the other wrappers compose Trigger with default content or use the documented rendering callback instead of that named slot."},{name:"content",description:"CollapsibleContent's content \u2014 the revealed panel.",frameworks:["vue"],exception:"derived-anatomy",frameworksReason:"The root exposes content as content projection in vue. Other wrappers project default content into the Content part or use their separately documented rendering property; they do not accept a root named slot with this spelling."},{name:"indicator",description:"CollapsibleIndicator's content \u2014 the chevron or caret glyph.",frameworks:["vue"],exception:"derived-anatomy",frameworksReason:"The root exposes indicator as content projection in vue. Other wrappers project default content into the Indicator part or use their separately documented rendering property; they do not accept a root named slot with this spelling."}],states:["open","closed"],controlledUncontrolled:"Supports both: `open` for controlled, `defaultOpen` for uncontrolled.",formBehavior:"Not applicable \u2014 Collapsible does not participate in forms.",validationBehavior:"Not applicable \u2014 Collapsible carries no value and participates in no validation.",accessibility:{role:"generic root; trigger is a native button",keyboard:[{key:"Enter",behavior:"Toggles the panel and fires exactly one open-change, via native <button> activation."},{key:"Space",behavior:"Toggles the panel and fires exactly one open-change, identically to Enter. Listed separately because a trigger that is not a native button gets Enter for free and Space only if something implements it."}],ariaAttributes:["trigger's aria-controls points at the content's id (only while content is in DOM; default: unmounted while closed)","trigger's aria-expanded reflects open state"],focusManagement:"Does not move focus on toggle."},styling:{cssParts:["root","trigger","content","indicator"],dataAttributes:[...e,"data-state","data-disabled",{name:"data-skdx-collapsible-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-collapsible-content-height","--skdx-collapsible-content-width"]},publicMethods:[{name:"setOpen",signature:"(next: boolean) => void",description:"Sets open and fires open-change; setting the prop directly is the equivalent declarative path.",frameworks:["webComponents"],exception:"imperative",frameworksReason:"Custom elements have no props; the trigger reaches its root through closest() and needs something to call."}]};export{o as collapsibleContract};
@@ -1 +1 @@
1
- import{changeDescription as i,changeDetail as e}from"./change-reason.js";import{constraintValidationMethods as r,setCustomValidityMethod as s}from"./form-validity.js";import{dismissalEvents as l,forceMountProp as t,openChangeCompleteEvent as d,popperContentProps as h,popperMeasurementProperties as u,portalPart as p,portalPropsSansForceMount as c}from"./overlay-parts.js";import{VIRTUAL_FOCUS_RULE as m}from"./rules.js";import{SELECTION_ATTRIBUTE_RULE as a,SELECTION_INPUT_RULE as n,SELECTION_OUTPUT_RULE as o}from"./selection-value.js";import{PART_DATA_ATTRIBUTES as f}from"./styling-hooks.js";var k={name:"Combobox",purpose:'An accessible text input with floating-ui-positioned listbox of options, following WAI-ARIA 1.2 "combobox with list autocomplete". Real DOM focus stays on input; highlighted option is virtual focus (aria-activedescendant). Accepts options array or hand-composed Item/Group children; parts are the same either way.',props:[{name:"value",type:"string | string[]",required:!1,description:`Selected option value(s), for controlled usage. Pair with the value-change event. Distinct from inputValue, which is the draft text in the field. ${n} ${o} ${a}`},{name:"defaultValue",type:"string | string[]",required:!1,description:`Initially selected option value(s), for uncontrolled usage. Same shape as \`value\`. ${n} ${a}`},{name:"multiple",type:"boolean",defaultValue:"false",required:!1,description:'Allows multiple options selected at once. Does not change `value`/`defaultValue` shape \u2014 both take string | string[] and return string[]. Sets `aria-multiselectable="true"` on Content; toggling an option clears draft text and keeps listbox open so several can be picked in one pass.'},{name:"allowCustomValue",type:"boolean",defaultValue:"false",required:!1,description:'Lets Enter commit unmatched draft text as a value ("creatable"). Off by default; a combobox accepting unmatched text suits open sets, not closed ones.'},{name:"filter",type:"'manual' | ((itemText: string, inputValue: string) => boolean | number)",defaultValue:"'manual'",required:!1,description:"How Items are filtered against draft text. `'manual'` (default): consumer renders only matching Items. A predicate moves filtering inside: every Item is measured (`textValue` or rendered text), rejected ones stop being options. Returns boolean to filter or number to rank (0 excludes, positive keeps and orders by score). With `options` supplied and no `filter`, a case-insensitive text match narrows the derived list. On `<skdx-combobox>` this is **property-only** (`el.filter = \u2026`): attributes carry strings, not predicates."},{name:"autoHighlight",type:"boolean",defaultValue:"false",required:!1,description:"Keeps first option highlighted when filtered list changes while open. Off by default; it commits an option the user never pointed at, which is wrong when draft text alone is valid."},{name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Wraps arrow navigation around option list ends. On by default; set `false` to clamp at ends. Home/End always jump to an end regardless."},{name:"openOn",type:"'type' | 'click' | 'focus'",defaultValue:"'type'",required:!1,description:"Which pointer/focus gesture opens the listbox, **on top of** keyboard ones (ArrowDown/ArrowUp and typing always open). `'type'` (default): list appears after typing. `'click'`: also opens on field click. `'focus'`: also opens on Tab; most eager for a search box, but unwanted in form rows. Does not open a `disabled` or `readOnly` combobox."},{name:"loading",type:"boolean",defaultValue:"false",required:!1,description:'Marks results as in flight, exposed as `aria-busy="true"` plus `data-loading` on Input and Content. Also suppresses the result-count announcement, since a count measured mid-fetch would announce "0 results available" for every request.'},{name:"inputValue",type:"string",required:!1,description:"The input's controlled draft text. Pair it with the input-value-change event and render only the Items that match it: with `filter` left `'manual'` the component filters nothing, so this prop *is* the filtering mechanism rather than a common use of it."},{name:"defaultInputValue",type:"string",defaultValue:"''",required:!1,description:"Initial draft text, for uncontrolled usage."},{name:"open",type:"boolean",required:!1,description:"Controlled open state. Pair with the open-change event."},{name:"defaultOpen",type:"boolean",defaultValue:"false",required:!1,description:"Initial open state, for uncontrolled usage."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Marks the combobox as invalid, exposed as aria-invalid/data-invalid on Input."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:"Makes Input read-only, exposed as the native readonly attribute plus aria-readonly/data-readonly."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables Input and prevents opening the listbox. Distinct from readOnly, which still allows focus and selection of the existing text."},{name:"name",type:"string",required:!1,description:"Form field name. The selected value \u2014 not the draft inputValue \u2014 is submitted under it; without it the combobox submits nothing."},{name:"form",type:"string | undefined",required:!1,defaultValue:"undefined",description:"Id of the `<form>` the combobox submits into; forwarded to every mirrored control. Needs `name` to have an effect. A `multiple` combobox reaches every mirrored control so the whole selection stays associated with the same form. Web Components names this `formId`, not `form`: the element already publishes a readonly `form` accessor."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Marks the combobox required. valueMissing while no option is selected."},{name:"getResultCountLabel",type:"(count: number) => string",defaultValue:"defaultGetResultCountLabel",required:!1,description:'Formats the message announced through the LiveAnnouncer whenever rendered Items count changes while the listbox is open, reaching screen-reader users. Return an empty string to announce nothing. The default **singularises**: `"1 result available"` for count 1, `"3 results available"` otherwise. Property-only on `<skdx-combobox>`, like `filter`: attributes cannot carry functions.'},{name:"options",type:"Array<{ value: string; label?: string; disabled?: boolean } | { label: string; options: Array<{ value: string; label?: string; disabled?: boolean }> }>",required:!1,description:"Declares the option collection as data instead of hand-composed Item/Group children, and the derived Content renders Item/Group/GroupLabel from it. A flat entry is a plain option; an entry carrying its own `options` array is a group, labelled by its `label`. Filtered by `filter` exactly like hand-composed Items. Property-only on `<skdx-combobox>` (`@property({ attribute: false })`): an array of objects has no attribute form."},{name:"renderOption",type:"(option: ComboboxOptionData, state: { selected: boolean }) => ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:'Web Components uses named light-DOM slot (`slot="option"`, keyed by `data-value`), the platform-native form; Vue uses scoped slot (`#option`). Both are that framework.s own idiom for the same hook.',description:"Custom rendering for an `options`-derived Item, given the option data and selection state. Angular uses `TemplateRef` instead of a function. Ignored for hand-composed Item children."},{name:"placeholder",type:"string",required:!1,description:"Placeholder text forwarded to the derived Input. Ignored under full manual composition."},{name:"aria-label",type:"string",required:!1,frameworks:["react","vue","svelte","angular"],exception:"attribute-passthrough",frameworksReason:"React forwards `aria-label`; Vue/Svelte declare it (`ariaLabel`); Angular takes `ariaLabel`. Derived name is `aria-label ?? placeholder` in all five. Web Components claims the native attribute off the host and relocates it to the derived control (platform mechanism, invisible to extractor).",description:"Convenience accessible name for the derived Input, and for Content/List, neither of which takes a name from its content. Equivalent to naming Input directly under manual composition."},{name:"clearable",frameworks:["angular","svelte"],exception:"derived-anatomy",frameworksReason:"Angular and Svelte fold the Clear part into their derived anatomy behind this switch. React, Vue and Web Components publish the same part for the consumer to place by hand, so the prop would only restate what writing the part already says.",type:"boolean",defaultValue:"false",required:!1,description:"Whether the derived anatomy renders a Clear button that empties the selection and draft text in one action. Off by default, matching the existing Clear part being opt-in under manual composition."},{name:"emptyMessage",frameworks:["angular","svelte"],exception:"derived-anatomy",frameworksReason:"Angular and Svelte fold the Empty part into their derived anatomy behind this switch. React, Vue and Web Components publish the same part for the consumer to place by hand, so the prop would only restate what writing the part already says.",type:"string",required:!1,description:"Content for the derived Empty part, shown when no Items are rendered. Where this prop is absent the package instead renders a hardcoded, unoverridable placeholder string."},{name:"shape",type:"'rounded' | 'square' | (string & {})",required:!1,description:"Corner rounding rung forwarded to the Input's data-shape; the attribute may be written on Input directly instead."},{name:"size",type:"'md' | 'sm' | 'lg' | (string & {})",required:!1,description:"Size rung forwarded to the Input's data-size; the attribute may be written on Input directly instead."}],events:[{name:"value-change",description:`${i("the selection")} Carries the whole selection, not the single option that was toggled; \`selectedValue\` names that one. ${o}`,detail:e("string[]","selectedValue: string | null")},{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 selection, the change reason and the toggled option.",detail:e("string[]","selectedValue: string | null")},{name:"input-value-change",detail:"string",description:"Fires with the input's new draft text as the user types, or when a selection updates it, controlled or not."},{name:"open-change",detail:"boolean",description:"Fired with the new open state whenever it changes, controlled or not."},{name:"highlight-change",detail:"{ value: string | null; previousValue: string | null; reason: 'keyboard' | 'pointer' | 'auto' }",description:"Fires whenever virtual-focus changes, carrying the highlighted option value, replaced value, and what moved it. Read-only: no `highlight` or `defaultHighlight` prop exists. A programmatic highlight could name an unrendered option, making aria-activedescendant invalid \u2014 precisely the failure the re-pointing effect prevents. `value` is the option's **value**, never element id (generated per-render/framework). `null` is valid: closed listbox, empty result, or fresh draft with `autoHighlight` off. `reason` is **not** ChangeReason: `'auto'` covers filtering, re-seeding, and opening actions; no programmatic setter exists."},d("listbox"),...l("listbox")],parts:[{name:"Input",lightDom:!0,description:'The text field (role="combobox") driving filtering. Keeps real DOM focus; highlighted option is virtual focus via aria-activedescendant.',props:[{name:"shape",type:"'rounded' | 'square' | (string & {})",required:!1,description:"Corner rounding rung, written to data-shape on the input; the data-shape attribute may be set directly instead."},{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:"Trigger",lightDom:!0,description:'An optional button that toggles the listbox, for pointer users unsure a field filters. `<button type="button" tabindex="-1">` with aria-expanded and aria-controls naming Content. Not a Tab stop: real DOM focus must stay on Input, so the button cancels mousedown and returns focus on click. Needs aria-label or visible text (glyph alone is not a name).'},{name:"Clear",description:'An optional button that empties selection and draft text in one action and returns focus to Input. `<button type="button" tabindex="-1">`, natively disabled when nothing to clear or when root is disabled/readOnly. Cancels mousedown to keep DOM focus on Input. Needs aria-label or visible text. Clicking while the listbox is open also dismisses it.'},{...p,props:[...c,{...t,frameworks:["react","vue","svelte"],exception:"force-mount",frameworksReason:"Web Components never unmounts closed overlays (only hides them), so forceMount has no effect. Angular has no Portal part \u2014 it portals via [skdxPortal] directive instead."}]},{name:"Content",description:'The floating listbox (role="listbox", aria-multiselectable="true" while `multiple`). Positioned below and start-aligned, as an extension of Input.',props:[...h({align:"'start'",sideOffset:"4"}),{...t,frameworks:["react","vue","svelte"],exception:"force-mount",frameworksReason:"Web Components never unmounts closed overlays (only hides them). Angular keeps this part in the tree, toggled with [hidden], so neither ships forceMount."}]},{name:"Item",description:'One selectable option (role="option"). When a `filter` predicate rejects an Item, it becomes unreachable through aria-activedescendant, uncounted in result announcements, and invisible to the Empty part\'s emptiness check. Removed from DOM in React/Vue/Svelte/Angular; hides in Web Components (cannot un-author consumer tags).',props:[{name:"value",type:"string",required:!0,description:"Identifier committed to the root's value when this option is chosen."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Excludes this option from selection and from pointer/keyboard highlight; exposed as aria-disabled/data-disabled."},{name:"textValue",type:"string",required:!1,description:"Text the `filter` predicate matches and selection writes back into Input. Falls back to rendered text content, which is wrong only when the option renders more than its label (icon, secondary line) \u2014 supply it then."}]},{name:"Group",description:'A named section of related Items (role="group") whose aria-labelledby points at its GroupLabel. Named automatically: a filtered listbox reorders and empties sections as the user types, so structure announcement is critical. Purely structural \u2014 registers no options, not in highlight order.'},{name:"GroupLabel",description:"The heading that names a Group, carrying the id its Group points aria-labelledby at. No role, so it never becomes an option the arrow keys can reach. Must be inside a Group."},{name:"Empty",description:"Shown in place of the item list when no Items are rendered \u2014 because the consumer filtered them all away, or because the `filter` predicate rejected every one."}],slots:[{name:"default",description:"Content's body \u2014 Item/Group/Empty entries."}],appearance:[{attribute:"data-shape",values:["rounded","square"],stylesheet:"combobox.css"},{attribute:"data-size",values:["md","sm","lg"],stylesheet:"combobox.css"}],states:["closed","open","checked","unchecked","disabled","highlighted","loading","multiple"],controlledUncontrolled:"value, inputValue, and open each independently support controlled or uncontrolled usage. In Angular the pair is split: `valueChange` emits the scalar for `[(value)]`, `valueChangeDetail` carries the detail.",formBehavior:'Form-associated: with a name, the selected option\'s value (not draft inputValue) is submitted; a required Combobox with no selection is valueMissing. A `multiple` Combobox submits one entry per value under the same name (like `<select multiple>`), readable via `formData.getAll(name)`. An empty `multiple` selection submits nothing except when `required` (then one empty-valued control renders for valueMissing). Mirrored controls are never `type="hidden"` or `readonly` (both disable validation); only `disabled` withholds values. Form reset restores initial selection and draft text.',validationBehavior:"invalid toggles aria-invalid/data-invalid presentation only; required participates in native constraint validation via checkValidity()/reportValidity(). Web Components publishes `required-message` (a FormAssociated mixin convention), unavailable in the other four frameworks where setCustomValidity() on the mirrored input answers the same need.",accessibility:{role:"combobox (Input), button (Trigger, Clear), listbox (Content), option (Item), group (Group), presentation (Empty, GroupLabel)",keyboard:[{key:"Typing",behavior:"Updates the draft text and opens the listbox."},{key:"ArrowDown / ArrowUp",behavior:"Opens the listbox highlighting the first/last option, or moves the highlight by one when already open \u2014 wrapping around the ends unless `loop` is `false`."},{key:"Alt+ArrowDown",behavior:`Opens the listbox and highlights nothing \u2014 APG's optional "show me the list" key. The missing highlight is the whole difference from the plain key: it lets the options be inspected without Enter then committing one the user never pointed at. Prevents the default.`},{key:"Alt+ArrowUp",behavior:'Commits the highlighted option and closes the listbox \u2014 closing even while `multiple`, where an ordinary commit keeps it open, because this key means "I am done here" rather than "select this one". With nothing highlighted it only closes. Prevents the default.'},{key:"Home / End",behavior:"While the listbox is open, moves the highlight to the first/last option and prevents the default. While it is closed neither key is intercepted: they are the text field's caret keys, and APG requires an editable combobox to leave them to the field."},{key:"PageUp / PageDown",behavior:'Aliases of Home/End, on the same open-only condition. Deliberately not a fixed multi-row jump: "one page" presupposes a row height and a viewport height, and a listbox knows neither \u2014 the consumer styles both.'},{key:"Enter",behavior:"Commits the highlighted option as the selected value and closes the listbox \u2014 or toggles it and keeps the listbox open while `multiple`. With `allowCustomValue` and nothing highlighted, commits the draft text itself."},{key:"Escape",behavior:"Closes the listbox without changing the selection."}],ariaAttributes:['aria-expanded, aria-controls, aria-autocomplete="list", and aria-activedescendant on Input',"Content's id matches Input's aria-controls",'aria-multiselectable="true" on Content while `multiple` (absent otherwise, never "false")','aria-busy="true" and data-loading on Input and Content while `loading`',"aria-selected and data-state on Item reflecting selection; data-highlighted reflecting virtual focus","aria-disabled and data-disabled on a disabled item, which is skipped by highlight/selection","the number of rendered Items is announced through the shared LiveAnnouncer polite region while the listbox is open, formatted by getResultCountLabel \u2014 including after a `filter` predicate narrows the list, and suppressed while `loading`","aria-expanded on Trigger, plus an aria-controls resolving to Content exactly while the listbox is open and absent while it is closed, since a closed listbox is unmounted and an IDREF that resolves to nothing is worse than no IDREF. It mirrors what Input reports rather than replacing it \u2014 two elements may both point at one listbox, and neither takes aria-activedescendant, which stays on Input alone",'role="group" with an aria-labelledby resolving to the GroupLabel inside it on Group; tabindex="-1" on Trigger and Clear, which are affordances rather than tab stops'],focusManagement:`${m} Here the anchor is the Input. When typing filters the highlighted option away, the highlight moves to the first survivor rather than disappearing \u2014 aria-activedescendant is dropped only when no option is left. Virtual focus scrolls via scrollIntoView({ block: "nearest" }); the highlight set while the listbox is *opening* scrolls the listbox itself instead (floating-ui renders at document origin before measuring). Focus out reconciles draft text with selection unless allowCustomValue is set: inputValue becomes the selected option's text or empty string \u2014 ensuring no unmatched text remains. Escape stays non-destructive; it closes the listbox and leaves the draft alone.`,namingRequirement:'Input must be named by <label>, aria-label, or aria-labelledby; role="combobox" takes no name from content, and Content is a sibling, not ancestor. Wrapping in Field family satisfies this automatically. Trigger and Clear need aria-label or visible text (glyph alone is not a name). Group is named by its GroupLabel.'},styling:{cssParts:["input","trigger","clear","content","item","group","label","empty"],dataAttributes:[...f,"data-state","data-side","data-align","data-disabled","data-highlighted","data-invalid","data-readonly","data-loading","data-multiple","data-value","data-shape","data-size",{name:"data-skdx-combobox-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:u("combobox")},publicMethods:[...r,s,{name:"focus",signature:"(): void",description:"Moves keyboard focus to the text field, which is where the combobox keeps real DOM focus.",frameworks:["vue","webComponents"],exception:"element-handoff",frameworksReason:"Vue hides the Input inside the root component instance, and the custom element forwards focus() to it. React, Svelte and Angular hand the consumer the Input element itself."}]};export{k as comboboxContract};
1
+ import{changeDescription as i,changeDetail as e}from"./change-reason.js";import{constraintValidationMethods as r,setCustomValidityMethod as s}from"./form-validity.js";import{dismissalEvents as l,forceMountProp as t,openChangeCompleteEvent as d,popperContentProps as p,popperMeasurementProperties as h,portalPart as u,portalPropsSansForceMount as c}from"./overlay-parts.js";import{VIRTUAL_FOCUS_RULE as m}from"./rules.js";import{SELECTION_ATTRIBUTE_RULE as a,SELECTION_INPUT_RULE as n,SELECTION_OUTPUT_RULE as o}from"./selection-value.js";import{PART_DATA_ATTRIBUTES as f}from"./styling-hooks.js";var k={name:"Combobox",purpose:'An accessible text input with floating-ui-positioned listbox of options, following WAI-ARIA 1.2 "combobox with list autocomplete". Real DOM focus stays on input; highlighted option is virtual focus (aria-activedescendant). Accepts options array or hand-composed Item/Group children; parts are the same either way.',props:[{name:"value",type:"string | string[]",required:!1,description:`Selected option value(s), for controlled usage. Pair with the value-change event. Distinct from inputValue, which is the draft text in the field. ${n} ${o} ${a}`},{name:"defaultValue",type:"string | string[]",required:!1,description:`Initially selected option value(s), for uncontrolled usage. Same shape as \`value\`. ${n} ${a}`},{name:"multiple",type:"boolean",defaultValue:"false",required:!1,description:'Allows multiple options selected at once. Does not change `value`/`defaultValue` shape \u2014 both take string | string[] and return string[]. Sets `aria-multiselectable="true"` on Content; toggling an option clears draft text and keeps listbox open so several can be picked in one pass.'},{name:"allowCustomValue",type:"boolean",defaultValue:"false",required:!1,description:'Lets Enter commit unmatched draft text as a value ("creatable"). Off by default; a combobox accepting unmatched text suits open sets, not closed ones.'},{name:"filter",type:"'manual' | ((itemText: string, inputValue: string) => boolean | number)",defaultValue:"'manual'",required:!1,description:"How Items are filtered against draft text. `'manual'` (default): consumer renders only matching Items. A predicate moves filtering inside: every Item is measured (`textValue` or rendered text), rejected ones stop being options. Returns boolean to filter or number to rank (0 excludes, positive keeps and orders by score). With `options` supplied and no `filter`, a case-insensitive text match narrows the derived list. On `<skdx-combobox>` this is **property-only** (`el.filter = \u2026`): attributes carry strings, not predicates."},{name:"autoHighlight",type:"boolean",defaultValue:"false",required:!1,description:"Keeps first option highlighted when filtered list changes while open. Off by default; it commits an option the user never pointed at, which is wrong when draft text alone is valid."},{name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Wraps arrow navigation around option list ends. On by default; set `false` to clamp at ends. Home/End always jump to an end regardless."},{name:"openOn",type:"'type' | 'click' | 'focus'",defaultValue:"'type'",required:!1,description:"Which pointer/focus gesture opens the listbox, **on top of** keyboard ones (ArrowDown/ArrowUp and typing always open). `'type'` (default): list appears after typing. `'click'`: also opens on field click. `'focus'`: also opens on Tab; most eager for a search box, but unwanted in form rows. Does not open a `disabled` or `readOnly` combobox."},{name:"loading",type:"boolean",defaultValue:"false",required:!1,description:'Marks results as in flight, exposed as `aria-busy="true"` plus `data-loading` on Input and Content. Also suppresses the result-count announcement, since a count measured mid-fetch would announce "0 results available" for every request.'},{name:"inputValue",type:"string",required:!1,description:"The input's controlled draft text. Pair it with the input-value-change event and render only the Items that match it: with `filter` left `'manual'` the component filters nothing, so this prop *is* the filtering mechanism rather than a common use of it."},{name:"defaultInputValue",type:"string",defaultValue:"''",required:!1,description:"Initial draft text, for uncontrolled usage."},{name:"open",type:"boolean",required:!1,description:"Controlled open state. Pair with the open-change event."},{name:"defaultOpen",type:"boolean",defaultValue:"false",required:!1,description:"Initial open state, for uncontrolled usage."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Marks the combobox as invalid, exposed as aria-invalid/data-invalid on Input."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:"Makes Input read-only, exposed as the native readonly attribute plus aria-readonly/data-readonly."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables Input and prevents opening the listbox. Distinct from readOnly, which still allows focus and selection of the existing text."},{name:"name",type:"string",required:!1,description:"Form field name. The selected value \u2014 not the draft inputValue \u2014 is submitted under it; without it the combobox submits nothing."},{name:"form",type:"string | undefined",required:!1,defaultValue:"undefined",description:"Id of the `<form>` the combobox submits into; forwarded to every mirrored control. Needs `name` to have an effect. A `multiple` combobox reaches every mirrored control so the whole selection stays associated with the same form. Web Components names this `formId`, not `form`: the element already publishes a readonly `form` accessor."},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Marks the combobox required. valueMissing while no option is selected."},{name:"getResultCountLabel",type:"(count: number) => string",defaultValue:"defaultGetResultCountLabel",required:!1,description:'Formats the message announced through the LiveAnnouncer whenever rendered Items count changes while the listbox is open, reaching screen-reader users. Return an empty string to announce nothing. The default **singularises**: `"1 result available"` for count 1, `"3 results available"` otherwise. Property-only on `<skdx-combobox>`, like `filter`: attributes cannot carry functions.'},{name:"options",type:"Array<{ value: string; label?: string; disabled?: boolean } | { label: string; options: Array<{ value: string; label?: string; disabled?: boolean }> }>",required:!1,description:"Declares the option collection as data instead of hand-composed Item/Group children, and the derived Content renders Item/Group/GroupLabel from it. A flat entry is a plain option; an entry carrying its own `options` array is a group, labelled by its `label`. Filtered by `filter` exactly like hand-composed Items. Property-only on `<skdx-combobox>` (`@property({ attribute: false })`): an array of objects has no attribute form."},{name:"renderOption",type:"(option: ComboboxOptionData, state: { selected: boolean }) => ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:'Web Components uses named light-DOM slot (`slot="option"`, keyed by `data-value`), the platform-native form; Vue uses scoped slot (`#option`). Both are that framework.s own idiom for the same hook.',description:"Custom rendering for an `options`-derived Item, given the option data and selection state. Angular uses `TemplateRef` instead of a function. Ignored for hand-composed Item children."},{name:"placeholder",type:"string",required:!1,description:"Placeholder text forwarded to the derived Input. Ignored under full manual composition."},{name:"aria-label",type:"string",required:!1,frameworks:["react","vue","svelte","angular"],exception:"attribute-passthrough",frameworksReason:"React forwards `aria-label`; Vue/Svelte declare it (`ariaLabel`); Angular takes `ariaLabel`. Derived name is `aria-label ?? placeholder` in all five. Web Components claims the native attribute off the host and relocates it to the derived control (platform mechanism, invisible to extractor).",description:"Convenience accessible name for the derived Input, and for Content/List, neither of which takes a name from its content. Equivalent to naming Input directly under manual composition."},{name:"clearable",frameworks:["angular","svelte"],exception:"derived-anatomy",frameworksReason:"Angular and Svelte fold the Clear part into their derived anatomy behind this switch. React, Vue and Web Components publish the same part for the consumer to place by hand, so the prop would only restate what writing the part already says.",type:"boolean",defaultValue:"false",required:!1,description:"Whether the derived anatomy renders a Clear button that empties the selection and draft text in one action. Off by default, matching the existing Clear part being opt-in under manual composition."},{name:"emptyMessage",frameworks:["angular","svelte"],exception:"derived-anatomy",frameworksReason:"Angular and Svelte fold the Empty part into their derived anatomy behind this switch. React, Vue and Web Components publish the same part for the consumer to place by hand, so the prop would only restate what writing the part already says.",type:"string",required:!1,description:"Content for the derived Empty part, shown when no Items are rendered. Where this prop is absent the package instead renders a hardcoded, unoverridable placeholder string."},{name:"shape",type:"'rounded' | 'square' | (string & {})",required:!1,description:"Corner rounding rung forwarded to the Input's data-shape; the attribute may be written on Input directly instead."},{name:"size",type:"'md' | 'sm' | 'lg' | (string & {})",required:!1,description:"Size rung forwarded to the Input's data-size; the attribute may be written on Input directly instead."}],events:[{name:"value-change",description:`${i("the selection")} Carries the whole selection, not the single option that was toggled; \`selectedValue\` names that one. ${o}`,detail:e("string[]","selectedValue: string | null")},{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 selection, the change reason and the toggled option.",detail:e("string[]","selectedValue: string | null")},{name:"input-value-change",detail:"string",description:"Fires with the input's new draft text as the user types, or when a selection updates it, controlled or not."},{name:"open-change",detail:"boolean",description:"Fired with the new open state whenever it changes, controlled or not."},{name:"highlight-change",detail:"{ value: string | null; previousValue: string | null; reason: 'keyboard' | 'pointer' | 'auto' }",description:"Fires whenever virtual-focus changes, carrying the highlighted option value, replaced value, and what moved it. Read-only: no `highlight` or `defaultHighlight` prop exists. A programmatic highlight could name an unrendered option, making aria-activedescendant invalid \u2014 precisely the failure the re-pointing effect prevents. `value` is the option's **value**, never element id (generated per-render/framework). `null` is valid: closed listbox, empty result, or fresh draft with `autoHighlight` off. `reason` is **not** ChangeReason: `'auto'` covers filtering, re-seeding, and opening actions; no programmatic setter exists."},d("listbox"),...l("listbox")],parts:[{name:"Input",lightDom:!0,description:'The text field (role="combobox") driving filtering. Keeps real DOM focus; highlighted option is virtual focus via aria-activedescendant.',props:[{name:"shape",type:"'rounded' | 'square' | (string & {})",required:!1,description:"Corner rounding rung, written to data-shape on the input; the data-shape attribute may be set directly instead."},{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:"Trigger",lightDom:!0,description:'An optional button that toggles the listbox, for pointer users unsure a field filters. `<button type="button" tabindex="-1">` with aria-expanded and aria-controls naming Content. Not a Tab stop: real DOM focus must stay on Input, so the button cancels mousedown and returns focus on click. Needs aria-label or visible text (glyph alone is not a name).'},{name:"Clear",description:'An optional button that empties selection and draft text in one action and returns focus to Input. `<button type="button" tabindex="-1">`, natively disabled when nothing to clear or when root is disabled/readOnly. Cancels mousedown to keep DOM focus on Input. Needs aria-label or visible text. Clicking while the listbox is open also dismisses it.'},{...u,props:[...c,{...t,frameworks:["react","vue","svelte"],exception:"force-mount",frameworksReason:"Web Components never unmounts closed overlays (only hides them), so forceMount has no effect. Angular has no Portal part \u2014 it portals via [skdxPortal] directive instead."}]},{name:"Content",description:'The floating listbox (role="listbox", aria-multiselectable="true" while `multiple`). Positioned below and start-aligned, as an extension of Input.',props:[...p({align:"'start'",sideOffset:"4"}),{...t,frameworks:["react","vue","svelte"],exception:"force-mount",frameworksReason:"Web Components never unmounts closed overlays (only hides them). Angular keeps this part in the tree, toggled with [hidden], so neither ships forceMount."}]},{name:"Item",description:'One selectable option (role="option"). When a `filter` predicate rejects an Item, it becomes unreachable through aria-activedescendant, uncounted in result announcements, and invisible to the Empty part\'s emptiness check. Removed from DOM in React/Vue/Svelte/Angular; hides in Web Components (cannot un-author consumer tags).',props:[{name:"value",type:"string",required:!0,description:"Identifier committed to the root's value when this option is chosen."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Excludes this option from selection and from pointer/keyboard highlight; exposed as aria-disabled/data-disabled."},{name:"textValue",type:"string",required:!1,description:"Text the `filter` predicate matches and selection writes back into Input. Falls back to rendered text content, which is wrong only when the option renders more than its label (icon, secondary line) \u2014 supply it then."}]},{name:"Group",description:'A named section of related Items (role="group") whose aria-labelledby points at its GroupLabel. Named automatically: a filtered listbox reorders and empties sections as the user types, so structure announcement is critical. Purely structural \u2014 registers no options, not in highlight order.'},{name:"GroupLabel",description:"The heading that names a Group, carrying the id its Group points aria-labelledby at. No role, so it never becomes an option the arrow keys can reach. Must be inside a Group."},{name:"Empty",description:"Shown in place of the item list when no Items are rendered \u2014 because the consumer filtered them all away, or because the `filter` predicate rejected every one."}],slots:[{name:"default",description:"Content's body \u2014 Item/Group/Empty entries."},{name:"option",frameworks:["vue","webComponents"],exception:"render-prop",frameworksReason:"vue, webComponents expose option as native content projection for the renderOption rendering capability. Other frameworks pass the documented renderOption render prop or template instead of a named slot with this spelling.",description:"Custom rendering for an `options`-derived Item, given the option data and selection state. Angular uses `TemplateRef` instead of a function. Ignored for hand-composed Item children."},{name:"render-option",frameworks:["svelte"],exception:"render-prop",frameworksReason:"svelte expose render-option as native content projection for the renderOption rendering capability. Other frameworks pass the documented renderOption render prop or template instead of a named slot with this spelling.",description:"Custom rendering for an `options`-derived Item, given the option data and selection state. Angular uses `TemplateRef` instead of a function. Ignored for hand-composed Item children."}],appearance:[{attribute:"data-shape",values:["rounded","square"],stylesheet:"combobox.css"},{attribute:"data-size",values:["md","sm","lg"],stylesheet:"combobox.css"}],states:["closed","open","checked","unchecked","disabled","highlighted","loading","multiple"],controlledUncontrolled:"value, inputValue, and open each independently support controlled or uncontrolled usage. In Angular the pair is split: `valueChange` emits the scalar for `[(value)]`, `valueChangeDetail` carries the detail.",formBehavior:'Form-associated: with a name, the selected option\'s value (not draft inputValue) is submitted; a required Combobox with no selection is valueMissing. A `multiple` Combobox submits one entry per value under the same name (like `<select multiple>`), readable via `formData.getAll(name)`. An empty `multiple` selection submits nothing except when `required` (then one empty-valued control renders for valueMissing). Mirrored controls are never `type="hidden"` or `readonly` (both disable validation); only `disabled` withholds values. Form reset restores initial selection and draft text.',validationBehavior:"invalid toggles aria-invalid/data-invalid presentation only; required participates in native constraint validation via checkValidity()/reportValidity(). Web Components publishes `required-message` (a FormAssociated mixin convention), unavailable in the other four frameworks where setCustomValidity() on the mirrored input answers the same need.",accessibility:{role:"combobox (Input), button (Trigger, Clear), listbox (Content), option (Item), group (Group), presentation (Empty, GroupLabel)",keyboard:[{key:"Typing",behavior:"Updates the draft text and opens the listbox."},{key:"ArrowDown / ArrowUp",behavior:"Opens the listbox highlighting the first/last option, or moves the highlight by one when already open \u2014 wrapping around the ends unless `loop` is `false`."},{key:"Alt+ArrowDown",behavior:`Opens the listbox and highlights nothing \u2014 APG's optional "show me the list" key. The missing highlight is the whole difference from the plain key: it lets the options be inspected without Enter then committing one the user never pointed at. Prevents the default.`},{key:"Alt+ArrowUp",behavior:'Commits the highlighted option and closes the listbox \u2014 closing even while `multiple`, where an ordinary commit keeps it open, because this key means "I am done here" rather than "select this one". With nothing highlighted it only closes. Prevents the default.'},{key:"Home / End",behavior:"While the listbox is open, moves the highlight to the first/last option and prevents the default. While it is closed neither key is intercepted: they are the text field's caret keys, and APG requires an editable combobox to leave them to the field."},{key:"PageUp / PageDown",behavior:'Aliases of Home/End, on the same open-only condition. Deliberately not a fixed multi-row jump: "one page" presupposes a row height and a viewport height, and a listbox knows neither \u2014 the consumer styles both.'},{key:"Enter",behavior:"Commits the highlighted option as the selected value and closes the listbox \u2014 or toggles it and keeps the listbox open while `multiple`. With `allowCustomValue` and nothing highlighted, commits the draft text itself."},{key:"Escape",behavior:"Closes the listbox without changing the selection."}],ariaAttributes:['aria-expanded, aria-controls, aria-autocomplete="list", and aria-activedescendant on Input',"Content's id matches Input's aria-controls",'aria-multiselectable="true" on Content while `multiple` (absent otherwise, never "false")','aria-busy="true" and data-loading on Input and Content while `loading`',"aria-selected and data-state on Item reflecting selection; data-highlighted reflecting virtual focus","aria-disabled and data-disabled on a disabled item, which is skipped by highlight/selection","the number of rendered Items is announced through the shared LiveAnnouncer polite region while the listbox is open, formatted by getResultCountLabel \u2014 including after a `filter` predicate narrows the list, and suppressed while `loading`","aria-expanded on Trigger, plus an aria-controls resolving to Content exactly while the listbox is open and absent while it is closed, since a closed listbox is unmounted and an IDREF that resolves to nothing is worse than no IDREF. It mirrors what Input reports rather than replacing it \u2014 two elements may both point at one listbox, and neither takes aria-activedescendant, which stays on Input alone",'role="group" with an aria-labelledby resolving to the GroupLabel inside it on Group; tabindex="-1" on Trigger and Clear, which are affordances rather than tab stops'],focusManagement:`${m} Here the anchor is the Input. When typing filters the highlighted option away, the highlight moves to the first survivor rather than disappearing \u2014 aria-activedescendant is dropped only when no option is left. Virtual focus scrolls via scrollIntoView({ block: "nearest" }); the highlight set while the listbox is *opening* scrolls the listbox itself instead (floating-ui renders at document origin before measuring). Focus out reconciles draft text with selection unless allowCustomValue is set: inputValue becomes the selected option's text or empty string \u2014 ensuring no unmatched text remains. Escape stays non-destructive; it closes the listbox and leaves the draft alone.`,namingRequirement:'Input must be named by <label>, aria-label, or aria-labelledby; role="combobox" takes no name from content, and Content is a sibling, not ancestor. Wrapping in Field family satisfies this automatically. Trigger and Clear need aria-label or visible text (glyph alone is not a name). Group is named by its GroupLabel.'},styling:{cssParts:["input","trigger","clear","content","item","group","label","empty"],dataAttributes:[...f,"data-state","data-side","data-align","data-disabled","data-highlighted","data-invalid","data-readonly","data-loading","data-multiple","data-value","data-shape","data-size",{name:"data-skdx-combobox-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:h("combobox")},publicMethods:[...r,s,{name:"focus",signature:"(): void",description:"Moves keyboard focus to the text field, which is where the combobox keeps real DOM focus.",frameworks:["vue","webComponents"],exception:"element-handoff",frameworksReason:"Vue hides the Input inside the root component instance, and the custom element forwards focus() to it. React, Svelte and Angular hand the consumer the Input element itself."}],frameworkExtensions:[{framework:"webComponents",name:"selectedValues",type:"string[]",description:"Selected values as array. This documented getter exposes the native element\u2019s derived live state. Other wrappers expose their state through context or framework refs; the shared component contract does not require identical getter spellings.",kind:"prop"},{framework:"webComponents",name:"selectedValues",type:"string[]",description:"Selected values as array. This documented getter exposes the native element\u2019s derived live state. Other wrappers expose their state through context or framework refs; the shared component contract does not require identical getter spellings."}]};export{k as comboboxContract};
@@ -1 +1 @@
1
- import{changeDetail as e}from"./change-reason.js";import{ROOT_DATA_ATTRIBUTES as t}from"./styling-hooks.js";var s={name:"Command",purpose:"Accessible command-palette list with virtual focus (aria-activedescendant) synced to mounted items; real DOM focus stays on Input. Root owns search text and filters items, unless filter is 'manual'. Not popper-anchored \u2014 mount in a Dialog or standalone.",props:[{name:"value",type:"string",required:!1,description:"The highlighted item's value (controlled). **This is the keyboard cursor, not a selection** \u2014 Combobox/Select use `value` for committed user input, Command uses it for highlight position. The name is cmdk's and deliberately diverges from family convention."},{name:"defaultValue",type:"string",required:!1,description:"Initial highlight value (uncontrolled); defaults to the first item."},{name:"search",type:"string",required:!1,description:"Current search text (controlled); Input updates it as the user types. **The rest of the family calls this `inputValue`** \u2014 Combobox/Autocomplete/Select do. `search` is kept as cmdk's name; the family spells one concept two ways."},{name:"defaultSearch",type:"string",defaultValue:"''",required:!1,description:"Initial search text (uncontrolled); the family's `defaultInputValue` under this component's name."},{name:"filter",type:"'manual' | ((itemValue: string, search: string, keywords?: readonly string[]) => boolean | number)",required:!1,description:"Replaces the built-in matcher (case-insensitive substring on value **or keywords**); return true to keep an item mounted. The item's `keywords` arrive as the third argument (undefined when omitted), so a custom predicate can honour aliases. 'manual' filters nothing. Same *shape* as Combobox's filter \u2014 and the **opposite default**: Command filters by default; Combobox does not. Both defaults suit their component. A number may rank instead of filter: 0 excludes, positive keeps, items order by score descending."},{name:"loop",type:"boolean",defaultValue:"false",required:!1,description:"Wraps arrow navigation around list ends: ArrowDown from last highlights first, ArrowUp from first highlights last. Off by default (cmdk's default). Deliberately the *opposite* default from Combobox/Autocomplete: a popup has nothing past its ends to walk into; a palette's list is the whole surface."},{name:"disablePointerSelection",type:"boolean",defaultValue:"false",required:!1,description:"Stops pointer-enter from moving the highlight; off by default so hover tracks the pointer. Turn on for keyboard-driven palettes to prevent mouse motion from stealing the highlight."},{name:"loading",type:"boolean",defaultValue:"false",required:!1,description:'Marks results in flight: data-loading on root/List, mounts Loading, hides Empty (prevents "No results" flash).'},{name:"groups",type:"{ label?: string; items: CommandItem[] }[]",required:!1,description:`The palette's contents as groups of items. Group wrapper only around labelled groups (unlabelled role="group" has no accessible name). groups={[{ items }]} is a flat palette; item's value defaults to its label. Supplying groups derives Input/List.`},{name:"placeholder",type:"string",required:!1,description:"Placeholder on Input; also List's accessible name when no aria-label is supplied."},{name:"emptyMessage",type:"string",required:!1,description:"Text for Empty part (shown when search matches nothing). **No default, deliberately; Empty derives only when set.** Default text would ship untranslated English to consumers who didn't opt in."},{name:"loadingMessage",type:"string",required:!1,description:'Text for Loading part (announced via role="status"). **No default, deliberately; Loading derives only when set.** Empty live regions are a11y noise; default text would be untranslated English.'},{name:"renderItem",type:"(item: CommandItem) => React.ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:`Vue uses scoped #item slot; Web Components uses light-DOM slot="item". Each framework's idiomatic hook; neither exposed as a declared prop. Web Components has no property-only equivalent (HTML attributes cannot carry functions); falls back to plain label when unslotted.`,description:"Customises what renders *inside* a derived item, never the item itself \u2014 role, id, data attributes, filtering, disabled state stay the library's. Only read while groups derives the anatomy."}],events:[{name:"value-change",description:"Fires with the highlighted item's value when the highlight moves (arrow keys, Home/End, pointer-enter, or filtering). Not a selection event; see the Item's `select` for that.",detail:e("string")},{name:"search-change",description:"Fires with new search text when Input changes. The family's `input-value-change` under this component's name.",detail:"string"},{name:"select",frameworks:["react","vue","svelte","angular"],exception:"event-shape",frameworksReason:"<skdx-command> cannot use this name: its Item part already dispatches a bubbling select through the same host carrying the item's value string, and two same-named events with different details on one node is a real ambiguity rather than a naming preference. It dispatches item-select instead \u2014 see the entry below.",description:"Recipe-level selection: fires with the CommandItem entry the derived anatomy activated (Item's select carries only its value). Fires after the item's onSelect; neither cancels the other.",detail:"CommandItem"},{name:"item-select",frameworks:["webComponents"],exception:"event-shape",frameworksReason:"React, Vue, Svelte and Angular spell the recipe-level callback select (onSelect / @select / (select)) on the root. <skdx-command> cannot: its Item part already dispatches a bubbling select through the same host with a different detail, so the recipe's is renamed here alone.",description:"Recipe-level select, dispatched with the activated CommandItem entry.",detail:"CommandItem"}],parts:[{name:"Input",description:'The search box that filters the list \u2014 a plain text field, deliberately without role="combobox", since Command anchors no popup. Owns aria-activedescendant, so the highlight moves without focus ever leaving it.',props:[]},{name:"Group",description:'A labelled section of items (role="group"). When all items filter out, heading remains (mount Group conditionally to hide it). No `forceMount` \u2014 the Group never unmounts itself.',props:[{name:"heading",type:"string | undefined",required:!1,description:"Group's accessible name, rendered as visible heading; referenced by aria-labelledby (aria-label in Web Components)."}]},{name:"Item",description:`Selectable command (role="option"). Virtual highlight via Input's aria-activedescendant; hidden when filter rejects it.`,props:[{name:"value",type:"string",required:!0,description:"What this item is filtered and selected on. Required: an item with no value cannot be matched or chosen."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Excludes item from selection and navigation (data-disabled, aria-disabled)."},{name:"keywords",type:"string[]",required:!1,description:'Aliases the filter matches alongside `value`. Example: "Toggle theme" searchable as "dark mode". Matched case-insensitive substring; passed to custom `filter` as third argument.'},{name:"forceMount",type:"boolean",defaultValue:"false",required:!1,description:'Keeps item mounted despite filter rejections (for pinned actions like "Create new\u2026"). Here, rejected items unmount entirely (unlike cmdk which hides them), changing item count and Empty state. Short-circuits the matcher, so custom filters honor it.'}],events:[{name:"select",description:"Fires with this item's `value` when activated (click or Enter). Per-item callback \u2014 the only selection signal (palette persists no state).",detail:"string"}]},{name:"Loading",description:'Renders only while root is loading. role="status" announces search progress without moving focus. **Sibling of List, never child** \u2014 role="status" cannot be a listbox child.'},{name:"Empty",description:'Renders only when no Item is mounted and never while the root is loading. **Sibling of List, never child** \u2014 role="presentation" cannot be a listbox child.'}],slots:[{name:"default",description:"List body \u2014 Item/Group/Separator entries. Empty and Loading sit beside List (not inside), as their roles cannot be listbox children."}],states:["highlighted","disabled","loading"],controlledUncontrolled:"Two independent controllable values: `value` (the highlighted item, with `defaultValue`) and `search` (the Input's text, with `defaultSearch`). Selection itself is still per-item: each Item carries its own onSelect callback, and Command persists no separate selected state.",formBehavior:"Not applicable \u2014 Command participates in no form.",validationBehavior:"Not applicable.",accessibility:{role:'listbox (List), option (Item), group (Group), separator (Separator), presentation (Empty/Group heading). Input is deliberately **not** role="combobox".',keyboard:[{key:"ArrowDown / ArrowUp",behavior:'Moves virtual highlight across mounted Items; clamps at ends unless `loop` is set. Scrolls with scrollIntoView({ block: "nearest" }) \u2014 virtual focus scrolls nothing on its own.'},{key:"Home / End",behavior:"While Items are mounted, moves highlight to first/last and prevents default (scrolls into view). Scoped to non-empty lists: Input is a text field, so these are caret keys and must reach the browser."},{key:"Enter",behavior:"Invokes the highlighted item's select handler, unless it is disabled."},{key:"Escape",behavior:"Deliberately **unhandled** \u2014 Command anchors no popup. The wrapping Dialog (usually) owns Escape; intercepting it here would swallow the user's dismiss action."}],ariaAttributes:["aria-controls on Input \u2192 List; aria-activedescendant on Input tracking the highlighted item",`Input carries **no role="combobox" and no aria-expanded** \u2014 both presuppose a popup, which Command lacks. Plain text field with aria-controls and aria-activedescendant follows APG's virtual-focus listbox pattern.`,"aria-selected and data-highlighted on Item reflecting virtual focus",'aria-disabled="true" and data-disabled on disabled items (skipped by navigation, cannot be selected); announced, never omitted','aria-labelledby on Group pointing to its heading (keeps role="presentation" so it never becomes an option)'],focusManagement:'Real focus stays on Input; highlight is virtual (via aria-activedescendant). First mounted item auto-highlights when current highlight becomes stale. Two scroll paths: user-requested moves use scrollIntoView({ block: "nearest" }); component-assigned highlights use List-local scroll that will never move an ancestor (prevents page drag on keystroke).',namingRequirement:'List must be named via aria-label or aria-labelledby (role="listbox" takes no name from content). Input names itself (sibling, not ancestor). Group names itself from its `heading`.'},styling:{cssParts:["input","list","item","group","group-label","separator","empty","loading","root"],dataAttributes:[...t,"data-highlighted","data-disabled","data-loading","data-value",{name:"data-skdx-command-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{s as commandContract};
1
+ import{changeDetail as e}from"./change-reason.js";import{ROOT_DATA_ATTRIBUTES as t}from"./styling-hooks.js";var s={name:"Command",purpose:"Accessible command-palette list with virtual focus (aria-activedescendant) synced to mounted items; real DOM focus stays on Input. Root owns search text and filters items, unless filter is 'manual'. Not popper-anchored \u2014 mount in a Dialog or standalone.",props:[{name:"value",type:"string",required:!1,description:"The highlighted item's value (controlled). **This is the keyboard cursor, not a selection** \u2014 Combobox/Select use `value` for committed user input, Command uses it for highlight position. The name is cmdk's and deliberately diverges from family convention."},{name:"defaultValue",type:"string",required:!1,description:"Initial highlight value (uncontrolled); defaults to the first item."},{name:"search",type:"string",required:!1,description:"Current search text (controlled); Input updates it as the user types. **The rest of the family calls this `inputValue`** \u2014 Combobox/Autocomplete/Select do. `search` is kept as cmdk's name; the family spells one concept two ways."},{name:"defaultSearch",type:"string",defaultValue:"''",required:!1,description:"Initial search text (uncontrolled); the family's `defaultInputValue` under this component's name."},{name:"filter",type:"'manual' | ((itemValue: string, search: string, keywords?: readonly string[]) => boolean | number)",required:!1,description:"Replaces the built-in matcher (case-insensitive substring on value **or keywords**); return true to keep an item mounted. The item's `keywords` arrive as the third argument (undefined when omitted), so a custom predicate can honour aliases. 'manual' filters nothing. Same *shape* as Combobox's filter \u2014 and the **opposite default**: Command filters by default; Combobox does not. Both defaults suit their component. A number may rank instead of filter: 0 excludes, positive keeps, items order by score descending."},{name:"loop",type:"boolean",defaultValue:"false",required:!1,description:"Wraps arrow navigation around list ends: ArrowDown from last highlights first, ArrowUp from first highlights last. Off by default (cmdk's default). Deliberately the *opposite* default from Combobox/Autocomplete: a popup has nothing past its ends to walk into; a palette's list is the whole surface."},{name:"disablePointerSelection",type:"boolean",defaultValue:"false",required:!1,description:"Stops pointer-enter from moving the highlight; off by default so hover tracks the pointer. Turn on for keyboard-driven palettes to prevent mouse motion from stealing the highlight."},{name:"loading",type:"boolean",defaultValue:"false",required:!1,description:'Marks results in flight: data-loading on root/List, mounts Loading, hides Empty (prevents "No results" flash).'},{name:"groups",type:"{ label?: string; items: CommandItem[] }[]",required:!1,description:`The palette's contents as groups of items. Group wrapper only around labelled groups (unlabelled role="group" has no accessible name). groups={[{ items }]} is a flat palette; item's value defaults to its label. Supplying groups derives Input/List.`},{name:"placeholder",type:"string",required:!1,description:"Placeholder on Input; also List's accessible name when no aria-label is supplied."},{name:"emptyMessage",type:"string",required:!1,description:"Text for Empty part (shown when search matches nothing). **No default, deliberately; Empty derives only when set.** Default text would ship untranslated English to consumers who didn't opt in."},{name:"loadingMessage",type:"string",required:!1,description:'Text for Loading part (announced via role="status"). **No default, deliberately; Loading derives only when set.** Empty live regions are a11y noise; default text would be untranslated English.'},{name:"renderItem",type:"(item: CommandItem) => React.ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:`Vue uses scoped #item slot; Web Components uses light-DOM slot="item". Each framework's idiomatic hook; neither exposed as a declared prop. Web Components has no property-only equivalent (HTML attributes cannot carry functions); falls back to plain label when unslotted.`,description:"Customises what renders *inside* a derived item, never the item itself \u2014 role, id, data attributes, filtering, disabled state stay the library's. Only read while groups derives the anatomy."}],events:[{name:"value-change",description:"Fires with the highlighted item's value when the highlight moves (arrow keys, Home/End, pointer-enter, or filtering). Not a selection event; see the Item's `select` for that.",detail:e("string")},{name:"search-change",description:"Fires with new search text when Input changes. The family's `input-value-change` under this component's name.",detail:"string"},{name:"select",frameworks:["react","vue","svelte","angular"],exception:"event-shape",frameworksReason:"<skdx-command> cannot use this name: its Item part already dispatches a bubbling select through the same host carrying the item's value string, and two same-named events with different details on one node is a real ambiguity rather than a naming preference. It dispatches item-select instead \u2014 see the entry below.",description:"Recipe-level selection: fires with the CommandItem entry the derived anatomy activated (Item's select carries only its value). Fires after the item's onSelect; neither cancels the other.",detail:"CommandItem"},{name:"item-select",frameworks:["webComponents"],exception:"event-shape",frameworksReason:"React, Vue, Svelte and Angular spell the recipe-level callback select (onSelect / @select / (select)) on the root. <skdx-command> cannot: its Item part already dispatches a bubbling select through the same host with a different detail, so the recipe's is renamed here alone.",description:"Recipe-level select, dispatched with the activated CommandItem entry.",detail:"CommandItem"}],parts:[{name:"Input",description:'The search box that filters the list \u2014 a plain text field, deliberately without role="combobox", since Command anchors no popup. Owns aria-activedescendant, so the highlight moves without focus ever leaving it.',props:[]},{name:"Group",description:'A labelled section of items (role="group"). When all items filter out, heading remains (mount Group conditionally to hide it). No `forceMount` \u2014 the Group never unmounts itself.',props:[{name:"heading",type:"string | undefined",required:!1,description:"Group's accessible name, rendered as visible heading; referenced by aria-labelledby (aria-label in Web Components)."}]},{name:"Item",description:`Selectable command (role="option"). Virtual highlight via Input's aria-activedescendant; hidden when filter rejects it.`,props:[{name:"value",type:"string",required:!0,description:"What this item is filtered and selected on. Required: an item with no value cannot be matched or chosen."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Excludes item from selection and navigation (data-disabled, aria-disabled)."},{name:"keywords",type:"string[]",required:!1,description:'Aliases the filter matches alongside `value`. Example: "Toggle theme" searchable as "dark mode". Matched case-insensitive substring; passed to custom `filter` as third argument.'},{name:"forceMount",type:"boolean",defaultValue:"false",required:!1,description:'Keeps item mounted despite filter rejections (for pinned actions like "Create new\u2026"). Here, rejected items unmount entirely (unlike cmdk which hides them), changing item count and Empty state. Short-circuits the matcher, so custom filters honor it.'}],events:[{name:"select",description:"Fires with this item's `value` when activated (click or Enter). Per-item callback \u2014 the only selection signal (palette persists no state).",detail:"string"}]},{name:"Loading",description:'Renders only while root is loading. role="status" announces search progress without moving focus. **Sibling of List, never child** \u2014 role="status" cannot be a listbox child.'},{name:"Empty",description:'Renders only when no Item is mounted and never while the root is loading. **Sibling of List, never child** \u2014 role="presentation" cannot be a listbox child.'}],slots:[{name:"default",description:"List body \u2014 Item/Group/Separator entries. Empty and Loading sit beside List (not inside), as their roles cannot be listbox children."},{name:"item",frameworks:["vue","webComponents"],exception:"render-prop",frameworksReason:"vue, webComponents expose item as native content projection for the renderItem rendering capability. Other frameworks pass the documented renderItem render prop or template instead of a named slot with this spelling.",description:"Customises what renders *inside* a derived item, never the item itself \u2014 role, id, data attributes, filtering, disabled state stay the library's. Only read while groups derives the anatomy."},{name:"render-item",frameworks:["svelte"],exception:"render-prop",frameworksReason:"svelte expose render-item as native content projection for the renderItem rendering capability. Other frameworks pass the documented renderItem render prop or template instead of a named slot with this spelling.",description:"Customises what renders *inside* a derived item, never the item itself \u2014 role, id, data attributes, filtering, disabled state stay the library's. Only read while groups derives the anatomy."}],states:["highlighted","disabled","loading"],controlledUncontrolled:"Two independent controllable values: `value` (the highlighted item, with `defaultValue`) and `search` (the Input's text, with `defaultSearch`). Selection itself is still per-item: each Item carries its own onSelect callback, and Command persists no separate selected state.",formBehavior:"Not applicable \u2014 Command participates in no form.",validationBehavior:"Not applicable.",accessibility:{role:'listbox (List), option (Item), group (Group), separator (Separator), presentation (Empty/Group heading). Input is deliberately **not** role="combobox".',keyboard:[{key:"ArrowDown / ArrowUp",behavior:'Moves virtual highlight across mounted Items; clamps at ends unless `loop` is set. Scrolls with scrollIntoView({ block: "nearest" }) \u2014 virtual focus scrolls nothing on its own.'},{key:"Home / End",behavior:"While Items are mounted, moves highlight to first/last and prevents default (scrolls into view). Scoped to non-empty lists: Input is a text field, so these are caret keys and must reach the browser."},{key:"Enter",behavior:"Invokes the highlighted item's select handler, unless it is disabled."},{key:"Escape",behavior:"Deliberately **unhandled** \u2014 Command anchors no popup. The wrapping Dialog (usually) owns Escape; intercepting it here would swallow the user's dismiss action."}],ariaAttributes:["aria-controls on Input \u2192 List; aria-activedescendant on Input tracking the highlighted item",`Input carries **no role="combobox" and no aria-expanded** \u2014 both presuppose a popup, which Command lacks. Plain text field with aria-controls and aria-activedescendant follows APG's virtual-focus listbox pattern.`,"aria-selected and data-highlighted on Item reflecting virtual focus",'aria-disabled="true" and data-disabled on disabled items (skipped by navigation, cannot be selected); announced, never omitted','aria-labelledby on Group pointing to its heading (keeps role="presentation" so it never becomes an option)'],focusManagement:'Real focus stays on Input; highlight is virtual (via aria-activedescendant). First mounted item auto-highlights when current highlight becomes stale. Two scroll paths: user-requested moves use scrollIntoView({ block: "nearest" }); component-assigned highlights use List-local scroll that will never move an ancestor (prevents page drag on keystroke).',namingRequirement:'List must be named via aria-label or aria-labelledby (role="listbox" takes no name from content). Input names itself (sibling, not ancestor). Group names itself from its `heading`.'},styling:{cssParts:["input","list","item","group","group-label","separator","empty","loading","root"],dataAttributes:[...t,"data-highlighted","data-disabled","data-loading","data-value",{name:"data-skdx-command-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{s as commandContract};
@@ -1 +1 @@
1
- import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var n={name:"DashboardLayout",purpose:"An application shell block: a top app bar with a navigation toggle, branding, title and actions; a side <nav> built from a navigation item list; and a <main> content region. Ships in the blocks package of each framework, not the core package.",props:[{name:"title",type:"string",required:!1,description:"Application title shown in the app bar after the branding. Nothing renders when omitted."},{name:"navigation",type:"DashboardNavigationItem[]",required:!0,description:`The side navigation, one entry per item: { kind?: 'item' | 'header' | 'divider', label?, href?, current?, children? }. An item with href renders a link, current marks it aria-current="page"; an item with children and no href renders a labelled nested list; a header renders a group label; a divider renders a separator.`},{name:"navOpen",type:"boolean",required:!1,description:"Whether the side navigation is shown, for controlled usage."},{name:"defaultNavOpen",type:"boolean",defaultValue:"true",required:!1,description:"Whether the side navigation starts shown, for uncontrolled usage."},{name:"navLabel",type:"string",defaultValue:"'Main navigation'",required:!1,description:"Accessible name of the side <nav>."},{name:"navToggleLabel",type:"string",defaultValue:"'Toggle navigation'",required:!1,description:"Accessible name of the icon-only button that shows and hides the side navigation."},{name:"branding",type:"unknown",required:!1,frameworks:["react","svelte"],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 \u2014 and Angular projects it through content marked skdxBranding, the shell idiom its template compiler reads. The slot spellings are declared under `slots`.",description:"Logo or product mark rendered at the start of the app bar. A prop in React and Svelte; Vue and Web Components use the `branding` slot, Angular projects content marked skdxBranding."},{name:"actions",type:"unknown",required:!1,frameworks:["react","svelte"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot rather than a prop, and Angular projects content marked skdxActions, for the same reasons `branding` does. The slot spellings are declared under `slots`.",description:"Controls rendered at the end of the app bar. A prop in React and Svelte; Vue and Web Components use the `actions` slot, Angular projects content marked skdxActions."}],events:[{name:"nav-open-change",detail:"boolean",description:"Fires with the new open state whenever the navigation toggle is activated."}],slots:[{name:"default",description:"The page content rendered inside the <main> region."},{name:"branding",description:"Logo or product mark at the start of the app bar."},{name:"actions",description:"Controls at the end of the app bar."}],states:["default"],controlledUncontrolled:"The navigation open state works controlled through navOpen or uncontrolled through defaultNavOpen.",formBehavior:"Not applicable \u2014 DashboardLayout participates in no form.",validationBehavior:"Not applicable \u2014 DashboardLayout carries no value and participates in no validation.",accessibility:{role:"generic root holding a banner (<header>), a navigation (<nav>) and a main (<main>) landmark",keyboard:[{key:"Enter/Space",behavior:"Activates the focused navigation toggle, showing or hiding the side navigation (native button activation)."}],ariaAttributes:["aria-expanded on the navigation toggle mirrors navOpen, with aria-controls pointing at the <nav> id","aria-label on the <nav> from navLabel, so a page with several navigation landmarks tells them apart",'aria-current="page" on the navigation link whose item is marked current','role="separator" on a divider item'],focusManagement:"The toggle is a native button and the navigation entries are native links; a hidden <nav> removes its links from the tab order through the hidden attribute."},styling:{cssParts:["dashboard-layout","app-bar","nav-toggle","branding","title","actions","body","nav","nav-list","nav-item","nav-header","nav-divider","content"],dataAttributes:[...e,"data-nav-open","data-icon-only",{name:"data-skdx-dashboard-layout-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 dashboardLayoutContract};
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var n={name:"DashboardLayout",purpose:"An application shell block: a top app bar with a navigation toggle, branding, title and actions; a side <nav> built from a navigation item list; and a <main> content region. Ships in the blocks package of each framework, not the core package.",props:[{name:"title",type:"string",required:!1,description:"Application title shown in the app bar after the branding. Nothing renders when omitted."},{name:"navigation",type:"DashboardNavigationItem[]",required:!0,description:`The side navigation, one entry per item: { kind?: 'item' | 'header' | 'divider', label?, href?, current?, children? }. An item with href renders a link, current marks it aria-current="page"; an item with children and no href renders a labelled nested list; a header renders a group label; a divider renders a separator.`},{name:"contentAs",type:"'main' | 'div'",defaultValue:"'main'",required:!1,description:"Element rendered for the content region: use div when the block sits inside an existing main landmark."},{name:"navOpen",type:"boolean",required:!1,description:"Whether the side navigation is shown, for controlled usage."},{name:"defaultNavOpen",type:"boolean",defaultValue:"true",required:!1,description:"Whether the side navigation starts shown, for uncontrolled usage."},{name:"navLabel",type:"string",defaultValue:"'Main navigation'",required:!1,description:"Accessible name of the side <nav>."},{name:"navToggleLabel",type:"string",defaultValue:"'Toggle navigation'",required:!1,description:"Accessible name of the icon-only button that shows and hides the side navigation."},{name:"branding",type:"unknown",required:!1,frameworks:["react","svelte"],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 \u2014 and Angular projects it through content marked skdxBranding, the shell idiom its template compiler reads. The slot spellings are declared under `slots`.",description:"Logo or product mark rendered at the start of the app bar. A prop in React and Svelte; Vue and Web Components use the `branding` slot, Angular projects content marked skdxBranding."},{name:"actions",type:"unknown",required:!1,frameworks:["react","svelte"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot rather than a prop, and Angular projects content marked skdxActions, for the same reasons `branding` does. The slot spellings are declared under `slots`.",description:"Controls rendered at the end of the app bar. A prop in React and Svelte; Vue and Web Components use the `actions` slot, Angular projects content marked skdxActions."}],events:[{name:"nav-open-change",detail:"boolean",description:"Fires with the new open state whenever the navigation toggle is activated."}],slots:[{name:"default",description:"The page content rendered inside the <main> region."},{name:"branding",description:"Logo or product mark at the start of the app bar."},{name:"actions",description:"Controls at the end of the app bar."}],states:["default"],controlledUncontrolled:"The navigation open state works controlled through navOpen or uncontrolled through defaultNavOpen.",formBehavior:"Not applicable \u2014 DashboardLayout participates in no form.",validationBehavior:"Not applicable \u2014 DashboardLayout carries no value and participates in no validation.",accessibility:{role:"generic root holding a banner (<header>), a navigation (<nav>) and a main (<main>) landmark",keyboard:[{key:"Enter/Space",behavior:"Activates the focused navigation toggle, showing or hiding the side navigation (native button activation)."}],ariaAttributes:["aria-expanded on the navigation toggle mirrors navOpen, with aria-controls pointing at the <nav> id","aria-label on the <nav> from navLabel, so a page with several navigation landmarks tells them apart",'aria-current="page" on the navigation link whose item is marked current','role="separator" on a divider item'],focusManagement:"The toggle is a native button and the navigation entries are native links; a hidden <nav> removes its links from the tab order through the hidden attribute."},styling:{cssParts:["dashboard-layout","app-bar","nav-toggle","branding","title","actions","body","nav","nav-list","nav-item","nav-header","nav-divider","content"],dataAttributes:[...e,"data-nav-open","data-icon-only",{name:"data-skdx-dashboard-layout-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 dashboardLayoutContract};