@kerfjs/ui 5.0.0-beta.105 → 5.0.0-beta.107

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 (227) hide show
  1. package/README.md +2 -1
  2. package/ai/application-ui-diagnostic-ids-v1.json +1 -0
  3. package/ai/application-ui-profile.defaults.json +6 -1
  4. package/ai/component-catalog.json +160 -27
  5. package/ai/component-composition-rules.json +20 -2
  6. package/ai/component-composition.d.ts +11 -0
  7. package/ai/component-composition.json +118 -19
  8. package/ai/component-composition.schema.json +32 -0
  9. package/ai/components/README.md +3 -2
  10. package/ai/components/button.md +4 -1
  11. package/ai/components/checkbox-group.md +89 -0
  12. package/ai/components/checkbox.md +3 -2
  13. package/ai/components/color-picker.md +10 -7
  14. package/ai/components/disclosure.md +6 -1
  15. package/ai/components/foundation.md +1 -1
  16. package/ai/components/list-detail-dialog.md +1 -1
  17. package/ai/components/message-composer.md +2 -1
  18. package/ai/components/radio-group.md +4 -3
  19. package/ai/components/split-button.md +5 -2
  20. package/ai/components/surface-scaffold.md +2 -1
  21. package/ai/components/switch.md +1 -1
  22. package/ai/components/text.md +2 -0
  23. package/ai/components/wa-checkbox-group.md +5 -5
  24. package/ai/components/workbench-dialog.md +1 -1
  25. package/ai/public-api-signatures-v1.md +198 -26
  26. package/ai/skill.md +73 -62
  27. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  28. package/dist/browser/checkbox-group.js +5 -0
  29. package/dist/button.d.ts +15 -2
  30. package/dist/button.js +1 -1
  31. package/dist/catalog.js +9 -8
  32. package/dist/catalog.js.map +1 -1
  33. package/dist/checkbox-group.d.ts +70 -0
  34. package/dist/checkbox-group.js +7 -0
  35. package/dist/checkbox-group.js.map +1 -0
  36. package/dist/{chunk-SQ2Q3OQI.js → chunk-2LM3PYHA.js} +2 -2
  37. package/dist/{chunk-SQ2Q3OQI.js.map → chunk-2LM3PYHA.js.map} +1 -1
  38. package/dist/{chunk-HYORKKYP.js → chunk-3VZ6SFD4.js} +1 -1
  39. package/dist/chunk-3VZ6SFD4.js.map +1 -0
  40. package/dist/{chunk-EKBMUXFV.js → chunk-3Z7N2NAZ.js} +141 -54
  41. package/dist/chunk-3Z7N2NAZ.js.map +1 -0
  42. package/dist/{chunk-FKKJHGN5.js → chunk-AZ3WT77F.js} +2 -2
  43. package/dist/{chunk-FKKJHGN5.js.map → chunk-AZ3WT77F.js.map} +1 -1
  44. package/dist/{chunk-FG6U7KQQ.js → chunk-DNWWF6UN.js} +2 -2
  45. package/dist/{chunk-FG6U7KQQ.js.map → chunk-DNWWF6UN.js.map} +1 -1
  46. package/dist/{chunk-C3RLKKFQ.js → chunk-EYDXFOSH.js} +13 -8
  47. package/dist/chunk-EYDXFOSH.js.map +1 -0
  48. package/dist/{chunk-TAHR457X.js → chunk-G4DRH4A5.js} +3 -1
  49. package/dist/chunk-G4DRH4A5.js.map +1 -0
  50. package/dist/{chunk-PE2KPZDW.js → chunk-HDXUHLTQ.js} +7 -2
  51. package/dist/chunk-HDXUHLTQ.js.map +1 -0
  52. package/dist/chunk-HU5IHXCI.js +73 -0
  53. package/dist/chunk-HU5IHXCI.js.map +1 -0
  54. package/dist/{chunk-DF2YKGIX.js → chunk-JCCN3U6X.js} +2 -2
  55. package/dist/{chunk-DF2YKGIX.js.map → chunk-JCCN3U6X.js.map} +1 -1
  56. package/dist/{chunk-GCAK23PU.js → chunk-MVKHSAKE.js} +2 -2
  57. package/dist/{chunk-GCAK23PU.js.map → chunk-MVKHSAKE.js.map} +1 -1
  58. package/dist/{chunk-DDSCVEO5.js → chunk-NLMEDZRM.js} +5 -5
  59. package/dist/{chunk-DDSCVEO5.js.map → chunk-NLMEDZRM.js.map} +1 -1
  60. package/dist/{chunk-ECFCAKWE.js → chunk-NR6O74ST.js} +5 -1
  61. package/dist/chunk-NR6O74ST.js.map +1 -0
  62. package/dist/{chunk-7W3GKMN4.js → chunk-OQP3PFKQ.js} +7 -4
  63. package/dist/chunk-OQP3PFKQ.js.map +1 -0
  64. package/dist/{chunk-WJKHLOP5.js → chunk-TI2GV36S.js} +8 -2
  65. package/dist/chunk-TI2GV36S.js.map +1 -0
  66. package/dist/{chunk-UTCAOOXU.js → chunk-TXRKCGT3.js} +8 -2
  67. package/dist/chunk-TXRKCGT3.js.map +1 -0
  68. package/dist/{chunk-ACUKTVS3.js → chunk-XWNXGFX3.js} +52 -42
  69. package/dist/chunk-XWNXGFX3.js.map +1 -0
  70. package/dist/{chunk-ZXZAECHZ.js → chunk-Z4DS77U2.js} +2 -2
  71. package/dist/{chunk-ZXZAECHZ.js.map → chunk-Z4DS77U2.js.map} +1 -1
  72. package/dist/collapsible-panel.js +2 -2
  73. package/dist/color-picker.d.ts +30 -5
  74. package/dist/color-picker.js +1 -1
  75. package/dist/disclosure.d.ts +13 -4
  76. package/dist/disclosure.js +1 -1
  77. package/dist/disclosure.js.map +1 -1
  78. package/dist/help-tags-register.js +1 -1
  79. package/dist/index.d.ts +2 -1
  80. package/dist/index.js +20 -19
  81. package/dist/list-action-row.js +1 -1
  82. package/dist/list-detail-dialog.d.ts +7 -1
  83. package/dist/list-detail-dialog.js +6 -4
  84. package/dist/list-detail-dialog.js.map +1 -1
  85. package/dist/list-header.d.ts +8 -1
  86. package/dist/list-header.js +1 -1
  87. package/dist/nav-stack.js +1 -1
  88. package/dist/popup-menu-register.js +2 -2
  89. package/dist/popup-menu.d.ts +15 -5
  90. package/dist/popup-menu.js +1 -1
  91. package/dist/select-register.js +3 -3
  92. package/dist/split-button.d.ts +14 -2
  93. package/dist/split-button.js +1 -1
  94. package/dist/split-view.js +1 -1
  95. package/dist/styles/anchored-surface.css +3 -0
  96. package/dist/styles/button.css +29 -0
  97. package/dist/styles/catalog/components/catalog-example.css +55 -18
  98. package/dist/styles/checkbox-group.css +63 -0
  99. package/dist/styles/checkbox.css +7 -6
  100. package/dist/styles/color-picker.css +69 -34
  101. package/dist/styles/components/actions/button/button.css +29 -0
  102. package/dist/styles/components/actions/split-button/split-button.css +51 -5
  103. package/dist/styles/components/collections/framed-list/framed-list.css +4 -0
  104. package/dist/styles/components/collections/list/list.css +6 -0
  105. package/dist/styles/components/collections/list-header/list-header.css +7 -0
  106. package/dist/styles/components/feedback/anchored-surface/anchored-surface.css +3 -0
  107. package/dist/styles/components/forms/checkbox/checkbox.css +7 -6
  108. package/dist/styles/components/forms/checkbox-group/checkbox-group.css +63 -0
  109. package/dist/styles/components/forms/color-picker/color-picker.css +69 -34
  110. package/dist/styles/components/forms/radio-group/radio-group.css +7 -5
  111. package/dist/styles/components/forms/select/select.css +6 -2
  112. package/dist/styles/components/forms/switch/switch.css +3 -3
  113. package/dist/styles/components/layout/pane/pane.css +9 -0
  114. package/dist/styles/components/layout/workbench/workbench.css +4 -0
  115. package/dist/styles/components/navigation/nav-stack/nav-stack.css +64 -1
  116. package/dist/styles/components/navigation/tab-navigator/tab-navigator.css +1 -0
  117. package/dist/styles/components/surfaces/content-item/content-item.css +30 -0
  118. package/dist/styles/components/surfaces/disclosure/disclosure.css +38 -0
  119. package/dist/styles/components/surfaces/sunken-panel/sunken-panel.css +3 -0
  120. package/dist/styles/components/surfaces/surface-scaffold/surface-scaffold.css +6 -0
  121. package/dist/styles/components/typography/text/text.css +10 -0
  122. package/dist/styles/content-item.css +30 -0
  123. package/dist/styles/disclosure.css +38 -0
  124. package/dist/styles/foundation.css +21 -0
  125. package/dist/styles/framed-list.css +4 -0
  126. package/dist/styles/list-header.css +7 -0
  127. package/dist/styles/list.css +6 -0
  128. package/dist/styles/nav-stack.css +64 -1
  129. package/dist/styles/pane.css +9 -0
  130. package/dist/styles/radio-group.css +7 -5
  131. package/dist/styles/select.css +6 -2
  132. package/dist/styles/split-button.css +51 -5
  133. package/dist/styles/styles.css +1 -0
  134. package/dist/styles/sunken-panel.css +3 -0
  135. package/dist/styles/surface-scaffold.css +6 -0
  136. package/dist/styles/switch.css +3 -3
  137. package/dist/styles/tab-navigator.css +1 -0
  138. package/dist/styles/text.css +10 -0
  139. package/dist/styles/webawesome.css +45 -9
  140. package/dist/styles/workbench.css +4 -0
  141. package/dist/surface-scaffold.d.ts +7 -1
  142. package/dist/surface-scaffold.js +1 -1
  143. package/dist/wire-color-fields.js +2 -2
  144. package/dist/wire-color-pickers.d.ts +4 -3
  145. package/dist/wire-color-pickers.js +1 -1
  146. package/dist/wire-comboboxes.js +1 -1
  147. package/dist/workbench-dialog.d.ts +11 -2
  148. package/dist/workbench-dialog.js +5 -2
  149. package/dist/workbench-dialog.js.map +1 -1
  150. package/dist/workbench.js +1 -1
  151. package/docs/accessibility.md +40 -1
  152. package/docs/anchored-surface.md +6 -1
  153. package/docs/catalog.md +26 -1
  154. package/docs/color-picker.md +39 -8
  155. package/docs/component-contract.md +33 -2
  156. package/docs/component-selection.md +20 -9
  157. package/docs/design/templates/button/full-width-dark.svg +1 -0
  158. package/docs/design/templates/button/full-width.svg +1 -0
  159. package/docs/design/templates/button-dark.svg +1 -1
  160. package/docs/design/templates/button.svg +1 -1
  161. package/docs/design/templates/checkbox/error-dark.svg +1 -1
  162. package/docs/design/templates/checkbox/error.svg +1 -1
  163. package/docs/design/templates/checkbox/states-dark.svg +1 -1
  164. package/docs/design/templates/checkbox/states.svg +1 -1
  165. package/docs/design/templates/checkbox-dark.svg +1 -1
  166. package/docs/design/templates/checkbox-group/horizontal-dark.svg +1 -0
  167. package/docs/design/templates/checkbox-group/horizontal.svg +1 -0
  168. package/docs/design/templates/checkbox-group/vertical-dark.svg +1 -0
  169. package/docs/design/templates/checkbox-group/vertical.svg +1 -0
  170. package/docs/design/templates/checkbox-group-dark.svg +1 -0
  171. package/docs/design/templates/checkbox-group.svg +1 -0
  172. package/docs/design/templates/checkbox.svg +1 -1
  173. package/docs/design/templates/color-picker/gray-dark.svg +1 -1
  174. package/docs/design/templates/color-picker/gray.svg +1 -1
  175. package/docs/design/templates/color-picker/hsb-dark.svg +1 -0
  176. package/docs/design/templates/color-picker/hsb.svg +1 -0
  177. package/docs/design/templates/color-picker/rgb-dark.svg +1 -1
  178. package/docs/design/templates/color-picker/rgb.svg +1 -1
  179. package/docs/design/templates/color-picker-dark.svg +1 -1
  180. package/docs/design/templates/color-picker.svg +1 -1
  181. package/docs/design/templates/disclosure/embedded-dark.svg +1 -0
  182. package/docs/design/templates/disclosure/embedded.svg +1 -0
  183. package/docs/design/templates/disclosure-dark.svg +1 -1
  184. package/docs/design/templates/disclosure.svg +1 -1
  185. package/docs/design/templates/radio-group/horizontal-dark.svg +1 -1
  186. package/docs/design/templates/radio-group/horizontal.svg +1 -1
  187. package/docs/design/templates/radio-group/vertical-dark.svg +1 -1
  188. package/docs/design/templates/radio-group/vertical.svg +1 -1
  189. package/docs/design/templates/radio-group-dark.svg +1 -1
  190. package/docs/design/templates/radio-group.svg +1 -1
  191. package/docs/design/templates/split-button/full-width-dark.svg +1 -0
  192. package/docs/design/templates/split-button/full-width.svg +1 -0
  193. package/docs/design/templates/split-button/pill-dark.svg +1 -0
  194. package/docs/design/templates/split-button/pill.svg +1 -0
  195. package/docs/design/templates/split-button/states-dark.svg +1 -0
  196. package/docs/design/templates/split-button/states.svg +1 -0
  197. package/docs/design/templates/split-button/tones-dark.svg +1 -0
  198. package/docs/design/templates/split-button/tones.svg +1 -0
  199. package/docs/design/templates/split-button-dark.svg +1 -0
  200. package/docs/design/templates/split-button.svg +1 -0
  201. package/docs/design/templates/switch/states-dark.svg +1 -1
  202. package/docs/design/templates/switch/states.svg +1 -1
  203. package/docs/design/templates/switch-dark.svg +1 -1
  204. package/docs/design/templates/switch.svg +1 -1
  205. package/docs/design/templates.md +10 -3
  206. package/docs/disclosure.md +34 -0
  207. package/docs/list-detail-dialog.md +4 -0
  208. package/docs/nav-stack.md +6 -2
  209. package/docs/surface-scaffold.md +6 -2
  210. package/docs/ui-doctor.md +16 -4
  211. package/docs/webawesome-migration.md +1 -1
  212. package/docs/webawesome-theme.md +48 -16
  213. package/docs/workbench-dialog.md +4 -1
  214. package/docs/writing.md +3 -3
  215. package/doctor/copy-capitalization-checks.mjs +10 -7
  216. package/llms.txt +50 -20
  217. package/package.json +7 -1
  218. package/dist/chunk-7W3GKMN4.js.map +0 -1
  219. package/dist/chunk-ACUKTVS3.js.map +0 -1
  220. package/dist/chunk-C3RLKKFQ.js.map +0 -1
  221. package/dist/chunk-ECFCAKWE.js.map +0 -1
  222. package/dist/chunk-EKBMUXFV.js.map +0 -1
  223. package/dist/chunk-HYORKKYP.js.map +0 -1
  224. package/dist/chunk-PE2KPZDW.js.map +0 -1
  225. package/dist/chunk-TAHR457X.js.map +0 -1
  226. package/dist/chunk-UTCAOOXU.js.map +0 -1
  227. package/dist/chunk-WJKHLOP5.js.map +0 -1
@@ -24,6 +24,7 @@ Choose exactly one of a few options that should stay visible with room for a lab
24
24
  - [Radio](./wa-radio.md) (prefer-over)
25
25
  - [Select](./select.md) (nearest) — Use Select for a long list.
26
26
  - [ChoiceChips](./choice-chips.md) (nearest) — Use ChoiceChips for wrapping pill choices.
27
+ - [CheckboxGroup](./checkbox-group.md) (nearest) — Use CheckboxGroup when people may choose several.
27
28
 
28
29
  ## Imports
29
30
 
@@ -62,7 +63,7 @@ No wiring helper.
62
63
 
63
64
  Margin: none · border: none · padding: self (layout role: controls). `self` means the component already owns it — do not add wrapper padding, margin, or borders around it.
64
65
 
65
- - The label and hint sit on the text column (1px + 8px); the choices sit on the 8px control column, 12px apart.
66
+ - The label and hint sit on the text column (1px + 8px); each choice's 20px circle (18px compact) sits on the group's inline-start edge, where a Checkbox draws its box, 8px (7px) before its label; choices stack 8px apart (--kui-space-xs), the same 28px pitch as Checkboxes in a List gap="xs", and a choice hint aligns with its label text.
66
67
 
67
68
  ## Accessibility
68
69
 
@@ -77,12 +78,12 @@ Public class hooks (select for layout placement only, never to change the compon
77
78
 
78
79
  Never put `kui-radio-group`, `kui-radio-group__label`, `kui-radio-group__choices`, `kui-radio-group__choice`, `kui-radio-group__row`, `kui-radio-group__control`, `kui-radio-group__input`, `kui-radio-group__circle`, `kui-radio-group__choice-label`, `kui-radio-group__choice-hint`, `kui-radio-group__hint`, `kui-radio-group__error` on an element you write; render `RadioGroup` instead (`KUI-L103`).
79
80
 
80
- Public tokens it reads: `--kui-color-brand-fill-loud`, `--kui-color-neutral-border-normal`, `--kui-color-surface`, `--kui-color-text`, `--kui-color-text-quiet`, `--kui-color-danger-border-loud`, `--kui-color-danger-on-quiet`, `--kui-focus-ring`, `--kui-font-m`, `--kui-font-s`, `--kui-font-xs`, `--kui-color-neutral-on-quiet`, `--kui-layout-item-padding`. Set a token only where its public contract allows; prefer a prop.
81
+ Public tokens it reads: `--kui-color-brand-fill-loud`, `--kui-color-neutral-border-normal`, `--kui-color-surface`, `--kui-color-text`, `--kui-color-text-quiet`, `--kui-color-danger-border-loud`, `--kui-color-danger-on-quiet`, `--kui-focus-ring`, `--kui-font-m`, `--kui-font-s`, `--kui-font-xs`, `--kui-color-neutral-on-quiet`, `--kui-layout-item-padding`, `--kui-space-xs`. Set a token only where its public contract allows; prefer a prop.
81
82
 
82
83
  Everything else is internal: `kerf-ui-analyze` reports private or unknown `.kui-*` selectors (`KUI-L001`, `KUI-L010`), unknown or private tokens (`KUI-L002`, `KUI-L012`), and any application rule that restyles the component, forced dimensions included (`KUI-L019`).
83
84
 
84
85
  ## Related
85
86
 
86
- - Components: [Radio Group](./wa-radio-group.md), [Radio](./wa-radio.md), [Select](./select.md), [ChoiceChips](./choice-chips.md).
87
+ - Components: [Radio Group](./wa-radio-group.md), [Radio](./wa-radio.md), [Select](./select.md), [ChoiceChips](./choice-chips.md), [CheckboxGroup](./checkbox-group.md).
87
88
  - Docs: [`docs/component-selection.md`](../../docs/component-selection.md), [`docs/component-selection.md#problem-to-component-matrix`](../../docs/component-selection.md#problem-to-component-matrix).
88
89
  - UX catalog route: `?component=radio-group`.
@@ -8,7 +8,7 @@ A primary action with an attached options trigger on one loud semantic fill.
8
8
 
9
9
  ## When to use
10
10
 
11
- Render a prominent primary action plus an options trigger (provider, model, target) as one control with a semantic tone, full-width sizing, a busy presentation, and native aria-expanded on the trigger, outside any Toolbar.
11
+ Render a prominent primary action plus an options trigger (provider, model, target) as one control with a semantic tone, full-width sizing, a rounded or pill shape, a busy presentation, and native aria-expanded on the trigger, outside any Toolbar.
12
12
 
13
13
  - A prominent primary action has a closely related set of options chosen from an attached trigger, such as Drive with a provider menu or Deploy with targets.
14
14
 
@@ -37,8 +37,10 @@ Exact prop names and types: [`@kerfjs/ui/split-button`](../public-api-signatures
37
37
 
38
38
  - brand, neutral, success, warning, or danger tone
39
39
  - content width or fill
40
+ - rounded or pill shape
40
41
  - busy
41
42
  - disabled primary or options
43
+ - focusRingInset: each half's focus ring drawn inside its box for an ancestor that clips overflow
42
44
 
43
45
  ## Composition
44
46
 
@@ -60,6 +62,7 @@ Margin: none · border: self · padding: self (layout role: controls). `self` me
60
62
  ## Accessibility
61
63
 
62
64
  - Both halves are native buttons in a group; the options trigger exposes aria-haspopup, aria-expanded, and optional aria-controls, and needs optionsLabel. busy sets aria-busy on the primary.
65
+ - Each half draws the focus ring 1px outside its box; with focusRingInset it is drawn inside, two-tone with a surface-colored line inside the ring color, so it keeps 3:1 contrast on every loud fill.
63
66
 
64
67
  ## Styling boundary
65
68
 
@@ -69,7 +72,7 @@ Public class hooks (select for layout placement only, never to change the compon
69
72
 
70
73
  Never put `kui-split-button`, `kui-split-button__options`, `kui-split-button__icon`, `kui-split-button__label` on an element you write; render `SplitButton` instead (`KUI-L103`).
71
74
 
72
- Public tokens it reads: `--kui-color-brand-fill-loud`, `--kui-color-brand-on-loud`, `--kui-color-neutral-fill-loud`, `--kui-color-neutral-on-loud`, `--kui-color-success-fill-loud`, `--kui-color-success-on-loud`, `--kui-color-warning-fill-loud`, `--kui-color-warning-on-loud`, `--kui-color-danger-fill-loud`, `--kui-color-danger-on-loud`, `--kui-focus-ring`, `--kui-font-weight-semibold`, `--kui-layout-rounded-radius`, `--kui-space-s`, `--kui-space-xs`. Set a token only where its public contract allows; prefer a prop.
75
+ Public tokens it reads: `--kui-color-brand-fill-loud`, `--kui-color-brand-on-loud`, `--kui-color-neutral-fill-loud`, `--kui-color-neutral-on-loud`, `--kui-color-success-fill-loud`, `--kui-color-success-on-loud`, `--kui-color-warning-fill-loud`, `--kui-color-warning-on-loud`, `--kui-color-danger-fill-loud`, `--kui-color-danger-on-loud`, `--kui-focus-ring`, `--kui-font-weight-semibold`, `--kui-layout-pill-radius`, `--kui-layout-rounded-radius`, `--kui-space-s`, `--kui-space-xs`. Set a token only where its public contract allows; prefer a prop.
73
76
 
74
77
  Everything else is internal: `kerf-ui-analyze` reports private or unknown `.kui-*` selectors (`KUI-L001`, `KUI-L010`), unknown or private tokens (`KUI-L002`, `KUI-L012`), and any application rule that restyles the component, forced dimensions included (`KUI-L019`).
75
78
 
@@ -56,6 +56,7 @@ Exact prop names and types: [`@kerfjs/ui/surface-scaffold`](../public-api-signat
56
56
  - core kerfjs/overlay confirm/prompt/form/choice as a bottom sheet styled by @kerfjs/ui/overlay-sheet.css
57
57
  - resizable core kerfjs/overlay bottom sheet: the kui-overlay-sheet-resizable class plus wireOverlaySheets adds the resizable DialogSurface sheet grabber
58
58
  - header with label text or heading content, headerActions, a close button, and an optional footer; withoutHeader for content that owns its heading and close control
59
+ - accessible description by describedBy: the heading ToolbarText descriptionId or app-owned body summary copy
59
60
  - light dismiss (a backdrop press closes; otherwise the panel pulses)
60
61
 
61
62
  **CSS-value props** (typed builders from `@kerfjs/ui/css-values`; raw CSS strings are rejected):
@@ -87,7 +88,7 @@ Margin: parent · border: child · padding: self (layout role: structure). `self
87
88
 
88
89
  - DialogSurface is a native \<dialog> opened modally (showModal): it is in the top layer, the rest of the page is inert, focus stays inside, and it returns to the opener on close. Focus starts on an autofocus element, otherwise on the panel.
89
90
  - Name it with label (also its title text) or labelledBy (the id of a heading, such as a ToolbarText). The close button is named Close (closeLabel) and Escape asks to close; the cancelable kui-request-close event reports source close-button, escape, or backdrop.
90
- - Name a PopoverDialogSurface with label or labelledBy, and describe it with describedBy (rendered as aria-describedby), usually a title ToolbarText descriptionId.
91
+ - Name a PopoverDialogSurface with label or labelledBy. Describe either surface with describedBy (rendered as aria-describedby on the dialog root), usually the heading ToolbarText descriptionId or app-owned summary copy in the body; rootAttributes accepts only data-\* attributes, so it never sets aria-describedby.
91
92
  - A floating header's title uses the normal text color, which keeps WCAG AA over the 80% raised chrome material on any content; the material turns opaque under prefers-reduced-transparency, prefers-contrast: more, forced colors, or without backdrop-filter.
92
93
  - A resizable bottom sheet's grabber is a focusable horizontal separator ("Resize sheet") with aria-valuemin, aria-valuenow, and aria-valuemax in visible px; the arrow keys, Page Up/Down, Home, and End resize it, and its slide motion is skipped under prefers-reduced-motion.
93
94
  - Use popup surfaces only for real dropdown menus with named triggers.
@@ -56,7 +56,7 @@ No wiring helper.
56
56
 
57
57
  Margin: none · border: self · padding: none (layout role: controls). `self` means the component already owns it — do not add wrapper padding, margin, or borders around it.
58
58
 
59
- - A 35×20 track (31.5×18 compact) 8px (7px) before its label; the hint aligns with the label text.
59
+ - A 35×20 track (31.5×18 compact) 8px (7px) before its label; the hint sits directly under the label, on its text column, like a Checkbox hint.
60
60
 
61
61
  ## Accessibility
62
62
 
@@ -64,6 +64,8 @@ Margin: self · border: self · padding: self (layout role: structure). `self` m
64
64
  - Block Text variants reset native margins and add a 1px transparent border plus the standard 8px item padding; flush removes the border and padding. Tight line height is available for compact copy. Span has no margin by default, border, or padding. FieldLabel mirrors the themed Web Awesome label typography, 9px inline inset, and bottom gap.
65
65
  - controlMargins adds the shared control gutter outside selected physical edges without changing border or padding; avoid duplicating a parent inset. Spans retain inline display and native inline margin behavior.
66
66
 
67
+ Inset-free (no margin, border, or padding) when `flush` or `variant="span"`: the form to use inside a parent that expects inset-free content (`KUI-L204`).
68
+
67
69
  ## Accessibility
68
70
 
69
71
  - Text renders a native paragraph by default; choose an h1 through h6 variant by document outline rather than appearance, or span for inline secondary text.
@@ -6,18 +6,18 @@
6
6
 
7
7
  ## When to use
8
8
 
9
- Ecosystem checkbox group; use Kerf Checkbox rows or ChoiceChips.
9
+ Ecosystem checkbox group; use Kerf CheckboxGroup or ChoiceChips.
10
10
 
11
11
  - Labels and validates a related set of checkboxes.
12
12
 
13
13
  **Not when:**
14
14
 
15
- - Do not use it in Kerf UI; use Checkbox rows in a List, or ChoiceChips multiple for wrapping pills.
15
+ - Do not use it in Kerf UI; use CheckboxGroup for a labeled set of options, or ChoiceChips multiple for wrapping pills.
16
16
 
17
17
  **Alternatives:**
18
18
 
19
- - [Checkbox](./checkbox.md) (prefer-kerf) — Use Checkbox rows in a List, or ChoiceChips multiple for wrapping pills.
20
- - [ChoiceChips](./choice-chips.md) (prefer-kerf) — Use Checkbox rows in a List, or ChoiceChips multiple for wrapping pills.
19
+ - [CheckboxGroup](./checkbox-group.md) (prefer-kerf) — Use CheckboxGroup for a labeled set of options, or ChoiceChips multiple for wrapping pills.
20
+ - [ChoiceChips](./choice-chips.md) (prefer-kerf) — Use CheckboxGroup for a labeled set of options, or ChoiceChips multiple for wrapping pills.
21
21
 
22
22
  ## Imports
23
23
 
@@ -57,6 +57,6 @@ Theme it only through `@kerfjs/ui/webawesome.css` and cataloged tokens. Do not r
57
57
 
58
58
  ## Related
59
59
 
60
- - Components: [Checkbox](./wa-checkbox.md), [Checkbox](./checkbox.md), [ChoiceChips](./choice-chips.md).
60
+ - Components: [Checkbox](./wa-checkbox.md), [CheckboxGroup](./checkbox-group.md), [ChoiceChips](./choice-chips.md).
61
61
  - Docs: [`docs/webawesome-theme.md#coverage`](../../docs/webawesome-theme.md#coverage).
62
62
  - UX catalog route: `?component=wa-checkbox-group`.
@@ -75,7 +75,7 @@ Margin: parent · border: self · padding: child (layout role: structure). `self
75
75
  ## Accessibility
76
76
 
77
77
  - It is a native modal \<dialog> named by label: the page is inert, focus stays inside, Escape asks to close, and focus returns to the opener on close.
78
- - The title is a level-2 heading; the close control is named Close (closeLabel) and stays the outermost trailing control. An open overlay rail takes focus, keeps Tab inside it, and closes on Escape before the dialog does.
78
+ - The title is a level-2 heading, and its description (id \<id>-description) is the dialog's accessible description unless describedBy names other content; the close control is named Close (closeLabel) and stays the outermost trailing control. An open overlay rail takes focus, keeps Tab inside it, and closes on Escape before the dialog does.
79
79
 
80
80
  ## Styling boundary
81
81
 
@@ -1,6 +1,6 @@
1
1
  # Public API signatures for the UI authoring corpus
2
2
 
3
- Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.105` and `kerfjs@5.0.0-beta.105`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
3
+ Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.107` and `kerfjs@5.0.0-beta.107`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
4
4
 
5
5
  ## `@kerfjs/ui/css-values`
6
6
 
@@ -602,7 +602,11 @@ type PopupMenuProps = PopupMenuTrigger & {
602
602
  /** Trigger icon, typically a `LucideIcon`, before any visible text. */
603
603
  icon?: KerfUiContent;
604
604
  items: readonly PopupMenuEntry[];
605
- /** Where the menu opens relative to its trigger. Defaults to `bottom-start`. */
605
+ /**
606
+ * Where the menu opens relative to its trigger, or to its anchor point for
607
+ * a `context` menu (`top-start` opens above the point). Defaults to
608
+ * `bottom-start`.
609
+ */
606
610
  placement?: PopupMenuPlacement;
607
611
  /** Show the disclosure caret after the trigger content. Defaults to true. */
608
612
  caret?: boolean;
@@ -616,13 +620,19 @@ type PopupMenuProps = PopupMenuTrigger & {
616
620
  type PopupMenuElement = HTMLElement;
617
621
  /**
618
622
  * Open a PopupMenu at viewport pointer coordinates. A `context` menu rendered
619
- * without `anchor` moves its invisible anchor there (a menu rendered with
620
- * `anchor` opens with `openPopupMenu` instead). A button-triggered menu (such
623
+ * without `anchor` moves its invisible anchor there and opens at its
624
+ * `placement` (a menu rendered with `anchor` opens with `openPopupMenu`
625
+ * instead). A button-triggered menu (such
621
626
  * as a `ListActionRow` trailing menu) opens `bottom-start` from the point,
622
627
  * like a context menu, for this opening only; its next opening returns to its
623
- * trigger and placement. Needs the `/register` entry.
628
+ * trigger and placement. `options.placement` sets the placement at the point
629
+ * for this opening instead (`top-start` sits above it, say), for either kind
630
+ * of menu; flipping, shifting, and the height cap still apply. Needs the
631
+ * `/register` entry.
624
632
  */
625
- declare function openPopupMenuAt(menu: PopupMenuElement, x: number, y: number): void;
633
+ declare function openPopupMenuAt(menu: PopupMenuElement, x: number, y: number, options?: {
634
+ placement?: PopupMenuPlacement;
635
+ }): void;
626
636
  /**
627
637
  * Open a PopupMenu from its trigger, or a context PopupMenu at the `anchor`
628
638
  * it was rendered with (or the point a previous `openPopupMenuAt` set).
@@ -664,6 +674,7 @@ type ListHeaderRootAttributes = Readonly<Record<`data-${string}`, string | undef
664
674
  'data-divider'?: never;
665
675
  'data-inline'?: never;
666
676
  'data-width'?: never;
677
+ 'data-wrap'?: never;
667
678
  'data-indicator-tone'?: never;
668
679
  'data-toggle'?: never;
669
680
  }>;
@@ -685,6 +696,12 @@ interface ListHeaderBaseProps {
685
696
  inline?: boolean;
686
697
  /** Fill the available row or shrink-wrap while retaining normal header geometry. */
687
698
  width?: 'fill' | 'content';
699
+ /**
700
+ * Wrap a long label onto further lines instead of truncating it to one
701
+ * ellipsized line. Default false. Use it where the whole label must stay
702
+ * readable in a narrow column, such as a specimen or form-section heading.
703
+ */
704
+ wrap?: boolean;
688
705
  indicatorTone?: 'neutral' | 'accent' | 'pop' | 'danger';
689
706
  /** Render as an unanimated loading skeleton: keep the label and action affordance, disable interaction. */
690
707
  placeholder?: boolean;
@@ -745,7 +762,7 @@ type ListHeaderIndicatorProps = {
745
762
  status?: SafeHtml | undefined;
746
763
  };
747
764
  type ListHeaderProps = ListHeaderBaseProps & ListHeaderIndicatorProps & ListHeaderModeProps;
748
- declare function ListHeader({ label, size, headingLevel, count, countLabel, badge, status, density, divider, inline, width, indicatorTone, action, actionLabel, actionIcon, actionDisabled, disabledReason, expanded, toggle, placeholder, rootAttributes, triggerAttributes, slot, }: ListHeaderProps): SafeHtml;
765
+ declare function ListHeader({ label, size, headingLevel, count, countLabel, badge, status, density, divider, inline, width, wrap, indicatorTone, action, actionLabel, actionIcon, actionDisabled, disabledReason, expanded, toggle, placeholder, rootAttributes, triggerAttributes, slot, }: ListHeaderProps): SafeHtml;
749
766
 
750
767
  export { ListHeader, type ListHeaderProps };
751
768
  ```
@@ -4123,8 +4140,8 @@ export { type SearchFieldCollapsibleOptions, type SearchFieldEdit, type SearchFi
4123
4140
  ## `kerfjs/actions`
4124
4141
 
4125
4142
  ```ts
4126
- import { A as AttrSpec } from './attrSelector-Cmu2ZoGO.js';
4127
- import { D as DelegateOptions } from './delegate-CL9VTZFb.js';
4143
+ import { A as AttrSpec } from './attr-Cmu2ZoGO.js';
4144
+ import { D as DelegateOptions } from './delegate--CrfgYtC.js';
4128
4145
 
4129
4146
  /**
4130
4147
  * `kerfjs/actions` — the delegated action-table helper.
@@ -4678,6 +4695,12 @@ type DialogSurfaceProps = DialogSurfaceName & DialogSurfaceOptions;
4678
4695
  interface DialogSurfaceOptions {
4679
4696
  /** The dialog's id, for `openDialog(document.getElementById(id))`. */
4680
4697
  id?: string;
4698
+ /**
4699
+ * Id of the element whose text is the dialog's accessible description,
4700
+ * such as the `heading` ToolbarText's `descriptionId` or app-owned summary
4701
+ * copy in the body; rendered as `aria-describedby` on the `<dialog>`.
4702
+ */
4703
+ describedBy?: string;
4681
4704
  /** The body content. */
4682
4705
  children: KerfUiContent;
4683
4706
  /**
@@ -4792,7 +4815,7 @@ interface DialogSurfaceOptions {
4792
4815
  * floating header and footer measurement, the bottom sheet's keyboard
4793
4816
  * clearance and grabber, and re-render resilience while open.
4794
4817
  */
4795
- declare function DialogSurface({ id, label, labelledBy, heading, headerActions, footer, withoutHeader, lightDismiss, closeLabel, children, size, presentation, preferredWidth, bodyInset, footerInset, viewportGutter, maxHeight, height, minHeight, resizable, enterMotion, exitMotion, bodyLayout, headerPresentation, footerPresentation, footerOffset, rootAttributes, className, slot, }: DialogSurfaceProps): kerfjs.SafeHtml;
4818
+ declare function DialogSurface({ id, label, labelledBy, describedBy, heading, headerActions, footer, withoutHeader, lightDismiss, closeLabel, children, size, presentation, preferredWidth, bodyInset, footerInset, viewportGutter, maxHeight, height, minHeight, resizable, enterMotion, exitMotion, bodyLayout, headerPresentation, footerPresentation, footerOffset, rootAttributes, className, slot, }: DialogSurfaceProps): kerfjs.SafeHtml;
4796
4819
  /** Where a PopoverDialogSurface appears: the top layer, or in flow. */
4797
4820
  type PopoverDialogSurfacePresentation = 'overlay' | 'embedded';
4798
4821
  /** Application `data-*` metadata on the surface root. */
@@ -4937,6 +4960,12 @@ interface ListDetailDialogProps {
4937
4960
  id: string;
4938
4961
  /** The dialog's accessible name. */
4939
4962
  label: string;
4963
+ /**
4964
+ * Id of the element whose text is the dialog's accessible description,
4965
+ * such as app-owned summary copy. The detail's `description` describes the
4966
+ * selection, not the dialog, so it is not wired automatically.
4967
+ */
4968
+ describedBy?: string;
4940
4969
  list: ListDetailDialogList;
4941
4970
  detail: ListDetailDialogDetail;
4942
4971
  /**
@@ -4979,7 +5008,7 @@ interface ListDetailDialogProps {
4979
5008
  * stack's back control dispatches `nav-back`). Built from `DialogSurface`,
4980
5009
  * `SplitView`, and `Pane`.
4981
5010
  */
4982
- declare function ListDetailDialog({ id, label, list, detail, compact, detailActive, backLabel, closeLabel, lightDismiss, size, preferredWidth, height, maxHeight, viewportGutter, rootAttributes, className, slot, }: ListDetailDialogProps): kerfjs.SafeHtml;
5011
+ declare function ListDetailDialog({ id, label, describedBy, list, detail, compact, detailActive, backLabel, closeLabel, lightDismiss, size, preferredWidth, height, maxHeight, viewportGutter, rootAttributes, className, slot, }: ListDetailDialogProps): kerfjs.SafeHtml;
4983
5012
 
4984
5013
  export { ListDetailDialog, type ListDetailDialogDetail, type ListDetailDialogList, type ListDetailDialogProps, type ListDetailDialogRootAttributes };
4985
5014
  ```
@@ -5023,8 +5052,17 @@ interface WorkbenchDialogProps {
5023
5052
  label: string;
5024
5053
  /** The dialog's primary title: an xl heading in the work area's toolbar. */
5025
5054
  title: string;
5026
- /** A short supporting line under the title. */
5055
+ /**
5056
+ * A short supporting line under the title. It is the dialog's accessible
5057
+ * description (`aria-describedby` to its `<id>-description`) unless
5058
+ * `describedBy` names other content.
5059
+ */
5027
5060
  description?: string;
5061
+ /**
5062
+ * Id of the element whose text is the dialog's accessible description, in
5063
+ * place of `description`, such as app-owned summary copy in `main`.
5064
+ */
5065
+ describedBy?: string;
5028
5066
  /** Groups after the title in the work area's toolbar. */
5029
5067
  leading?: KerfUiContent;
5030
5068
  /** Header controls before the close control, such as a `ToolbarControlGroup`. */
@@ -5081,7 +5119,7 @@ interface WorkbenchDialogProps {
5081
5119
  * Escape or a press outside it before the dialog sees the Escape. Built from
5082
5120
  * `DialogSurface` and `Workbench`.
5083
5121
  */
5084
- declare function WorkbenchDialog({ id, label, title, description, leading, actions, main, mainFooter, mainBottomToolbar, leftRail, rightRail, bottomDrawer, compact, closeLabel, lightDismiss, size, preferredWidth, height, maxHeight, viewportGutter, mainMinSize, rootAttributes, className, slot, }: WorkbenchDialogProps): kerfjs.SafeHtml;
5122
+ declare function WorkbenchDialog({ id, label, title, description, describedBy, leading, actions, main, mainFooter, mainBottomToolbar, leftRail, rightRail, bottomDrawer, compact, closeLabel, lightDismiss, size, preferredWidth, height, maxHeight, viewportGutter, mainMinSize, rootAttributes, className, slot, }: WorkbenchDialogProps): kerfjs.SafeHtml;
5085
5123
 
5086
5124
  export { WorkbenchDialog, type WorkbenchDialogProps, type WorkbenchDialogRootAttributes };
5087
5125
  ```
@@ -5603,10 +5641,12 @@ import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
5603
5641
 
5604
5642
  /**
5605
5643
  * The Disclosure's surface: `plain` (default) on the surrounding surface,
5606
- * `framed` with the standard neutral border, or `sunken` on the lowered,
5607
- * textured work surface with a border.
5644
+ * `framed` with the standard neutral border, `sunken` on the lowered,
5645
+ * textured work surface with a border, or `embedded` inside owner chrome such
5646
+ * as a `ContentItem`: no margin, border, or padding of its own and a compact
5647
+ * summary row, so the arrow sits on the owner's content inset.
5608
5648
  */
5609
- type DisclosureAppearance = 'plain' | 'framed' | 'sunken';
5649
+ type DisclosureAppearance = 'plain' | 'framed' | 'sunken' | 'embedded';
5610
5650
  /**
5611
5651
  * Application `data-*` identity on the `<details>` root, such as `data-key`;
5612
5652
  * the Disclosure's own configuration attributes stay protected.
@@ -5631,6 +5671,11 @@ interface DisclosureProps {
5631
5671
  * where opening one closes the others (the native `<details name>`).
5632
5672
  */
5633
5673
  name?: string;
5674
+ /**
5675
+ * Surface treatment; defaults to `plain`. Use `embedded` only inside chrome
5676
+ * that already owns the content-item inset, such as a `ContentItem`, and
5677
+ * give it content that draws no inset of its own (`Text flush`).
5678
+ */
5634
5679
  appearance?: DisclosureAppearance;
5635
5680
  /**
5636
5681
  * A `data-action` value on the `<details>` root, for a delegated listener of
@@ -5648,7 +5693,9 @@ interface DisclosureProps {
5648
5693
  * Content a person shows and hides under a summary row: a native `<details>`
5649
5694
  * with a `<summary>` that carries a `DisclosureArrow` and the title, on the
5650
5695
  * shared content-item geometry (8px inline margin, a 1px border, 8px
5651
- * padding, the rounded radius). Keyboard and screen-reader behavior is the
5696
+ * padding, the rounded radius). `appearance="embedded"` drops that geometry
5697
+ * for a Disclosure inside owner chrome (a `ContentItem`) that already insets
5698
+ * it. Keyboard and screen-reader behavior is the
5652
5699
  * platform's: the summary is a button that Enter and Space toggle, and it
5653
5700
  * reports its expanded state. Disclosures sharing a `name` form an accordion.
5654
5701
  */
@@ -5805,22 +5852,47 @@ interface ColorPickerProps {
5805
5852
  /** Native named-slot assignment when composed inside a web component. */
5806
5853
  slot?: string;
5807
5854
  }
5808
- /** The labels, accessible names, and maximum of each channel field per mode. */
5855
+ /**
5856
+ * The labels, accessible names, maximum, and spoken unit of each channel per
5857
+ * mode; the mode's sliders and fields both follow it.
5858
+ */
5809
5859
  declare const COLOR_PICKER_CHANNELS: Record<ColorPickerMode, readonly {
5810
5860
  short: string;
5811
5861
  name: string;
5812
5862
  max: number;
5863
+ unit: '' | '%' | '°';
5813
5864
  }[]>;
5814
5865
  /** The rounded channel values a mode shows for an HSV color. */
5815
5866
  declare function colorPickerChannels(mode: ColorPickerMode, hsv: Hsva): number[];
5867
+ /** One channel slider's attributes; see {@link colorPickerSlider}. */
5868
+ interface ColorPickerSliderState {
5869
+ max: number;
5870
+ value: string;
5871
+ label: string;
5872
+ valueText: string;
5873
+ style: string;
5874
+ }
5875
+ /**
5876
+ * The attributes of one channel slider for a mode's exact channel values:
5877
+ * its range, value, accessible name and spoken value, and an inline style
5878
+ * with the track gradient of the colors that channel produces while the
5879
+ * others hold (the full rainbow for the HSL and HSB hue) and the color under
5880
+ * the thumb.
5881
+ * `undefined` for a slot the mode does not use.
5882
+ */
5883
+ declare function colorPickerSlider(mode: ColorPickerMode, index: number, values: readonly number[]): ColorPickerSliderState | undefined;
5816
5884
  /** The area's spoken value. */
5817
5885
  declare function colorPickerAreaText(hsv: Hsva): string;
5818
5886
  /** The CSS custom properties that place the thumbs and paint the tracks. */
5819
5887
  declare function colorPickerStyle(hsv: Hsva): string;
5820
5888
  /**
5821
- * A full color picker panel: a saturation and brightness area, a hue slider,
5822
- * an optional opacity slider on a checkerboard, a color-model menu (RGB, HSL,
5823
- * HSB, Grayscale) with its channel fields, a hex field (8 digits below full
5889
+ * A full color picker panel: a saturation and brightness area; a slider for
5890
+ * each channel of the color model (red, green, and blue; hue, saturation, and
5891
+ * lightness or brightness; or one gray level), each track painting the colors
5892
+ * that channel produces while the others hold (the hue track the full
5893
+ * rainbow); an optional opacity slider on
5894
+ * a checkerboard; a color-model menu (RGB, HSL, HSB, Grayscale) with its
5895
+ * channel fields, a hex field (8 digits below full
5824
5896
  * opacity) and an opacity field, an optional screen sampler (EyeDropper), and
5825
5897
  * optional preset and sample swatches. The controlled `value` renders it;
5826
5898
  * wire `wireColorPickers` from `@kerfjs/ui/wire-color-pickers` to make it
@@ -5830,7 +5902,7 @@ declare function colorPickerStyle(hsv: Hsva): string;
5830
5902
  */
5831
5903
  declare function ColorPicker({ id, label, value, mode, alpha, name, form, eyedropper, presets, samples, addSampleAction, disabled, className, rootAttributes, slot, }: ColorPickerProps): kerfjs.SafeHtml;
5832
5904
 
5833
- export { COLOR_PICKER_CHANNELS, COLOR_PICKER_SWATCH_ACTION, ColorPicker, type ColorPickerMode, type ColorPickerProps, type ColorPickerRootAttributes, type ColorPickerSamples, colorPickerAreaText, colorPickerChannels, colorPickerStyle };
5905
+ export { COLOR_PICKER_CHANNELS, COLOR_PICKER_SWATCH_ACTION, ColorPicker, type ColorPickerMode, type ColorPickerProps, type ColorPickerRootAttributes, type ColorPickerSamples, type ColorPickerSliderState, colorPickerAreaText, colorPickerChannels, colorPickerSlider, colorPickerStyle };
5834
5906
  ```
5835
5907
 
5836
5908
  ## `@kerfjs/ui/color-field`
@@ -6137,6 +6209,81 @@ declare function Checkbox({ label, checked, indeterminate, name, value, hint, er
6137
6209
  export { Checkbox, type CheckboxProps, type CheckboxRootAttributes, type CheckboxSize };
6138
6210
  ```
6139
6211
 
6212
+ ## `@kerfjs/ui/checkbox-group`
6213
+
6214
+ ```ts
6215
+ import * as kerfjs from 'kerfjs';
6216
+
6217
+ /** `default` is a 20px box beside 16px text; `compact` 18px and 14px. */
6218
+ type CheckboxGroupSize = 'default' | 'compact';
6219
+ /** `vertical` stacks the choices; `horizontal` lines them up and wraps. */
6220
+ type CheckboxGroupOrientation = 'vertical' | 'horizontal';
6221
+ /** Application `data-*` metadata; the CheckboxGroup's own markers stay protected. */
6222
+ type CheckboxGroupRootAttributes = Readonly<Record<`data-${string}`, string | undefined>>;
6223
+ interface CheckboxGroupChoice<Value extends string = string> {
6224
+ value: Value;
6225
+ /** Visible label; it is also the checkbox's accessible name. */
6226
+ label: string;
6227
+ /** Supporting text under this choice's label, also its description. */
6228
+ hint?: string;
6229
+ disabled?: boolean;
6230
+ }
6231
+ /**
6232
+ * A group is named by a visible `label` (its legend), by `ariaLabel`, or by
6233
+ * `labelledBy`, the id of a visible heading elsewhere that names it.
6234
+ */
6235
+ type CheckboxGroupName = {
6236
+ label: string;
6237
+ ariaLabel?: never;
6238
+ labelledBy?: never;
6239
+ } | {
6240
+ label?: never;
6241
+ ariaLabel: string;
6242
+ labelledBy?: never;
6243
+ } | {
6244
+ label?: never;
6245
+ ariaLabel?: never;
6246
+ labelledBy: string;
6247
+ };
6248
+ interface CheckboxGroupOptions<Value extends string = string> {
6249
+ /** Native input `name`: the form field every checked value submits under. */
6250
+ name: string;
6251
+ choices: readonly CheckboxGroupChoice<Value>[];
6252
+ /** The checked values. Omit for none. */
6253
+ value?: readonly NoInfer<Value>[];
6254
+ /** Supporting text below the choices, also the group's description. */
6255
+ hint?: string;
6256
+ /** A validation message: shown in the danger color and marking it invalid. */
6257
+ error?: string;
6258
+ size?: CheckboxGroupSize;
6259
+ orientation?: CheckboxGroupOrientation;
6260
+ /** Disable the whole group. */
6261
+ disabled?: boolean;
6262
+ /** Delegated `data-action` on every checkbox; listen for `change`. */
6263
+ action?: string;
6264
+ /** Associate the checkboxes with a form outside their ancestor chain. */
6265
+ form?: string;
6266
+ /** The fieldset's id. */
6267
+ id?: string;
6268
+ className?: string;
6269
+ /** Safe `data-*` metadata (a `data-key`). */
6270
+ rootAttributes?: CheckboxGroupRootAttributes;
6271
+ /** Native named-slot assignment when composed inside a web component. */
6272
+ slot?: string;
6273
+ }
6274
+ type CheckboxGroupProps<Value extends string = string> = CheckboxGroupName & CheckboxGroupOptions<Value>;
6275
+ /**
6276
+ * Any number of related options among a few visible choices: a native
6277
+ * fieldset of `Checkbox`es with the group label above and hint and error text
6278
+ * below, laid out like a `RadioGroup` so stacked checkboxes and radios share
6279
+ * one control column and one 28px pitch. Every checked value submits under
6280
+ * `name`.
6281
+ */
6282
+ declare function CheckboxGroup<Value extends string>({ label, ariaLabel, labelledBy, name, choices, value, hint, error, size, orientation, disabled, action, form, id, className, rootAttributes, slot, }: CheckboxGroupProps<Value>): kerfjs.SafeHtml;
6283
+
6284
+ export { CheckboxGroup, type CheckboxGroupChoice, type CheckboxGroupName, type CheckboxGroupOptions, type CheckboxGroupOrientation, type CheckboxGroupProps, type CheckboxGroupRootAttributes, type CheckboxGroupSize };
6285
+ ```
6286
+
6140
6287
  ## `@kerfjs/ui/radio-group`
6141
6288
 
6142
6289
  ```ts
@@ -6450,6 +6597,12 @@ interface ButtonOptions {
6450
6597
  size?: ButtonSize;
6451
6598
  /** Corner shape (default `rounded`). */
6452
6599
  shape?: ButtonShape;
6600
+ /**
6601
+ * Span the full width of the parent instead of sizing to the label, as on
6602
+ * `SplitButton`. The label stays centered and ellipsizes when it no longer
6603
+ * fits.
6604
+ */
6605
+ fill?: boolean;
6453
6606
  /**
6454
6607
  * Make it a toggle: `aria-pressed` reports the state, and a pressed look is
6455
6608
  * drawn on top of the tone and emphasis. The application owns the state and
@@ -6475,6 +6628,12 @@ interface ButtonOptions {
6475
6628
  target?: '_self' | '_blank' | '_parent' | '_top';
6476
6629
  /** Delegated `data-action` the application handles. */
6477
6630
  action?: string;
6631
+ /**
6632
+ * Keep the button's focus ring inside its box when an ancestor clips
6633
+ * overflow. The inset ring is two-tone, a surface-colored line inside the
6634
+ * ring color, so it stays visible on a loud fill of the ring's own hue.
6635
+ */
6636
+ focusRingInset?: boolean;
6478
6637
  /**
6479
6638
  * A count, short text, or `true` for a text-free dot over the button's
6480
6639
  * top-trailing corner, such as how many items a filter hides. It stays out
@@ -6503,12 +6662,13 @@ interface ButtonOptions {
6503
6662
  * A standalone action button: a native `<button>` (or a link with `href`)
6504
6663
  * in one of three tones and three emphases, at the 44px control height or
6505
6664
  * compact, with a label or as an icon-only square, rounded or pill-shaped,
6506
- * and optionally a `pressed` toggle. Inside a
6665
+ * sized to its label or filling its parent's width, and optionally a
6666
+ * `pressed` toggle. Inside a
6507
6667
  * `ToolbarControlGroup`, use a plain `<button>`, which the group styles; use
6508
6668
  * Button for a dialog footer, a form, or a standalone action beside other
6509
6669
  * content.
6510
6670
  */
6511
- declare function Button({ children, tone, emphasis, size, shape, pressed, icon, loading, disabled, type, name, value, form, href, target, action, badge, badgeLabel, badgeTone, ariaLabel, title, id, className, rootAttributes, slot, }: ButtonProps): kerfjs.SafeHtml;
6671
+ declare function Button({ children, tone, emphasis, size, shape, fill, pressed, icon, loading, disabled, type, name, value, form, href, target, action, focusRingInset, badge, badgeLabel, badgeTone, ariaLabel, title, id, className, rootAttributes, slot, }: ButtonProps): kerfjs.SafeHtml;
6512
6672
 
6513
6673
  export { Button, type ButtonContent, type ButtonEmphasis, type ButtonLabel, type ButtonOptions, type ButtonProps, type ButtonRootAttributes, type ButtonShape, type ButtonSize, type ButtonTone, type ButtonType };
6514
6674
  ```
@@ -6520,11 +6680,15 @@ import { SafeHtml } from 'kerfjs';
6520
6680
 
6521
6681
  /** The loud fill the whole split button paints. */
6522
6682
  type SplitButtonTone = 'brand' | 'neutral' | 'success' | 'warning' | 'danger';
6683
+ /** Corner shape: the shared `rounded` control radius (default) or a full `pill`, as on `Button`. */
6684
+ type SplitButtonShape = 'rounded' | 'pill';
6523
6685
  type SplitButtonRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
6524
6686
  'data-component'?: never;
6525
6687
  'data-tone'?: never;
6526
6688
  'data-fill'?: never;
6527
6689
  'data-busy'?: never;
6690
+ 'data-shape'?: never;
6691
+ 'data-focus-ring-inset'?: never;
6528
6692
  }>;
6529
6693
  interface SplitButtonProps {
6530
6694
  /** Visible primary label. */
@@ -6549,6 +6713,14 @@ interface SplitButtonProps {
6549
6713
  tone?: SplitButtonTone;
6550
6714
  /** Span the full width of the parent instead of sizing to the label. */
6551
6715
  fill?: boolean;
6716
+ /** Corner shape (default `rounded`); `pill` fully rounds both outer ends. */
6717
+ shape?: SplitButtonShape;
6718
+ /**
6719
+ * Keep each half's focus ring inside its box when an ancestor clips
6720
+ * overflow. The inset ring is two-tone, a surface-colored line inside the
6721
+ * ring color, so it stays visible on every loud fill.
6722
+ */
6723
+ focusRingInset?: boolean;
6552
6724
  /** Show work in progress: a spinner replaces the icon and the primary is `aria-busy`. */
6553
6725
  busy?: boolean;
6554
6726
  /** Disable the primary half. */
@@ -6570,9 +6742,9 @@ interface SplitButtonProps {
6570
6742
  * technology directly; the application opens its own menu from the options
6571
6743
  * action and owns the running state.
6572
6744
  */
6573
- declare function SplitButton({ label, action, icon, accessibleLabel, optionsLabel, optionsAction, optionsExpanded, optionsPopup, optionsControls, tone, fill, busy, disabled, optionsDisabled, title, className, rootAttributes, slot, }: SplitButtonProps): SafeHtml;
6745
+ declare function SplitButton({ label, action, icon, accessibleLabel, optionsLabel, optionsAction, optionsExpanded, optionsPopup, optionsControls, tone, fill, shape, focusRingInset, busy, disabled, optionsDisabled, title, className, rootAttributes, slot, }: SplitButtonProps): SafeHtml;
6574
6746
 
6575
- export { SplitButton, type SplitButtonProps, type SplitButtonTone };
6747
+ export { SplitButton, type SplitButtonProps, type SplitButtonShape, type SplitButtonTone };
6576
6748
  ```
6577
6749
 
6578
6750
  ## `@kerfjs/ui/file-picker`