@kerfjs/ui 5.0.0-beta.49 → 5.0.0-beta.50

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 (257) hide show
  1. package/README.md +41 -11
  2. package/ai/catalog-authoring.json +12 -1
  3. package/ai/catalog-authoring.schema.json +49 -1
  4. package/ai/compile-time-contracts-v1.json +14 -0
  5. package/ai/compile-time-contracts-v1.schema.json +1 -0
  6. package/ai/component-catalog-v2-overrides.json +7 -0
  7. package/ai/component-catalog-v2.json +79 -23
  8. package/ai/component-catalog.json +86 -27
  9. package/ai/public-api-signatures-v1.md +217 -169
  10. package/ai/skill.md +23 -9
  11. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  12. package/dist/app-tab.d.ts +3 -1
  13. package/dist/app-tab.js +1 -1
  14. package/dist/badge.d.ts +24 -0
  15. package/dist/badge.js +3 -0
  16. package/dist/badge.js.map +1 -0
  17. package/dist/browser/badge.js +3 -0
  18. package/dist/browser/list-header.js +1 -0
  19. package/dist/browser/state-banner.js +1 -0
  20. package/dist/catalog-resources.d.ts +2 -2
  21. package/dist/catalog.d.ts +24 -125
  22. package/dist/catalog.js +387 -261
  23. package/dist/catalog.js.map +1 -1
  24. package/dist/{chunk-OGTJNHRG.js → chunk-2WMSE4MK.js} +5 -3
  25. package/dist/chunk-2WMSE4MK.js.map +1 -0
  26. package/dist/{chunk-GYGM363P.js → chunk-2YOUUEWR.js} +16 -6
  27. package/dist/chunk-2YOUUEWR.js.map +1 -0
  28. package/dist/{chunk-UDHHKZWO.js → chunk-3V75EQIP.js} +8 -4
  29. package/dist/chunk-3V75EQIP.js.map +1 -0
  30. package/dist/{chunk-W2FK7ZNY.js → chunk-4R777DUZ.js} +10 -2
  31. package/dist/chunk-4R777DUZ.js.map +1 -0
  32. package/dist/{chunk-T7DOWS6T.js → chunk-54HM36IQ.js} +6 -3
  33. package/dist/chunk-54HM36IQ.js.map +1 -0
  34. package/dist/{chunk-DAO2VFTT.js → chunk-5CE64WGC.js} +6 -4
  35. package/dist/chunk-5CE64WGC.js.map +1 -0
  36. package/dist/{chunk-SOK5EUF7.js → chunk-6ZXOQEAN.js} +4 -2
  37. package/dist/chunk-6ZXOQEAN.js.map +1 -0
  38. package/dist/{chunk-OGNE3OFT.js → chunk-AQSKJ6U6.js} +4 -2
  39. package/dist/chunk-AQSKJ6U6.js.map +1 -0
  40. package/dist/{chunk-VDUJZF5G.js → chunk-CMUIXJZM.js} +2 -2
  41. package/dist/{chunk-VDUJZF5G.js.map → chunk-CMUIXJZM.js.map} +1 -1
  42. package/dist/{chunk-OMSRSL3B.js → chunk-COUPLRZG.js} +5 -3
  43. package/dist/chunk-COUPLRZG.js.map +1 -0
  44. package/dist/{chunk-2TYUFZUC.js → chunk-D7GWXIAS.js} +4 -2
  45. package/dist/chunk-D7GWXIAS.js.map +1 -0
  46. package/dist/{chunk-AQFWBG23.js → chunk-DARTMI5Z.js} +5 -3
  47. package/dist/chunk-DARTMI5Z.js.map +1 -0
  48. package/dist/{chunk-V6GQKOX2.js → chunk-DJKWFYAA.js} +5 -3
  49. package/dist/chunk-DJKWFYAA.js.map +1 -0
  50. package/dist/{chunk-6NDBE2OK.js → chunk-E36EVCKG.js} +5 -3
  51. package/dist/chunk-E36EVCKG.js.map +1 -0
  52. package/dist/{chunk-IU4QUY5I.js → chunk-ELRMBQEC.js} +4 -2
  53. package/dist/chunk-ELRMBQEC.js.map +1 -0
  54. package/dist/{chunk-TIGSG6BX.js → chunk-HJKRCKDR.js} +7 -3
  55. package/dist/chunk-HJKRCKDR.js.map +1 -0
  56. package/dist/{chunk-Y6LYKFXY.js → chunk-HMQ2ZDGG.js} +5 -3
  57. package/dist/chunk-HMQ2ZDGG.js.map +1 -0
  58. package/dist/{chunk-WN52USHV.js → chunk-J3EE6XWD.js} +2 -2
  59. package/dist/{chunk-WN52USHV.js.map → chunk-J3EE6XWD.js.map} +1 -1
  60. package/dist/{chunk-CK6P5AUK.js → chunk-KKNK3JUT.js} +7 -4
  61. package/dist/chunk-KKNK3JUT.js.map +1 -0
  62. package/dist/{chunk-ZPWZIVI6.js → chunk-N3GKMPDW.js} +7 -3
  63. package/dist/chunk-N3GKMPDW.js.map +1 -0
  64. package/dist/{chunk-DYBPI5O2.js → chunk-NDUGJ4TU.js} +4 -2
  65. package/dist/chunk-NDUGJ4TU.js.map +1 -0
  66. package/dist/{chunk-WSXUPSID.js → chunk-NN6GYOA2.js} +7 -3
  67. package/dist/chunk-NN6GYOA2.js.map +1 -0
  68. package/dist/{chunk-VXFGMDA7.js → chunk-OQI7RCRP.js} +10 -2
  69. package/dist/chunk-OQI7RCRP.js.map +1 -0
  70. package/dist/{chunk-E34TE2ZI.js → chunk-S6ZTTTV7.js} +5 -3
  71. package/dist/chunk-S6ZTTTV7.js.map +1 -0
  72. package/dist/{chunk-V6HCTCVD.js → chunk-SIU2AC5W.js} +8 -4
  73. package/dist/chunk-SIU2AC5W.js.map +1 -0
  74. package/dist/{chunk-WVLMZ5SG.js → chunk-UMGY5JSP.js} +4 -2
  75. package/dist/chunk-UMGY5JSP.js.map +1 -0
  76. package/dist/{chunk-I4V3UDSA.js → chunk-V6RZWDII.js} +7 -5
  77. package/dist/chunk-V6RZWDII.js.map +1 -0
  78. package/dist/{chunk-CAB6NQ2T.js → chunk-VOCPXGQN.js} +3 -1
  79. package/dist/chunk-VOCPXGQN.js.map +1 -0
  80. package/dist/chunk-XD7DWYXG.js +34 -0
  81. package/dist/chunk-XD7DWYXG.js.map +1 -0
  82. package/dist/{chunk-B6JYRX3P.js → chunk-ZIYOJFZD.js} +43 -4
  83. package/dist/chunk-ZIYOJFZD.js.map +1 -0
  84. package/dist/{chunk-EYALJQQD.js → chunk-ZK5EGVFP.js} +4 -2
  85. package/dist/chunk-ZK5EGVFP.js.map +1 -0
  86. package/dist/{chunk-6WTETUZ6.js → chunk-ZLWQZUGF.js} +8 -2
  87. package/dist/chunk-ZLWQZUGF.js.map +1 -0
  88. package/dist/{chunk-XKFRMGMW.js → chunk-ZNZ2JDBW.js} +3 -1
  89. package/dist/chunk-ZNZ2JDBW.js.map +1 -0
  90. package/dist/{chunk-I45QO2IZ.js → chunk-ZSYLBVWG.js} +6 -4
  91. package/dist/chunk-ZSYLBVWG.js.map +1 -0
  92. package/dist/collapsible-panel.d.ts +3 -1
  93. package/dist/collapsible-panel.js +4 -2
  94. package/dist/collapsible-panel.js.map +1 -1
  95. package/dist/disclosure-arrow.d.ts +3 -1
  96. package/dist/disclosure-arrow.js +1 -1
  97. package/dist/empty-state.d.ts +3 -1
  98. package/dist/empty-state.js +1 -1
  99. package/dist/floating-toolbar.d.ts +3 -1
  100. package/dist/floating-toolbar.js +1 -1
  101. package/dist/grid.d.ts +3 -1
  102. package/dist/grid.js +1 -1
  103. package/dist/index.d.ts +3 -2
  104. package/dist/index.js +33 -32
  105. package/dist/list-action-row.d.ts +3 -1
  106. package/dist/list-action-row.js +1 -1
  107. package/dist/list-header.d.ts +6 -1
  108. package/dist/list-header.js +2 -1
  109. package/dist/list-inset-control.d.ts +3 -1
  110. package/dist/list-inset-control.js +1 -1
  111. package/dist/list-inset-text.d.ts +3 -1
  112. package/dist/list-inset-text.js +1 -1
  113. package/dist/list-item.d.ts +3 -1
  114. package/dist/list-item.js +1 -1
  115. package/dist/list.d.ts +3 -1
  116. package/dist/list.js +1 -1
  117. package/dist/loading-spinner.d.ts +3 -1
  118. package/dist/loading-spinner.js +1 -1
  119. package/dist/lucide-icon.d.ts +3 -1
  120. package/dist/lucide-icon.js +1 -1
  121. package/dist/nav-stack.d.ts +3 -1
  122. package/dist/nav-stack.js +1 -1
  123. package/dist/pane.d.ts +3 -1
  124. package/dist/pane.js +1 -1
  125. package/dist/resizable-region.d.ts +5 -2
  126. package/dist/resizable-region.js +1 -1
  127. package/dist/row.d.ts +3 -1
  128. package/dist/row.js +1 -1
  129. package/dist/segmented-control.d.ts +3 -1
  130. package/dist/segmented-control.js +1 -1
  131. package/dist/select.d.ts +3 -1
  132. package/dist/select.js +1 -1
  133. package/dist/skeleton.d.ts +3 -1
  134. package/dist/skeleton.js +1 -1
  135. package/dist/spacer.d.ts +3 -1
  136. package/dist/spacer.js +1 -1
  137. package/dist/split-view.d.ts +3 -1
  138. package/dist/split-view.js +24 -5
  139. package/dist/split-view.js.map +1 -1
  140. package/dist/state-banner.d.ts +3 -1
  141. package/dist/state-banner.js +2 -1
  142. package/dist/styles/badge.css +86 -0
  143. package/dist/styles/catalog/components/catalog-detail.css +35 -0
  144. package/dist/styles/catalog/components/catalog-example-stack.css +6 -0
  145. package/dist/styles/catalog/components/catalog-example.css +35 -0
  146. package/dist/styles/catalog/components/catalog-resource-footer.css +37 -0
  147. package/dist/styles/catalog/components/catalog-secondary-sections.css +38 -0
  148. package/dist/styles/catalog/components/catalog-section-list.css +22 -0
  149. package/dist/styles/catalog/components/catalog-sidebar.css +82 -0
  150. package/dist/styles/catalog/components/catalog-stage.css +60 -0
  151. package/dist/styles/catalog/components/catalog.css +22 -0
  152. package/dist/styles/catalog.css +10 -587
  153. package/dist/styles/list-header.css +4 -60
  154. package/dist/styles/resizable-region.css +24 -0
  155. package/dist/styles/select.css +0 -3
  156. package/dist/styles/split-view.css +1 -1
  157. package/dist/styles/state-banner.css +0 -27
  158. package/dist/styles/styles.css +1 -0
  159. package/dist/styles/tab-bar.css +6 -1
  160. package/dist/styles/text.css +4 -0
  161. package/dist/styles/token-search-field.css +5 -40
  162. package/dist/styles/toolbar-control-group.css +110 -16
  163. package/dist/styles/toolbar-text.css +4 -0
  164. package/dist/styles/toolbar.css +72 -0
  165. package/dist/styles/webawesome.css +22 -7
  166. package/dist/sunken-panel.d.ts +3 -1
  167. package/dist/sunken-panel.js +1 -1
  168. package/dist/surface-scaffold.d.ts +6 -2
  169. package/dist/surface-scaffold.js +1 -1
  170. package/dist/tab-bar.d.ts +8 -1
  171. package/dist/tab-bar.js +1 -1
  172. package/dist/tab-scaffold.d.ts +3 -1
  173. package/dist/tab-scaffold.js +3 -1
  174. package/dist/tab-scaffold.js.map +1 -1
  175. package/dist/text.d.ts +5 -2
  176. package/dist/text.js +1 -1
  177. package/dist/token-search-field.d.ts +5 -1
  178. package/dist/token-search-field.js +1 -1
  179. package/dist/toolbar-control-group.d.ts +33 -3
  180. package/dist/toolbar-control-group.js +1 -1
  181. package/dist/toolbar-text.d.ts +3 -1
  182. package/dist/toolbar-text.js +1 -1
  183. package/dist/toolbar.d.ts +9 -1
  184. package/dist/toolbar.js +1 -1
  185. package/dist/types-CzgSrFXP.d.ts +64 -0
  186. package/dist/value-table.d.ts +6 -2
  187. package/dist/value-table.js +1 -1
  188. package/dist/wire-resizable-regions.js +1 -1
  189. package/dist/wire-token-search-fields.js +1 -1
  190. package/dist/workbench.d.ts +3 -1
  191. package/dist/workbench.js +3 -1
  192. package/dist/workbench.js.map +1 -1
  193. package/docs/accessibility.md +11 -1
  194. package/docs/catalog.md +25 -7
  195. package/docs/component-contract.md +71 -22
  196. package/docs/component-selection.md +11 -9
  197. package/docs/design-philosophy.md +6 -5
  198. package/docs/recipes.md +5 -5
  199. package/docs/type-contracts.md +1 -0
  200. package/docs/ux-demo.md +4 -4
  201. package/docs/webawesome-theme.md +5 -4
  202. package/llms.txt +30 -10
  203. package/package.json +9 -2
  204. package/ux-demo/recipes/app-shell.css +87 -0
  205. package/ux-demo/recipes/app-shell.tsx +207 -178
  206. package/ux-demo/recipes/collapsible-sidebar.css +83 -0
  207. package/ux-demo/recipes/collapsible-sidebar.tsx +152 -122
  208. package/ux-demo/recipes/compact-toolbar.css +35 -0
  209. package/ux-demo/recipes/compact-toolbar.tsx +104 -100
  210. package/ux-demo/recipes/composer-form.css +19 -0
  211. package/ux-demo/recipes/composer-form.tsx +19 -15
  212. package/ux-demo/recipes/list-detail-dialog.css +42 -0
  213. package/ux-demo/recipes/list-detail-dialog.tsx +127 -125
  214. package/ux-demo/recipes/list-workspace-states.css +30 -0
  215. package/ux-demo/recipes/list-workspace-states.tsx +66 -60
  216. package/ux-demo/recipes/loading-inspector.css +7 -0
  217. package/ux-demo/recipes/loading-inspector.tsx +151 -131
  218. package/ux-demo/recipes/navigation-sidebar.css +12 -0
  219. package/ux-demo/recipes/navigation-sidebar.tsx +116 -105
  220. package/ux-demo/recipes/navigation-stack.css +12 -0
  221. package/ux-demo/recipes/navigation-stack.tsx +47 -37
  222. package/ux-demo/recipes/recipe-root.css +67 -0
  223. package/ux-demo/recipes/recipe-root.tsx +87 -0
  224. package/ux-demo/recipes/workspace-header.css +7 -0
  225. package/ux-demo/recipes/workspace-header.tsx +60 -61
  226. package/dist/chunk-2TYUFZUC.js.map +0 -1
  227. package/dist/chunk-6NDBE2OK.js.map +0 -1
  228. package/dist/chunk-6WTETUZ6.js.map +0 -1
  229. package/dist/chunk-AQFWBG23.js.map +0 -1
  230. package/dist/chunk-B6JYRX3P.js.map +0 -1
  231. package/dist/chunk-CAB6NQ2T.js.map +0 -1
  232. package/dist/chunk-CK6P5AUK.js.map +0 -1
  233. package/dist/chunk-DAO2VFTT.js.map +0 -1
  234. package/dist/chunk-DYBPI5O2.js.map +0 -1
  235. package/dist/chunk-E34TE2ZI.js.map +0 -1
  236. package/dist/chunk-EYALJQQD.js.map +0 -1
  237. package/dist/chunk-GYGM363P.js.map +0 -1
  238. package/dist/chunk-I45QO2IZ.js.map +0 -1
  239. package/dist/chunk-I4V3UDSA.js.map +0 -1
  240. package/dist/chunk-IU4QUY5I.js.map +0 -1
  241. package/dist/chunk-OGNE3OFT.js.map +0 -1
  242. package/dist/chunk-OGTJNHRG.js.map +0 -1
  243. package/dist/chunk-OMSRSL3B.js.map +0 -1
  244. package/dist/chunk-SOK5EUF7.js.map +0 -1
  245. package/dist/chunk-T7DOWS6T.js.map +0 -1
  246. package/dist/chunk-TIGSG6BX.js.map +0 -1
  247. package/dist/chunk-UDHHKZWO.js.map +0 -1
  248. package/dist/chunk-V6GQKOX2.js.map +0 -1
  249. package/dist/chunk-V6HCTCVD.js.map +0 -1
  250. package/dist/chunk-VXFGMDA7.js.map +0 -1
  251. package/dist/chunk-W2FK7ZNY.js.map +0 -1
  252. package/dist/chunk-WSXUPSID.js.map +0 -1
  253. package/dist/chunk-WVLMZ5SG.js.map +0 -1
  254. package/dist/chunk-XKFRMGMW.js.map +0 -1
  255. package/dist/chunk-Y6LYKFXY.js.map +0 -1
  256. package/dist/chunk-ZPWZIVI6.js.map +0 -1
  257. package/ux-demo/recipes/recipes.css +0 -453
@@ -17,7 +17,7 @@
17
17
  border-inline-end: 1px solid var(--kui-color-border);
18
18
  }
19
19
 
20
- .kui-split-view > .kui-resizable-region .kui-split-view__list {
20
+ .kui-split-view__list[data-resizable="true"] {
21
21
  width: 100%;
22
22
  border-inline-end: 0;
23
23
  }
@@ -21,14 +21,6 @@
21
21
  )
22
22
  );
23
23
  --_kui-state-banner-detail: var(--kui-state-banner-detail, currentColor);
24
- --_kui-state-banner-badge-background: var(
25
- --kui-state-banner-badge-background,
26
- var(--_kui-state-banner-foreground)
27
- );
28
- --_kui-state-banner-badge-foreground: var(
29
- --kui-state-banner-badge-foreground,
30
- var(--kui-color-surface)
31
- );
32
24
  --_kui-state-banner-action-background: var(
33
25
  --kui-state-banner-action-background,
34
26
  color-mix(in srgb, var(--kui-color-surface) 52%, transparent)
@@ -151,22 +143,6 @@
151
143
  .kui-state-banner__copy strong {
152
144
  font-size: var(--kui-font-xs);
153
145
  }
154
- .kui-state-banner__badge {
155
- display: inline-grid;
156
- min-width: 1.25rem;
157
- min-height: 1.25rem;
158
- padding-inline: 0.35rem;
159
- box-sizing: border-box;
160
- border-radius: var(--kui-radius-pill);
161
- color: var(--_kui-state-banner-badge-foreground);
162
- background: var(--_kui-state-banner-badge-background);
163
- place-items: center;
164
- flex: none;
165
- font-size: var(--kui-font-2xs);
166
- font-weight: 700;
167
- letter-spacing: 0;
168
- line-height: 1;
169
- }
170
146
  .kui-state-banner__detail {
171
147
  overflow: hidden;
172
148
  color: var(--_kui-state-banner-detail);
@@ -203,9 +179,6 @@
203
179
  grid-template-columns: auto 1fr;
204
180
  gap: 0.05rem;
205
181
  }
206
- .kui-state-banner__badge {
207
- justify-self: start;
208
- }
209
182
  .kui-state-banner__detail {
210
183
  grid-column: 1 / -1;
211
184
  }
@@ -1,5 +1,6 @@
1
1
  @import "./foundation.css";
2
2
  @import "./layout.css";
3
+ @import "./badge.css";
3
4
  @import "./lucide-icon.css";
4
5
  @import "./disclosure-arrow.css";
5
6
  @import "./toolbar.css";
@@ -61,9 +61,14 @@
61
61
  }
62
62
 
63
63
  .kui-tab-bar__leading,
64
- .kui-tab-bar__trailing {
64
+ .kui-tab-bar__trailing,
65
+ .kui-tab-bar__end {
65
66
  display: flex;
66
67
  min-height: var(--kui-toolbar-group-size, calc(2px + 2.625rem));
67
68
  align-items: center;
68
69
  flex: none;
69
70
  }
71
+
72
+ .kui-tab-bar__end {
73
+ margin-inline-start: auto;
74
+ }
@@ -20,3 +20,7 @@
20
20
  .kui-text[data-font="monospace"] {
21
21
  font-family: var(--kui-font-mono);
22
22
  }
23
+
24
+ .kui-text[data-border="none"] {
25
+ border: 0;
26
+ }
@@ -213,30 +213,7 @@
213
213
  margin-inline-start: 0.375rem;
214
214
  }
215
215
 
216
- .kui-toolbar-control-group:has(> .kui-token-search[data-collapsible="true"]) {
217
- width: min(var(--kui-token-search-expanded-width, 30rem), 100%);
218
- max-width: 100%;
219
- height: auto;
220
- min-width: 0;
221
- overflow: hidden;
222
- /* Same reason as the field above (KF-EPEM88): drive the inline size through
223
- `width`, not `flex-basis`, so a group placed in a flex column is not
224
- stretched to the expanded width in its cross axis. */
225
- flex: 0 1 auto;
226
- transition:
227
- width 0.25s ease,
228
- background-color 0.2s ease,
229
- border-color 0.2s ease;
230
- }
231
-
232
- .kui-toolbar-control-group[data-expanded="false"]:has(
233
- > .kui-token-search[data-collapsible="true"]
234
- ) {
235
- width: var(--kui-toolbar-group-size, calc(2px + 2.625rem));
236
- flex: 0 0 auto;
237
- }
238
-
239
- .kui-toolbar-control-group > .kui-token-search[data-collapsible="true"] {
216
+ .kui-token-search[data-presentation="toolbar-group"][data-collapsible="true"] {
240
217
  --kui-token-search-line-size: 2rem;
241
218
 
242
219
  min-height: 2.5rem;
@@ -250,14 +227,12 @@
250
227
  box-shadow: none;
251
228
  }
252
229
 
253
- .kui-toolbar-control-group
254
- > .kui-token-search[data-collapsible="true"]:focus-within {
230
+ .kui-token-search[data-presentation="toolbar-group"][data-collapsible="true"]:focus-within {
255
231
  border-color: var(--kui-color-focus);
256
232
  background: var(--kui-token-search-background);
257
233
  }
258
234
 
259
- .kui-toolbar-control-group
260
- > .kui-token-search[data-collapsible="true"][data-expanded="false"] {
235
+ .kui-token-search[data-presentation="toolbar-group"][data-collapsible="true"][data-expanded="false"] {
261
236
  width: 2.5rem;
262
237
  min-width: 2.5rem;
263
238
  height: 2.5rem;
@@ -265,23 +240,13 @@
265
240
  padding: 0;
266
241
  }
267
242
 
268
- .kui-toolbar-control-group
269
- > .kui-token-search[data-collapsible="true"][data-expanded="false"]
243
+ .kui-token-search[data-presentation="toolbar-group"][data-collapsible="true"][data-expanded="false"]
270
244
  .kui-token-search__expand {
271
245
  padding-inline: 0;
272
246
  }
273
247
 
274
- .kui-toolbar-control-group:has(
275
- > .kui-token-search[data-collapsible="true"]
276
- ):focus-within {
277
- border-color: var(--kui-color-text-link);
278
- box-shadow: 0 0 0 3px
279
- color-mix(in srgb, var(--kui-color-text-link) 22%, transparent);
280
- }
281
-
282
248
  @media (prefers-reduced-motion: reduce) {
283
- .kui-token-search[data-collapsible="true"],
284
- .kui-toolbar-control-group:has(> .kui-token-search[data-collapsible="true"]) {
249
+ .kui-token-search[data-collapsible="true"] {
285
250
  transition-duration: 0s;
286
251
  }
287
252
  }
@@ -35,6 +35,16 @@
35
35
  gap: 0;
36
36
  }
37
37
 
38
+ .kui-toolbar-control-group[data-visibility="compact-only"] {
39
+ display: none;
40
+ }
41
+
42
+ @container kui-toolbar (max-width: 44rem) {
43
+ .kui-toolbar-control-group[data-visibility="compact-only"] {
44
+ display: inline-flex;
45
+ }
46
+ }
47
+
38
48
  /* `shape="rounded"` swaps the default pill radius for the design system's softer
39
49
  rounded rectangle. The shared highlight contract derives every inner hover or
40
50
  selected surface from this outer radius and the group's full inset. */
@@ -65,8 +75,30 @@
65
75
  .kui-toolbar-control-group[data-density="tight"] {
66
76
  --kui-layout-item-padding: 0.3125rem;
67
77
  }
68
- .kui-toolbar-control-group[data-content="text"] > :is(button, wa-button),
69
- .kui-toolbar-control-group[data-content="mixed"] > :is(button, wa-button) {
78
+ .kui-toolbar-control-group[data-overflow="scroll"] {
79
+ max-width: 100%;
80
+ overflow-x: auto;
81
+ }
82
+ .kui-toolbar-control-group[data-content="search"] {
83
+ width: min(var(--kui-token-search-expanded-width, 30rem), 100%);
84
+ max-width: 100%;
85
+ height: auto;
86
+ min-width: 0;
87
+ overflow: hidden;
88
+ flex: 0 1 auto;
89
+ transition:
90
+ width 0.25s ease,
91
+ background-color 0.2s ease,
92
+ border-color 0.2s ease;
93
+ }
94
+ .kui-toolbar-control-group[data-content="search"][data-expanded="false"] {
95
+ width: var(--kui-toolbar-group-size, calc(2px + 2.625rem));
96
+ flex: 0 0 auto;
97
+ }
98
+ .kui-toolbar-control-group[data-content="text"]
99
+ > :is(button, wa-button, .kui-toolbar-action-link),
100
+ .kui-toolbar-control-group[data-content="mixed"]
101
+ > :is(button, wa-button, .kui-toolbar-action-link) {
70
102
  min-width: max-content;
71
103
  }
72
104
  .kui-toolbar-control-group[data-content="mixed"] > button {
@@ -123,7 +155,8 @@
123
155
  background: transparent;
124
156
  }
125
157
 
126
- .kui-toolbar-control-group > :is(button, wa-button, wa-dropdown) {
158
+ .kui-toolbar-control-group
159
+ > :is(button, wa-button, wa-dropdown, .kui-toolbar-action-link) {
127
160
  flex: 0 0 auto;
128
161
  }
129
162
  .kui-toolbar-control-group > wa-dropdown {
@@ -154,8 +187,48 @@
154
187
  background: var(--kui-toolbar-control-hover-background);
155
188
  }
156
189
 
190
+ .kui-toolbar-control-group > .kui-toolbar-action-link {
191
+ position: relative;
192
+ display: inline-flex;
193
+ min-width: 2.5rem;
194
+ height: 2.5rem;
195
+ padding-inline: var(--kui-layout-item-padding, 0.5rem);
196
+ box-sizing: border-box;
197
+ border: 1px solid transparent;
198
+ border-radius: var(
199
+ --kui-toolbar-item-radius,
200
+ var(--kui-layout-pill-radius, calc(1px + 1.3125rem))
201
+ );
202
+ color: inherit;
203
+ background: transparent;
204
+ align-items: center;
205
+ justify-content: center;
206
+ gap: var(--kui-space-2xs);
207
+ text-decoration: none;
208
+ white-space: nowrap;
209
+ }
210
+
211
+ .kui-toolbar-control-group > .kui-toolbar-action-link:hover {
212
+ border-color: var(--kui-toolbar-control-border);
213
+ background: var(--kui-toolbar-control-hover-background);
214
+ }
215
+
216
+ .kui-toolbar-action-link code {
217
+ position: absolute;
218
+ inset-block-start: 0;
219
+ inset-inline-start: 0;
220
+ width: 1px;
221
+ height: 1px;
222
+ padding: 0;
223
+ overflow: hidden;
224
+ border: 0;
225
+ clip-path: inset(50%);
226
+ white-space: nowrap;
227
+ }
228
+
157
229
  .kui-toolbar-control-group > button svg,
158
- .kui-toolbar-control-group wa-button > svg {
230
+ .kui-toolbar-control-group wa-button > svg,
231
+ .kui-toolbar-control-group > .kui-toolbar-action-link svg {
159
232
  display: block;
160
233
  width: 1rem;
161
234
  height: 1rem;
@@ -169,6 +242,7 @@
169
242
  height: 2.5rem;
170
243
  }
171
244
  .kui-toolbar-control-group[data-size="compact"] > button,
245
+ .kui-toolbar-control-group[data-size="compact"] > .kui-toolbar-action-link,
172
246
  .kui-toolbar-control-group[data-size="compact"] > wa-button,
173
247
  .kui-toolbar-control-group[data-size="compact"] > wa-dropdown,
174
248
  .kui-toolbar-control-group[data-size="compact"] > wa-dropdown > wa-button,
@@ -186,6 +260,17 @@
186
260
  min-height: 2rem;
187
261
  }
188
262
 
263
+ .kui-toolbar-control-group[data-menu-inset="standard"] wa-dropdown::part(menu) {
264
+ padding: var(--kui-wa-surface-inset, 0.5rem);
265
+ }
266
+ .kui-toolbar-control-group[data-menu-inset="compact"] wa-dropdown::part(menu) {
267
+ padding: 0.25rem;
268
+ }
269
+ .kui-toolbar-control-group[data-menu-inset="list-zero"]
270
+ wa-dropdown::part(menu) {
271
+ padding: 0;
272
+ }
273
+
189
274
  /* Compact mixed controls keep the default horizontal breathing room. Their
190
275
  raised selection grows over the group's own border instead of becoming a
191
276
  smaller inset lozenge, while negative margins keep the outer geometry and
@@ -260,12 +345,13 @@
260
345
  }
261
346
 
262
347
  .kui-toolbar-control-group[data-single="true"]:has(
263
- > :is(button, wa-button, wa-dropdown)
348
+ > :is(button, wa-button, wa-dropdown, .kui-toolbar-action-link)
264
349
  ):hover {
265
350
  background-color: var(--kui-toolbar-control-hover-background);
266
351
  }
267
352
 
268
- .kui-toolbar-control-group[data-single="true"] > :is(button, wa-button):hover,
353
+ .kui-toolbar-control-group[data-single="true"]
354
+ > :is(button, wa-button, .kui-toolbar-action-link):hover,
269
355
  .kui-toolbar-control-group[data-single="true"] wa-button:hover::part(base) {
270
356
  border-color: transparent;
271
357
  background: transparent;
@@ -276,15 +362,15 @@
276
362
  inner layer inset from the border (KF-J9P1ZD — a heading toolbar's lone Close/
277
363
  Done action). */
278
364
  .kui-toolbar-control-group:not([data-single="true"]):has(
279
- > :is(button, wa-button):only-child
365
+ > :is(button, wa-button, .kui-toolbar-action-link):only-child
280
366
  ):hover {
281
367
  background-color: var(--kui-toolbar-control-hover-background);
282
368
  }
283
369
 
284
370
  .kui-toolbar-control-group:not([data-single="true"]):has(
285
- > :is(button, wa-button):only-child
371
+ > :is(button, wa-button, .kui-toolbar-action-link):only-child
286
372
  )
287
- > :is(button, wa-button):hover,
373
+ > :is(button, wa-button, .kui-toolbar-action-link):hover,
288
374
  .kui-toolbar-control-group:not([data-single="true"]):has(
289
375
  > :is(button, wa-button):only-child
290
376
  )
@@ -317,21 +403,23 @@
317
403
  box-shadow: var(--kui-toolbar-control-selected-shadow);
318
404
  }
319
405
 
320
- .kui-toolbar-control-group > :is(button, wa-button):focus-visible {
406
+ .kui-toolbar-control-group
407
+ > :is(button, wa-button, .kui-toolbar-action-link):focus-visible {
321
408
  outline: var(--kui-focus-ring);
322
409
  outline-offset: 1px;
323
410
  }
324
411
 
325
- /* A composed Select can delegate focus paint to the group so the visible ring
326
- follows the group's selected pill/rounded geometry instead of Web Awesome's
327
- form-control radius. */
328
- .kui-toolbar-control-group:has(
329
- > .kui-select[data-focus-ring-owner="group"]:is(:focus-within, [open])
330
- ) {
412
+ .kui-toolbar-control-group[data-focus-ring="outline"]:focus-within {
331
413
  outline: var(--kui-focus-ring);
332
414
  outline-offset: 1px;
333
415
  }
334
416
 
417
+ .kui-toolbar-control-group[data-focus-ring="halo"]:focus-within {
418
+ border-color: var(--kui-color-text-link);
419
+ box-shadow: 0 0 0 3px
420
+ color-mix(in srgb, var(--kui-color-text-link) 22%, transparent);
421
+ }
422
+
335
423
  .kui-toolbar-control-group[data-button-appearance="push"][data-single="true"]:has(
336
424
  > :is(button, wa-button)[aria-pressed="true"]
337
425
  ) {
@@ -346,6 +434,12 @@
346
434
  color: var(--kui-toolbar-control-pressed-color);
347
435
  }
348
436
 
437
+ @media (prefers-reduced-motion: reduce) {
438
+ .kui-toolbar-control-group[data-content="search"] {
439
+ transition-duration: 0s;
440
+ }
441
+ }
442
+
349
443
  /* Avatar controls paint the image as chrome rather than inserting a replaced
350
444
  <img> into the control. `background-size: contain` is the background-image
351
445
  equivalent of `object-fit: contain`: the whole avatar remains visible. A
@@ -18,6 +18,10 @@
18
18
  min-width: 0;
19
19
  max-width: 100%;
20
20
  overflow: hidden;
21
+ /* Keep the line box larger than the font's em square. Glyph ink can extend
22
+ below a 1em line box, so clipping for ellipsis must not also shave off
23
+ descenders such as g, j, p, q, and y. */
24
+ line-height: 1.2;
21
25
  white-space: nowrap;
22
26
  text-overflow: ellipsis;
23
27
  }
@@ -85,6 +85,15 @@
85
85
  grid-column: 2;
86
86
  }
87
87
 
88
+ .kui-toolbar[data-center-align="stretch"] > .kui-toolbar__center {
89
+ justify-content: flex-start;
90
+ }
91
+
92
+ .kui-toolbar[data-center-align="stretch"] > .kui-toolbar__center > * {
93
+ width: 100%;
94
+ flex-basis: 100%;
95
+ }
96
+
88
97
  .kui-toolbar__trailing {
89
98
  justify-content: flex-end;
90
99
  grid-column: -2 / -1;
@@ -95,3 +104,66 @@
95
104
  .kui-toolbar__trailing:empty {
96
105
  display: none;
97
106
  }
107
+
108
+ @container kui-toolbar (max-width: 52rem) {
109
+ .kui-toolbar[data-responsive="stack"][data-responsive-at="narrow"] {
110
+ height: auto;
111
+ grid-template-columns: minmax(0, 1fr);
112
+ grid-template-areas: "leading" "center" "trailing";
113
+ row-gap: var(--kui-toolbar-gap, 0.5rem);
114
+ }
115
+
116
+ .kui-toolbar[data-responsive="stack"][data-responsive-at="narrow"]
117
+ > .kui-toolbar__leading,
118
+ .kui-toolbar[data-responsive="stack"][data-responsive-at="narrow"]
119
+ > .kui-toolbar__center,
120
+ .kui-toolbar[data-responsive="stack"][data-responsive-at="narrow"]
121
+ > .kui-toolbar__trailing {
122
+ width: 100%;
123
+ grid-column: 1;
124
+ justify-content: flex-start;
125
+ }
126
+ }
127
+
128
+ @container kui-toolbar (max-width: 44rem) {
129
+ .kui-toolbar[data-responsive="stack"][data-responsive-at="compact"] {
130
+ height: auto;
131
+ grid-template-columns: minmax(0, 1fr);
132
+ grid-template-areas: "leading" "center" "trailing";
133
+ row-gap: var(--kui-toolbar-gap, 0.5rem);
134
+ }
135
+
136
+ .kui-toolbar[data-responsive="stack"][data-responsive-at="compact"]
137
+ > .kui-toolbar__leading,
138
+ .kui-toolbar[data-responsive="stack"][data-responsive-at="compact"]
139
+ > .kui-toolbar__center,
140
+ .kui-toolbar[data-responsive="stack"][data-responsive-at="compact"]
141
+ > .kui-toolbar__trailing {
142
+ width: 100%;
143
+ grid-column: 1;
144
+ justify-content: flex-start;
145
+ }
146
+ }
147
+
148
+ @container kui-toolbar (max-width: 42rem) {
149
+ .kui-toolbar[data-responsive="center-priority"]:has(
150
+ > .kui-toolbar__center [data-expanded="true"]
151
+ ) {
152
+ grid-template-columns: minmax(0, 1fr);
153
+ }
154
+
155
+ .kui-toolbar[data-responsive="center-priority"]:has(
156
+ > .kui-toolbar__center [data-expanded="true"]
157
+ )
158
+ > .kui-toolbar__center {
159
+ width: 100%;
160
+ grid-column: 1;
161
+ }
162
+
163
+ .kui-toolbar[data-responsive="center-priority"]:has(
164
+ > .kui-toolbar__center [data-expanded="true"]
165
+ )
166
+ > :is(.kui-toolbar__leading, .kui-toolbar__trailing) {
167
+ display: none;
168
+ }
169
+ }
@@ -336,22 +336,37 @@
336
336
  box-shadow: none;
337
337
  }
338
338
 
339
- /* Unframed disclosures align directly with their surrounding content.
340
- Framed disclosure headers use the roomier container tier so the trigger
341
- reads as the surface heading while the body keeps its compact inset. */
342
- wa-details[appearance="plain"]::part(header),
343
- wa-details[appearance="plain"]::part(content),
339
+ wa-details[appearance="plain"]::part(header) {
340
+ padding-inline: var(--kui-wa-surface-inset);
341
+ }
342
+
343
+ wa-details[appearance="plain"]::part(content) {
344
+ padding-inline: 0;
345
+ }
346
+
347
+ wa-details:is([appearance="outlined"], [appearance="sunken"])::part(header) {
348
+ padding-inline: var(--kui-wa-container-inset);
349
+ }
350
+
351
+ wa-details:is([appearance="outlined"], [appearance="sunken"])::part(content) {
352
+ padding-inline: var(--kui-wa-surface-inset);
353
+ }
354
+
344
355
  wa-accordion[appearance="plain"] > wa-accordion-item::part(button),
345
356
  wa-accordion[appearance="plain"] > wa-accordion-item::part(content) {
346
- padding-inline: 0;
357
+ padding-inline: var(--kui-wa-surface-inset);
347
358
  }
348
359
 
349
- wa-details:is([appearance="outlined"], [appearance="sunken"])::part(header),
350
360
  wa-accordion:is([appearance="outlined"], [appearance="sunken"])
351
361
  > wa-accordion-item::part(button) {
352
362
  padding-inline: var(--kui-wa-container-inset);
353
363
  }
354
364
 
365
+ wa-accordion:is([appearance="outlined"], [appearance="sunken"])
366
+ > wa-accordion-item::part(content) {
367
+ padding-inline: var(--kui-wa-container-inset);
368
+ }
369
+
355
370
  wa-card,
356
371
  wa-details,
357
372
  wa-accordion-item {
@@ -9,12 +9,14 @@ interface SunkenPanelProps {
9
9
  /** Corner shape: a rounded rectangle (default) or square corners. */
10
10
  shape?: SunkenPanelShape;
11
11
  className?: string;
12
+ /** Native named-slot assignment when composed inside a web component. */
13
+ slot?: string;
12
14
  }
13
15
  /**
14
16
  * A lowered application surface with one compact inset and a vertical content
15
17
  * stack. The panel owns its background and padding; children own their own
16
18
  * borders and internal geometry.
17
19
  */
18
- declare function SunkenPanel({ children, ariaLabel, shape, className, }: SunkenPanelProps): kerfjs.SafeHtml;
20
+ declare function SunkenPanel({ children, ariaLabel, shape, className, slot, }: SunkenPanelProps): kerfjs.SafeHtml;
19
21
 
20
22
  export { SunkenPanel, type SunkenPanelProps, type SunkenPanelShape };
@@ -1,3 +1,3 @@
1
- export { SunkenPanel } from './chunk-SOK5EUF7.js';
1
+ export { SunkenPanel } from './chunk-6ZXOQEAN.js';
2
2
 
3
3
  //# sourceMappingURL=sunken-panel.js.map
@@ -11,16 +11,20 @@ interface DialogSurfaceProps {
11
11
  bodyInset?: SurfaceInset;
12
12
  footerInset?: SurfaceInset;
13
13
  className?: string;
14
+ /** Native named-slot assignment when composed inside a web component. */
15
+ slot?: string;
14
16
  }
15
17
  /** Configure recurring Web Awesome dialog geometry without consumer ::part() CSS. */
16
- declare function DialogSurface({ children, size, presentation, bodyInset, footerInset, className, }: DialogSurfaceProps): kerfjs.SafeHtml;
18
+ declare function DialogSurface({ children, size, presentation, bodyInset, footerInset, className, slot, }: DialogSurfaceProps): kerfjs.SafeHtml;
17
19
  type PopupSurfaceInset = 'standard' | 'compact' | 'list-zero';
18
20
  interface PopupSurfaceProps {
19
21
  children: KerfUiContent;
20
22
  inset?: PopupSurfaceInset;
21
23
  className?: string;
24
+ /** Native named-slot assignment when composed inside a web component. */
25
+ slot?: string;
22
26
  }
23
27
  /** Configure recurring Web Awesome dropdown-menu geometry without consumer ::part() CSS. */
24
- declare function PopupSurface({ children, inset, className, }: PopupSurfaceProps): kerfjs.SafeHtml;
28
+ declare function PopupSurface({ children, inset, className, slot, }: PopupSurfaceProps): kerfjs.SafeHtml;
25
29
 
26
30
  export { DialogSurface, type DialogSurfacePresentation, type DialogSurfaceProps, type DialogSurfaceSize, PopupSurface, type PopupSurfaceInset, type PopupSurfaceProps, type SurfaceInset };
@@ -1,3 +1,3 @@
1
- export { DialogSurface, PopupSurface } from './chunk-WSXUPSID.js';
1
+ export { DialogSurface, PopupSurface } from './chunk-NN6GYOA2.js';
2
2
 
3
3
  //# sourceMappingURL=surface-scaffold.js.map
package/dist/tab-bar.d.ts CHANGED
@@ -11,6 +11,11 @@ interface TabBarProps {
11
11
  children: KerfUiContent;
12
12
  leading?: KerfUiContent;
13
13
  trailing?: KerfUiContent;
14
+ /**
15
+ * Action pinned to the far edge of the bar. Combine with an adjacent `trailing`
16
+ * action when the tab-local and workspace-level actions must remain distinct.
17
+ */
18
+ end?: KerfUiContent;
14
19
  className?: string;
15
20
  /**
16
21
  * Keyboard activation mode for this strip, emitted as `data-tab-activation` for
@@ -25,8 +30,10 @@ interface TabBarProps {
25
30
  presentation?: TabBarPresentation;
26
31
  /** Keep a trailing action beside the final tab or at the far edge of the bar. */
27
32
  trailingPlacement?: TabBarTrailingPlacement;
33
+ /** Native named-slot assignment when composed inside a web component. */
34
+ slot?: string;
28
35
  }
29
36
  /** Render a controlled tab strip. The application owns selection, order, and persistence. */
30
- declare function TabBar({ id, label, children, leading, trailing, className, activation, allocation, presentation, trailingPlacement, }: TabBarProps): kerfjs.SafeHtml;
37
+ declare function TabBar({ id, label, children, leading, trailing, end, className, activation, allocation, presentation, trailingPlacement, slot, }: TabBarProps): kerfjs.SafeHtml;
31
38
 
32
39
  export { type TabActivation, TabBar, type TabBarAllocation, type TabBarPresentation, type TabBarProps, type TabBarTrailingPlacement };
package/dist/tab-bar.js CHANGED
@@ -1,3 +1,3 @@
1
- export { TabBar } from './chunk-ZPWZIVI6.js';
1
+ export { TabBar } from './chunk-N3GKMPDW.js';
2
2
 
3
3
  //# sourceMappingURL=tab-bar.js.map
@@ -17,6 +17,8 @@ interface TabScaffoldProps<Id extends string = string> {
17
17
  /** The controlled active tab id (the app owns selection). */
18
18
  active: NoInfer<Id>;
19
19
  className?: string;
20
+ /** Native named-slot assignment when composed inside a web component. */
21
+ slot?: string;
20
22
  }
21
23
  /**
22
24
  * A mobile-first, iOS-like bottom tab scaffold: a bottom tab bar that switches
@@ -26,6 +28,6 @@ interface TabScaffoldProps<Id extends string = string> {
26
28
  * On larger classes, promote the tabs to a `Workbench` rail or sidebar instead of
27
29
  * a bottom bar. See `docs/23-app-layouts.md` §3.4.
28
30
  */
29
- declare function TabScaffold<Id extends string>({ id, label, tabs, active, className, }: TabScaffoldProps<Id>): SafeHtml;
31
+ declare function TabScaffold<Id extends string>({ id, label, tabs, active, className, slot, }: TabScaffoldProps<Id>): SafeHtml;
30
32
 
31
33
  export { TabScaffold, type TabScaffoldProps, type TabScaffoldTab };
@@ -6,7 +6,8 @@ function TabScaffold({
6
6
  label,
7
7
  tabs,
8
8
  active,
9
- className = ""
9
+ className = "",
10
+ slot
10
11
  }) {
11
12
  return /* @__PURE__ */ jsxs(
12
13
  "section",
@@ -15,6 +16,7 @@ function TabScaffold({
15
16
  id,
16
17
  "data-component": "tab-scaffold",
17
18
  "data-tab-scaffold-id": id,
19
+ slot,
18
20
  children: [
19
21
  /* @__PURE__ */ jsx("div", { class: "kui-tab-scaffold__scenes", children: tabs.map((tab) => /* @__PURE__ */ jsx(
20
22
  "div",
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tab-scaffold.tsx"],"names":[],"mappings":";;;AA+BO,SAAS,WAAA,CAA+B;AAAA,EAC7C,EAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA,GAAY;AACd,CAAA,EAAyB;AACvB,EAAA,uBACE,IAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,CAAA,iBAAA,EAAoB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,MAC5C,EAAA;AAAA,MACA,gBAAA,EAAe,cAAA;AAAA,MACf,sBAAA,EAAsB,EAAA;AAAA,MAEtB,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,SAAI,KAAA,EAAM,0BAAA,EACR,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,qBACT,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAM,yBAAA;AAAA,YACN,2BAAyB,GAAA,CAAI,EAAA;AAAA,YAC7B,aAAA,EAAa,MAAA,CAAO,GAAA,CAAI,EAAA,KAAO,MAAM,CAAA;AAAA,YACrC,aAAA,EAAa,MAAA,CAAO,GAAA,CAAI,EAAA,KAAO,MAAM,CAAA;AAAA,YAEpC,QAAA,EAAA,GAAA,CAAI;AAAA;AAAA,SAER,CAAA,EACH,CAAA;AAAA,wBACA,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,uBAAA,EAAwB,IAAA,EAAK,SAAA,EAAU,YAAA,EAAY,KAAA,EAC3D,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,qBACT,IAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,KAAA,EAAM,uBAAA;AAAA,YACN,IAAA,EAAK,KAAA;AAAA,YACL,yBAAuB,GAAA,CAAI,EAAA;AAAA,YAC3B,eAAA,EAAe,MAAA,CAAO,GAAA,CAAI,EAAA,KAAO,MAAM,CAAA;AAAA,YACvC,QAAA,EAAU,GAAA,CAAI,EAAA,KAAO,MAAA,GAAS,GAAA,GAAM,IAAA;AAAA,YAEnC,QAAA,EAAA;AAAA,cAAA,GAAA,CAAI,IAAA,wBACF,MAAA,EAAA,EAAK,KAAA,EAAM,8BAA6B,aAAA,EAAY,MAAA,EAClD,cAAI,IAAA,EACP,CAAA;AAAA,8BAEF,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAM,6BAAA,EAA+B,cAAI,KAAA,EAAM;AAAA;AAAA;AAAA,SAExD,CAAA,EACH;AAAA;AAAA;AAAA,GACF;AAEJ","file":"tab-scaffold.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport type { KerfUiContent } from './semantic-content.js';\n\nexport interface TabScaffoldTab<Id extends string = string> {\n id: Id;\n label: string;\n /** Decorative icon shown above the label in the bottom bar. */\n icon?: SafeHtml;\n /** The tab's content — typically a `NavStack` so each tab keeps its own stack. */\n content: KerfUiContent;\n}\n\nexport interface TabScaffoldProps<Id extends string = string> {\n id: string;\n /** Accessible name for the tab bar. */\n label: string;\n tabs: readonly TabScaffoldTab<Id>[];\n /** The controlled active tab id (the app owns selection). */\n active: NoInfer<Id>;\n className?: string;\n}\n\n/**\n * A mobile-first, iOS-like bottom tab scaffold: a bottom tab bar that switches\n * between major sections, each tab keeping its own content (usually a `NavStack`)\n * mounted so its stack and scroll survive a switch. Controlled — the app owns\n * `active`; wire selection with `@kerfjs/ui/wire-tab-scaffold`'s `wireTabScaffold`.\n * On larger classes, promote the tabs to a `Workbench` rail or sidebar instead of\n * a bottom bar. See `docs/23-app-layouts.md` §3.4.\n */\nexport function TabScaffold<Id extends string>({\n id,\n label,\n tabs,\n active,\n className = '',\n}: TabScaffoldProps<Id>) {\n return (\n <section\n class={`kui-tab-scaffold ${className}`.trim()}\n id={id}\n data-component=\"tab-scaffold\"\n data-tab-scaffold-id={id}\n >\n <div class=\"kui-tab-scaffold__scenes\">\n {tabs.map((tab) => (\n <div\n class=\"kui-tab-scaffold__scene\"\n data-tab-scaffold-scene={tab.id}\n data-active={String(tab.id === active)}\n aria-hidden={String(tab.id !== active)}\n >\n {tab.content}\n </div>\n ))}\n </div>\n <nav class=\"kui-tab-scaffold__bar\" role=\"tablist\" aria-label={label}>\n {tabs.map((tab) => (\n <button\n type=\"button\"\n class=\"kui-tab-scaffold__tab\"\n role=\"tab\"\n data-tab-scaffold-tab={tab.id}\n aria-selected={String(tab.id === active)}\n tabindex={tab.id === active ? '0' : '-1'}\n >\n {tab.icon && (\n <span class=\"kui-tab-scaffold__tab-icon\" aria-hidden=\"true\">\n {tab.icon}\n </span>\n )}\n <span class=\"kui-tab-scaffold__tab-label\">{tab.label}</span>\n </button>\n ))}\n </nav>\n </section>\n );\n}\n"]}
1
+ {"version":3,"sources":["../src/tab-scaffold.tsx"],"names":[],"mappings":";;;AAiCO,SAAS,WAAA,CAA+B;AAAA,EAC7C,EAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ;AACF,CAAA,EAAyB;AACvB,EAAA,uBACE,IAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,CAAA,iBAAA,EAAoB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,MAC5C,EAAA;AAAA,MACA,gBAAA,EAAe,cAAA;AAAA,MACf,sBAAA,EAAsB,EAAA;AAAA,MACtB,IAAA;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,SAAI,KAAA,EAAM,0BAAA,EACR,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,qBACT,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAM,yBAAA;AAAA,YACN,2BAAyB,GAAA,CAAI,EAAA;AAAA,YAC7B,aAAA,EAAa,MAAA,CAAO,GAAA,CAAI,EAAA,KAAO,MAAM,CAAA;AAAA,YACrC,aAAA,EAAa,MAAA,CAAO,GAAA,CAAI,EAAA,KAAO,MAAM,CAAA;AAAA,YAEpC,QAAA,EAAA,GAAA,CAAI;AAAA;AAAA,SAER,CAAA,EACH,CAAA;AAAA,wBACA,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,uBAAA,EAAwB,IAAA,EAAK,SAAA,EAAU,YAAA,EAAY,KAAA,EAC3D,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,qBACT,IAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,KAAA,EAAM,uBAAA;AAAA,YACN,IAAA,EAAK,KAAA;AAAA,YACL,yBAAuB,GAAA,CAAI,EAAA;AAAA,YAC3B,eAAA,EAAe,MAAA,CAAO,GAAA,CAAI,EAAA,KAAO,MAAM,CAAA;AAAA,YACvC,QAAA,EAAU,GAAA,CAAI,EAAA,KAAO,MAAA,GAAS,GAAA,GAAM,IAAA;AAAA,YAEnC,QAAA,EAAA;AAAA,cAAA,GAAA,CAAI,IAAA,wBACF,MAAA,EAAA,EAAK,KAAA,EAAM,8BAA6B,aAAA,EAAY,MAAA,EAClD,cAAI,IAAA,EACP,CAAA;AAAA,8BAEF,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAM,6BAAA,EAA+B,cAAI,KAAA,EAAM;AAAA;AAAA;AAAA,SAExD,CAAA,EACH;AAAA;AAAA;AAAA,GACF;AAEJ","file":"tab-scaffold.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport type { KerfUiContent } from './semantic-content.js';\n\nexport interface TabScaffoldTab<Id extends string = string> {\n id: Id;\n label: string;\n /** Decorative icon shown above the label in the bottom bar. */\n icon?: SafeHtml;\n /** The tab's content — typically a `NavStack` so each tab keeps its own stack. */\n content: KerfUiContent;\n}\n\nexport interface TabScaffoldProps<Id extends string = string> {\n id: string;\n /** Accessible name for the tab bar. */\n label: string;\n tabs: readonly TabScaffoldTab<Id>[];\n /** The controlled active tab id (the app owns selection). */\n active: NoInfer<Id>;\n className?: string;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\n/**\n * A mobile-first, iOS-like bottom tab scaffold: a bottom tab bar that switches\n * between major sections, each tab keeping its own content (usually a `NavStack`)\n * mounted so its stack and scroll survive a switch. Controlled — the app owns\n * `active`; wire selection with `@kerfjs/ui/wire-tab-scaffold`'s `wireTabScaffold`.\n * On larger classes, promote the tabs to a `Workbench` rail or sidebar instead of\n * a bottom bar. See `docs/23-app-layouts.md` §3.4.\n */\nexport function TabScaffold<Id extends string>({\n id,\n label,\n tabs,\n active,\n className = '',\n slot,\n}: TabScaffoldProps<Id>) {\n return (\n <section\n class={`kui-tab-scaffold ${className}`.trim()}\n id={id}\n data-component=\"tab-scaffold\"\n data-tab-scaffold-id={id}\n slot={slot}\n >\n <div class=\"kui-tab-scaffold__scenes\">\n {tabs.map((tab) => (\n <div\n class=\"kui-tab-scaffold__scene\"\n data-tab-scaffold-scene={tab.id}\n data-active={String(tab.id === active)}\n aria-hidden={String(tab.id !== active)}\n >\n {tab.content}\n </div>\n ))}\n </div>\n <nav class=\"kui-tab-scaffold__bar\" role=\"tablist\" aria-label={label}>\n {tabs.map((tab) => (\n <button\n type=\"button\"\n class=\"kui-tab-scaffold__tab\"\n role=\"tab\"\n data-tab-scaffold-tab={tab.id}\n aria-selected={String(tab.id === active)}\n tabindex={tab.id === active ? '0' : '-1'}\n >\n {tab.icon && (\n <span class=\"kui-tab-scaffold__tab-icon\" aria-hidden=\"true\">\n {tab.icon}\n </span>\n )}\n <span class=\"kui-tab-scaffold__tab-label\">{tab.label}</span>\n </button>\n ))}\n </nav>\n </section>\n );\n}\n"]}