@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{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var t={name:"Resizable",purpose:"A split-panel layout with draggable, keyboard-operable handles. Panels and handles form an alternating set that may change after mount: every Handle resolves its own index from its position in the DOM at the moment of interaction. A drag redistributes size ONLY between the two panels immediately adjacent to the handle \u2014 the predictable default. Composed of root, Panel, and Handle parts.",props:[{name:"step",type:"number",defaultValue:"2",required:!1,description:"Percentage points per Arrow key press. Group-level so a multi-panel group does not repeat the value silently. Overridable per Handle. The unit is percentage points, not pixels."},{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Layout axis: flex direction, arrow-key pair, cursor, aria-orientation. Exposed as data-orientation. Optional."},{name:"sizes",type:"number[]",required:!1,description:"Controlled panel sizes (percentages, Panel order). Supplied: group renders and reports through `layout`/`layout-commit`. Omitted: uses each Panel's defaultSize."},{name:"panels",type:"ReadonlyArray<{ defaultSize?: number; minSize?: number; maxSize?: number; collapsible?: boolean; collapsedSize?: number; id?: string; content?: unknown }>",required:!1,description:"The panes the group derives \u2014 one Panel per entry. Composition is optional."},{name:"panelTemplate",frameworks:["angular"],exception:"render-prop",frameworksReason:"Angular's `panels[].content` can only be a string, because a component input cannot carry template markup. The other four put markup straight into that entry \u2014 a ReactNode, a VNode, a snippet, or a Node \u2014 so they need no second input; Angular reaches the same capability with an *ngTemplateOutlet fed by this TemplateRef.",type:"TemplateRef<{ $implicit: PanelItem; panel: PanelItem; index: number }>",required:!1,description:"Template rendered as each derived panel's body, replacing that entry's content string."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Handle target-size rung, written to data-size on the root; the data-size attribute may be set directly instead."}],events:[{name:"layout",description:"Fires with sizes array (percentages) on every pointermove that moves the split.",detail:"number[]"},{name:"layout-commit",description:"Fires with sizes array (percentages) when the user finishes: on pointerup/pointercancel or after keyboard nudge. The event to persist on.",detail:"number[]"},{name:"collapse",description:"Fires when a collapsible Panel reaches collapsedSize, carrying the panel id.",detail:"{ panelId: string }"},{name:"expand",description:"Fires when a collapsed Panel reopens, carrying the panel id. Reachable by pointer and arrow key.",detail:"{ panelId: string }"}],parts:[{name:"Panel",description:"One resizable pane. Registers size constraints on mount and is sized thereafter. No per-Panel `size` prop. Lays out through flexbox before the group computes a size.",props:[{name:"defaultSize",type:"number | undefined",required:!1,description:"Initial size as a percentage of the group's main axis (0-100). Omit to split remaining space evenly. Percentages are the only unit accepted."},{name:"minSize",type:"number",defaultValue:"10",required:!1,description:"Minimum size as a percentage (0-100). Default 10 prevents accidental loss."},{name:"maxSize",type:"number",defaultValue:"90",required:!1,description:"Maximum size as a percentage (0-100). Default 90 pairs with minSize 10."},{name:"collapsible",type:"boolean",defaultValue:"false",required:!1,description:"Lets this panel close: below minSize snaps to collapsedSize. Off by default. Reopens on any movement."},{name:"collapsedSize",type:"number",defaultValue:"0",required:!1,description:"Size (percentage) while closed. Panel carries data-collapsed; group fires collapse/expand."}]},{name:"Handle",description:'The draggable divider (role="separator"), its own tab stop. Carries data-dragging during pointer gestures.',props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:'Refuses every drag and every key. Focusable-and-inert: the handle keeps its tab stop and announces aria-disabled="true".'},{name:"step",type:"number | undefined",defaultValue:"undefined \u2014 inherits the group's step (2)",required:!1,description:"Nudge per Arrow key press, overriding the group's step. Percentage points, not pixels."}]}],slots:[{name:"default",description:"Root content \u2014 alternating Panel, Handle, Panel, ... entries."}],appearance:[{attribute:"data-size",values:["sm","lg"],stylesheet:"resizable.css"}],states:["disabled","dragging","collapsed"],controlledUncontrolled:"Standard. Uncontrolled: sizes seeded from each Panel's defaultSize. Controlled: supply `sizes` for a pure renderer. No `defaultSizes` on root.",formBehavior:"Not applicable \u2014 Resizable does not participate in forms.",validationBehavior:"Not applicable \u2014 Resizable carries no value and participates in no validation.",accessibility:{role:"(none, root); separator (Handle)",keyboard:[{key:"ArrowLeft/ArrowRight (horizontal groups) or ArrowUp/ArrowDown (vertical groups)",behavior:"Nudges the focused Handle by step (default 2 percentage points)."},{key:"Home",behavior:"Shrinks the Handle's left/top panel to its minSize."},{key:"End",behavior:"Grows the Handle's left/top panel to its maxSize."}],ariaAttributes:["Handle's aria-orientation is perpendicular to the group's direction","Handle's aria-valuenow/aria-valuemin/aria-valuemax describe the adjacent panel size; a collapsible panel reports collapsedSize as its aria-valuemin, since that is the smallest size it can legally reach","Handle's aria-valuetext expresses size as a percentage","Handle's aria-controls is the DOM id of the start-side panel","data-dragging on Handle during pointer gesture",'data-disabled on disabled Handle with aria-disabled="true"',"aria-label or aria-labelledby on Handle, forwarded to separator element"],namingRequirement:"Groups with multiple Handles MUST name each distinctly with aria-label/aria-labelledby. Single Handles need no name.",focusManagement:"Each Handle is its own tab stop (tabIndex 0), including while disabled. Disabled Handles are focusable-and-inert."},styling:{cssParts:["panel","handle","root"],dataAttributes:[...e,"data-orientation","data-disabled","data-dragging","data-collapsed","data-size","data-skdx-resizable-handle","data-skdx-resizable-panel",{name:"data-skdx-resizable-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-resizable-handle-size"]},publicMethods:[{name:"getSizes",frameworks:["vue","svelte","angular","webComponents"],exception:"imperative",frameworksReason:"React uses `useResizableContext`; see contextApi below.",signature:"() => number[]",description:"Current sizes as percentages, in Panel order."},{name:"setSizes",frameworks:["vue","svelte","angular","webComponents"],exception:"imperative",frameworksReason:"React uses `useResizableContext`; see contextApi below.",signature:"(sizes: number[]) => void",description:"Drive layout to sizes (percentages, Panel order). Clamped and renormalized to 100."},{name:"resetSizes",frameworks:["vue","svelte","angular","webComponents"],exception:"imperative",frameworksReason:"React uses `useResizableContext`; see contextApi below.",signature:"() => void",description:"Return every panel to its defaultSize or even split: fresh mount layout."}],contextApi:[{name:"getSizes",signature:"() => number[]",description:"Current sizes as percentages, in Panel order.",accessors:{react:"useResizableContext('MyComponent').getSizes",vue:"inject(RESIZABLE_CONTEXT).getSizes",svelte:"requireContext(RESIZABLE_CONTEXT).getSizes",angular:"inject(SkdxResizableState).getSizes",webComponents:"document.querySelector('skdx-resizable-panel-group').getSizes"}},{name:"setSizes",signature:"(sizes: number[]) => void",description:"Drive layout to sizes, clamped and renormalized to 100.",accessors:{react:"useResizableContext('MyComponent').setSizes",vue:"inject(RESIZABLE_CONTEXT).setSizes",svelte:"requireContext(RESIZABLE_CONTEXT).setSizes",angular:"inject(SkdxResizableState).setSizes",webComponents:"document.querySelector('skdx-resizable-panel-group').setSizes"}},{name:"resetSizes",signature:"() => void",description:"Reset every panel to defaultSize or even split.",accessors:{react:"useResizableContext('MyComponent').resetSizes",vue:"inject(RESIZABLE_CONTEXT).resetSizes",svelte:"requireContext(RESIZABLE_CONTEXT).resetSizes",angular:"inject(SkdxResizableState).resetSizes",webComponents:"document.querySelector('skdx-resizable-panel-group').resetSizes"}}]};export{t as resizableContract};
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var t={name:"Resizable",purpose:"A split-panel layout with draggable, keyboard-operable handles. Panels and handles form an alternating set that may change after mount: every Handle resolves its own index from its position in the DOM at the moment of interaction. A drag redistributes size ONLY between the two panels immediately adjacent to the handle \u2014 the predictable default. Composed of root, Panel, and Handle parts.",props:[{name:"step",type:"number",defaultValue:"2",required:!1,description:"Percentage points per Arrow key press. Group-level so a multi-panel group does not repeat the value silently. Overridable per Handle. The unit is percentage points, not pixels."},{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Layout axis: flex direction, arrow-key pair, cursor, aria-orientation. Exposed as data-orientation. Optional."},{name:"sizes",type:"number[]",required:!1,description:"Controlled panel sizes (percentages, Panel order). Supplied: group renders and reports through `layout`/`layout-commit`. Omitted: uses each Panel's defaultSize."},{name:"panels",type:"ReadonlyArray<{ defaultSize?: number; minSize?: number; maxSize?: number; collapsible?: boolean; collapsedSize?: number; id?: string; content?: unknown }>",required:!1,description:"The panes the group derives \u2014 one Panel per entry. Composition is optional."},{name:"panelTemplate",frameworks:["angular"],exception:"render-prop",frameworksReason:"Angular's `panels[].content` can only be a string, because a component input cannot carry template markup. The other four put markup straight into that entry \u2014 a ReactNode, a VNode, a snippet, or a Node \u2014 so they need no second input; Angular reaches the same capability with an *ngTemplateOutlet fed by this TemplateRef.",type:"TemplateRef<{ $implicit: PanelItem; panel: PanelItem; index: number }>",required:!1,description:"Template rendered as each derived panel's body, replacing that entry's content string."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Handle target-size rung, written to data-size on the root; the data-size attribute may be set directly instead."}],events:[{name:"layout",description:"Fires with sizes array (percentages) on every pointermove that moves the split.",detail:"number[]"},{name:"layout-commit",description:"Fires with sizes array (percentages) when the user finishes: on pointerup/pointercancel or after keyboard nudge. The event to persist on.",detail:"number[]"},{name:"collapse",description:"Fires when a collapsible Panel reaches collapsedSize, carrying the panel id.",detail:"{ panelId: string }"},{name:"expand",description:"Fires when a collapsed Panel reopens, carrying the panel id. Reachable by pointer and arrow key.",detail:"{ panelId: string }"}],parts:[{name:"Panel",description:"One resizable pane. Registers size constraints on mount and is sized thereafter. No per-Panel `size` prop. Lays out through flexbox before the group computes a size.",props:[{name:"defaultSize",type:"number | undefined",required:!1,description:"Initial size as a percentage of the group's main axis (0-100). Omit to split remaining space evenly. Percentages are the only unit accepted."},{name:"minSize",type:"number",defaultValue:"10",required:!1,description:"Minimum size as a percentage (0-100). Default 10 prevents accidental loss."},{name:"maxSize",type:"number",defaultValue:"90",required:!1,description:"Maximum size as a percentage (0-100). Default 90 pairs with minSize 10."},{name:"collapsible",type:"boolean",defaultValue:"false",required:!1,description:"Lets this panel close: below minSize snaps to collapsedSize. Off by default. Reopens on any movement."},{name:"collapsedSize",type:"number",defaultValue:"0",required:!1,description:"Size (percentage) while closed. Panel carries data-collapsed; group fires collapse/expand."}]},{name:"Handle",description:'The draggable divider (role="separator"), its own tab stop. Carries data-dragging during pointer gestures.',props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:'Refuses every drag and every key. Focusable-and-inert: the handle keeps its tab stop and announces aria-disabled="true".'},{name:"step",type:"number | undefined",defaultValue:"undefined \u2014 inherits the group's step (2)",required:!1,description:"Nudge per Arrow key press, overriding the group's step. Percentage points, not pixels."}]}],slots:[{name:"default",description:"Root content \u2014 alternating Panel, Handle, Panel, ... entries."}],appearance:[{attribute:"data-size",values:["sm","lg"],stylesheet:"resizable.css"}],states:["disabled","dragging","collapsed"],controlledUncontrolled:"Standard. Uncontrolled: sizes seeded from each Panel's defaultSize. Controlled: supply `sizes` for a pure renderer. No `defaultSizes` on root.",formBehavior:"Not applicable \u2014 Resizable does not participate in forms.",validationBehavior:"Not applicable \u2014 Resizable carries no value and participates in no validation.",accessibility:{role:"(none, root); separator (Handle)",keyboard:[{key:"ArrowLeft/ArrowRight (horizontal groups) or ArrowUp/ArrowDown (vertical groups)",behavior:"Nudges the focused Handle by step (default 2 percentage points)."},{key:"Home",behavior:"Shrinks the Handle's left/top panel to its minSize."},{key:"End",behavior:"Grows the Handle's left/top panel to its maxSize."}],ariaAttributes:["Handle's aria-orientation is perpendicular to the group's direction","Handle's aria-valuenow/aria-valuemin/aria-valuemax describe the adjacent panel size; a collapsible panel reports collapsedSize as its aria-valuemin, since that is the smallest size it can legally reach","Handle's aria-valuetext expresses size as a percentage","Handle's aria-controls is the DOM id of the start-side panel","data-dragging on Handle during pointer gesture",'data-disabled on disabled Handle with aria-disabled="true"',"aria-label or aria-labelledby on Handle, forwarded to separator element"],namingRequirement:"Groups with multiple Handles MUST name each distinctly with aria-label/aria-labelledby. Single Handles need no name.",focusManagement:"Each Handle is its own tab stop (tabIndex 0), including while disabled. Disabled Handles are focusable-and-inert."},styling:{cssParts:["panel","handle","root"],dataAttributes:[...e,"data-orientation","data-disabled","data-dragging","data-collapsed","data-size","data-skdx-resizable-handle","data-skdx-resizable-panel",{name:"data-skdx-resizable-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-resizable-handle-size"]},publicMethods:[{name:"getSizes",frameworks:["vue","svelte","angular","webComponents"],exception:"imperative",frameworksReason:"React uses `useResizableContext`; see contextApi below.",signature:"() => number[]",description:"Current sizes as percentages, in Panel order."},{name:"setSizes",frameworks:["vue","svelte","angular","webComponents"],exception:"imperative",frameworksReason:"React uses `useResizableContext`; see contextApi below.",signature:"(sizes: number[]) => void",description:"Drive layout to sizes (percentages, Panel order). Clamped and renormalized to 100."},{name:"resetSizes",frameworks:["vue","svelte","angular","webComponents"],exception:"imperative",frameworksReason:"React uses `useResizableContext`; see contextApi below.",signature:"() => void",description:"Return every panel to its defaultSize or even split: fresh mount layout."}],contextApi:[{name:"getSizes",signature:"() => number[]",description:"Current sizes as percentages, in Panel order.",accessors:{react:"useResizableContext('MyComponent').getSizes",vue:"inject(RESIZABLE_CONTEXT).getSizes",svelte:"requireContext(RESIZABLE_CONTEXT).getSizes",angular:"inject(SkdxResizableState).getSizes",webComponents:"document.querySelector('skdx-resizable-panel-group').getSizes"}},{name:"setSizes",signature:"(sizes: number[]) => void",description:"Drive layout to sizes, clamped and renormalized to 100.",accessors:{react:"useResizableContext('MyComponent').setSizes",vue:"inject(RESIZABLE_CONTEXT).setSizes",svelte:"requireContext(RESIZABLE_CONTEXT).setSizes",angular:"inject(SkdxResizableState).setSizes",webComponents:"document.querySelector('skdx-resizable-panel-group').setSizes"}},{name:"resetSizes",signature:"() => void",description:"Reset every panel to defaultSize or even split.",accessors:{react:"useResizableContext('MyComponent').resetSizes",vue:"inject(RESIZABLE_CONTEXT).resetSizes",svelte:"requireContext(RESIZABLE_CONTEXT).resetSizes",angular:"inject(SkdxResizableState).resetSizes",webComponents:"document.querySelector('skdx-resizable-panel-group').resetSizes"}}],frameworkExtensions:[{framework:"vue",kind:"slot",name:"panel",type:"Content projection",description:"Panel body for markup `panels` content cannot express. 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:"vue",kind:"slot",name:"panel",type:"Content projection",description:"Panel body for markup `panels` content cannot express. 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{t as resizableContract};
@@ -1 +1 @@
1
- import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var a={name:"ScrollArea",purpose:"Wraps a natively-scrollable viewport and exposes a custom scrollbar thumb kept in sync with it, so brands can style scrollbars consistently across platforms. Composed of a root plus Viewport, Scrollbar, Thumb, and Corner parts.",props:[{name:"type",type:"'auto' | 'always' | 'hover' | 'scroll'",defaultValue:"'hover'",required:!1,description:'When scrollbar is visible: "hover" on pointer over, "scroll" on scroll, "always"/"auto" always. "auto" mounts track only while axis overflows; "always" always mounts it.'},{name:"scrollHideDelay",type:"number",defaultValue:"600",required:!1,description:'Milliseconds scrollbar stays visible after scroll stops (type="scroll" only).'},{name:"scrollbars",type:"'vertical' | 'horizontal' | 'both'",defaultValue:"'both'",required:!1,description:"Which scrollbars to derive."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Track/thumb size rung, written to data-size on the root; the data-size attribute may be set directly instead."}],events:[{name:"scroll-position-change",description:"Fires with viewport scroll offsets on every scroll tick.",detail:"{ x: number, y: number }"}],parts:[{name:"Scrollbar",description:'Track for one axis with aria-hidden="true"; rendered only while that axis overflows. Its data-state is gated on overflow before anything else: an axis with nothing to scroll stays data-state="hidden" whatever hover, scrolling or type would otherwise say, so a skin never paints a track over content that already fits.',props:[{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'vertical'",required:!1,description:"Track axis; selects which overflow state drives render."},{name:"forceMount",type:"boolean",defaultValue:"false",required:!1,description:"Keep track in flow even when axis does not overflow."}]},{name:"Corner",description:"Square filling the gap where vertical and horizontal scrollbars meet.",props:[{name:"forceMount",type:"boolean",defaultValue:"false",required:!1,description:"Keep corner mounted even when both axes do not overflow."}]}],slots:[{name:"default",description:"Root content \u2014 Viewport, Scrollbar(s), and Corner."}],appearance:[{attribute:"data-size",values:["sm","lg"],stylesheet:"scroll-area.css"}],states:["visible","hidden"],controlledUncontrolled:"Not applicable \u2014 ScrollArea has no value; scroll position is native browser state.",formBehavior:"Not applicable \u2014 ScrollArea does not participate in forms.",validationBehavior:"Not applicable \u2014 ScrollArea carries no value and participates in no validation.",accessibility:{role:"region on Viewport when named; none otherwise",namingRequirement:'Name Viewport with aria-label or aria-labelledby to emit role="region".',keyboard:[{key:"(native)",behavior:"Native scroll keys (Arrow, Page Up/Down, Home/End, Space) on Viewport."}],ariaAttributes:['Viewport carries role="region" plus aria-label or aria-labelledby when named','aria-hidden="true" on Scrollbar, Thumb and Corner'],focusManagement:"Focus stays on Viewport; Scrollbar/Thumb are pointer-only visual affordances."},styling:{cssParts:["viewport","scrollbar","thumb","corner","root"],dataAttributes:[...e,"data-state","data-orientation","data-overflow-x","data-overflow-y","data-size","data-skdx-scroll-area","data-skdx-scroll-area-content","data-skdx-scroll-area-corner","data-skdx-scroll-area-scrollbar","data-skdx-scroll-area-thumb","data-skdx-scroll-area-viewport",{name:"data-skdx-scroll-area-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-scroll-area-track-size","--skdx-scroll-area-thumb-min-length"]},publicMethods:[{name:"scrollTo",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 `useScrollAreaContext` 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:"(options: { top?: number, left?: number, behavior?: 'auto' | 'smooth' }) => void",description:"Scroll Viewport; omitted axes stay where they are."}],contextApi:[{name:"scrollTo",signature:"(options: { top?: number, left?: number, behavior?: 'auto' | 'smooth' }) => void",description:"Scrolls the Viewport to the given position.",accessors:{react:"useScrollAreaContext('MyComponent').scrollTo",vue:"inject(SCROLL_AREA_CONTEXT).scrollTo",svelte:"getContext(SCROLL_AREA_CONTEXT).scrollTo",angular:"inject(SkdxScrollAreaState).scrollTo",webComponents:"document.querySelector('skdx-scroll-area').scrollTo"}}]};export{a as scrollAreaContract};
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var r={name:"ScrollArea",purpose:"Wraps a natively-scrollable viewport and exposes a custom scrollbar thumb kept in sync with it, so brands can style scrollbars consistently across platforms. Composed of a root plus Viewport, Scrollbar, Thumb, and Corner parts.",props:[{name:"type",type:"'auto' | 'always' | 'hover' | 'scroll'",defaultValue:"'hover'",required:!1,description:'When scrollbar is visible: "hover" on pointer over, "scroll" on scroll, "always"/"auto" always. "auto" mounts track only while axis overflows; "always" always mounts it.'},{name:"scrollHideDelay",type:"number",defaultValue:"600",required:!1,description:'Milliseconds scrollbar stays visible after scroll stops (type="scroll" only).'},{name:"scrollbars",type:"'vertical' | 'horizontal' | 'both'",defaultValue:"'both'",required:!1,description:"Which scrollbars to derive."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Track/thumb size rung, written to data-size on the root; the data-size attribute may be set directly instead."}],events:[{name:"scroll-position-change",description:"Fires with viewport scroll offsets on every scroll tick.",detail:"{ x: number, y: number }"}],parts:[{name:"Scrollbar",description:'Track for one axis with aria-hidden="true"; rendered only while that axis overflows. Its data-state is gated on overflow before anything else: an axis with nothing to scroll stays data-state="hidden" whatever hover, scrolling or type would otherwise say, so a skin never paints a track over content that already fits.',props:[{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'vertical'",required:!1,description:"Track axis; selects which overflow state drives render."},{name:"forceMount",type:"boolean",defaultValue:"false",required:!1,description:"Keep track in flow even when axis does not overflow."}]},{name:"Corner",description:"Square filling the gap where vertical and horizontal scrollbars meet.",props:[{name:"forceMount",type:"boolean",defaultValue:"false",required:!1,description:"Keep corner mounted even when both axes do not overflow."}]}],slots:[{name:"default",description:"Root content \u2014 Viewport, Scrollbar(s), and Corner."}],appearance:[{attribute:"data-size",values:["sm","lg"],stylesheet:"scroll-area.css"}],states:["visible","hidden"],controlledUncontrolled:"Not applicable \u2014 ScrollArea has no value; scroll position is native browser state.",formBehavior:"Not applicable \u2014 ScrollArea does not participate in forms.",validationBehavior:"Not applicable \u2014 ScrollArea carries no value and participates in no validation.",accessibility:{role:"region on Viewport when named; none otherwise",namingRequirement:'Name Viewport with aria-label or aria-labelledby to emit role="region".',keyboard:[{key:"(native)",behavior:"Native scroll keys (Arrow, Page Up/Down, Home/End, Space) on Viewport."}],ariaAttributes:['Viewport carries role="region" plus aria-label or aria-labelledby when named','aria-hidden="true" on Scrollbar, Thumb and Corner'],focusManagement:"Focus stays on Viewport; Scrollbar/Thumb are pointer-only visual affordances."},styling:{cssParts:["viewport","scrollbar","thumb","corner","root"],dataAttributes:[...e,"data-state","data-orientation","data-overflow-x","data-overflow-y","data-size","data-skdx-scroll-area","data-skdx-scroll-area-content","data-skdx-scroll-area-corner","data-skdx-scroll-area-scrollbar","data-skdx-scroll-area-thumb","data-skdx-scroll-area-viewport",{name:"data-skdx-scroll-area-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-scroll-area-track-size","--skdx-scroll-area-thumb-min-length"]},publicMethods:[{name:"scrollTo",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 `useScrollAreaContext` 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:"(options: { top?: number, left?: number, behavior?: 'auto' | 'smooth' }) => void",description:"Scroll Viewport; omitted axes stay where they are."}],contextApi:[{name:"scrollTo",signature:"(options: { top?: number, left?: number, behavior?: 'auto' | 'smooth' }) => void",description:"Scrolls the Viewport to the given position.",accessors:{react:"useScrollAreaContext('MyComponent').scrollTo",vue:"inject(SCROLL_AREA_CONTEXT).scrollTo",svelte:"getContext(SCROLL_AREA_CONTEXT).scrollTo",angular:"inject(SkdxScrollAreaState).scrollTo",webComponents:"document.querySelector('skdx-scroll-area').scrollTo"}}],frameworkExtensions:[{framework:"react",part:"Viewport",name:"contentProps",type:"React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> | undefined",description:"Props for the internal content wrapper the children are measured through; merged with, not replacing, its measurement defaults. This wrapper owns the inner scroll content node and offers an attributes object for it. Other wrappers let consumers compose/configure the content element using their native element and styling hooks.",kind:"prop"},{framework:"vue",part:"Viewport",name:"contentProps",type:"{ class?: string; style?: StyleValue }",description:"Class and style for the internal content wrapper; style merges onto, not replaces, its measurement defaults. This wrapper owns the inner scroll content node and offers an attributes object for it. Other wrappers let consumers compose/configure the content element using their native element and styling hooks.",kind:"prop"},{framework:"svelte",part:"Viewport",name:"contentProps",type:"{ class?: string; style?: string } | undefined",description:"Class and style for the internal `data-skdx-scroll-area-content` wrapper\nchildren are measured through. Style is appended after its\n`min-width: 100%; display: table` measurement defaults, so yours wins. This wrapper owns the inner scroll content node and offers an attributes object for it. Other wrappers let consumers compose/configure the content element using their native element and styling hooks.",kind:"prop"},{framework:"react",part:"Viewport",name:"contentProps",type:"React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> | undefined",description:"Props for the internal content wrapper the children are measured through; merged with, not replacing, its measurement defaults. This wrapper owns the inner scroll content node and offers an attributes object for it. Other wrappers let consumers compose/configure the content element using their native element and styling hooks."},{framework:"vue",part:"Viewport",name:"contentProps",type:"{ class?: string; style?: StyleValue }",description:"Class and style for the internal content wrapper; style merges onto, not replaces, its measurement defaults. This wrapper owns the inner scroll content node and offers an attributes object for it. Other wrappers let consumers compose/configure the content element using their native element and styling hooks."},{framework:"svelte",part:"Viewport",name:"contentProps",type:"{ class?: string; style?: string } | undefined",description:"Class and style for the internal `data-skdx-scroll-area-content` wrapper\nchildren are measured through. Style is appended after its\n`min-width: 100%; display: table` measurement defaults, so yours wins. This wrapper owns the inner scroll content node and offers an attributes object for it. Other wrappers let consumers compose/configure the content element using their native element and styling hooks."}]};export{r as scrollAreaContract};
@@ -1 +1 @@
1
- import{changeDetail as t}from"./change-reason.js";import{constraintValidationMethods as r,setCustomValidityMethod as s}from"./form-validity.js";import{closeAutoFocusEvent as l,dismissalEvents as d,forceMountProp as e,openChangeCompleteEvent as h,popperContentProps as p,popperMeasurementProperties as c,portalPart as a,portalPropsSansForceMount as u}from"./overlay-parts.js";import{VIRTUAL_FOCUS_RULE as m}from"./rules.js";import{SELECTION_ATTRIBUTE_RULE as n,SELECTION_INPUT_RULE as i,SELECTION_OUTPUT_RULE as o}from"./selection-value.js";import{PART_DATA_ATTRIBUTES as g}from"./styling-hooks.js";import{withoutScope as b}from"./types.js";var C={name:"Select",purpose:"A button trigger that displays the current value and opens a positioned popup listbox of options. Derives trigger and listbox from option data when provided. With `multiple` it accumulates values and renders a TagList of removable Tags; with `filterable` it swaps the trigger for a filter Input that narrows the options as the user types.",props:[{name:"options",type:"Array<{ value: string; label?: string; disabled?: boolean } | { label: string; options: Array<{ value: string; label?: string; disabled?: boolean }> }>",required:!1,description:"Flat or grouped option data to render automatically \u2014 trigger, tag list, filter input, Clear button, portal, listbox, and Items \u2014 instead of hand composing them. Seeds items for typeahead and labels on first paint. Property-only on <skdx-select>: HTML attributes cannot carry arrays."},{name:"renderOption",type:"(option: { value: string; label?: string; disabled?: boolean }, state: { selected: boolean }) => React.ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:'Web Components uses a named slot (`slot="option"`, keyed by `data-value`), Vue uses a scoped slot (`#option`), and Angular uses a TemplateRef input. HTML attributes cannot carry functions.',description:"Customises how a derived option renders inside its Item. Receives the option and whether it is currently selected. Only read while options is deriving the anatomy."},{name:"renderValue",type:"(selected: { value: string; label?: string; disabled?: boolean } | Array<{ value: string; label?: string; disabled?: boolean }> | null) => React.ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:'Web Components uses a named slot (`slot="value"`), Vue uses a scoped slot (`#value`), and Angular uses a TemplateRef input always receiving an array. HTML attributes cannot carry functions.',description:"Customizes the trigger's displayed content in place of the default label (or chips in multiple mode). Receives selected option(s) or null."},{name:"renderTag",type:"(option: { value: string; label?: string; disabled?: boolean }) => React.ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:'Web Components uses a named slot (`slot="tag"`, keyed by `data-value`), Vue uses a scoped slot (`#tag`), and Angular uses a TemplateRef input. HTML attributes cannot carry functions.',description:"Customises a selected value's content inside its derived Tag. Only read while `multiple` and options is deriving the anatomy."},{name:"placeholder",type:"string",required:!1,description:"Placeholder shown by the derived trigger while nothing is selected, or by the derived filter Input while `filterable`. Only read while options is deriving the anatomy \u2014 pass it to SelectValue directly under manual composition."},{name:"aria-label",type:"string",required:!1,frameworks:["react","vue","svelte","angular"],exception:"attribute-passthrough",frameworksReason:"Web Components claims the host `aria-label` attribute and relocates it to the derived control; the other four declare it as a prop.",description:"Accessible name for the derived Trigger or filter Input, and for the tag list beside it. Only read while options is deriving the anatomy."},{name:"value",type:"string | string[]",required:!1,description:`Selected option value(s), for controlled usage. Pair with a value-change event/emit/callback. ${i} ${o} ${n}`},{name:"defaultValue",type:"string | string[]",required:!1,description:`Initially selected value(s), for uncontrolled usage. Same shape as \`value\`. ${i} ${n}`},{name:"multiple",type:"boolean",defaultValue:"false",required:!1,description:'Allows more than one option selected. Sets `aria-multiselectable="true"` on Content, toggles options instead of replacing, keeps the listbox open to pick several at once, and lets the derived anatomy render a TagList of removable Tags beside the field.'},{name:"deselectable",type:"boolean",defaultValue:"false",required:!1,description:'Whether picking the already-selected option in single-select mode clears it. Ignored in multiple mode (always toggles). Cleared selection is `[]` with `selectedValue: null` \u2014 the same empty shape an untouched Select reports \u2014 so no third state is needed for "emptied single-select".'},{name:"maxSelected",type:"number",required:!1,description:"Largest number of values selectable while `multiple`. Once reached, unselected options go aria-disabled rather than silently swallowing clicks; already-selected ones stay removable. Inert in single-select mode, where one value is the cap."},{name:"allowSelectAll",type:"boolean",defaultValue:"true",required:!1,description:"Whether Control+A (Command+A) selects every enabled option while `multiple` and the listbox is open, and whether the derived anatomy offers a SelectAll row. With the listbox closed, Control+A keeps its native meaning of selecting draft text and is never intercepted. Stops where `maxSelected` runs out, and clears the selection if every option is already selected."},{name:"items",type:"Array<{ value: string; label?: string; disabled?: boolean }>",required:!1,description:"Option collection declared up front. Enables closed-trigger typeahead and labels on first paint before Content mounts. Purely a data declaration; rendered Items remain the source of truth."},{name:"filterable",type:"boolean",defaultValue:"false",required:!1,description:"Whether the derived anatomy renders a filter Input that narrows the options as the user types. The Input holds DOM focus in place of the Trigger, so `inputValue`, `defaultInputValue`, `filter` and the input-value-change event only mean anything while this is set."},{name:"inputValue",type:"string",required:!1,description:"Controlled draft text in the filter Input. Pair with the input-value-change event. The string the option list is narrowed by; filtering is the consumer's job unless a `filter` predicate is supplied. Read only while `filterable`."},{name:"defaultInputValue",type:"string",defaultValue:"''",required:!1,description:"Initial draft text in the filter Input, for uncontrolled usage."},{name:"filter",type:"(itemText: string, inputValue: string) => boolean | number",required:!1,description:"Predicate deciding which options survive the current draft text. Returns a boolean to filter, or a number to filter and rank (0 excludes, positive keeps). Surviving options are ordered by score descending. Read only while `filterable`."},{name:"loading",type:"boolean",defaultValue:"false",required:!1,description:'Whether the option list is in flight. Publishes aria-busy="true" and data-loading on Content and on the filter Input, and suppresses the selection-count announcement until options arrive. Does not block interaction.'},{name:"clearable",type:"boolean",defaultValue:"false",required:!1,description:"Whether the derived anatomy renders a Clear button that empties the selection and any draft text in one action. Only read while options is deriving the anatomy."},{name:"closeOnSelect",type:"boolean | undefined",defaultValue:"!multiple",required:!1,description:"Whether picking an option closes the listbox. Defaults to `!multiple` \u2014 single-select closes, and a multiple selection stays open, because picking five things should cost five clicks rather than five clicks and five reopenings. Can be set explicitly to override the default."},{name:"open",type:"boolean",required:!1,description:"Whether the listbox is open, for controlled usage."},{name:"defaultOpen",type:"boolean",defaultValue:"false",required:!1,description:"Initial open state, for uncontrolled usage."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the trigger and prevents opening the listbox; tags cannot be removed and the filter Input is disabled. Distinct from `readOnly`, which keeps the trigger focusable and keeps the value in the form."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:'Displays an unchangeable value. Trigger keeps its tab stop and focus, carries aria-readonly="true" and data-readonly, and submits the value; tags stay visible but cannot be removed. Listbox does not open; typeahead commits nothing. Unlike `disabled`, does not drop out of tab order or stop announcing.'},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Marks the hidden native form-participation input as required. Only meaningful with `name`."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Marks the select as invalid, exposed as aria-invalid/data-invalid on the trigger."},{name:"name",type:"string",required:!1,description:"When set, a visually-hidden native form control is kept in sync with `value` so the select participates in native form submission/validation. A `multiple` selection produces one control per value, and so repeated name=value entries."},{name:"form",type:"string | undefined",required:!1,description:"Id of the `<form>` the select submits into, forwarded to every mirrored hidden control, so a select can live outside the form it belongs to \u2014 a filter bar above a table, a control in a portal, a field in a sticky footer. Exactly the native `form` content attribute, and it needs `name` to mean anything, since with no `name` there is no control to associate. The Web Components port gets it for free: `<skdx-select>` is a form-associated custom element, so the platform honours the `form` attribute on the host without the component doing anything \u2014 the property is still declared there so the manifest lists one prop rather than four. It is spelled `formId` in Web Components, never `form`: a form-associated custom element already publishes `form` as a readonly `HTMLFormElement`, and shadowing that reserved property with a writable string would break `select.form`. The markup attribute stays `form` in all five packages."},{name:"autoComplete",type:"string | undefined",required:!1,description:"Browser autofill hint, forwarded to the first mirrored hidden control \u2014 the same one that answers for the whole set's validity. One control rather than all of them, because an autofill token names a single field of an address or a payment method and repeating it across the entries of a `multiple` selection would offer the browser several places to write one value. Any value the HTML autocomplete attribute takes, including `off`."},{name:"getSelectionLabel",type:"(count: number) => string",required:!1,description:'Formats the message announced after each selection change while `multiple`. Without this, screen-reader users get no confirmation that anything happened, since the option that changed is neither focused nor always visible. Return empty string to announce nothing. Defaults to "2 selected". Counts selected options, not rendered ones.'},{name:"shape",type:"'rounded' | 'square' | 'pill' | (string & {})",required:!1,description:"Corner rounding rung forwarded to the Trigger's data-shape, and to every derived Tag's; the attribute may be written on either directly instead."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Size rung forwarded to the Trigger's data-size, and to every derived Tag's; the attribute may be written on either directly instead."},{name:"status",type:"'info' | 'success' | 'warning' | 'danger' | (string & {})",required:!1,description:"Severity rung forwarded to every derived Tag's data-status; the attribute may be written on a Tag directly instead."},{name:"density",type:"'comfortable' | 'compact' | (string & {})",required:!1,description:"Vertical rhythm rung forwarded to the TagList's data-density; the attribute may be written on TagList directly instead."},{name:"matchWidth",type:"boolean",required:!1,description:"Match-width switch forwarded to the Content panel's data-match-width; the attribute may be written on Content directly instead."}],events:[{name:"value-change",description:`Fires whenever the selected option changes, controlled or not \u2014 carrying the whole selection, not the single option that was toggled, so the array can be written straight back to state. ${o}`,detail:t("string[]","selectedValue: string | null")},{name:"value-change-detail",frameworks:["angular"],exception:"event-shape",frameworksReason:"Angular's `valueChange` emits the whole `string[]` selection so `[(value)]` round-trips it; this second output carries the detail object the other four hand to `value-change`.",description:"Fires with valueChange, carrying the whole selection plus the option that changed.",detail:t("string[]","selectedValue: string | null")},{name:"input-value-change",description:"Fires with the new draft text on every keystroke in the filter Input, and with the empty string when a selection or the Clear button empties it.",detail:"string"},{name:"open-change",detail:"boolean",description:"Fires with the new open state whenever the listbox opens or closes, controlled or not."},h("listbox"),...d("listbox"),l("listbox")],parts:[{name:"Trigger",lightDom:!0,description:"The button that opens the listbox and displays the current value. Replaced by the Input part while `filterable`.",props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,frameworks:["react","webComponents"],exception:"root-prop",frameworksReason:"Vue, Svelte and Angular read the root's `disabled` off context and expose no per-trigger override; disabling the Select root disables its trigger there, which is the same switch one level up.",description:"Disables this trigger on its own; a disabled root disables every trigger regardless of this value."},{name:"shape",type:"'rounded' | 'square' | 'pill' | (string & {})",required:!1,description:"Corner rounding rung, written to data-shape on the trigger; the data-shape attribute may be set directly instead."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the trigger; the data-size attribute may be set directly instead."}]},{name:"Value",description:"Renders the selected option's label, or placeholder when nothing is selected. In multiple mode, renders one chip per selection (not interactive, as Trigger is a button). Deselecting happens in the listbox, or on the removable Tags of a TagList.",props:[{name:"placeholder",type:"string",required:!1,description:"Content shown while no option is selected."}]},{name:"Icon",description:"Decorative open/close indicator inside Trigger."},{name:"TagList",description:"The tag strip rendering one Tag per selected value while `multiple`, in selection order. Built on TagGroup, which is where removal gets its focus behaviour; `disabled` comes from the root.",props:[{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Layout axis of the tag strip, published as data-orientation and deciding arrow-key direction: Left/Right when horizontal, Up/Down when vertical."},{name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Whether arrow-key navigation wraps between the first and last tag."},{name:"density",type:"'comfortable' | 'compact' | (string & {})",required:!1,description:"Vertical rhythm rung, written to data-density on the tag list; the data-density attribute may be set directly instead."},{name:"tags",type:"ReadonlyArray<{ value: string; label: string; disabled?: boolean }>",required:!1,frameworks:["webComponents"],exception:"wc-internals",frameworksReason:"`<skdx-select-tag-list>` subclasses `<skdx-tag-group>`, so the base element's entry data reaches it too. The other four compose TagGroup and render one Tag per selected value themselves, which is what this strip is for.",description:"Entry data the tag group would derive Badges from, inherited from the base element and left unset here."},{name:"removable",type:"boolean",defaultValue:"false",required:!1,frameworks:["webComponents"],exception:"wc-internals",frameworksReason:"`<skdx-select-tag-list>` subclasses `<skdx-tag-group>`, so the base element's switch reaches it too. The other four compose TagGroup and give every Tag its own TagRemove instead.",description:"Whether a tag derived from the inherited entry data carries its own remove button."}],events:[{name:"remove",frameworks:["webComponents"],exception:"wc-internals",frameworksReason:"`<skdx-select-tag-list>` subclasses `<skdx-tag-group>` and inherits its removal event; React, Vue, Svelte and Angular compose TagGroup instead, so a removed tag reaches the consumer through the root value-change alone.",description:"Fires when a tag is removed without veto, carrying the removed tag's text and position.",detail:"{ label: string; index: number }"}]},{name:"Tag",description:"One selected value inside TagList, showing the option's text or the raw value if none was declared. Carries `data-skdx-select-tag` so a tag can be told from the chips Value renders inside the button trigger.",props:[{name:"value",type:"string",required:!0,description:"The selected value this tag represents. Required: it deselects when remove is clicked and decides the tag's place in roving tab order."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Locks this tag: the remove button refuses, it is painted with data-disabled, and roving focus steps over it. Per-tag rather than per-root, for pinned values like mandatory scopes. ORs with the root's locked state."},{name:"shape",type:"'rounded' | 'square' | 'pill' | (string & {})",required:!1,description:"Corner rounding rung, written to data-shape on the tag; the data-shape attribute may be set directly instead."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the tag; the data-size attribute may be set directly instead."},{name:"status",type:"'info' | 'success' | 'warning' | 'danger' | (string & {})",required:!1,description:"Severity rung, written to data-status on the tag; the data-status attribute may be set directly instead."}]},{name:"TagRemove",description:'The remove button inside a Tag, deselecting that value. Named automatically ("Remove Ruby"). Override with `aria-label` or the `label` prop.',props:[{name:"label",type:"string",required:!1,frameworks:["webComponents"],exception:"attribute-passthrough",frameworksReason:"React, Vue, Svelte and Angular take `aria-label` on the element through attribute passthrough.",description:"Accessible name for the remove button, replacing the generated `Remove <value>`."}]},{name:"Input",lightDom:!0,description:'The filter text field rendered while `filterable`, holding DOM focus in the Trigger\'s place. Carries role="combobox", aria-expanded, aria-controls, aria-autocomplete, and aria-activedescendant naming the highlighted option.'},{name:"Clear",description:'Button emptying the selection and any draft text in one press, then returning focus to the Input, or the Trigger where there is none. Rendered beside the field rather than inside TagList, with its own tab stop, and named automatically ("Clear selection"). Disabled while the root is disabled or readOnly, or the selection is empty and the draft blank.'},{...a,description:`${a.description} React and Web Components only. Vue, Svelte, and Angular position Content with @floating-ui/dom's strategy: 'fixed' and do not teleport. In Web Components, parts hide with hidden rather than unmounting.`,frameworks:["react","webComponents"],exception:"portal",frameworksReason:"Vue, Svelte, and Angular position Content with strategy: 'fixed' and do not need SelectPortal. Scoped to the part so both members inherit it.",props:[...u,{...e,frameworks:["react"],exception:"force-mount",frameworksReason:"The part's own scope already excludes Vue, Svelte and Angular; this narrows the prop one framework further. <skdx-select-portal> declares no force-mount and says so in its own doc comment \u2014 its parts never unmount, they hide via `hidden`, so there is nothing to force and nothing to keep alive for an exit animation. A prop's `frameworks` overrides its part's rather than intersecting, so this list names the one package that ships it."}]},{name:"Content",description:'The floating listbox (role="listbox", plus aria-multiselectable="true" in multiple mode). Opens below and start-aligned. Manages dismissal: Escape and outside interactions trigger cancelable dismissal events before closing.',props:[...p({align:"'start'",sideOffset:"4"}),{...e,frameworks:["react"],exception:"force-mount",frameworksReason:"Only React unmounts. Vue, Svelte, Angular, and Web Components toggle hidden on the element, so it persists for exit animations."},{name:"matchWidth",type:"boolean",required:!1,description:"Matches the listbox width to the trigger, written to data-match-width on Content; the data-match-width attribute may be set directly instead."}]},{name:"Viewport",description:"Scrollable container for Items inside Content."},{name:"SelectAll",description:"A row at the head of the listbox toggling every enabled option at once, offered while `multiple` and `allowSelectAll`. Its aria-selected reports whether the whole enabled set is currently selected, and it stops where `maxSelected` runs out."},{name:"Item",description:'One selectable option (role="option"). Goes aria-disabled while unselected and `maxSelected` is reached, so the cap is announced rather than felt as a dead click.',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 from selection and keyboard navigation. Carries aria-disabled="true" and data-disabled, so it remains accessible to screen readers.'},{name:"textValue",type:"string",required:!1,description:"Text for Trigger label, typeahead and the root filter, published as `data-text-value`; falls back to rendered text. Needed when the item contains more than text alone."}]},{name:"ItemText",description:"An Item's label content, captured so Value can render it inside Trigger."},{name:"ItemIndicator",description:"Selected-state glyph inside an Item, rendered only while that item is selected.",props:[b(e)]},{name:"Group",description:'Groups related Items under a Label (role="group"). Automatically wires aria-labelledby. Label is required inside Group.'},{name:"Label",description:"Non-interactive heading for Group, providing its accessible name. Outside a Group it renders but does not name anything."},{name:"Separator",description:'Visual divider between Items or Groups inside Content. Renders an aria-hidden element, not role="separator".'},{name:"Empty",description:'Message shown when the filter leaves no option to render. Rendered inside Portal as a sibling of Content with aria-live="polite", never inside the role="listbox" \u2014 an empty-state string announced as an option is worse than one not announced at all.'}],slots:[{name:"default",description:"Root content \u2014 the trigger, portal and content parts."},{name:"trigger",description:"SelectTrigger content: Value part (current selection) and Icon part (open/close indicator)."},{name:"content",description:"SelectContent: SelectOption, SelectGroup, SelectLabel, SelectSeparator."},{name:"option",frameworks:["vue","webComponents"],exception:"render-prop",frameworksReason:"React, Svelte and Angular reach the same customisation through the `renderOption` prop \u2014 a function, a snippet and a TemplateRef \u2014 because their content projection is not addressable by name from option data.",description:"Body of one derived option row, in place of the label its option data carries."},{name:"value",frameworks:["vue","webComponents"],exception:"render-prop",frameworksReason:"React, Svelte and Angular reach the same customisation through the `renderValue` prop, which receives the selected option(s) a slot would have to be handed some other way.",description:"Replacement body for the derived Value part, rendered instead of the resolved label."},{name:"tag",frameworks:["vue","webComponents"],exception:"render-prop",frameworksReason:"React, Svelte and Angular reach the same customisation through the `renderTag` prop, keyed by value rather than by a named slot the markup repeats per tag.",description:"Body of one derived Tag, in place of the resolved option label."},{name:"renderTag",frameworks:["svelte"],exception:"snippet-opaque",frameworksReason:"Svelte spells a render prop as a snippet, so `renderTag` is both the prop and the slot there; Vue and Web Components take the same content through the `tag` slot, and React and Angular through a prop that is not projection at all.",description:"Snippet form of the `tag` slot, passed as the `renderTag` prop."}],appearance:[{attribute:"data-match-width",values:[],stylesheet:"select.css"},{attribute:"data-shape",values:["rounded","square","pill"],stylesheet:"select.css"},{attribute:"data-size",values:["sm","lg"],stylesheet:"select.css"},{attribute:"data-status",values:["info","success","warning","danger"],stylesheet:"select.css"},{attribute:"data-density",values:["comfortable","compact"],stylesheet:"select.css"}],states:["closed","open","loading","disabled","readonly","invalid","required","multiple","highlighted","checked","unchecked"],controlledUncontrolled:"Three independent axes (value, inputValue, open) each start from their default and switch to controlled when the matching prop is passed, paired with a change event. In Angular the value pair is split: `valueChange` emits the whole `string[]` selection for `[(value)]`, `valueChangeDetail` carries the detail.",formBehavior:'With `name` set, a visually-hidden native control mirrors `value` for submission, reset and \u2014 with `required` \u2014 validation. It is never `type="hidden"` and never `readonly`; both bar an input from constraint validation, which would make `required` silently inert. A `multiple` select mirrors one hidden control per selected value under the same `name`, producing the repeated entries a native `<select multiple>` produces rather than one joined string, and an empty `multiple` selection submits nothing at all \u2014 except under `required`, where one empty-valued control still renders so `valueMissing` has somewhere to fire. A single select keeps one control at all times. Draft text in the filter Input never submits. Web Components publish value and validity through `ElementInternals` instead, because their mirrored input lives in the shadow root and is not associated with the ancestor form. A form reset restores `defaultValue` and `defaultInputValue` \u2014 silently in Web Components, and by firing value-change in React/Vue/Svelte/Angular. `form` associates every mirrored control with a form the select does not sit inside, and `autoComplete` hints the first of them. A `readOnly` select submits exactly as an editable one does; only `disabled` withholds the value.',validationBehavior:"`invalid` is a purely presentational flag (aria-invalid/data-invalid on the trigger); `required` participates in native constraint validation only when `name` is set. With `name` and `required` and no selection, `checkValidity()`/`reportValidity()` report `valueMissing` and block submission identically in all five frameworks; a select with a value is valid. `maxSelected` makes further options inert rather than invalid \u2014 reaching a cap is not an error. A minimum count, or any cross-field rule, belongs to the surrounding Field or Form.",accessibility:{role:'combobox (trigger, or the filter Input) with aria-haspopup="listbox"; listbox (content, with aria-multiselectable in multiple mode); option (each SelectOption)',keyboard:[{key:"Enter, Space, Alt+ArrowDown (on a closed trigger)",behavior:"Opens the listbox without moving the active option: the active option is the already-selected one. With nothing selected, the first enabled option becomes active."},{key:"ArrowDown / Home (on a closed trigger)",behavior:"Opens the listbox and makes the first enabled option active."},{key:"ArrowUp / End (on a closed trigger)",behavior:"Opens the listbox and makes the last enabled option active."},{key:"ArrowDown / ArrowUp (in listbox)",behavior:"Moves the active option to the next/previous enabled one (no wrap). Virtual focus handles this on the trigger, or on the filter Input while `filterable`."},{key:"PageDown / PageUp (in listbox)",behavior:"Moves the active option ten enabled options down/up, clamped at the ends. Ten is a fixed count for consistency across frameworks."},{key:"Home / End (in listbox)",behavior:"Makes the first / last enabled option active. Only while the listbox is open: with a `filterable` select closed, both are caret keys of the text field and must not be intercepted."},{key:"Alt+ArrowUp (while the listbox is open)",behavior:"Commits the active option and closes the listbox (counterpart to Alt+ArrowDown). Alt+ArrowDown while open does nothing."},{key:"Printable characters (in listbox)",behavior:"Typeahead: makes the next option whose label starts with the typed text active. Matched against `data-text-value` when present, else the option's text. While `filterable` the same keys type into the Input and narrow the list instead."},{key:"Printable characters (on trigger, closed)",behavior:"Typeahead against labels (like native `<select>`): selects the next matching option without opening. Supply `items` for labels before Content mounts. In multiple mode the same keys open the listbox instead of committing, because toggling an option the user cannot see would change the selection blind."},{key:"Enter or Space (while the listbox is open)",behavior:"Selects the active option. Single-select closes the listbox; `multiple` toggles the option and leaves the listbox open. Either way the trigger already holds DOM focus and never loses it."},{key:"Shift+ArrowDown / Shift+ArrowUp (in listbox, multiple)",behavior:"Moves the active option and toggles what it lands on, extending the selection without an Enter at every step. Nothing toggles if the highlight did not move (clamped at the ends). The cap needs no rule of its own: unselected options are already aria-disabled."},{key:"Shift+Space (in listbox, multiple)",behavior:"Selects every enabled option between the last one toggled \u2014 the range anchor \u2014 and the active one, inclusive. Never deselects. Stops where `maxSelected` runs out. With no anchor, selects the active option alone."},{key:"Control+Shift+Home / Control+Shift+End (in listbox, multiple)",behavior:"Selects every enabled option from the active one to the first or last, inclusive. Additive and never deselecting. The active option does not move, and the range anchor stays where the last toggle put it. Inert while the listbox is closed."},{key:"Control+A (in listbox, multiple)",behavior:"While `allowSelectAll`: selects every enabled option, and clears them all if they are already selected. Only while the listbox is open \u2014 closed, it keeps its native meaning of selecting draft text. Stops where `maxSelected` runs out."},{key:"Backspace (on an empty filter Input)",behavior:"Removes the last selected value. Only on an empty input: it must never eat a character the user is still editing."},{key:"Arrow keys (in TagList)",behavior:"Move between the tags of a multiple selection in one roving tab stop."},{key:"Escape",behavior:"Closes the listbox and returns focus to the trigger."},{key:"Tab / Shift+Tab (while the listbox is open)",behavior:"Commits the active option, closes the listbox, and lets focus continue: the default action is never prevented. In multiple mode, Tab *adds* the active option to selection without removing others."}],ariaAttributes:['aria-expanded, aria-controls, aria-haspopup="listbox", aria-required, aria-invalid on the trigger',"aria-autocomplete on the filter Input, which takes aria-expanded and aria-controls in the trigger's place while `filterable`",'aria-readonly="true" and data-readonly on the trigger while `readOnly` (absent otherwise) \u2014 trigger keeps its tab stop, so the state is announced',"aria-labelledby on the trigger, naming the Value part (see `namingRequirement`)","aria-activedescendant on the trigger, or the filter Input, naming the active option (only when open)",'aria-multiselectable="true" on the listbox in multiple mode (absent otherwise)',"aria-selected on each option; data-highlighted on the active one",'aria-disabled="true" and data-disabled on a disabled option (absent otherwise), and on an unselected option once `maxSelected` is reached','aria-busy="true" and data-loading on Content and the filter Input while `loading`',"aria-labelledby on each Group, naming its Label part",'the Empty part carries aria-live="polite" and sits outside the role="listbox"',"the selection count is announced after every change in multiple mode"],focusManagement:`${m} Here the anchor is the trigger, or the filter Input while \`filterable\`. Opening makes the selected (or first enabled) option active. Arrows, Home/End, typeahead, and pointer hover move the active option. Tab closes the listbox and lets focus continue. TagList separately roves real DOM focus among the tags: removing one moves focus to the next tag, the preceding tag if it was the last, or TagList itself if it was the only one \u2014 never to the field. That focus behaviour is inherited from TagGroup rather than re-implemented here.`,namingRequirement:'role="combobox" does NOT take an accessible name from content. Trigger uses aria-labelledby pointing to Value (which is its current value), so a consumer must supply an associated <label> or aria-label for context; the filter Input needs the same. TagList needs its own name, since the tags are its content and cannot name it. Group is named similarly with aria-labelledby and requires a Label part.'},styling:{cssParts:["trigger","value","chip","icon","tag-list","tag","tag-remove","remove","input","clear","content","select-all","item","group","label","separator","item-text","item-indicator","viewport","empty"],dataAttributes:[...g,"data-state","data-disabled","data-readonly","data-invalid","data-loading","data-placeholder","data-highlighted","data-multiple","data-chip","data-skdx-select-tag","data-value","data-text-value","data-side","data-align","data-match-width","data-shape","data-size","data-status","data-density",{name:"data-skdx-select-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:c("select")},publicMethods:[...r,s],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{C as selectContract};
1
+ import{changeDetail as t}from"./change-reason.js";import{constraintValidationMethods as r,setCustomValidityMethod as s}from"./form-validity.js";import{closeAutoFocusEvent as l,dismissalEvents as d,forceMountProp as e,openChangeCompleteEvent as h,popperContentProps as p,popperMeasurementProperties as c,portalPart as a,portalPropsSansForceMount as u}from"./overlay-parts.js";import{VIRTUAL_FOCUS_RULE as m}from"./rules.js";import{SELECTION_ATTRIBUTE_RULE as n,SELECTION_INPUT_RULE as i,SELECTION_OUTPUT_RULE as o}from"./selection-value.js";import{PART_DATA_ATTRIBUTES as g}from"./styling-hooks.js";import{withoutScope as f}from"./types.js";var C={name:"Select",purpose:"A button trigger that displays the current value and opens a positioned popup listbox of options. Derives trigger and listbox from option data when provided. With `multiple` it accumulates values and renders a TagList of removable Tags; with `filterable` it swaps the trigger for a filter Input that narrows the options as the user types.",props:[{name:"options",type:"Array<{ value: string; label?: string; disabled?: boolean } | { label: string; options: Array<{ value: string; label?: string; disabled?: boolean }> }>",required:!1,description:"Flat or grouped option data to render automatically \u2014 trigger, tag list, filter input, Clear button, portal, listbox, and Items \u2014 instead of hand composing them. Seeds items for typeahead and labels on first paint. Property-only on <skdx-select>: HTML attributes cannot carry arrays."},{name:"renderOption",type:"(option: { value: string; label?: string; disabled?: boolean }, state: { selected: boolean }) => React.ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:'Web Components uses a named slot (`slot="option"`, keyed by `data-value`), Vue uses a scoped slot (`#option`), and Angular uses a TemplateRef input. HTML attributes cannot carry functions.',description:"Customises how a derived option renders inside its Item. Receives the option and whether it is currently selected. Only read while options is deriving the anatomy."},{name:"renderValue",type:"(selected: { value: string; label?: string; disabled?: boolean } | Array<{ value: string; label?: string; disabled?: boolean }> | null) => React.ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:'Web Components uses a named slot (`slot="value"`), Vue uses a scoped slot (`#value`), and Angular uses a TemplateRef input always receiving an array. HTML attributes cannot carry functions.',description:"Customizes the trigger's displayed content in place of the default label (or chips in multiple mode). Receives selected option(s) or null."},{name:"renderTag",type:"(option: { value: string; label?: string; disabled?: boolean }) => React.ReactNode",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:'Web Components uses a named slot (`slot="tag"`, keyed by `data-value`), Vue uses a scoped slot (`#tag`), and Angular uses a TemplateRef input. HTML attributes cannot carry functions.',description:"Customises a selected value's content inside its derived Tag. Only read while `multiple` and options is deriving the anatomy."},{name:"placeholder",type:"string",required:!1,description:"Placeholder shown by the derived trigger while nothing is selected, or by the derived filter Input while `filterable`. Only read while options is deriving the anatomy \u2014 pass it to SelectValue directly under manual composition."},{name:"aria-label",type:"string",required:!1,frameworks:["react","vue","svelte","angular"],exception:"attribute-passthrough",frameworksReason:"Web Components claims the host `aria-label` attribute and relocates it to the derived control; the other four declare it as a prop.",description:"Accessible name for the derived Trigger or filter Input, and for the tag list beside it. Only read while options is deriving the anatomy."},{name:"value",type:"string | string[]",required:!1,description:`Selected option value(s), for controlled usage. Pair with a value-change event/emit/callback. ${i} ${o} ${n}`},{name:"defaultValue",type:"string | string[]",required:!1,description:`Initially selected value(s), for uncontrolled usage. Same shape as \`value\`. ${i} ${n}`},{name:"multiple",type:"boolean",defaultValue:"false",required:!1,description:'Allows more than one option selected. Sets `aria-multiselectable="true"` on Content, toggles options instead of replacing, keeps the listbox open to pick several at once, and lets the derived anatomy render a TagList of removable Tags beside the field.'},{name:"deselectable",type:"boolean",defaultValue:"false",required:!1,description:'Whether picking the already-selected option in single-select mode clears it. Ignored in multiple mode (always toggles). Cleared selection is `[]` with `selectedValue: null` \u2014 the same empty shape an untouched Select reports \u2014 so no third state is needed for "emptied single-select".'},{name:"maxSelected",type:"number",required:!1,description:"Largest number of values selectable while `multiple`. Once reached, unselected options go aria-disabled rather than silently swallowing clicks; already-selected ones stay removable. Inert in single-select mode, where one value is the cap."},{name:"allowSelectAll",type:"boolean",defaultValue:"true",required:!1,description:"Whether Control+A (Command+A) selects every enabled option while `multiple` and the listbox is open, and whether the derived anatomy offers a SelectAll row. With the listbox closed, Control+A keeps its native meaning of selecting draft text and is never intercepted. Stops where `maxSelected` runs out, and clears the selection if every option is already selected."},{name:"items",type:"Array<{ value: string; label?: string; disabled?: boolean }>",required:!1,description:"Option collection declared up front. Enables closed-trigger typeahead and labels on first paint before Content mounts. Purely a data declaration; rendered Items remain the source of truth."},{name:"filterable",type:"boolean",defaultValue:"false",required:!1,description:"Whether the derived anatomy renders a filter Input that narrows the options as the user types. The Input holds DOM focus in place of the Trigger, so `inputValue`, `defaultInputValue`, `filter` and the input-value-change event only mean anything while this is set."},{name:"inputValue",type:"string",required:!1,description:"Controlled draft text in the filter Input. Pair with the input-value-change event. The string the option list is narrowed by; filtering is the consumer's job unless a `filter` predicate is supplied. Read only while `filterable`."},{name:"defaultInputValue",type:"string",defaultValue:"''",required:!1,description:"Initial draft text in the filter Input, for uncontrolled usage."},{name:"filter",type:"(itemText: string, inputValue: string) => boolean | number",required:!1,description:"Predicate deciding which options survive the current draft text. Returns a boolean to filter, or a number to filter and rank (0 excludes, positive keeps). Surviving options are ordered by score descending. Read only while `filterable`."},{name:"loading",type:"boolean",defaultValue:"false",required:!1,description:'Whether the option list is in flight. Publishes aria-busy="true" and data-loading on Content and on the filter Input, and suppresses the selection-count announcement until options arrive. Does not block interaction.'},{name:"clearable",type:"boolean",defaultValue:"false",required:!1,description:"Whether the derived anatomy renders a Clear button that empties the selection and any draft text in one action. Only read while options is deriving the anatomy."},{name:"closeOnSelect",type:"boolean | undefined",defaultValue:"!multiple",required:!1,description:"Whether picking an option closes the listbox. Defaults to `!multiple` \u2014 single-select closes, and a multiple selection stays open, because picking five things should cost five clicks rather than five clicks and five reopenings. Can be set explicitly to override the default."},{name:"open",type:"boolean",required:!1,description:"Whether the listbox is open, for controlled usage."},{name:"defaultOpen",type:"boolean",defaultValue:"false",required:!1,description:"Initial open state, for uncontrolled usage."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the trigger and prevents opening the listbox; tags cannot be removed and the filter Input is disabled. Distinct from `readOnly`, which keeps the trigger focusable and keeps the value in the form."},{name:"readOnly",type:"boolean",defaultValue:"false",required:!1,description:'Displays an unchangeable value. Trigger keeps its tab stop and focus, carries aria-readonly="true" and data-readonly, and submits the value; tags stay visible but cannot be removed. Listbox does not open; typeahead commits nothing. Unlike `disabled`, does not drop out of tab order or stop announcing.'},{name:"required",type:"boolean",defaultValue:"false",required:!1,description:"Marks the hidden native form-participation input as required. Only meaningful with `name`."},{name:"invalid",type:"boolean",defaultValue:"false",required:!1,description:"Marks the select as invalid, exposed as aria-invalid/data-invalid on the trigger."},{name:"name",type:"string",required:!1,description:"When set, a visually-hidden native form control is kept in sync with `value` so the select participates in native form submission/validation. A `multiple` selection produces one control per value, and so repeated name=value entries."},{name:"form",type:"string | undefined",required:!1,description:"Id of the `<form>` the select submits into, forwarded to every mirrored hidden control, so a select can live outside the form it belongs to \u2014 a filter bar above a table, a control in a portal, a field in a sticky footer. Exactly the native `form` content attribute, and it needs `name` to mean anything, since with no `name` there is no control to associate. The Web Components port gets it for free: `<skdx-select>` is a form-associated custom element, so the platform honours the `form` attribute on the host without the component doing anything \u2014 the property is still declared there so the manifest lists one prop rather than four. It is spelled `formId` in Web Components, never `form`: a form-associated custom element already publishes `form` as a readonly `HTMLFormElement`, and shadowing that reserved property with a writable string would break `select.form`. The markup attribute stays `form` in all five packages."},{name:"autoComplete",type:"string | undefined",required:!1,description:"Browser autofill hint, forwarded to the first mirrored hidden control \u2014 the same one that answers for the whole set's validity. One control rather than all of them, because an autofill token names a single field of an address or a payment method and repeating it across the entries of a `multiple` selection would offer the browser several places to write one value. Any value the HTML autocomplete attribute takes, including `off`."},{name:"getSelectionLabel",type:"(count: number) => string",required:!1,description:'Formats the message announced after each selection change while `multiple`. Without this, screen-reader users get no confirmation that anything happened, since the option that changed is neither focused nor always visible. Return empty string to announce nothing. Defaults to "2 selected". Counts selected options, not rendered ones.'},{name:"shape",type:"'rounded' | 'square' | 'pill' | (string & {})",required:!1,description:"Corner rounding rung forwarded to the Trigger's data-shape, and to every derived Tag's; the attribute may be written on either directly instead."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Size rung forwarded to the Trigger's data-size, and to every derived Tag's; the attribute may be written on either directly instead."},{name:"status",type:"'info' | 'success' | 'warning' | 'danger' | (string & {})",required:!1,description:"Severity rung forwarded to every derived Tag's data-status; the attribute may be written on a Tag directly instead."},{name:"density",type:"'comfortable' | 'compact' | (string & {})",required:!1,description:"Vertical rhythm rung forwarded to the TagList's data-density; the attribute may be written on TagList directly instead."},{name:"matchWidth",type:"boolean",required:!1,description:"Match-width switch forwarded to the Content panel's data-match-width; the attribute may be written on Content directly instead."}],events:[{name:"value-change",description:`Fires whenever the selected option changes, controlled or not \u2014 carrying the whole selection, not the single option that was toggled, so the array can be written straight back to state. ${o}`,detail:t("string[]","selectedValue: string | null")},{name:"value-change-detail",frameworks:["angular"],exception:"event-shape",frameworksReason:"Angular's `valueChange` emits the whole `string[]` selection so `[(value)]` round-trips it; this second output carries the detail object the other four hand to `value-change`.",description:"Fires with valueChange, carrying the whole selection plus the option that changed.",detail:t("string[]","selectedValue: string | null")},{name:"input-value-change",description:"Fires with the new draft text on every keystroke in the filter Input, and with the empty string when a selection or the Clear button empties it.",detail:"string"},{name:"open-change",detail:"boolean",description:"Fires with the new open state whenever the listbox opens or closes, controlled or not."},h("listbox"),...d("listbox"),l("listbox")],parts:[{name:"Trigger",lightDom:!0,description:"The button that opens the listbox and displays the current value. Replaced by the Input part while `filterable`.",props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,frameworks:["react","webComponents"],exception:"root-prop",frameworksReason:"Vue, Svelte and Angular read the root's `disabled` off context and expose no per-trigger override; disabling the Select root disables its trigger there, which is the same switch one level up.",description:"Disables this trigger on its own; a disabled root disables every trigger regardless of this value."},{name:"shape",type:"'rounded' | 'square' | 'pill' | (string & {})",required:!1,description:"Corner rounding rung, written to data-shape on the trigger; the data-shape attribute may be set directly instead."},{name:"size",type:"'sm' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the trigger; the data-size attribute may be set directly instead."}],slots:[{name:"default",description:"SelectTrigger content: Value part (current selection) and Icon part (open/close indicator)."}]},{name:"Value",description:"Renders the selected option's label, or placeholder when nothing is selected. In multiple mode, renders one chip per selection (not interactive, as Trigger is a button). Deselecting happens in the listbox, or on the removable Tags of a TagList.",props:[{name:"placeholder",type:"string",required:!1,description:"Content shown while no option is selected."}]},{name:"Icon",description:"Decorative open/close indicator inside Trigger."},{name:"TagList",description:"The tag strip rendering one Tag per selected value while `multiple`, in selection order. Built on TagGroup, which is where removal gets its focus behaviour; `disabled` comes from the root.",props:[{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Layout axis of the tag strip, published as data-orientation and deciding arrow-key direction: Left/Right when horizontal, Up/Down when vertical."},{name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Whether arrow-key navigation wraps between the first and last tag."},{name:"density",type:"'comfortable' | 'compact' | (string & {})",required:!1,description:"Vertical rhythm rung, written to data-density on the tag list; the data-density attribute may be set directly instead."},{name:"tags",type:"ReadonlyArray<{ value: string; label: string; disabled?: boolean }>",required:!1,frameworks:["webComponents"],exception:"wc-internals",frameworksReason:"`<skdx-select-tag-list>` subclasses `<skdx-tag-group>`, so the base element's entry data reaches it too. The other four compose TagGroup and render one Tag per selected value themselves, which is what this strip is for.",description:"Entry data the tag group would derive Badges from, inherited from the base element and left unset here."},{name:"removable",type:"boolean",defaultValue:"false",required:!1,frameworks:["webComponents"],exception:"wc-internals",frameworksReason:"`<skdx-select-tag-list>` subclasses `<skdx-tag-group>`, so the base element's switch reaches it too. The other four compose TagGroup and give every Tag its own TagRemove instead.",description:"Whether a tag derived from the inherited entry data carries its own remove button."}],events:[{name:"remove",frameworks:["webComponents"],exception:"wc-internals",frameworksReason:"`<skdx-select-tag-list>` subclasses `<skdx-tag-group>` and inherits its removal event; React, Vue, Svelte and Angular compose TagGroup instead, so a removed tag reaches the consumer through the root value-change alone.",description:"Fires when a tag is removed without veto, carrying the removed tag's text and position.",detail:"{ label: string; index: number }"}]},{name:"Tag",description:"One selected value inside TagList, showing the option's text or the raw value if none was declared. Carries `data-skdx-select-tag` so a tag can be told from the chips Value renders inside the button trigger.",props:[{name:"value",type:"string",required:!0,description:"The selected value this tag represents. Required: it deselects when remove is clicked and decides the tag's place in roving tab order."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Locks this tag: the remove button refuses, it is painted with data-disabled, and roving focus steps over it. Per-tag rather than per-root, for pinned values like mandatory scopes. ORs with the root's locked state."},{name:"shape",type:"'rounded' | 'square' | 'pill' | (string & {})",required:!1,description:"Corner rounding rung, written to data-shape on the tag; the data-shape attribute may be set directly instead."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the tag; the data-size attribute may be set directly instead."},{name:"status",type:"'info' | 'success' | 'warning' | 'danger' | (string & {})",required:!1,description:"Severity rung, written to data-status on the tag; the data-status attribute may be set directly instead."}]},{name:"TagRemove",description:'The remove button inside a Tag, deselecting that value. Named automatically ("Remove Ruby"). Override with `aria-label` or the `label` prop.',props:[{name:"label",type:"string",required:!1,frameworks:["webComponents"],exception:"attribute-passthrough",frameworksReason:"React, Vue, Svelte and Angular take `aria-label` on the element through attribute passthrough.",description:"Accessible name for the remove button, replacing the generated `Remove <value>`."}]},{name:"Input",lightDom:!0,description:'The filter text field rendered while `filterable`, holding DOM focus in the Trigger\'s place. Carries role="combobox", aria-expanded, aria-controls, aria-autocomplete, and aria-activedescendant naming the highlighted option.'},{name:"Clear",description:'Button emptying the selection and any draft text in one press, then returning focus to the Input, or the Trigger where there is none. Rendered beside the field rather than inside TagList, with its own tab stop, and named automatically ("Clear selection"). Disabled while the root is disabled or readOnly, or the selection is empty and the draft blank.'},{...a,description:`${a.description} React and Web Components only. Vue, Svelte, and Angular position Content with @floating-ui/dom's strategy: 'fixed' and do not teleport. In Web Components, parts hide with hidden rather than unmounting.`,frameworks:["react","webComponents"],exception:"portal",frameworksReason:"Vue, Svelte, and Angular position Content with strategy: 'fixed' and do not need SelectPortal. Scoped to the part so both members inherit it.",props:[...u,{...e,frameworks:["react"],exception:"force-mount",frameworksReason:"The part's own scope already excludes Vue, Svelte and Angular; this narrows the prop one framework further. <skdx-select-portal> declares no force-mount and says so in its own doc comment \u2014 its parts never unmount, they hide via `hidden`, so there is nothing to force and nothing to keep alive for an exit animation. A prop's `frameworks` overrides its part's rather than intersecting, so this list names the one package that ships it."}]},{name:"Content",description:'The floating listbox (role="listbox", plus aria-multiselectable="true" in multiple mode). Opens below and start-aligned. Manages dismissal: Escape and outside interactions trigger cancelable dismissal events before closing.',props:[...p({align:"'start'",sideOffset:"4"}),{...e,frameworks:["react"],exception:"force-mount",frameworksReason:"Only React unmounts. Vue, Svelte, Angular, and Web Components toggle hidden on the element, so it persists for exit animations."},{name:"matchWidth",type:"boolean",required:!1,description:"Matches the listbox width to the trigger, written to data-match-width on Content; the data-match-width attribute may be set directly instead."}],slots:[{name:"default",description:"SelectContent: SelectOption, SelectGroup, SelectLabel, SelectSeparator."}]},{name:"Viewport",description:"Scrollable container for Items inside Content."},{name:"SelectAll",description:"A row at the head of the listbox toggling every enabled option at once, offered while `multiple` and `allowSelectAll`. Its aria-selected reports whether the whole enabled set is currently selected, and it stops where `maxSelected` runs out."},{name:"Item",description:'One selectable option (role="option"). Goes aria-disabled while unselected and `maxSelected` is reached, so the cap is announced rather than felt as a dead click.',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 from selection and keyboard navigation. Carries aria-disabled="true" and data-disabled, so it remains accessible to screen readers.'},{name:"textValue",type:"string",required:!1,description:"Text for Trigger label, typeahead and the root filter, published as `data-text-value`; falls back to rendered text. Needed when the item contains more than text alone."}]},{name:"ItemText",description:"An Item's label content, captured so Value can render it inside Trigger."},{name:"ItemIndicator",description:"Selected-state glyph inside an Item, rendered only while that item is selected.",props:[f(e)]},{name:"Group",description:'Groups related Items under a Label (role="group"). Automatically wires aria-labelledby. Label is required inside Group.'},{name:"Label",description:"Non-interactive heading for Group, providing its accessible name. Outside a Group it renders but does not name anything."},{name:"Separator",description:'Visual divider between Items or Groups inside Content. Renders an aria-hidden element, not role="separator".'},{name:"Empty",description:'Message shown when the filter leaves no option to render. Rendered inside Portal as a sibling of Content with aria-live="polite", never inside the role="listbox" \u2014 an empty-state string announced as an option is worse than one not announced at all.'}],slots:[{name:"default",description:"Root content \u2014 the trigger, portal and content parts."},{name:"option",frameworks:["vue","webComponents"],exception:"render-prop",frameworksReason:"React, Svelte and Angular reach the same customisation through the `renderOption` prop \u2014 a function, a snippet and a TemplateRef \u2014 because their content projection is not addressable by name from option data.",description:"Body of one derived option row, in place of the label its option data carries."},{name:"value",frameworks:["vue","webComponents"],exception:"render-prop",frameworksReason:"React, Svelte and Angular reach the same customisation through the `renderValue` prop, which receives the selected option(s) a slot would have to be handed some other way.",description:"Replacement body for the derived Value part, rendered instead of the resolved label."},{name:"tag",frameworks:["vue","webComponents"],exception:"render-prop",frameworksReason:"React, Svelte and Angular reach the same customisation through the `renderTag` prop, keyed by value rather than by a named slot the markup repeats per tag.",description:"Body of one derived Tag, in place of the resolved option label."},{name:"renderTag",frameworks:["svelte"],exception:"snippet-opaque",frameworksReason:"Svelte spells a render prop as a snippet, so `renderTag` is both the prop and the slot there; Vue and Web Components take the same content through the `tag` slot, and React and Angular through a prop that is not projection at all.",description:"Snippet form of the `tag` slot, passed as the `renderTag` prop."},{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:"Customises how a derived option renders inside its Item. Receives the option and whether it is currently selected. Only read while options is deriving the anatomy."},{name:"render-value",frameworks:["svelte"],exception:"render-prop",frameworksReason:"svelte expose render-value as native content projection for the renderValue rendering capability. Other frameworks pass the documented renderValue render prop or template instead of a named slot with this spelling.",description:"Customizes the trigger's displayed content in place of the default label (or chips in multiple mode). Receives selected option(s) or null."}],appearance:[{attribute:"data-match-width",values:[],stylesheet:"select.css"},{attribute:"data-shape",values:["rounded","square","pill"],stylesheet:"select.css"},{attribute:"data-size",values:["sm","lg"],stylesheet:"select.css"},{attribute:"data-status",values:["info","success","warning","danger"],stylesheet:"select.css"},{attribute:"data-density",values:["comfortable","compact"],stylesheet:"select.css"}],states:["closed","open","loading","disabled","readonly","invalid","required","multiple","highlighted","checked","unchecked"],controlledUncontrolled:"Three independent axes (value, inputValue, open) each start from their default and switch to controlled when the matching prop is passed, paired with a change event. In Angular the value pair is split: `valueChange` emits the whole `string[]` selection for `[(value)]`, `valueChangeDetail` carries the detail.",formBehavior:'With `name` set, a visually-hidden native control mirrors `value` for submission, reset and \u2014 with `required` \u2014 validation. It is never `type="hidden"` and never `readonly`; both bar an input from constraint validation, which would make `required` silently inert. A `multiple` select mirrors one hidden control per selected value under the same `name`, producing the repeated entries a native `<select multiple>` produces rather than one joined string, and an empty `multiple` selection submits nothing at all \u2014 except under `required`, where one empty-valued control still renders so `valueMissing` has somewhere to fire. A single select keeps one control at all times. Draft text in the filter Input never submits. Web Components publish value and validity through `ElementInternals` instead, because their mirrored input lives in the shadow root and is not associated with the ancestor form. A form reset restores `defaultValue` and `defaultInputValue` \u2014 silently in Web Components, and by firing value-change in React/Vue/Svelte/Angular. `form` associates every mirrored control with a form the select does not sit inside, and `autoComplete` hints the first of them. A `readOnly` select submits exactly as an editable one does; only `disabled` withholds the value.',validationBehavior:"`invalid` is a purely presentational flag (aria-invalid/data-invalid on the trigger); `required` participates in native constraint validation only when `name` is set. With `name` and `required` and no selection, `checkValidity()`/`reportValidity()` report `valueMissing` and block submission identically in all five frameworks; a select with a value is valid. `maxSelected` makes further options inert rather than invalid \u2014 reaching a cap is not an error. A minimum count, or any cross-field rule, belongs to the surrounding Field or Form.",accessibility:{role:'combobox (trigger, or the filter Input) with aria-haspopup="listbox"; listbox (content, with aria-multiselectable in multiple mode); option (each SelectOption)',keyboard:[{key:"Enter, Space, Alt+ArrowDown (on a closed trigger)",behavior:"Opens the listbox without moving the active option: the active option is the already-selected one. With nothing selected, the first enabled option becomes active."},{key:"ArrowDown / Home (on a closed trigger)",behavior:"Opens the listbox and makes the first enabled option active."},{key:"ArrowUp / End (on a closed trigger)",behavior:"Opens the listbox and makes the last enabled option active."},{key:"ArrowDown / ArrowUp (in listbox)",behavior:"Moves the active option to the next/previous enabled one (no wrap). Virtual focus handles this on the trigger, or on the filter Input while `filterable`."},{key:"PageDown / PageUp (in listbox)",behavior:"Moves the active option ten enabled options down/up, clamped at the ends. Ten is a fixed count for consistency across frameworks."},{key:"Home / End (in listbox)",behavior:"Makes the first / last enabled option active. Only while the listbox is open: with a `filterable` select closed, both are caret keys of the text field and must not be intercepted."},{key:"Alt+ArrowUp (while the listbox is open)",behavior:"Commits the active option and closes the listbox (counterpart to Alt+ArrowDown). Alt+ArrowDown while open does nothing."},{key:"Printable characters (in listbox)",behavior:"Typeahead: makes the next option whose label starts with the typed text active. Matched against `data-text-value` when present, else the option's text. While `filterable` the same keys type into the Input and narrow the list instead."},{key:"Printable characters (on trigger, closed)",behavior:"Typeahead against labels (like native `<select>`): selects the next matching option without opening. Supply `items` for labels before Content mounts. In multiple mode the same keys open the listbox instead of committing, because toggling an option the user cannot see would change the selection blind."},{key:"Enter or Space (while the listbox is open)",behavior:"Selects the active option. Single-select closes the listbox; `multiple` toggles the option and leaves the listbox open. Either way the trigger already holds DOM focus and never loses it."},{key:"Shift+ArrowDown / Shift+ArrowUp (in listbox, multiple)",behavior:"Moves the active option and toggles what it lands on, extending the selection without an Enter at every step. Nothing toggles if the highlight did not move (clamped at the ends). The cap needs no rule of its own: unselected options are already aria-disabled."},{key:"Shift+Space (in listbox, multiple)",behavior:"Selects every enabled option between the last one toggled \u2014 the range anchor \u2014 and the active one, inclusive. Never deselects. Stops where `maxSelected` runs out. With no anchor, selects the active option alone."},{key:"Control+Shift+Home / Control+Shift+End (in listbox, multiple)",behavior:"Selects every enabled option from the active one to the first or last, inclusive. Additive and never deselecting. The active option does not move, and the range anchor stays where the last toggle put it. Inert while the listbox is closed."},{key:"Control+A (in listbox, multiple)",behavior:"While `allowSelectAll`: selects every enabled option, and clears them all if they are already selected. Only while the listbox is open \u2014 closed, it keeps its native meaning of selecting draft text. Stops where `maxSelected` runs out."},{key:"Backspace (on an empty filter Input)",behavior:"Removes the last selected value. Only on an empty input: it must never eat a character the user is still editing."},{key:"Arrow keys (in TagList)",behavior:"Move between the tags of a multiple selection in one roving tab stop."},{key:"Escape",behavior:"Closes the listbox and returns focus to the trigger."},{key:"Tab / Shift+Tab (while the listbox is open)",behavior:"Commits the active option, closes the listbox, and lets focus continue: the default action is never prevented. In multiple mode, Tab *adds* the active option to selection without removing others."}],ariaAttributes:['aria-expanded, aria-controls, aria-haspopup="listbox", aria-required, aria-invalid on the trigger',"aria-autocomplete on the filter Input, which takes aria-expanded and aria-controls in the trigger's place while `filterable`",'aria-readonly="true" and data-readonly on the trigger while `readOnly` (absent otherwise) \u2014 trigger keeps its tab stop, so the state is announced',"aria-labelledby on the trigger, naming the Value part (see `namingRequirement`)","aria-activedescendant on the trigger, or the filter Input, naming the active option (only when open)",'aria-multiselectable="true" on the listbox in multiple mode (absent otherwise)',"aria-selected on each option; data-highlighted on the active one",'aria-disabled="true" and data-disabled on a disabled option (absent otherwise), and on an unselected option once `maxSelected` is reached','aria-busy="true" and data-loading on Content and the filter Input while `loading`',"aria-labelledby on each Group, naming its Label part",'the Empty part carries aria-live="polite" and sits outside the role="listbox"',"the selection count is announced after every change in multiple mode"],focusManagement:`${m} Here the anchor is the trigger, or the filter Input while \`filterable\`. Opening makes the selected (or first enabled) option active. Arrows, Home/End, typeahead, and pointer hover move the active option. Tab closes the listbox and lets focus continue. TagList separately roves real DOM focus among the tags: removing one moves focus to the next tag, the preceding tag if it was the last, or TagList itself if it was the only one \u2014 never to the field. That focus behaviour is inherited from TagGroup rather than re-implemented here.`,namingRequirement:'role="combobox" does NOT take an accessible name from content. Trigger uses aria-labelledby pointing to Value (which is its current value), so a consumer must supply an associated <label> or aria-label for context; the filter Input needs the same. TagList needs its own name, since the tags are its content and cannot name it. Group is named similarly with aria-labelledby and requires a Label part.'},styling:{cssParts:["trigger","value","chip","icon","tag-list","tag","tag-remove","remove","input","clear","content","select-all","item","group","label","separator","item-text","item-indicator","viewport","empty"],dataAttributes:[...g,"data-state","data-disabled","data-readonly","data-invalid","data-loading","data-placeholder","data-highlighted","data-multiple","data-chip","data-skdx-select-tag","data-value","data-text-value","data-side","data-align","data-match-width","data-shape","data-size","data-status","data-density",{name:"data-skdx-select-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:c("select")},publicMethods:[...r,s],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{C as selectContract};
@@ -1 +1 @@
1
- import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var r={name:"SignUpPage",purpose:"A registration block composing Heading, Alert, Button, Divider, Form, Field, TextField, PasswordInput and Checkbox. Every provider renders a button and the credentials form always renders, so the block reports either a chosen provider or the submitted account details through one sign-up event. Ships in the blocks package of each framework, not the core package.",props:[{name:"title",type:"string",defaultValue:"'Create account'",required:!1,description:"Heading text, rendered into a derived <h1> that names the section."},{name:"providers",type:"ReadonlyArray<{ id: string; name: string }>",required:!1,description:"Third-party providers, in render order, each rendering one button above the credentials form. No provider region and no divider render when omitted."},{name:"error",type:"string",required:!1,description:"Message rendered into a derived error Alert above the form. The block never clears it: set it from the sign-up handler and reset it when the next attempt starts."},{name:"pending",type:"boolean",defaultValue:"false",required:!1,description:"Marks the request in flight, making the submit button busy and unusable while every field stays editable, so the user can still correct a typo."},{name:"nameLabel",type:"string",required:!1,description:"Label of the name field; supplying it is what makes that field render at all, and what adds name to the event detail."},{name:"emailLabel",type:"string",defaultValue:"'Email'",required:!1,description:"Label of the email field in the credentials form."},{name:"passwordLabel",type:"string",defaultValue:"'Password'",required:!1,description:"Label of the password field in the credentials form."},{name:"confirmPasswordLabel",type:"string",required:!1,description:"Label of the confirmation field; supplying it is what makes that field render and what turns on password matching."},{name:"passwordMismatchMessage",type:"string",defaultValue:"'Passwords do not match'",required:!1,description:"Validation message pushed onto the confirmation field as a custom validity when the two passwords differ."},{name:"terms",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot rather than a prop \u2014 Vue because a renderable region is a slot in Vue's own idiom, Web Components because a custom element attribute carries a string and cannot carry a node. Both slot spellings are declared under `slots`.",description:"Terms copy and links, rendered as the label of a required checkbox before the submit button. No terms field renders when omitted. A prop in React, Svelte, and Angular; Vue and Web Components use the `terms` slot."},{name:"submitLabel",type:"string",defaultValue:"'Create account'",required:!1,description:"Text of the credentials form submit button."},{name:"getProviderLabel",type:"(provider: { id: string; name: string }) => string",defaultValue:"defaultProviderLabel",required:!1,description:`Formats a provider button's text from its entry. The default reads "Sign in with Google".`},{name:"footer",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot rather than a prop \u2014 Vue because a renderable region is a slot in Vue's own idiom, Web Components because a custom element attribute carries a string and cannot carry a node. Both slot spellings are declared under `slots`.",description:"Navigation rendered below the form, such as a link back to the sign-in page. No footer region renders when omitted. A prop in React, Svelte, and Angular; Vue and Web Components use the `footer` slot."}],events:[{name:"sign-up",detail:"{ providerId: string; name?: string; email?: string; password?: string; termsAccepted?: boolean }",description:"Fires when a provider button is activated or the form is submitted with matching, valid fields. A button carries only providerId; the form carries 'credentials' plus the values of the fields that rendered. The native submit is prevented, so the consumer performs the request and sets error on failure."}],slots:[{name:"default",description:"Extra fields rendered inside the form, above the terms and the submit button."},{name:"terms",description:"Terms copy and links used as the label of the required terms checkbox; nothing renders without it."},{name:"footer",description:"Navigation below the form, such as a link back to the sign-in page."}],states:["default"],controlledUncontrolled:"Stateless apart from the field values the native inputs hold; error, pending and success wording are always controlled by the consumer.",formBehavior:"The credentials form is a core Form root with required, natively validated fields; an invalid form reports through constraint validation and emits nothing. The submit button is disabled while pending, and the fields stay editable.",validationBehavior:'Fields are required, the email field is type="email", and the terms checkbox must be ticked. When a confirmation field renders, a mismatch is pushed onto it as a custom validity, reported through the form, and cleared on the next edit of that field.',accessibility:{role:"region (native <section> named by its heading through aria-labelledby)",keyboard:[{key:"Enter",behavior:"Submits the form whose field has focus (native form submission)."},{key:"Enter/Space",behavior:"Activates a focused provider button (native button activation)."},{key:"Space",behavior:"Toggles the terms checkbox when it has focus."}],ariaAttributes:["aria-labelledby on the <section> points at the derived heading","the derived error Alert is a live region, so a new error is announced without moving focus","each field is labelled through the core Field, which wires aria-describedby and aria-invalid"],focusManagement:"Focus stays where the user put it, except that a reported password mismatch moves focus to the confirmation field the way constraint validation does."},styling:{cssParts:["sign-up-page","panel","title","error","providers","provider","divider","form","field","terms","submit","footer"],dataAttributes:[...e,"data-provider",{name:"data-skdx-sign-up-page-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'},{name:"data-skdx-sign-up-page-content",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[]},publicMethods:[]};export{r as signUpPageContract};
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var r={name:"SignUpPage",purpose:"A registration block composing Heading, Alert, Button, Divider, Form, Field, TextField, PasswordInput and Checkbox. Every provider renders a button and the credentials form always renders, so the block reports either a chosen provider or the submitted account details through one sign-up event. Ships in the blocks package of each framework, not the core package.",props:[{name:"title",type:"string",defaultValue:"'Create account'",required:!1,description:"Heading text, rendered into a derived <h1> that names the section."},{name:"providers",type:"ReadonlyArray<{ id: string; name: string }>",required:!1,description:"Third-party providers, in render order, each rendering one button above the credentials form. No provider region and no divider render when omitted."},{name:"error",type:"string",required:!1,description:"Message rendered into a derived error Alert above the form. The block never clears it: set it from the sign-up handler and reset it when the next attempt starts."},{name:"pending",type:"boolean",defaultValue:"false",required:!1,description:"Marks the request in flight, making the submit button busy and unusable while every field stays editable, so the user can still correct a typo."},{name:"nameLabel",type:"string",required:!1,description:"Label of the name field; supplying it is what makes that field render at all, and what adds name to the event detail."},{name:"emailLabel",type:"string",defaultValue:"'Email'",required:!1,description:"Label of the email field in the credentials form."},{name:"passwordLabel",type:"string",defaultValue:"'Password'",required:!1,description:"Label of the password field in the credentials form."},{name:"confirmPasswordLabel",type:"string",required:!1,description:"Label of the confirmation field; supplying it is what makes that field render and what turns on password matching."},{name:"passwordMismatchMessage",type:"string",defaultValue:"'Passwords do not match'",required:!1,description:"Validation message pushed onto the confirmation field as a custom validity when the two passwords differ."},{name:"terms",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot rather than a prop \u2014 Vue because a renderable region is a slot in Vue's own idiom, Web Components because a custom element attribute carries a string and cannot carry a node. Both slot spellings are declared under `slots`.",description:"Terms copy and links, rendered as the label of a required checkbox before the submit button. No terms field renders when omitted. A prop in React, Svelte, and Angular; Vue and Web Components use the `terms` slot."},{name:"submitLabel",type:"string",defaultValue:"'Create account'",required:!1,description:"Text of the credentials form submit button."},{name:"getProviderLabel",type:"(provider: { id: string; name: string }) => string",defaultValue:"defaultProviderLabel",required:!1,description:`Formats a provider button's text from its entry. The default reads "Sign in with Google".`},{name:"footer",type:"unknown",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:"Vue and Web Components take this as a named slot rather than a prop \u2014 Vue because a renderable region is a slot in Vue's own idiom, Web Components because a custom element attribute carries a string and cannot carry a node. Both slot spellings are declared under `slots`.",description:"Navigation rendered below the form, such as a link back to the sign-in page. No footer region renders when omitted. A prop in React, Svelte, and Angular; Vue and Web Components use the `footer` slot."}],events:[{name:"sign-up",detail:"{ providerId: string; name?: string; email?: string; password?: string; termsAccepted?: boolean }",description:"Fires when a provider button is activated or the form is submitted with matching, valid fields. A button carries only providerId; the form carries 'credentials' plus the values of the fields that rendered. The native submit is prevented, so the consumer performs the request and sets error on failure."}],slots:[{name:"default",description:"Extra fields rendered inside the form, above the terms and the submit button."},{name:"terms",description:"Terms copy and links used as the label of the required terms checkbox; nothing renders without it."},{name:"footer",description:"Navigation below the form, such as a link back to the sign-in page."}],states:["default"],controlledUncontrolled:"Stateless apart from the field values the native inputs hold; error, pending and success wording are always controlled by the consumer.",formBehavior:"The credentials form is a core Form root with required, natively validated fields; an invalid form reports through constraint validation and emits nothing. The submit button is disabled while pending, and the fields stay editable.",validationBehavior:`Fields are required, the email field is type="email", and the terms checkbox must be ticked. A refused terms box is reported on the checkbox itself \u2014 aria-invalid on the control and the browser's own wording in the field's error part \u2014 since the constraint lives on a hidden mirror input no message can be anchored to; ticking the box clears it. When a confirmation field renders, a mismatch is pushed onto it as a custom validity, reported through the form, and cleared on the next edit of that field.`,accessibility:{role:"region (native <section> named by its heading through aria-labelledby)",keyboard:[{key:"Enter",behavior:"Submits the form whose field has focus (native form submission)."},{key:"Enter/Space",behavior:"Activates a focused provider button (native button activation)."},{key:"Space",behavior:"Toggles the terms checkbox when it has focus."}],ariaAttributes:["aria-labelledby on the <section> points at the derived heading","the derived error Alert is a live region, so a new error is announced without moving focus","each field is labelled through the core Field, which wires aria-describedby and aria-invalid"],focusManagement:"Focus stays where the user put it, except that a reported password mismatch moves focus to the confirmation field the way constraint validation does."},styling:{cssParts:["sign-up-page","panel","title","error","providers","provider","divider","form","field","terms","submit","footer"],dataAttributes:[...e,"data-provider",{name:"data-skdx-sign-up-page-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'},{name:"data-skdx-sign-up-page-content",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[]},publicMethods:[]};export{r as signUpPageContract};
@@ -1 +1 @@
1
- import{changeDescription as t,changeDetail as e}from"./change-reason.js";import{webComponentsValidationMethods as a}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as r}from"./styling-hooks.js";var o={name:"Slider",purpose:"A multi-thumb slider. Clicking or dragging anywhere in the track moves the thumb closest to the pointer; onValueCommit fires once, on pointer up. Each thumb is independently keyboard-operable.",props:[{name:"value",type:"number[]",required:!1,description:"Selected values, one per thumb, for controlled usage."},{name:"defaultValue",type:"number[]",defaultValue:"[0]",required:!1,description:"Initial values, one per thumb, for uncontrolled usage.",frameworks:["react","vue","svelte","angular"],exception:"wc-default",frameworksReason:"Web Components has no defaultValue member and will not grow one: the authored value attribute is the default, exactly as <input value> is a native input's. <skdx-slider> snapshots it on connect and formResetCallback() restores that snapshot."},{name:"min",type:"number",defaultValue:"0",required:!1,description:"Minimum value of the range."},{name:"max",type:"number",defaultValue:"100",required:!1,description:"Maximum value of the range."},{name:"step",type:"number",defaultValue:"1",required:!1,description:"Increment values are rounded to, for both pointer and keyboard interaction."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables pointer and keyboard interaction on all thumbs."},{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Layout axis, used to map pointer position and Arrow keys to a value."},{name:"largeStep",type:"number",defaultValue:"Math.max((max - min) / 10, step)",required:!1,description:"Increment for PageUp/PageDown and Shift+Arrow on the focused thumb. Defaults to one-tenth of the range (floored at one step) \u2014 the increment these keys already used, so the property changes no shipped slider. Base UI defaults to flat 10, which jumps a 0\u20131 range ten times over; deriving it from min/max keeps the coarse gear proportional to what the slider measures."},{name:"minStepsBetweenValues",type:"number",defaultValue:"0",required:!1,description:"Minimum gap in steps that adjacent values must keep. At default 0, two thumbs may be dragged onto the same value (they clamp but never separate); at 1, the neighbouring thumb is pushed one step away, so a range slider never reports an empty range. Counted in steps, not value units, so it stays meaningful when step changes. Named for values, not thumbs, because array entries are values \u2014 a thumb is what renders one."},{name:"name",type:"string",required:!1,description:"Form field name. A multi-thumb slider submits one name[i] entry per thumb. Without it the slider submits nothing."},{name:"form",type:"string | undefined",required:!1,defaultValue:"undefined",description:"Id of the <form> the slider submits into, forwarded to each thumb's hidden input, so a slider can live outside its form (filter bar, portal, sticky footer). Needs name to mean anything. **Property is `formId`, not `form`, in Web Components** \u2014 form-associated elements already publish `form` as readonly HTMLFormElement; shadowing it with writable string would break `slider.form`. The browser's form-owner algorithm honours the form attribute on form-associated custom elements, so `formId` is declared for API consistency."},{name:"marks",type:"ReadonlyArray<{ value: number; label?: string }>",required:!1,description:"Marks the slider derives along its track \u2014 one per entry at its value, captioned by label. Hand composition stays default and wins when the consumer writes their own."},{name:"showTooltip",type:"boolean",defaultValue:"false",required:!1,description:"Renders the thumb's current value in a tooltip the skin positions; no floating behaviour added."},{name:"thumbLabels",type:"readonly string[]",required:!1,description:`Accessible names for derived thumbs, one per value entry in order (e.g., ["Minimum price", "Maximum price"]). Multi-thumb sliders need these: role="slider" takes no content name, so unnamed thumbs announce identically and users can't tell which end they're moving (see accessibility.namingRequirement). Single-thumb sliders need none. Ignored under hand composition, where each Thumb carries its own aria-label. Deriving a multi-thumb slider without them warns in development.`},{name:"size",type:"'md' | 'sm' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the root; the data-size attribute may be set directly instead."}],events:[{name:"value-change",description:t("the slider values"),detail:e("number[]")},{name:"value-change-detail",frameworks:["angular"],exception:"event-shape",frameworksReason:"Angular's `valueChange` emits the scalar so `[(value)]` round-trips the value itself; this second output carries the detail object the other four hand to `value-change`.",description:"Fires with valueChange, carrying the previous values and the reason for the change.",detail:e("number[]")},{name:"value-commit",detail:"number[]",description:"Fires once with final values when a drag ends (pointer up). Suppressed when values at pointer up match pointer down \u2014 a bare click without drag commits nothing, preventing unwanted writes."}],parts:[{name:"Track",description:"The full-length bar the thumbs move along. Purely presentational."},{name:"Range",description:"The filled band between the lowest and highest value (from the start of the track for a single-thumb slider). Purely presentational."},{name:"Thumb",description:'One draggable handle, the role="slider" that reports a value. One per entry in the values array.',props:[{name:"index",type:"number",required:!1,description:"Which entry of the values array this thumb controls. Omitting it resolves the index from DOM order among sibling thumbs, which is what a single-thumb slider wants and what a statically-rendered range slider gets right too. A server-rendered range slider must pass it explicitly: the resolution runs in a layout effect (or its framework's equivalent) that never runs on the server, so every thumb serialises as index 0 and the markup sent to the client reports the first value on both handles until hydration corrects it. Angular is the exception \u2014 its thumb takes an explicit index defaulting to 0 and does no DOM resolution."},{name:"valueText",type:"string",required:!1,description:`Human-readable announcement of this thumb's value, written to aria-valuetext. Supply it when the raw number is not what the user is choosing \u2014 "Medium" for a size scale, "\xA320" for a price, "Tuesday" for a day index \u2014 and a screen reader announces that instead of the bare aria-valuenow. Left unset the attribute is absent, which is correct for a slider whose value really is a number.`}]},{name:"Mark",description:`An optional tick at a declared value along the track, positioned by the same logical inline offset the Thumb uses so it mirrors correctly under dir="rtl". Renders its own children as the label and publishes the value as data-value; the tick itself is drawn by the skin. aria-hidden, like AngleSlider's Mark: a mark redraws the scale the thumb already reports through aria-valuemin/aria-valuemax, and unhidden its labels are announced as loose text inside the slider.`,props:[{name:"value",type:"number",required:!0,description:"The value on the track this mark sits at."}]}],slots:[{name:"default",description:"SliderTrack (containing SliderRange) plus one SliderThumb per value."},{name:"thumb",description:"A single thumb's optional custom content."},{name:"mark",description:"A single mark's label content."}],appearance:[{attribute:"data-size",values:["md","sm","lg"],stylesheet:"slider.css"}],states:["default","dragging","disabled"],controlledUncontrolled:"Supports both: value + onValueChange (controlled) or defaultValue (uncontrolled). Web Components expresses the uncontrolled seed as the authored `value` attribute rather than a separate `default-value`, the way `<input value>` seeds a native input; that attribute is snapshotted on connect and is what a form reset restores. In Angular the pair is split: `valueChange` emits the scalar for `[(value)]`, `valueChangeDetail` carries the detail.",formBehavior:"Form-associated: with a name, single-thumb submits one name entry; multi-thumb submits one name[i] entry per thumb. A slider always has a value, so checkValidity() always passes. Form reset restores initial values. (Web Components publish through ElementInternals on root; other frameworks render hidden number input per thumb.) form associates hidden inputs with forms the slider doesn't sit inside; Web Components honours form attribute on the form-associated host.",validationBehavior:"Not applicable at the component level.",accessibility:{role:"slider (each thumb)",keyboard:[{key:"ArrowRight/ArrowUp",behavior:"Increases the focused thumb by one step under dir='ltr'. The vertical arrow is unaffected by writing direction; ArrowRight decreases under dir='rtl', where the start of the track is its right edge."},{key:"ArrowLeft/ArrowDown",behavior:"Decreases the focused thumb by one step under dir='ltr'; ArrowLeft increases under dir='rtl'. ArrowDown always decreases."},{key:"PageUp/PageDown",behavior:"Changes the focused thumb by largeStep \u2014 a tenth of the range unless the property overrides it. Not mirrored: these keys name a magnitude, not a direction on the inline axis."},{key:"Shift+Arrow keys",behavior:"Move by largeStep instead of step, in the direction that arrow moves (mirrored under RTL like the unmodified arrows) \u2014 the same coarse gear as PageUp/PageDown, on the keys a laptop keyboard actually has. AngleSlider binds Shift+Arrow the same way."},{key:"Home/End",behavior:"Jumps the focused thumb to the slider's min/max."}],ariaAttributes:["aria-valuemin/aria-valuemax/aria-valuenow/aria-orientation on each thumb","aria-valuetext on a thumb given a valueText, so a value that is not a plain number ('Medium', '\xA320') is announced as what it means","aria-label or aria-labelledby on each thumb of a multi-thumb slider","aria-hidden on each Mark, which redraws a scale the thumb already reports"],focusManagement:"Each SliderThumb is independently focusable and keyboard-operable.",namingRequirement:'A slider with more than one thumb must name each thumb distinctly with aria-label or aria-labelledby (for example "Minimum price" / "Maximum price"). role="slider" takes no name from content and a thumb renders none, so two unnamed thumbs announce identically and the user cannot tell which end of the range they are moving. A single-thumb slider needs no thumb name \u2014 the surrounding field names it and there is nothing to tell apart.'},styling:{cssParts:["slider","track","range","thumb","mark","tooltip"],dataAttributes:[...r,"data-orientation","data-disabled","data-dragging","data-value","data-size",{name:"data-skdx-slider-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[]},publicMethods:[...a],frameworkExtensions:[{framework:"webComponents",part:"Thumb",name:"showTooltip",type:"boolean",description:"Per-thumb version of the root's `showTooltip`, written from markup as show-tooltip. <skdx-slider-thumb> renders its own value readout inside a shadow root, so the switch has to reach the element that draws it; React, Vue, Svelte and Angular compose the readout as their own children of Thumb and decide per thumb by writing different children."},{framework:"webComponents",name:"updateValue",type:"(index: number, rawValue: number, reason?: 'pointer' | 'keyboard' | 'programmatic') => void",description:"Commits one thumb's value after clamping it to the step grid, the range and its neighbouring thumbs, then dispatches value-change with the given reason. Web Components only: it is how the element's own pointer and keyboard handlers write a value, and an element has no other channel for a caller to enter that path. React, Vue, Svelte and Angular set the controlled `value` prop instead, which runs the same clamping before it renders."}]};export{o as sliderContract};
1
+ import{changeDescription as t,changeDetail as e}from"./change-reason.js";import{webComponentsValidationMethods as a}from"./form-validity.js";import{ROOT_DATA_ATTRIBUTES as r}from"./styling-hooks.js";var o={name:"Slider",purpose:"A multi-thumb slider. Clicking or dragging anywhere in the track moves the thumb closest to the pointer; onValueCommit fires once, on pointer up. Each thumb is independently keyboard-operable.",props:[{name:"value",type:"number[]",required:!1,description:"Selected values, one per thumb, for controlled usage."},{name:"defaultValue",type:"number[]",defaultValue:"[0]",required:!1,description:"Initial values, one per thumb, for uncontrolled usage.",frameworks:["react","vue","svelte","angular"],exception:"wc-default",frameworksReason:"Web Components has no defaultValue member and will not grow one: the authored value attribute is the default, exactly as <input value> is a native input's. <skdx-slider> snapshots it on connect and formResetCallback() restores that snapshot."},{name:"min",type:"number",defaultValue:"0",required:!1,description:"Minimum value of the range."},{name:"max",type:"number",defaultValue:"100",required:!1,description:"Maximum value of the range."},{name:"step",type:"number",defaultValue:"1",required:!1,description:"Increment values are rounded to, for both pointer and keyboard interaction."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables pointer and keyboard interaction on all thumbs."},{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Layout axis, used to map pointer position and Arrow keys to a value."},{name:"largeStep",type:"number",defaultValue:"Math.max((max - min) / 10, step)",required:!1,description:"Increment for PageUp/PageDown and Shift+Arrow on the focused thumb. Defaults to one-tenth of the range (floored at one step) \u2014 the increment these keys already used, so the property changes no shipped slider. Base UI defaults to flat 10, which jumps a 0\u20131 range ten times over; deriving it from min/max keeps the coarse gear proportional to what the slider measures."},{name:"minStepsBetweenValues",type:"number",defaultValue:"0",required:!1,description:"Minimum gap in steps that adjacent values must keep. At default 0, two thumbs may be dragged onto the same value (they clamp but never separate); at 1, the neighbouring thumb is pushed one step away, so a range slider never reports an empty range. Counted in steps, not value units, so it stays meaningful when step changes. Named for values, not thumbs, because array entries are values \u2014 a thumb is what renders one."},{name:"name",type:"string",required:!1,description:"Form field name. A multi-thumb slider submits one name[i] entry per thumb. Without it the slider submits nothing."},{name:"form",type:"string | undefined",required:!1,defaultValue:"undefined",description:"Id of the <form> the slider submits into, forwarded to each thumb's hidden input, so a slider can live outside its form (filter bar, portal, sticky footer). Needs name to mean anything. **Property is `formId`, not `form`, in Web Components** \u2014 form-associated elements already publish `form` as readonly HTMLFormElement; shadowing it with writable string would break `slider.form`. The browser's form-owner algorithm honours the form attribute on form-associated custom elements, so `formId` is declared for API consistency."},{name:"marks",type:"ReadonlyArray<{ value: number; label?: string }>",required:!1,description:"Marks the slider derives along its track \u2014 one per entry at its value, captioned by label. Hand composition stays default and wins when the consumer writes their own."},{name:"showTooltip",type:"boolean",defaultValue:"false",required:!1,description:"Renders the thumb's current value in a tooltip the skin positions; no floating behaviour added."},{name:"thumbLabels",type:"readonly string[]",required:!1,description:`Accessible names for derived thumbs, one per value entry in order (e.g., ["Minimum price", "Maximum price"]). Multi-thumb sliders need these: role="slider" takes no content name, so unnamed thumbs announce identically and users can't tell which end they're moving (see accessibility.namingRequirement). Single-thumb sliders need none. Ignored under hand composition, where each Thumb carries its own aria-label. Deriving a multi-thumb slider without them warns in development.`},{name:"size",type:"'md' | 'sm' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the root; the data-size attribute may be set directly instead."}],events:[{name:"value-change",description:t("the slider values"),detail:e("number[]")},{name:"value-change-detail",frameworks:["angular"],exception:"event-shape",frameworksReason:"Angular's `valueChange` emits the scalar so `[(value)]` round-trips the value itself; this second output carries the detail object the other four hand to `value-change`.",description:"Fires with valueChange, carrying the previous values and the reason for the change.",detail:e("number[]")},{name:"value-commit",detail:"number[]",description:"Fires once with final values when a drag ends (pointer up). Suppressed when values at pointer up match pointer down \u2014 a bare click without drag commits nothing, preventing unwanted writes."}],parts:[{name:"Track",description:"The full-length bar the thumbs move along. Purely presentational."},{name:"Range",description:"The filled band between the lowest and highest value (from the start of the track for a single-thumb slider). Purely presentational."},{name:"Thumb",description:'One draggable handle, the role="slider" that reports a value. One per entry in the values array.',props:[{name:"index",type:"number",required:!1,description:"Which entry of the values array this thumb controls. Omitting it resolves the index from DOM order among sibling thumbs, which is what a single-thumb slider wants and what a statically-rendered range slider gets right too. A server-rendered range slider must pass it explicitly: the resolution runs in a layout effect (or its framework's equivalent) that never runs on the server, so every thumb serialises as index 0 and the markup sent to the client reports the first value on both handles until hydration corrects it. Angular is the exception \u2014 its thumb takes an explicit index defaulting to 0 and does no DOM resolution."},{name:"valueText",type:"string",required:!1,description:`Human-readable announcement of this thumb's value, written to aria-valuetext. Supply it when the raw number is not what the user is choosing \u2014 "Medium" for a size scale, "\xA320" for a price, "Tuesday" for a day index \u2014 and a screen reader announces that instead of the bare aria-valuenow. Left unset the attribute is absent, which is correct for a slider whose value really is a number.`}],slots:[{name:"default",description:"A single thumb's optional custom content."}]},{name:"Mark",description:`An optional tick at a declared value along the track, positioned by the same logical inline offset the Thumb uses so it mirrors correctly under dir="rtl". Renders its own children as the label and publishes the value as data-value; the tick itself is drawn by the skin. aria-hidden, like AngleSlider's Mark: a mark redraws the scale the thumb already reports through aria-valuemin/aria-valuemax, and unhidden its labels are announced as loose text inside the slider.`,props:[{name:"value",type:"number",required:!0,description:"The value on the track this mark sits at."}],slots:[{name:"default",description:"A single mark's label content."}]}],slots:[{name:"default",description:"SliderTrack (containing SliderRange) plus one SliderThumb per value."}],appearance:[{attribute:"data-size",values:["md","sm","lg"],stylesheet:"slider.css"}],states:["default","dragging","disabled"],controlledUncontrolled:"Supports both: value + onValueChange (controlled) or defaultValue (uncontrolled). Web Components expresses the uncontrolled seed as the authored `value` attribute rather than a separate `default-value`, the way `<input value>` seeds a native input; that attribute is snapshotted on connect and is what a form reset restores. In Angular the pair is split: `valueChange` emits the scalar for `[(value)]`, `valueChangeDetail` carries the detail.",formBehavior:"Form-associated: with a name, single-thumb submits one name entry; multi-thumb submits one name[i] entry per thumb. A slider always has a value, so checkValidity() always passes. Form reset restores initial values. (Web Components publish through ElementInternals on root; other frameworks render hidden number input per thumb.) form associates hidden inputs with forms the slider doesn't sit inside; Web Components honours form attribute on the form-associated host.",validationBehavior:"Not applicable at the component level.",accessibility:{role:"slider (each thumb)",keyboard:[{key:"ArrowRight/ArrowUp",behavior:"Increases the focused thumb by one step under dir='ltr'. The vertical arrow is unaffected by writing direction; ArrowRight decreases under dir='rtl', where the start of the track is its right edge."},{key:"ArrowLeft/ArrowDown",behavior:"Decreases the focused thumb by one step under dir='ltr'; ArrowLeft increases under dir='rtl'. ArrowDown always decreases."},{key:"PageUp/PageDown",behavior:"Changes the focused thumb by largeStep \u2014 a tenth of the range unless the property overrides it. Not mirrored: these keys name a magnitude, not a direction on the inline axis."},{key:"Shift+Arrow keys",behavior:"Move by largeStep instead of step, in the direction that arrow moves (mirrored under RTL like the unmodified arrows) \u2014 the same coarse gear as PageUp/PageDown, on the keys a laptop keyboard actually has. AngleSlider binds Shift+Arrow the same way."},{key:"Home/End",behavior:"Jumps the focused thumb to the slider's min/max."}],ariaAttributes:["aria-valuemin/aria-valuemax/aria-valuenow/aria-orientation on each thumb","aria-valuetext on a thumb given a valueText, so a value that is not a plain number ('Medium', '\xA320') is announced as what it means","aria-label or aria-labelledby on each thumb of a multi-thumb slider","aria-hidden on each Mark, which redraws a scale the thumb already reports"],focusManagement:"Each SliderThumb is independently focusable and keyboard-operable.",namingRequirement:'A slider with more than one thumb must name each thumb distinctly with aria-label or aria-labelledby (for example "Minimum price" / "Maximum price"). role="slider" takes no name from content and a thumb renders none, so two unnamed thumbs announce identically and the user cannot tell which end of the range they are moving. A single-thumb slider needs no thumb name \u2014 the surrounding field names it and there is nothing to tell apart.'},styling:{cssParts:["slider","track","range","thumb","mark","tooltip"],dataAttributes:[...r,"data-orientation","data-disabled","data-dragging","data-value","data-size",{name:"data-skdx-slider-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[]},publicMethods:[...a],frameworkExtensions:[{framework:"webComponents",part:"Thumb",name:"showTooltip",type:"boolean",description:"Per-thumb version of the root's `showTooltip`, written from markup as show-tooltip. <skdx-slider-thumb> renders its own value readout inside a shadow root, so the switch has to reach the element that draws it; React, Vue, Svelte and Angular compose the readout as their own children of Thumb and decide per thumb by writing different children."},{framework:"webComponents",name:"updateValue",type:"(index: number, rawValue: number, reason?: 'pointer' | 'keyboard' | 'programmatic') => void",description:"Commits one thumb's value after clamping it to the step grid, the range and its neighbouring thumbs, then dispatches value-change with the given reason. Web Components only: it is how the element's own pointer and keyboard handlers write a value, and an element has no other channel for a caller to enter that path. React, Vue, Svelte and Angular set the controlled `value` prop instead, which runs the same clamping before it renders."},{framework:"webComponents",kind:"method",name:"updateValue",type:"(index: number, rawValue: number, reason?: SkdxSliderValueChangeDetail['reason']) => void",description:"Clamps/steps `rawValue` against neighboring thumbs and commits it, dispatching `value-change` with `reason` (default `'programmatic'`). 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:"updateValue",type:"(index: number, rawValue: number, reason?: SkdxSliderValueChangeDetail['reason']) => void",description:"Clamps/steps `rawValue` against neighboring thumbs and commits it, dispatching `value-change` with `reason` (default `'programmatic'`). 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."}]};export{o as sliderContract};
@@ -1 +1 @@
1
- import{dismissalEvents as t,forceMountProp as a,openChangeCompleteEvent as n,popperContentProps as o,popperMeasurementProperties as i,portalPart as r}from"./overlay-parts.js";import{PART_DATA_ATTRIBUTES as s}from"./styling-hooks.js";var d={name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Whether arrow-key navigation wraps from the last action back to the first, and vice versa."},c={name:"SpeedDial",purpose:"A floating action button revealing a short fan of related actions along one axis, positioned via the shared popper layer and navigated as a WAI-ARIA menu. Each action is stamped with its ordinal for a staggered CSS reveal. Composed of a root plus Trigger, Portal, Content, Item, and ItemLabel parts, and an optional Overlay.",props:[{name:"open",type:"boolean",required:!1,description:"Controlled open state \u2014 whether the actions are revealed. Pair with the open-change event."},{name:"defaultOpen",type:"boolean",defaultValue:"false",required:!1,description:"Initial open state, for uncontrolled usage. The dial starts collapsed to just its trigger."},{name:"direction",type:"'up' | 'down' | 'left' | 'right'",defaultValue:"'up'",required:!1,description:'Which way the actions fan out from the trigger. Decides the side Content is positioned on, the axis the arrow keys walk, and the data-direction attribute the stagger CSS reads. Physical rather than logical: the viewport corner a speed dial is anchored to does not move under dir="rtl".'},{name:"openOnHover",type:"boolean",defaultValue:"false",required:!1,description:"Also open on pointer-enter of the trigger, not only on click. The click and keyboard paths work either way; this only adds the hover path, which touch pointers never take."},{name:"hoverCloseDelay",type:"number",defaultValue:"300",required:!1,description:"Milliseconds the dial stays open after the pointer leaves the trigger or the content. The gap between the two is dead space the pointer must cross, so closing on the first pointer-leave would snap the fan shut mid-travel; re-entering either element within the window cancels the pending close. Only consulted when openOnHover is set."},{name:"hoverOpenDelay",type:"number",defaultValue:"0",required:!1,description:"Milliseconds the pointer must rest on the trigger before the fan opens, only consulted when openOnHover is set. Prevents a pointer passing over the button from opening the fan. A value of 0 opens synchronously."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Blocks the dial from opening by any route \u2014 click, hover, or keyboard \u2014 and marks the trigger natively disabled. Setting it while open also closes the fan, firing open-change with false. Focus returns to the trigger only if it was inside Content."},{name:"trigger",type:"ReactElement | Snippet | TemplateRef<unknown>",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:`React, Svelte and Angular take this as a typed prop. Vue uses the #trigger slot and Web Components use light-DOM children marked slot="trigger". Only React's derived trigger is a whole interactive element merged via asChild; the others render their own button around this prop's content.`,description:`The floating action button for the derived anatomy. Its content model differs per framework: React merges a whole element via asChild, while Svelte and Angular take only the button's inner content. The button must carry an accessible name \u2014 an icon-only floating action button announces as "button" and says nothing about what it opens. The triggerLabel prop names the derived button in the frameworks whose trigger content model has no other way to reach it.`},{name:"triggerLabel",type:"string",required:!1,description:"Accessible name applied to the derived trigger's aria-label, for the frameworks where trigger only supplies the button's content rather than a whole element carrying its own name."},{name:"actions",type:"SpeedDialAction[]",required:!1,description:"The entries the derived fan renders \u2014 one Item per entry with its ItemLabel. Supplying it renders the whole anatomy from data; hand composition uses each framework's primitives/speed-dial subpath. An entry is { label, icon?, onSelect?, disabled? }. A disabled entry still occupies its place in the fan and counts towards the positional custom properties the stagger CSS reads. `icon` differs per framework (ReactNode in React, Component in Vue, Snippet in Svelte, TemplateRef in Angular, slotted light-DOM in Web Components)."},{name:"overlay",type:"boolean",defaultValue:"false",required:!1,description:"Paint the scrim behind the derived Content. On the hand-composed path the Overlay part is opt-in; on the derived path this boolean enables it. It does not make the dial modal: focus is not trapped and the page behind stays live."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Size rung forwarded to the Trigger's and every derived Item's data-size; either attribute may be written directly instead."}],events:[{name:"open-change",detail:"boolean",description:"Fired with the new open state whenever the dial opens or closes, controlled or not."},n("speed dial"),...t("speed dial"),{name:"select",detail:"{ action: SpeedDialAction; index: number } | null",description:"Fired by an Item when it is activated by click, Enter, or Space. Preventing default keeps the dial open \u2014 on the hand-composed path, which is the only one where a cancelable Item event is in reach. One event, not two: on the derived path it additionally carries the actions entry that was activated and its index, so a consumer reading the recipe gets the data back without a second same-named event on the same node \u2014 the ambiguity Menu had to rename its way out of. Hand-composed Items carry no entry, because on that path there is none. The derived payload is the entry and the index and nothing else: the recipe reports what was selected, it does not gate it."}],parts:[{name:"Trigger",description:`The floating action button that reveals the actions and anchors their position. Carries aria-haspopup="menu", aria-expanded, aria-controls, and an id that Content points its aria-labelledby at, so the menu inherits the floating button's name without a second prop to keep in sync.`,props:[{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the trigger; the data-size attribute may be set directly instead."}]},r,{name:"Overlay",description:"An optional scrim painted behind Content, dimming the page so a fan opened over dense content is separated from it. Rendered only when the consumer includes it \u2014 there is no prop and no default, and a dial without one is unchanged. A real element rather than a style prop, so it carries data-state of its own and can fade on a different timeline from the staggered actions. It does not make the dial modal: the fan keeps its own dismissal, and a pointer-down on the scrim is an outside interaction that closes it."},{name:"Content",description:`The fanned-out action list (role="menu"). Owns positioning and roving focus. Sets each Item's ordinal custom properties for the staggered reveal. Takes the shared popper positioning props except side, which the root's direction owns.`,props:[...o({sideOffset:"8"}).filter(e=>e.name!=="side"),a,d]},{name:"Item",description:'One action in the fan (role="menuitem"), a roving tab stop activated by click, Enter, or Space. Carries --skdx-speed-dial-index and --skdx-speed-dial-offset for the stagger.',props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Excludes the action from arrow-key navigation and blocks selection. It keeps its slot in the fan, so the actions around it do not shuffle."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the item; the data-size attribute may be set directly instead."}]},{name:"ItemLabel",description:"The visible text naming its Item. Registers its id as the Item's aria-labelledby, so an icon-only action is named by the label beside it rather than needing the name repeated in an aria-label."}],slots:[{name:"trigger",description:"The floating button's content: typically one icon. The button must carry an accessible name whenever content is icon-only \u2014 an unnamed floating action button says nothing about what it opens."},{name:"default",description:"Content's body \u2014 Item entries, each optionally with an ItemLabel."}],appearance:[{attribute:"data-size",values:["sm","md","lg"],stylesheet:"speed-dial.css"}],states:["closed","open","disabled"],controlledUncontrolled:"Stateless by default (uncontrolled): starts at defaultOpen and manages its own open state internally. Passing open switches to controlled.",formBehavior:'Not applicable \u2014 SpeedDial participates in no form; Trigger is type="button".',validationBehavior:"Not applicable \u2014 SpeedDial invokes actions, it collects no value.",accessibility:{role:"menu (Content), menuitem (Item)",keyboard:[{key:"Enter / Space",behavior:"Opens the dial from the trigger and moves focus to the first enabled action."},{key:"Arrow keys along the direction axis",behavior:"Open the dial from the trigger: Up/Down when direction is up or down, Left/Right when it is left or right. Focus lands on the first enabled action."},{key:"Arrow keys (inside the fan)",behavior:'Move focus between enabled actions in DOM order along the direction axis, wrapping unless loop is false. A disabled action is skipped rather than focused. Mirrored under dir="rtl" for the horizontal directions.'},{key:"Home / End",behavior:"Jump focus to the first/last enabled action, skipping disabled ones."},{key:"Printable characters",behavior:'Move focus to the next enabled action whose accessible name starts with the typed string, searching forward from the focused one and wrapping. Disabled actions never match. The buffer resets after one second of inactivity, so typing "s", pausing, then "h" looks for two different actions while "sh" typed quickly looks for one.'},{key:"Enter / Space (on an action)",behavior:"Selects the focused action and closes the dial unless the select event is prevented."},{key:"Escape",behavior:"Requests close (cancelable via escape-key-down) and returns focus to Trigger."},{key:"Tab",behavior:"Closes the dial and returns focus to Trigger, per the WAI-ARIA menu pattern."}],ariaAttributes:['aria-haspopup="menu", aria-expanded, and aria-controls on Trigger',"Content's id matches Trigger's aria-controls",'aria-labelledby on Content pointing at Trigger \u2014 role="menu" is not name-from-content, so a fan of perfectly named actions still announces as an unnamed "menu" without it. One name in one place rather than a second prop to keep in sync; where Trigger is a host element the reference resolves to that host, because that is the element the author writes the name on and the only one an IDREF can reach across a shadow boundary',"aria-orientation on Content reflecting the axis direction implies \u2014 vertical for up/down, horizontal for left/right","aria-labelledby on an Item pointing at its ItemLabel when one is rendered","aria-disabled and data-disabled on a disabled Item, which is skipped by navigation and cannot be selected"],focusManagement:"Opening moves focus to the first action, by every route except hover: keyboard, click, and a programmatic or defaultOpen open all land on it, and the fan is then a single roving tab stop, so only one action is tabbable at a time. Escape, Tab, or selecting an action returns focus to Trigger. Hover-opening moves no focus, which is what keeps the hover path from stealing the caret out from under a keyboard user \u2014 the route is tracked internally rather than being carried on open-change, because contracts/change-reason.ts keeps an enumerated roster of the events that carry a reason and this is not one of them. A click is deliberately not treated as the hover case: pressing a menu button is a request for the menu, and every other menu button in this system focuses its first item for it.",namingRequirement:"Trigger must carry an accessible name (aria-label or visible text) \u2014 it is normally icon-only, and an unnamed floating button announces nothing about what it opens. Each Item is named by its ItemLabel, or by aria-label when it renders an icon alone."},styling:{cssParts:["trigger","overlay","content","item","item-label"],dataAttributes:[...s,"data-state","data-side","data-align","data-direction","data-disabled","data-size",{name:"data-skdx-speed-dial-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[...i("speed-dial"),"--skdx-speed-dial-index","--skdx-speed-dial-offset"]},publicMethods:[]};export{c as speedDialContract};
1
+ import{dismissalEvents as t,forceMountProp as n,openChangeCompleteEvent as a,popperContentProps as o,popperMeasurementProperties as i,portalPart as r}from"./overlay-parts.js";import{PART_DATA_ATTRIBUTES as s}from"./styling-hooks.js";var d={name:"loop",type:"boolean",defaultValue:"true",required:!1,description:"Whether arrow-key navigation wraps from the last action back to the first, and vice versa."},c={name:"SpeedDial",purpose:"A floating action button revealing a short fan of related actions along one axis, positioned via the shared popper layer and navigated as a WAI-ARIA menu. Each action is stamped with its ordinal for a staggered CSS reveal. Composed of a root plus Trigger, Portal, Content, Item, and ItemLabel parts, and an optional Overlay.",props:[{name:"open",type:"boolean",required:!1,description:"Controlled open state \u2014 whether the actions are revealed. Pair with the open-change event."},{name:"defaultOpen",type:"boolean",defaultValue:"false",required:!1,description:"Initial open state, for uncontrolled usage. The dial starts collapsed to just its trigger."},{name:"direction",type:"'up' | 'down' | 'left' | 'right'",defaultValue:"'up'",required:!1,description:'Which way the actions fan out from the trigger. Decides the side Content is positioned on, the axis the arrow keys walk, and the data-direction attribute the stagger CSS reads. Physical rather than logical: the viewport corner a speed dial is anchored to does not move under dir="rtl".'},{name:"openOnHover",type:"boolean",defaultValue:"false",required:!1,description:"Also open on pointer-enter of the trigger, not only on click. The click and keyboard paths work either way; this only adds the hover path, which touch pointers never take."},{name:"hoverCloseDelay",type:"number",defaultValue:"300",required:!1,description:"Milliseconds the dial stays open after the pointer leaves the trigger or the content. The gap between the two is dead space the pointer must cross, so closing on the first pointer-leave would snap the fan shut mid-travel; re-entering either element within the window cancels the pending close. Only consulted when openOnHover is set."},{name:"hoverOpenDelay",type:"number",defaultValue:"0",required:!1,description:"Milliseconds the pointer must rest on the trigger before the fan opens, only consulted when openOnHover is set. Prevents a pointer passing over the button from opening the fan. A value of 0 opens synchronously."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Blocks the dial from opening by any route \u2014 click, hover, or keyboard \u2014 and marks the trigger natively disabled. Setting it while open also closes the fan, firing open-change with false. Focus returns to the trigger only if it was inside Content."},{name:"trigger",type:"ReactElement | Snippet | TemplateRef<unknown>",required:!1,frameworks:["react","svelte","angular"],exception:"render-prop",frameworksReason:`React, Svelte and Angular take this as a typed prop. Vue uses the #trigger slot and Web Components use light-DOM children marked slot="trigger". Only React's derived trigger is a whole interactive element merged via asChild; the others render their own button around this prop's content.`,description:`The floating action button for the derived anatomy. Its content model differs per framework: React merges a whole element via asChild, while Svelte and Angular take only the button's inner content. The button must carry an accessible name \u2014 an icon-only floating action button announces as "button" and says nothing about what it opens. The triggerLabel prop names the derived button in the frameworks whose trigger content model has no other way to reach it.`},{name:"triggerLabel",type:"string",required:!1,description:"Accessible name applied to the derived trigger's aria-label, for the frameworks where trigger only supplies the button's content rather than a whole element carrying its own name."},{name:"actions",type:"SpeedDialAction[]",required:!1,description:"The entries the derived fan renders \u2014 one Item per entry with its ItemLabel. Supplying it renders the whole anatomy from data; hand composition uses each framework's primitives/speed-dial subpath. An entry is { label, icon?, onSelect?, disabled? }. A disabled entry still occupies its place in the fan and counts towards the positional custom properties the stagger CSS reads. `icon` differs per framework (ReactNode in React, Component in Vue, Snippet in Svelte, TemplateRef in Angular, slotted light-DOM in Web Components)."},{name:"overlay",type:"boolean",defaultValue:"false",required:!1,description:"Paint the scrim behind the derived Content. On the hand-composed path the Overlay part is opt-in; on the derived path this boolean enables it. It does not make the dial modal: focus is not trapped and the page behind stays live."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Size rung forwarded to the Trigger's and every derived Item's data-size; either attribute may be written directly instead."}],events:[{name:"open-change",detail:"boolean",description:"Fired with the new open state whenever the dial opens or closes, controlled or not."},a("speed dial"),...t("speed dial"),{name:"select",detail:"{ action: SpeedDialAction; index: number } | null",description:"Fired by an Item when it is activated by click, Enter, or Space. Preventing default keeps the dial open \u2014 on the hand-composed path, which is the only one where a cancelable Item event is in reach. One event, not two: on the derived path it additionally carries the actions entry that was activated and its index, so a consumer reading the recipe gets the data back without a second same-named event on the same node \u2014 the ambiguity Menu had to rename its way out of. Hand-composed Items carry no entry, because on that path there is none. The derived payload is the entry and the index and nothing else: the recipe reports what was selected, it does not gate it."}],parts:[{name:"Trigger",description:`The floating action button that reveals the actions and anchors their position. Carries aria-haspopup="menu", aria-expanded, aria-controls, and an id that Content points its aria-labelledby at, so the menu inherits the floating button's name without a second prop to keep in sync.`,props:[{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the trigger; the data-size attribute may be set directly instead."}],slots:[{name:"default",description:"The floating button's content: typically one icon. The button must carry an accessible name whenever content is icon-only \u2014 an unnamed floating action button says nothing about what it opens."}]},r,{name:"Overlay",description:"An optional scrim painted behind Content, dimming the page so a fan opened over dense content is separated from it. Rendered only when the consumer includes it \u2014 there is no prop and no default, and a dial without one is unchanged. A real element rather than a style prop, so it carries data-state of its own and can fade on a different timeline from the staggered actions. It does not make the dial modal: the fan keeps its own dismissal, and a pointer-down on the scrim is an outside interaction that closes it."},{name:"Content",description:`The fanned-out action list (role="menu"). Owns positioning and roving focus. Sets each Item's ordinal custom properties for the staggered reveal. Takes the shared popper positioning props except side, which the root's direction owns.`,props:[...o({sideOffset:"8"}).filter(e=>e.name!=="side"),n,d]},{name:"Item",description:'One action in the fan (role="menuitem"), a roving tab stop activated by click, Enter, or Space. Carries --skdx-speed-dial-index and --skdx-speed-dial-offset for the stagger.',props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Excludes the action from arrow-key navigation and blocks selection. It keeps its slot in the fan, so the actions around it do not shuffle."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the item; the data-size attribute may be set directly instead."}]},{name:"ItemLabel",description:"The visible text naming its Item. Registers its id as the Item's aria-labelledby, so an icon-only action is named by the label beside it rather than needing the name repeated in an aria-label."}],slots:[{name:"trigger",description:"The floating button's content: typically one icon. The button must carry an accessible name whenever content is icon-only \u2014 an unnamed floating action button says nothing about what it opens."},{name:"default",description:"Content's body \u2014 Item entries, each optionally with an ItemLabel."}],appearance:[{attribute:"data-size",values:["sm","md","lg"],stylesheet:"speed-dial.css"}],states:["closed","open","disabled"],controlledUncontrolled:"Stateless by default (uncontrolled): starts at defaultOpen and manages its own open state internally. Passing open switches to controlled.",formBehavior:'Not applicable \u2014 SpeedDial participates in no form; Trigger is type="button".',validationBehavior:"Not applicable \u2014 SpeedDial invokes actions, it collects no value.",accessibility:{role:"menu (Content), menuitem (Item)",keyboard:[{key:"Enter / Space",behavior:"Opens the dial from the trigger and moves focus to the first enabled action."},{key:"Arrow keys along the direction axis",behavior:"Open the dial from the trigger: Up/Down when direction is up or down, Left/Right when it is left or right. Focus lands on the first enabled action."},{key:"Arrow keys (inside the fan)",behavior:'Move focus between enabled actions in DOM order along the direction axis, wrapping unless loop is false. A disabled action is skipped rather than focused. Mirrored under dir="rtl" for the horizontal directions.'},{key:"Home / End",behavior:"Jump focus to the first/last enabled action, skipping disabled ones."},{key:"Printable characters",behavior:'Move focus to the next enabled action whose accessible name starts with the typed string, searching forward from the focused one and wrapping. Disabled actions never match. The buffer resets after one second of inactivity, so typing "s", pausing, then "h" looks for two different actions while "sh" typed quickly looks for one.'},{key:"Enter / Space (on an action)",behavior:"Selects the focused action and closes the dial unless the select event is prevented."},{key:"Escape",behavior:"Requests close (cancelable via escape-key-down) and returns focus to Trigger."},{key:"Tab",behavior:"Closes the dial and returns focus to Trigger, per the WAI-ARIA menu pattern."}],ariaAttributes:['aria-haspopup="menu", aria-expanded, and aria-controls on Trigger',"Content's id matches Trigger's aria-controls",'aria-labelledby on Content pointing at Trigger \u2014 role="menu" is not name-from-content, so a fan of perfectly named actions still announces as an unnamed "menu" without it. One name in one place rather than a second prop to keep in sync; where Trigger is a host element the reference resolves to that host, because that is the element the author writes the name on and the only one an IDREF can reach across a shadow boundary',"aria-orientation on Content reflecting the axis direction implies \u2014 vertical for up/down, horizontal for left/right","aria-labelledby on an Item pointing at its ItemLabel when one is rendered","aria-disabled and data-disabled on a disabled Item, which is skipped by navigation and cannot be selected"],focusManagement:"Opening moves focus to the first action, by every route except hover: keyboard, click, and a programmatic or defaultOpen open all land on it, and the fan is then a single roving tab stop, so only one action is tabbable at a time. Escape, Tab, or selecting an action returns focus to Trigger. Hover-opening moves no focus, which is what keeps the hover path from stealing the caret out from under a keyboard user \u2014 the route is tracked internally rather than being carried on open-change, because contracts/change-reason.ts keeps an enumerated roster of the events that carry a reason and this is not one of them. A click is deliberately not treated as the hover case: pressing a menu button is a request for the menu, and every other menu button in this system focuses its first item for it.",namingRequirement:"Trigger must carry an accessible name (aria-label or visible text) \u2014 it is normally icon-only, and an unnamed floating button announces nothing about what it opens. Each Item is named by its ItemLabel, or by aria-label when it renders an icon alone."},styling:{cssParts:["trigger","overlay","content","item","item-label"],dataAttributes:[...s,"data-state","data-side","data-align","data-direction","data-disabled","data-size",{name:"data-skdx-speed-dial-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[...i("speed-dial"),"--skdx-speed-dial-index","--skdx-speed-dial-offset"]},publicMethods:[]};export{c as speedDialContract};
@@ -1 +1 @@
1
- import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var n={name:"SplitButton",purpose:"Groups a primary action button with a small trigger that opens a menu of related actions. Renders a group container plus Action and Trigger parts, derived from label/items or hand-composed; owns no open/menu state of its own.",props:[{name:"label",type:"string",required:!1,description:"Text of the derived primary Action. Absent prop, absent element. Hand-composed children take precedence."},{name:"items",type:"ReadonlyArray<{ value: string; label: string; disabled?: boolean }>",required:!1,description:"The menu entries behind the derived trigger, rendered into a Menu. Absent prop, absent menu. An entry's value is what the select event reports; disabled marks it aria-disabled and blocks selection. Flat only \u2014 no submenus."},{name:"menuLabel",type:"string",defaultValue:"'More options'",required:!1,description:"Accessible name of the derived trigger (bare chevron with no text of its own). Must be distinct from `label` to tell the two halves apart. Web Components renders as visually-hidden text."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the root; the data-size attribute may be set directly instead."},{name:"variant",type:"'secondary' | 'primary' | 'danger' | 'outline' | 'ghost' | (string & {})",required:!1,description:"Fill style rung, written to data-variant on the root; the data-variant attribute may be set directly instead."}],events:[{name:"action-click",description:"Fires when the derived primary Action is pressed, carrying the pointer event. Nothing fires for a hand-composed Action.",detail:"MouseEvent",frameworks:["react","vue","svelte","angular"],exception:"event-shape",frameworksReason:"Web Components derives a real `<button>` in the light DOM, so platform's native `click` is the only event. Re-dispatching would fire twice."},{name:"select",description:"Fires with the activated menu entry. Never fires for disabled entries or hand-composed menus.",detail:"{ value: string; label: string; disabled?: boolean }",frameworks:["react","vue","svelte","angular"],exception:"event-shape",frameworksReason:"Web Components derives a real `<skdx-menu>` as the second half, so its own `item-select` already bubbles out."}],parts:[{name:"Action",description:'The primary action button (type="button"). Clicking it must never open the menu. Note: `Action` is the labelled half; `Trigger` is the disclosure beside it.',props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the primary action independently of Trigger. No root-level equivalent: SplitButton renders no buttons. Disable both halves by composition."}]},{name:"Trigger",description:'The disclosure button (type="button", aria-haspopup="menu"). Owns no open state; meant to *be* the menu\'s trigger element so the menu supplies aria-expanded/aria-controls. React: `MenuTrigger asChild` composes behavior onto this part. Vue/Svelte/Angular/Web Components: nesting this inside the menu\'s trigger creates nested `<button>` elements (invalid). Use the menu\'s own trigger instead.',props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables opening the menu independently of Action."},{name:"aria-label",type:"string",required:!1,description:"Accessible name for the trigger (usually an unlabelled glyph). In Web Components and Angular, must reach the inner `<button>`, not the host."}]}],slots:[{name:"default",description:"SplitButton body \u2014 typically an Action part and a Trigger part."},{name:"action",description:"Action's content \u2014 the primary button's label."}],appearance:[{attribute:"data-size",values:["sm","md","lg"],stylesheet:"split-button.css"},{attribute:"data-variant",values:["secondary","primary","danger","outline","ghost"],stylesheet:"split-button.css"}],states:["default"],controlledUncontrolled:"Stateless \u2014 SplitButton holds no internal state; any menu it pairs with owns its own.",formBehavior:'Not applicable at the group level \u2014 Action and Trigger are both type="button", so neither submits an enclosing form by default.',validationBehavior:"Not applicable \u2014 SplitButton carries no value and participates in no validation.",accessibility:{role:"group",keyboard:[{key:"Enter / Space (on Trigger)",behavior:"Opens the attached menu and moves focus to its first item."},{key:"ArrowDown (on Trigger)",behavior:"Opens the menu and moves focus to its first item (without prior click)."},{key:"ArrowUp (on Trigger)",behavior:"Opens the menu and moves focus to its *last* item (one keystroke to the bottom)."},{key:"Alt+ArrowUp (inside the open menu)",behavior:"Closes the menu and returns focus to Trigger, the mirror of the ArrowDown that opened it."},{key:"Escape (inside the open menu)",behavior:"Closes the menu and returns focus to Trigger."}],ariaAttributes:['aria-haspopup="menu" on Trigger',"aria-expanded and aria-controls on Trigger \u2014 supplied by the menu it is composed into, not by SplitButton"],focusManagement:"Action and Trigger are independently focusable buttons. Composed menu moves focus into its panel on open and **returns it to Trigger when it closes**: Escape, Alt+ArrowUp, pointer outside, or item selection. Menu performs this return; SplitButton does not intercept. Except: pointer dismissal does not return focus.",namingRequirement:`The root must carry aria-label or aria-labelledby (role="group" is not name-from-content). Action is named by its own text. Trigger must have an explicit name distinct from Action's.`},styling:{cssParts:["split-button","action","trigger"],dataAttributes:[...e,"data-size","data-variant",{name:"data-skdx-split-button-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[]},publicMethods:[]};export{n as splitButtonContract};
1
+ import{ROOT_DATA_ATTRIBUTES as e}from"./styling-hooks.js";var n={name:"SplitButton",purpose:"Groups a primary action button with a small trigger that opens a menu of related actions. Renders a group container plus Action and Trigger parts, derived from label/items or hand-composed; owns no open/menu state of its own.",props:[{name:"label",type:"string",required:!1,description:"Text of the derived primary Action. Absent prop, absent element. Hand-composed children take precedence."},{name:"items",type:"ReadonlyArray<{ value: string; label: string; disabled?: boolean }>",required:!1,description:"The menu entries behind the derived trigger, rendered into a Menu. Absent prop, absent menu. An entry's value is what the select event reports; disabled marks it aria-disabled and blocks selection. Flat only \u2014 no submenus."},{name:"menuLabel",type:"string",defaultValue:"'More options'",required:!1,description:"Accessible name of the derived trigger (bare chevron with no text of its own). Must be distinct from `label` to tell the two halves apart. Web Components renders as visually-hidden text."},{name:"size",type:"'sm' | 'md' | 'lg' | (string & {})",required:!1,description:"Visual size rung, written to data-size on the root; the data-size attribute may be set directly instead."},{name:"variant",type:"'secondary' | 'primary' | 'danger' | 'outline' | 'ghost' | (string & {})",required:!1,description:"Fill style rung, written to data-variant on the root; the data-variant attribute may be set directly instead."}],events:[{name:"action-click",description:"Fires when the derived primary Action is pressed, carrying the pointer event. Nothing fires for a hand-composed Action.",detail:"MouseEvent",frameworks:["react","vue","svelte","angular"],exception:"event-shape",frameworksReason:"Web Components derives a real `<button>` in the light DOM, so platform's native `click` is the only event. Re-dispatching would fire twice."},{name:"select",description:"Fires with the activated menu entry. Never fires for disabled entries or hand-composed menus.",detail:"{ value: string; label: string; disabled?: boolean }",frameworks:["react","vue","svelte","angular"],exception:"event-shape",frameworksReason:"Web Components derives a real `<skdx-menu>` as the second half, so its own `item-select` already bubbles out."}],parts:[{name:"Action",description:'The primary action button (type="button"). Clicking it must never open the menu. Note: `Action` is the labelled half; `Trigger` is the disclosure beside it.',props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables the primary action independently of Trigger. No root-level equivalent: SplitButton renders no buttons. Disable both halves by composition."}],slots:[{name:"default",description:"Action's content \u2014 the primary button's label."}]},{name:"Trigger",description:'The disclosure button (type="button", aria-haspopup="menu"). Owns no open state; meant to *be* the menu\'s trigger element so the menu supplies aria-expanded/aria-controls. React: `MenuTrigger asChild` composes behavior onto this part. Vue/Svelte/Angular/Web Components: nesting this inside the menu\'s trigger creates nested `<button>` elements (invalid). Use the menu\'s own trigger instead.',props:[{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Disables opening the menu independently of Action."},{name:"aria-label",type:"string",required:!1,description:"Accessible name for the trigger (usually an unlabelled glyph). In Web Components and Angular, must reach the inner `<button>`, not the host."}]}],slots:[{name:"default",description:"SplitButton body \u2014 typically an Action part and a Trigger part."},{name:"action",description:"Action's content \u2014 the primary button's label.",frameworks:["vue","svelte","angular","webComponents"],exception:"derived-anatomy",frameworksReason:"The root exposes action as content projection in vue, svelte, angular, webComponents. Other wrappers project default content into the Action part or use their separately documented rendering property; they do not accept a root named slot with this spelling."}],appearance:[{attribute:"data-size",values:["sm","md","lg"],stylesheet:"split-button.css"},{attribute:"data-variant",values:["secondary","primary","danger","outline","ghost"],stylesheet:"split-button.css"}],states:["default"],controlledUncontrolled:"Stateless \u2014 SplitButton holds no internal state; any menu it pairs with owns its own.",formBehavior:'Not applicable at the group level \u2014 Action and Trigger are both type="button", so neither submits an enclosing form by default.',validationBehavior:"Not applicable \u2014 SplitButton carries no value and participates in no validation.",accessibility:{role:"group",keyboard:[{key:"Enter / Space (on Trigger)",behavior:"Opens the attached menu and moves focus to its first item."},{key:"ArrowDown (on Trigger)",behavior:"Opens the menu and moves focus to its first item (without prior click)."},{key:"ArrowUp (on Trigger)",behavior:"Opens the menu and moves focus to its *last* item (one keystroke to the bottom)."},{key:"Alt+ArrowUp (inside the open menu)",behavior:"Closes the menu and returns focus to Trigger, the mirror of the ArrowDown that opened it."},{key:"Escape (inside the open menu)",behavior:"Closes the menu and returns focus to Trigger."}],ariaAttributes:['aria-haspopup="menu" on Trigger',"aria-expanded and aria-controls on Trigger \u2014 supplied by the menu it is composed into, not by SplitButton"],focusManagement:"Action and Trigger are independently focusable buttons. Composed menu moves focus into its panel on open and **returns it to Trigger when it closes**: Escape, Alt+ArrowUp, pointer outside, or item selection. Menu performs this return; SplitButton does not intercept. Except: pointer dismissal does not return focus.",namingRequirement:`The root must carry aria-label or aria-labelledby (role="group" is not name-from-content). Action is named by its own text. Trigger must have an explicit name distinct from Action's.`},styling:{cssParts:["split-button","action","trigger"],dataAttributes:[...e,"data-size","data-variant",{name:"data-skdx-split-button-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[]},publicMethods:[],frameworkExtensions:[{framework:"webComponents",kind:"event",name:"item-select",type:"Content projection",description:"Dispatched when the derived menu item is activated. This element exposes its native/custom bubbling event to addEventListener consumers; other wrappers integrate the corresponding action through callback props or native DOM listeners. This records the element event spelling without inventing an emitted event on the other wrappers."},{framework:"svelte",name:"action",type:"Snippet | undefined",description:"Action's content, overriding `label` when both are 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",name:"action",type:"TemplateRef<unknown>",description:"The derived Action's content, in place of plain-text label; wins over label when both are 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:"webComponents",kind:"event",name:"item-select",type:"Content projection",description:"Dispatched when the derived menu item is activated. This element exposes its native/custom bubbling event to addEventListener consumers; other wrappers integrate the corresponding action through callback props or native DOM listeners. This records the element event spelling without inventing an emitted event on the other wrappers."},{framework:"svelte",name:"action",type:"Snippet | undefined",description:"Action's content, overriding `label` when both are 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",name:"action",type:"TemplateRef<unknown>",description:"The derived Action's content, in place of plain-text label; wins over label when both are 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."}]};export{n as splitButtonContract};
@@ -1 +1 @@
1
- import{changeDetail as e}from"./change-reason.js";import{ROOT_DATA_ATTRIBUTES as t}from"./styling-hooks.js";var i={name:"Stepper",purpose:'An ordered list of steps in a multi-step task. Renders an <ol>; the current step carries aria-current="step" and visually-hidden status text (completed/current/error/incomplete/disabled). Optionally interactive via per-step Trigger, in linear or non-linear navigation mode.',props:[{name:"value",type:"string",required:!1,description:"Current step's value, for controlled usage. Pair with the value-change event."},{name:"defaultValue",type:"string",required:!1,description:"Initially current step's value, for uncontrolled usage."},{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Layout axis, exposed as data-orientation styling hook. No ARIA orientation or arrow-key handling (each Trigger is an ordinary tab stop)."},{name:"navigationMode",type:"'linear' | 'non-linear'",defaultValue:"'linear'",required:!1,description:"'linear' restricts trigger-driven navigation to completed, current, and first incomplete step. 'non-linear' allows any non-disabled step. Neither restricts programmatic changes to value."},{name:"completedLabel",type:"string",defaultValue:"'Completed'",required:!1,description:"Visually-hidden status text rendered inside a step whose status is completed."},{name:"currentLabel",type:"string",defaultValue:"'Current step'",required:!1,description:"Visually-hidden status text rendered inside the step whose status is current."},{name:"incompleteLabel",type:"string",defaultValue:"'Not completed'",required:!1,description:"Visually-hidden status text rendered inside a step whose status is incomplete."},{name:"disabledLabel",type:"string",defaultValue:"'Disabled'",required:!1,description:"Visually-hidden status text rendered inside a step whose status is disabled."},{name:"errorLabel",type:"string",defaultValue:"'Error'",required:!1,description:"Visually-hidden status text rendered inside a step whose status is error."},{name:"items",type:"ReadonlyArray<{ label: string; description?: string }>",required:!1,description:"The steps the list derives (one Item per entry with its Trigger). Label titles the step; description sits under it. Hand composition takes precedence."},{name:"current",type:"number",required:!1,description:"Which derived step is current, as a **positional index**. The string model (`value`/`defaultValue`/`value-change`) still works and wins when both are set."}],events:[{name:"value-change",description:"Fired when the current step changes, controlled or not. Never fires for a blocked activation (linear mode or disabled step), and never for the step that is already current.",detail:e("string")}],parts:[{name:"Item",description:'One step: an <li> carrying data-state and aria-current="step" (when current) plus visually-hidden status label.',props:[{name:"value",type:"string",required:!0,description:"Unique identifier matched against the root's value and against a Trigger's value."},{name:"completed",type:"boolean",defaultValue:"false",required:!1,description:"Whether this step has been completed. Drives data-state and, in linear mode, which steps a Trigger may activate."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Whether this step can be activated. A disabled step is skipped in tab order and refuses activation, but does not move the linear frontier."},{name:"error",type:"boolean",defaultValue:"false",required:!1,description:"Whether this step is in an error state (form failed, upload rejected). Drives data-state='error' and errorLabel status text (announced, not only painted red). Still navigable and counts as incomplete unless also completed. Ranks below current in precedence."}]},{name:"Trigger",description:"The optional interactive control inside an Item that makes the step navigable. Omit it for a read-only progress indicator.",props:[{name:"value",type:"string",required:!0,description:"The owning Item's value \u2014 the step this trigger activates."}]}],slots:[{name:"default",description:"One Item per step, in order."},{name:"item",description:"A single step's content: its label, marker, and optional Trigger."},{name:"trigger",description:"A single step's interactive control."}],states:["completed","current","error","incomplete","disabled"],controlledUncontrolled:"Stateless by default (uncontrolled): starts at defaultValue and manages the current step internally. Passing value switches to controlled \u2014 the consumer owns state and must update it from value-change, or the DOM will not change. Completion is always consumer-owned: Stepper never marks a step completed by itself.",formBehavior:"Not applicable \u2014 Stepper carries no value that participates in form submission. In a wizard, each step owns its own Form/Field controls.",validationBehavior:"Not applicable \u2014 Stepper runs no validation. A wizard gates forward progress by keeping the next step incomplete until its own form validates.",accessibility:{role:"list (native <ol>) / listitem (native <li>) / button (Trigger)",keyboard:[{key:"Tab / Shift+Tab",behavior:"Moves between step triggers (ordinary tab stops; no roving tabindex)."},{key:"Enter / Space",behavior:"Activates the focused trigger (subject to navigation mode and enabled state), via native button behavior."}],ariaAttributes:['aria-current="step" on the current Item',"aria-disabled on a Trigger that the navigation mode blocks","aria-controls on a Trigger that reveals content (consumer supplies the region id)."],focusManagement:"Each enabled step's Trigger is its own tab stop; disabled step's Trigger is removed from tab order. Activating a step does not move focus.",namingRequirement:'The root should carry aria-label or aria-labelledby (e.g. "Checkout progress").'},styling:{cssParts:["stepper","item","trigger","indicator","title","description","separator"],dataAttributes:[...t,"data-state","data-orientation","data-disabled","data-value","data-state-text",{name:"data-skdx-stepper-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[]},publicMethods:[{name:"getCurrentValue",signature:"(): string | undefined",description:"Reads the value of the step that is current, or undefined while none is.",frameworks:["webComponents"],exception:"imperative",frameworksReason:"The other four publish the same reading through context under a different name \u2014 React as `value` on StepperContextValue, Vue, Svelte and Angular as `currentValue()` \u2014 so listing it here unscoped would read as four packages missing a member they all have. Only the custom element, which has no context to hand it through, spells it as a method."}],contextApi:[{name:"canActivate",signature:"(value: string) => boolean",description:"Whether a trigger for value may activate its step under the current navigationMode. False for a disabled step, and for any step the mode puts out of reach \u2014 the same predicate a Trigger disables itself on.",accessors:{react:"useStepperContext('MyComponent').canActivate",vue:"inject(STEPPER_CONTEXT).canActivate",svelte:"requireContext(STEPPER_CONTEXT).canActivate",angular:"inject(SKDX_STEPPER_CONTEXT).canActivate",webComponents:"document.querySelector('skdx-stepper').canActivate"}},{name:"activate",signature:"(value: string) => void",description:"Makes value the current step and fires value-change, when canActivate allows it. A no-op otherwise \u2014 it never throws, so a blocked target is refused rather than reported.",accessors:{react:"useStepperContext('MyComponent').activate",vue:"inject(STEPPER_CONTEXT).activate",svelte:"requireContext(STEPPER_CONTEXT).activate",angular:"inject(SKDX_STEPPER_CONTEXT).activate",webComponents:"document.querySelector('skdx-stepper').activate"}}]};export{i as stepperContract};
1
+ import{changeDetail as e}from"./change-reason.js";import{ROOT_DATA_ATTRIBUTES as t}from"./styling-hooks.js";var n={name:"Stepper",purpose:'An ordered list of steps in a multi-step task. Renders an <ol>; the current step carries aria-current="step" and visually-hidden status text (completed/current/error/incomplete/disabled). Optionally interactive via per-step Trigger, in linear or non-linear navigation mode.',props:[{name:"value",type:"string",required:!1,description:"Current step's value, for controlled usage. Pair with the value-change event."},{name:"defaultValue",type:"string",required:!1,description:"Initially current step's value, for uncontrolled usage."},{name:"orientation",type:"'horizontal' | 'vertical'",defaultValue:"'horizontal'",required:!1,description:"Layout axis, exposed as data-orientation styling hook. No ARIA orientation or arrow-key handling (each Trigger is an ordinary tab stop)."},{name:"navigationMode",type:"'linear' | 'non-linear'",defaultValue:"'linear'",required:!1,description:"'linear' restricts trigger-driven navigation to completed, current, and first incomplete step. 'non-linear' allows any non-disabled step. Neither restricts programmatic changes to value."},{name:"completedLabel",type:"string",defaultValue:"'Completed'",required:!1,description:"Visually-hidden status text rendered inside a step whose status is completed."},{name:"currentLabel",type:"string",defaultValue:"'Current step'",required:!1,description:"Visually-hidden status text rendered inside the step whose status is current."},{name:"incompleteLabel",type:"string",defaultValue:"'Not completed'",required:!1,description:"Visually-hidden status text rendered inside a step whose status is incomplete."},{name:"disabledLabel",type:"string",defaultValue:"'Disabled'",required:!1,description:"Visually-hidden status text rendered inside a step whose status is disabled."},{name:"errorLabel",type:"string",defaultValue:"'Error'",required:!1,description:"Visually-hidden status text rendered inside a step whose status is error."},{name:"items",type:"ReadonlyArray<{ label: string; description?: string }>",required:!1,description:"The steps the list derives (one Item per entry with its Trigger). Label titles the step; description sits under it. Hand composition takes precedence."},{name:"current",type:"number",required:!1,description:"Which derived step is current, as a **positional index**. The string model (`value`/`defaultValue`/`value-change`) still works and wins when both are set."}],events:[{name:"value-change",description:"Fired when the current step changes, controlled or not. Never fires for a blocked activation (linear mode or disabled step), and never for the step that is already current.",detail:e("string")}],parts:[{name:"Item",description:'One step: an <li> carrying data-state and aria-current="step" (when current) plus visually-hidden status label.',props:[{name:"value",type:"string",required:!0,description:"Unique identifier matched against the root's value and against a Trigger's value."},{name:"completed",type:"boolean",defaultValue:"false",required:!1,description:"Whether this step has been completed. Drives data-state and, in linear mode, which steps a Trigger may activate."},{name:"disabled",type:"boolean",defaultValue:"false",required:!1,description:"Whether this step can be activated. A disabled step is skipped in tab order and refuses activation, but does not move the linear frontier."},{name:"error",type:"boolean",defaultValue:"false",required:!1,description:"Whether this step is in an error state (form failed, upload rejected). Drives data-state='error' and errorLabel status text (announced, not only painted red). Still navigable and counts as incomplete unless also completed. Ranks below current in precedence."}],slots:[{name:"default",description:"A single step's content: its label, marker, and optional Trigger."}]},{name:"Trigger",description:"The optional interactive control inside an Item that makes the step navigable. Omit it for a read-only progress indicator.",props:[{name:"value",type:"string",required:!0,description:"The owning Item's value \u2014 the step this trigger activates."}],slots:[{name:"default",description:"A single step's interactive control."}]}],slots:[{name:"default",description:"One Item per step, in order."}],states:["completed","current","error","incomplete","disabled"],controlledUncontrolled:"Stateless by default (uncontrolled): starts at defaultValue and manages the current step internally. Passing value switches to controlled \u2014 the consumer owns state and must update it from value-change, or the DOM will not change. Completion is always consumer-owned: Stepper never marks a step completed by itself.",formBehavior:"Not applicable \u2014 Stepper carries no value that participates in form submission. In a wizard, each step owns its own Form/Field controls.",validationBehavior:"Not applicable \u2014 Stepper runs no validation. A wizard gates forward progress by keeping the next step incomplete until its own form validates.",accessibility:{role:"list (native <ol>) / listitem (native <li>) / button (Trigger)",keyboard:[{key:"Tab / Shift+Tab",behavior:"Moves between step triggers (ordinary tab stops; no roving tabindex)."},{key:"Enter / Space",behavior:"Activates the focused trigger (subject to navigation mode and enabled state), via native button behavior."}],ariaAttributes:['aria-current="step" on the current Item',"aria-disabled on a Trigger that the navigation mode blocks","aria-controls on a Trigger that reveals content (consumer supplies the region id)."],focusManagement:"Each enabled step's Trigger is its own tab stop; disabled step's Trigger is removed from tab order. Activating a step does not move focus.",namingRequirement:'The root should carry aria-label or aria-labelledby (e.g. "Checkout progress").'},styling:{cssParts:["stepper","item","trigger","indicator","title","description","separator"],dataAttributes:[...t,"data-state","data-orientation","data-disabled","data-value","data-state-text",{name:"data-skdx-stepper-generated",frameworks:["webComponents"],exception:"wc-marker",frameworksReason:'Marks a node the element generated for itself rather than one the consumer authored. React, Vue, Svelte and Angular re-render their derived anatomy declaratively, so "mine or theirs" is answered by the framework and no marker is needed.'}],cssCustomProperties:[]},publicMethods:[{name:"getCurrentValue",signature:"(): string | undefined",description:"Reads the value of the step that is current, or undefined while none is.",frameworks:["webComponents"],exception:"imperative",frameworksReason:"The other four publish the same reading through context under a different name \u2014 React as `value` on StepperContextValue, Vue, Svelte and Angular as `currentValue()` \u2014 so listing it here unscoped would read as four packages missing a member they all have. Only the custom element, which has no context to hand it through, spells it as a method."}],contextApi:[{name:"canActivate",signature:"(value: string) => boolean",description:"Whether a trigger for value may activate its step under the current navigationMode. False for a disabled step, and for any step the mode puts out of reach \u2014 the same predicate a Trigger disables itself on.",accessors:{react:"useStepperContext('MyComponent').canActivate",vue:"inject(STEPPER_CONTEXT).canActivate",svelte:"requireContext(STEPPER_CONTEXT).canActivate",angular:"inject(SKDX_STEPPER_CONTEXT).canActivate",webComponents:"document.querySelector('skdx-stepper').canActivate"}},{name:"activate",signature:"(value: string) => void",description:"Makes value the current step and fires value-change, when canActivate allows it. A no-op otherwise \u2014 it never throws, so a blocked target is refused rather than reported.",accessors:{react:"useStepperContext('MyComponent').activate",vue:"inject(STEPPER_CONTEXT).activate",svelte:"requireContext(STEPPER_CONTEXT).activate",angular:"inject(SKDX_STEPPER_CONTEXT).activate",webComponents:"document.querySelector('skdx-stepper').activate"}}],frameworkExtensions:[{framework:"webComponents",kind:"method",name:"activate",type:"(value: string) => void",description:"Activates `value` when SkdxStepper.canActivate allows it, firing `value-change`; a no-op otherwise. 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:"canActivate",type:"(value: string) => boolean",description:"Whether a trigger for `value` may activate its step under the current navigation mode. 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:"activate",type:"(value: string) => void",description:"Activates `value` when SkdxStepper.canActivate allows it, firing `value-change`; a no-op otherwise. 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:"canActivate",type:"(value: string) => boolean",description:"Whether a trigger for `value` may activate its step under the current navigation mode. 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."}]};export{n as stepperContract};