@kerfjs/ui 5.0.0-beta.68 → 5.0.0-beta.69

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 (92) hide show
  1. package/README.md +3 -0
  2. package/ai/component-catalog-extension.schema.json +12 -0
  3. package/ai/component-catalog.json +14 -4
  4. package/ai/component-catalog.schema.json +14 -0
  5. package/ai/component-composition-rules.json +2 -2
  6. package/ai/component-composition.d.ts +2 -0
  7. package/ai/component-composition.json +2 -2
  8. package/ai/component-composition.schema.json +23 -0
  9. package/ai/components/loading-spinner.md +1 -0
  10. package/ai/components/tab-bar.md +5 -4
  11. package/ai/components/toolbar-control-group.md +2 -2
  12. package/ai/public-api-signatures-v1.md +34 -14
  13. package/ai/skill.md +18 -3
  14. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  15. package/analyzer/index.d.mts +1 -0
  16. package/analyzer/index.mjs +108 -12
  17. package/dist/catalog.js +4 -4
  18. package/dist/catalog.js.map +1 -1
  19. package/dist/{chunk-P4UXSYIJ.js → chunk-2ZOLX3IE.js} +2 -2
  20. package/dist/{chunk-P4UXSYIJ.js.map → chunk-2ZOLX3IE.js.map} +1 -1
  21. package/dist/{chunk-E36EVCKG.js → chunk-47CKKLBE.js} +2 -2
  22. package/dist/{chunk-E36EVCKG.js.map → chunk-47CKKLBE.js.map} +1 -1
  23. package/dist/{chunk-JCV4GXWB.js → chunk-6DFDTWGG.js} +100 -61
  24. package/dist/chunk-6DFDTWGG.js.map +1 -0
  25. package/dist/{chunk-IAOAZUOO.js → chunk-7OKX3EF6.js} +2 -2
  26. package/dist/{chunk-IAOAZUOO.js.map → chunk-7OKX3EF6.js.map} +1 -1
  27. package/dist/{chunk-C74LITXE.js → chunk-B3XWUX3A.js} +2 -2
  28. package/dist/{chunk-C74LITXE.js.map → chunk-B3XWUX3A.js.map} +1 -1
  29. package/dist/{chunk-F7OCOBTG.js → chunk-CRVDF4A6.js} +4 -1
  30. package/dist/chunk-CRVDF4A6.js.map +1 -0
  31. package/dist/{chunk-TGM424PI.js → chunk-H7IODXGY.js} +3 -3
  32. package/dist/{chunk-TGM424PI.js.map → chunk-H7IODXGY.js.map} +1 -1
  33. package/dist/chunk-KVBRMEPM.js +44 -0
  34. package/dist/chunk-KVBRMEPM.js.map +1 -0
  35. package/dist/{chunk-EN4LDR5Y.js → chunk-NC4CFOID.js} +2 -2
  36. package/dist/{chunk-EN4LDR5Y.js.map → chunk-NC4CFOID.js.map} +1 -1
  37. package/dist/{chunk-5SYE4CCT.js → chunk-PQZPVBP4.js} +25 -18
  38. package/dist/chunk-PQZPVBP4.js.map +1 -0
  39. package/dist/{chunk-NXWE5S57.js → chunk-QJ5VFCW3.js} +12 -3
  40. package/dist/chunk-QJ5VFCW3.js.map +1 -0
  41. package/dist/{chunk-RKTTF3L4.js → chunk-X3TPECWG.js} +1 -1
  42. package/dist/chunk-X3TPECWG.js.map +1 -0
  43. package/dist/{chunk-VY6YRCTV.js → chunk-X3X4KRDK.js} +2 -2
  44. package/dist/{chunk-VY6YRCTV.js.map → chunk-X3X4KRDK.js.map} +1 -1
  45. package/dist/collapsible-panel.js +2 -2
  46. package/dist/empty-state.js +2 -1
  47. package/dist/index.js +10 -10
  48. package/dist/list-action-row.js +1 -1
  49. package/dist/list-item.js +1 -1
  50. package/dist/loading-spinner.d.ts +7 -2
  51. package/dist/loading-spinner.js +2 -1
  52. package/dist/nav-stack.js +1 -1
  53. package/dist/select.d.ts +4 -2
  54. package/dist/select.js +1 -1
  55. package/dist/split-view.js +1 -1
  56. package/dist/styles/app-tab.css +18 -1
  57. package/dist/styles/loading-spinner.css +4 -0
  58. package/dist/styles/select.css +79 -0
  59. package/dist/styles/tab-bar.css +12 -8
  60. package/dist/styles/token-search-field.css +19 -10
  61. package/dist/styles/toolbar-control-group.css +96 -3
  62. package/dist/tab-bar.d.ts +2 -0
  63. package/dist/tab-bar.js +1 -1
  64. package/dist/token-search-field.js +1 -1
  65. package/dist/toolbar-control-group.d.ts +13 -5
  66. package/dist/toolbar-control-group.js +2 -1
  67. package/dist/wire-catalog.js +1 -1
  68. package/dist/wire-scroll-dividers.d.ts +7 -4
  69. package/dist/wire-scroll-dividers.js +1 -1
  70. package/dist/wire-token-search-fields.js +1 -1
  71. package/dist/workbench.js +1 -1
  72. package/docs/accessibility.md +10 -0
  73. package/docs/catalog.md +3 -0
  74. package/docs/component-contract.md +58 -9
  75. package/docs/component-selection.md +22 -6
  76. package/docs/examples/component-catalog-extension.json +1 -0
  77. package/docs/layout.md +6 -0
  78. package/docs/ui-analyzer.md +12 -0
  79. package/docs/ui-doctor.md +15 -3
  80. package/doctor/cli.mjs +5 -0
  81. package/doctor/config.schema.json +2 -0
  82. package/doctor/index.d.mts +3 -0
  83. package/doctor/index.mjs +27 -1
  84. package/llms.txt +15 -5
  85. package/package.json +1 -1
  86. package/dist/chunk-5SYE4CCT.js.map +0 -1
  87. package/dist/chunk-F7OCOBTG.js.map +0 -1
  88. package/dist/chunk-JCV4GXWB.js.map +0 -1
  89. package/dist/chunk-NXWE5S57.js.map +0 -1
  90. package/dist/chunk-RKTTF3L4.js.map +0 -1
  91. package/dist/chunk-ZLWQZUGF.js +0 -27
  92. package/dist/chunk-ZLWQZUGF.js.map +0 -1
@@ -43,13 +43,30 @@
43
43
  position: absolute;
44
44
  z-index: -1;
45
45
  inset-block: 0;
46
- inset-inline-start: calc(-1 * var(--kui-tab-bar-strip-padding, 1px));
46
+ inset-inline-start: calc(
47
+ -1 *
48
+ (
49
+ var(--kui-tab-bar-strip-padding, 1px) +
50
+ var(--kui-tab-bar-strip-border-width, 1px)
51
+ )
52
+ );
47
53
  inset-inline-end: 0;
48
54
  background: var(
49
55
  --kui-app-tab-pinned-background,
50
56
  var(--_kui-app-tab-pinned-default-background, var(--kui-color-surface))
51
57
  );
52
58
  }
59
+ /* The leading overflow line belongs after the pinned tab, where its scrolling
60
+ peers disappear. Reuse the opaque backing so drag indicators can still use
61
+ ::after. */
62
+ .kui-tab-bar__tabs:dir(ltr)[data-scroll-overflow*="l"]
63
+ > .kui-app-tab[data-pinned="true"]::before,
64
+ .kui-tab-bar__tabs:dir(rtl)[data-scroll-overflow*="r"]
65
+ > .kui-app-tab[data-pinned="true"]::before {
66
+ inset-inline-end: -1px;
67
+ border-inline-end: 1px solid
68
+ var(--kui-tab-bar-divider-color, var(--kui-color-neutral-border-normal));
69
+ }
53
70
  .kui-tab-bar[data-presentation="segmented"] .kui-app-tab[data-pinned="true"],
54
71
  .kui-tab-bar[data-presentation="inspector"] .kui-app-tab[data-pinned="true"] {
55
72
  --_kui-app-tab-pinned-default-background: var(
@@ -5,6 +5,10 @@
5
5
  overflow: visible;
6
6
  fill: currentColor;
7
7
  }
8
+ .kui-loading-spinner[data-size] {
9
+ width: var(--_kui-loading-spinner-size);
10
+ height: var(--_kui-loading-spinner-size);
11
+ }
8
12
  .kui-loading-spinner path {
9
13
  transform-origin: 12px 12px;
10
14
  animation: kui-loading-spinner-rotate 0.85s linear infinite;
@@ -40,6 +40,55 @@
40
40
  width: max-content;
41
41
  max-width: 100%;
42
42
  }
43
+ .kui-select[data-presentation="title"] {
44
+ width: max-content;
45
+ max-width: 100%;
46
+ }
47
+ .kui-select[data-presentation="title"]::part(combobox) {
48
+ width: max-content;
49
+ min-height: 2.25rem;
50
+ padding-inline: 0;
51
+ border-color: transparent;
52
+ background: transparent;
53
+ box-shadow: none;
54
+ font-size: var(--kui-font-l, 1.25rem);
55
+ font-weight: 700;
56
+ }
57
+ .kui-select[data-presentation="title"]::part(display-input) {
58
+ field-sizing: content;
59
+ flex: 0 0 auto;
60
+ }
61
+ .kui-select[data-presentation="title"]::part(expand-icon) {
62
+ margin-inline-start: 0;
63
+ }
64
+ /* A Toolbar has an 8px inset; ListItem text starts at 17px after its own
65
+ margin, border, and padding. The group contributes 3px, so the title
66
+ Select advances 6px to share the list's text edge. */
67
+ .kui-toolbar-control-group > .kui-select[data-presentation="title"] {
68
+ margin-inline-start: 0.375rem;
69
+ }
70
+ .kui-select[data-presentation="inline"] {
71
+ width: max-content;
72
+ max-width: 100%;
73
+ }
74
+ .kui-select[data-presentation="inline"]::part(combobox) {
75
+ width: max-content;
76
+ min-height: 0;
77
+ padding: 0;
78
+ border-width: 0;
79
+ background: transparent;
80
+ }
81
+ .kui-select--custom-selected[data-presentation="inline"]::part(start) {
82
+ flex: 0 0 auto;
83
+ }
84
+ .kui-select--custom-selected[data-presentation="inline"]
85
+ .kui-select__custom-selected {
86
+ margin-inline-end: 0 !important;
87
+ }
88
+ .kui-select--custom-selected[data-presentation="inline"]
89
+ .kui-select__custom-selected-content {
90
+ display: flex;
91
+ }
43
92
  .kui-select[data-focus-ring-owner="group"]:focus-within::part(combobox) {
44
93
  outline: none;
45
94
  box-shadow: none;
@@ -101,6 +150,12 @@
101
150
  outline: var(--kui-focus-ring);
102
151
  outline-offset: 1px;
103
152
  }
153
+ .kui-select[data-focus-ring-inset="true"][data-focus-ring-owner="select"]:focus-within:not(
154
+ [open]
155
+ )::part(combobox) {
156
+ outline: var(--kui-focus-ring);
157
+ outline-offset: -3px;
158
+ }
104
159
  /* The popup-menu wa-button draws the same chevron glyph at 0.875em inside a
105
160
  20px box; match its box, spacing, and glyph size rather than the smaller
106
161
  form-field disclosure scale. */
@@ -332,6 +387,30 @@
332
387
  width: max-content;
333
388
  max-width: 100%;
334
389
  }
390
+ .kui-select--placeholder[data-presentation="title"] {
391
+ width: max-content;
392
+ max-width: 100%;
393
+ }
394
+ .kui-select--placeholder[data-presentation="title"]
395
+ .kui-select__placeholder-box {
396
+ min-height: 2.25rem;
397
+ padding-inline: 0;
398
+ border-color: transparent;
399
+ background: transparent;
400
+ font-size: var(--kui-font-l, 1.25rem);
401
+ font-weight: 700;
402
+ }
403
+ .kui-select--placeholder[data-presentation="inline"] {
404
+ width: max-content;
405
+ max-width: 100%;
406
+ }
407
+ .kui-select--placeholder[data-presentation="inline"]
408
+ .kui-select__placeholder-box {
409
+ min-height: 0;
410
+ padding: 0;
411
+ border-width: 0;
412
+ background: transparent;
413
+ }
335
414
  .kui-select__placeholder-hint {
336
415
  /* The live wa-select hint part: small body text at Web Awesome's form-control
337
416
  hint metrics (1.6 line height, 7px below the box), inset like the value. */
@@ -136,12 +136,12 @@
136
136
  margin-inline-start: calc(-1px - var(--kui-toolbar-gap, 0.5rem));
137
137
  }
138
138
 
139
- .kui-tab-bar[data-presentation="rail"]:dir(ltr):has(
140
- > .kui-tab-bar__tabs[data-scroll-overflow*="l"]
141
- )::before,
142
- .kui-tab-bar[data-presentation="rail"]:dir(rtl):has(
143
- > .kui-tab-bar__tabs[data-scroll-overflow*="r"]
144
- )::before,
139
+ .kui-tab-bar[data-presentation="rail"]:dir(ltr):not(
140
+ :has(> .kui-tab-bar__tabs > .kui-app-tab[data-pinned="true"])
141
+ ):has(> .kui-tab-bar__tabs[data-scroll-overflow*="l"])::before,
142
+ .kui-tab-bar[data-presentation="rail"]:dir(rtl):not(
143
+ :has(> .kui-tab-bar__tabs > .kui-app-tab[data-pinned="true"])
144
+ ):has(> .kui-tab-bar__tabs[data-scroll-overflow*="r"])::before,
145
145
  .kui-tab-bar[data-presentation="rail"]:dir(ltr):has(
146
146
  > .kui-tab-bar__tabs[data-scroll-overflow*="r"]
147
147
  )::after,
@@ -155,7 +155,9 @@
155
155
  }
156
156
 
157
157
  .kui-tab-bar:not([data-presentation="rail"])
158
- > .kui-tab-bar__tabs[data-scroll-overflow*="l"] {
158
+ > .kui-tab-bar__tabs[data-scroll-overflow*="l"]:not(
159
+ :dir(ltr):has(> .kui-app-tab[data-pinned="true"])
160
+ ) {
159
161
  border-left-color: var(
160
162
  --kui-tab-bar-divider-color,
161
163
  var(--kui-color-neutral-border-normal)
@@ -163,7 +165,9 @@
163
165
  }
164
166
 
165
167
  .kui-tab-bar:not([data-presentation="rail"])
166
- > .kui-tab-bar__tabs[data-scroll-overflow*="r"] {
168
+ > .kui-tab-bar__tabs[data-scroll-overflow*="r"]:not(
169
+ :dir(rtl):has(> .kui-app-tab[data-pinned="true"])
170
+ ) {
167
171
  border-right-color: var(
168
172
  --kui-tab-bar-divider-color,
169
173
  var(--kui-color-neutral-border-normal)
@@ -28,10 +28,6 @@
28
28
  }
29
29
 
30
30
  .kui-token-search {
31
- --kui-token-search-background: var(--kui-color-surface);
32
- --kui-token-search-border: var(--kui-color-neutral-border-normal);
33
- --kui-token-search-token-background: var(--kui-color-brand-fill-normal);
34
- --kui-token-search-token-foreground: var(--kui-color-brand-on-quiet);
35
31
  --kui-token-search-line-size: 2.125rem;
36
32
 
37
33
  display: grid;
@@ -41,10 +37,11 @@
41
37
  min-height: 2.75rem;
42
38
  padding: 0.25rem 0.5rem;
43
39
  box-sizing: border-box;
44
- border: 1px solid var(--kui-token-search-border);
40
+ border: 1px solid
41
+ var(--kui-token-search-border, var(--kui-color-neutral-border-normal));
45
42
  border-radius: var(--kui-layout-pill-radius, calc(1px + 1.3125rem));
46
43
  color: var(--kui-color-text);
47
- background: var(--kui-token-search-background);
44
+ background: var(--kui-token-search-background, var(--kui-color-surface));
48
45
  grid-template-columns: auto minmax(0, 1fr) auto auto;
49
46
  align-items: start;
50
47
  gap: var(--kui-layout-item-gap, 0.5rem);
@@ -119,8 +116,14 @@
119
116
  margin-inline: 0.125rem;
120
117
  padding-inline-start: 0.45rem;
121
118
  border-radius: var(--kui-radius-pill);
122
- color: var(--kui-token-search-token-foreground);
123
- background: var(--kui-token-search-token-background);
119
+ color: var(
120
+ --kui-token-search-token-foreground,
121
+ var(--kui-color-brand-on-quiet)
122
+ );
123
+ background: var(
124
+ --kui-token-search-token-background,
125
+ var(--kui-color-brand-fill-normal)
126
+ );
124
127
  font-size: var(--kui-font-xs);
125
128
  line-height: 1;
126
129
  white-space: nowrap;
@@ -255,7 +258,13 @@
255
258
  }
256
259
 
257
260
  .kui-token-search[data-collapsible="true"] {
258
- width: min(var(--kui-token-search-expanded-width, 30rem), 100%);
261
+ width: min(
262
+ var(
263
+ --_kui-toolbar-group-grow-search-width,
264
+ var(--kui-token-search-expanded-width, 30rem)
265
+ ),
266
+ 100%
267
+ );
259
268
  max-width: 100%;
260
269
  overflow: hidden;
261
270
  /* Size the inline axis through `width` only. A `flex-basis` of the expanded
@@ -343,7 +352,7 @@
343
352
 
344
353
  .kui-token-search[data-presentation="toolbar-group"][data-collapsible="true"]:focus-within {
345
354
  border-color: var(--kui-color-focus);
346
- background: var(--kui-token-search-background);
355
+ background: var(--kui-token-search-background, var(--kui-color-surface));
347
356
  }
348
357
 
349
358
  .kui-token-search[data-presentation="toolbar-group"][data-collapsible="true"][data-expanded="false"] {
@@ -102,6 +102,24 @@
102
102
  }
103
103
  }
104
104
 
105
+ @container kui-toolbar (max-width: 14rem) {
106
+ .kui-toolbar-control-group[data-visibility="hide-collapsed-tiny"][data-expanded="false"] {
107
+ display: none;
108
+ }
109
+ }
110
+
111
+ /* An expanded trailing control owns the compact row when sibling groups opt
112
+ into yielding. Scoping to the trailing zone keeps independent center and
113
+ leading controls visible, and the siblings return when it closes. */
114
+ @container kui-toolbar (max-width: 30rem) {
115
+ .kui-toolbar__trailing:has(> .kui-toolbar-control-group[data-expanded="true"])
116
+ > .kui-toolbar-control-group[data-visibility="yield-to-expanded-sibling"]:not(
117
+ [data-expanded="true"]
118
+ ) {
119
+ display: none;
120
+ }
121
+ }
122
+
105
123
  /* `shape="rounded"` swaps the default pill radius for the design system's softer
106
124
  rounded rectangle. The shared highlight contract derives every inner hover or
107
125
  selected surface from this outer radius and the group's full inset. */
@@ -143,6 +161,16 @@
143
161
  max-width: 100%;
144
162
  overflow-x: auto;
145
163
  }
164
+ .kui-toolbar-control-group[data-overflow="wrap"] {
165
+ max-width: 100%;
166
+ height: auto;
167
+ flex-wrap: wrap;
168
+ }
169
+ :is(.kui-toolbar__leading, .kui-toolbar__center, .kui-toolbar__trailing)
170
+ > .kui-toolbar-control-group[data-overflow="wrap"] {
171
+ margin-block-start: 0;
172
+ align-self: center;
173
+ }
146
174
  .kui-toolbar-control-group[data-content="search"] {
147
175
  width: min(var(--kui-token-search-expanded-width, 30rem), 100%);
148
176
  max-width: 100%;
@@ -179,6 +207,55 @@
179
207
  width: var(--kui-toolbar-group-size, calc(2px + 2.625rem));
180
208
  flex: 0 0 auto;
181
209
  }
210
+
211
+ .kui-toolbar-control-group[data-sizing="grow"][data-expanded="true"] {
212
+ --_kui-toolbar-group-grow-search-width: 100%;
213
+ width: auto;
214
+ min-width: min(100%, var(--kui-toolbar-group-grow-basis, 19rem));
215
+ flex: 1 1 var(--kui-toolbar-group-grow-basis, 19rem);
216
+ }
217
+ .kui-toolbar-control-group[data-sizing="fill"] {
218
+ width: 100%;
219
+ min-width: 0;
220
+ flex: 1 1 100%;
221
+ }
222
+
223
+ /* Auto margin consumes the free space before this group on its flex line;
224
+ when the expanded fill search takes a whole line, the margin resolves to 0. */
225
+ .kui-toolbar[data-responsive="stack"]
226
+ > :is(.kui-toolbar__center, .kui-toolbar__trailing)
227
+ > .kui-toolbar-control-group[data-placement="end"] {
228
+ margin-inline-start: auto;
229
+ }
230
+
231
+ /* A fill search crosses from the preceding control line to its own line.
232
+ Move its visual down one control band as it opens without changing layout. */
233
+ .kui-toolbar[data-responsive="stack"]
234
+ > :is(.kui-toolbar__center, .kui-toolbar__trailing)
235
+ > .kui-toolbar-control-group[data-content="search"][data-sizing="fill"][data-expanded="true"] {
236
+ animation: kui-toolbar-fill-search-enter 0.25s ease-out both;
237
+ }
238
+
239
+ @keyframes kui-toolbar-fill-search-enter {
240
+ from {
241
+ transform: translateY(
242
+ calc(
243
+ -1 * (var(--_kui-toolbar-band) + var(--kui-toolbar-gap, 0.5rem))
244
+ )
245
+ );
246
+ }
247
+ to {
248
+ transform: translateY(0);
249
+ }
250
+ }
251
+
252
+ @container kui-toolbar (max-width: 30rem) {
253
+ .kui-toolbar-control-group[data-sizing="grow"][data-expanded="true"] {
254
+ width: 100%;
255
+ min-width: 0;
256
+ flex: 1 1 100%;
257
+ }
258
+ }
182
259
  .kui-toolbar-control-group[data-content="text"]
183
260
  > :is(button, wa-button, .kui-toolbar-action-link),
184
261
  .kui-toolbar-control-group[data-content="mixed"]
@@ -284,7 +361,12 @@
284
361
  place-items: center;
285
362
  }
286
363
 
287
- .kui-toolbar-control-group > button:hover {
364
+ .kui-toolbar-control-group > button:disabled {
365
+ opacity: 0.5;
366
+ cursor: not-allowed;
367
+ }
368
+
369
+ .kui-toolbar-control-group > button:not(:disabled):hover {
288
370
  border-color: var(--kui-toolbar-control-border);
289
371
  background: var(--kui-toolbar-control-hover-background);
290
372
  }
@@ -495,7 +577,7 @@
495
577
 
496
578
  .kui-toolbar-control-group[data-single="true"]:has(
497
579
  > :is(
498
- button,
580
+ button:not(:disabled),
499
581
  wa-button,
500
582
  .kui-popup-menu,
501
583
  wa-dropdown:not(.kui-popup-menu),
@@ -519,7 +601,12 @@
519
601
  inner layer inset from the border (KF-J9P1ZD — a heading toolbar's lone Close/
520
602
  Done action). */
521
603
  .kui-toolbar-control-group:not([data-single="true"]):has(
522
- > :is(button, wa-button, .kui-select, .kui-toolbar-action-link):only-child
604
+ > :is(
605
+ button:not(:disabled),
606
+ wa-button,
607
+ .kui-select,
608
+ .kui-toolbar-action-link
609
+ ):only-child
523
610
  ):hover {
524
611
  background-color: var(--kui-toolbar-control-hover-background);
525
612
  }
@@ -653,6 +740,12 @@
653
740
  .kui-toolbar-control-group[data-content="search"] {
654
741
  transition-duration: 0s;
655
742
  }
743
+
744
+ .kui-toolbar[data-responsive="stack"]
745
+ > :is(.kui-toolbar__center, .kui-toolbar__trailing)
746
+ > .kui-toolbar-control-group[data-content="search"][data-sizing="fill"][data-expanded="true"] {
747
+ animation: none;
748
+ }
656
749
  }
657
750
 
658
751
  /* Avatar controls paint the image as chrome rather than inserting a replaced
package/dist/tab-bar.d.ts CHANGED
@@ -12,10 +12,12 @@ interface TabBarProps {
12
12
  label: string;
13
13
  children: KerfUiContent;
14
14
  leading?: KerfUiContent;
15
+ /** Tab-local action: a ToolbarControlGroup or a standalone Web Awesome button. */
15
16
  trailing?: KerfUiContent;
16
17
  /**
17
18
  * Action pinned to the far edge of the bar. Combine with an adjacent `trailing`
18
19
  * action when the tab-local and workspace-level actions must remain distinct.
20
+ * Accepts a ToolbarControlGroup or a standalone Web Awesome button.
19
21
  */
20
22
  end?: KerfUiContent;
21
23
  className?: string;
package/dist/tab-bar.js CHANGED
@@ -1,3 +1,3 @@
1
- export { TabBar } from './chunk-RKTTF3L4.js';
1
+ export { TabBar } from './chunk-X3TPECWG.js';
2
2
 
3
3
  //# sourceMappingURL=tab-bar.js.map
@@ -1,4 +1,4 @@
1
- export { TokenSearchField, placeTokenSearchCaret, readTokenSearchField } from './chunk-5SYE4CCT.js';
1
+ export { TokenSearchField, placeTokenSearchCaret, readTokenSearchField } from './chunk-PQZPVBP4.js';
2
2
 
3
3
 
4
4
 
@@ -11,9 +11,11 @@ type ToolbarControlGroupContent = 'icon' | 'text' | 'mixed' | 'avatar' | 'search
11
11
  type ToolbarControlGroupFocusRing = 'control' | 'outline' | 'halo';
12
12
  type ToolbarControlGroupSelectedChrome = 'raised' | 'filled' | 'outline';
13
13
  type ToolbarControlGroupSelectedTone = 'brand' | 'neutral' | 'pop';
14
- type ToolbarControlGroupOverflow = 'visible' | 'scroll';
14
+ type ToolbarControlGroupOverflow = 'visible' | 'scroll' | 'wrap';
15
15
  type ToolbarControlGroupMenuInset = 'standard' | 'compact' | 'list-zero';
16
- type ToolbarControlGroupVisibility = 'always' | 'compact-only';
16
+ type ToolbarControlGroupVisibility = 'always' | 'compact-only' | 'hide-collapsed-tiny' | 'yield-to-expanded-sibling';
17
+ type ToolbarControlGroupSizing = 'content' | 'grow' | 'fill';
18
+ type ToolbarControlGroupPlacement = 'start' | 'end';
17
19
  interface ToolbarActionLinkProps {
18
20
  href: string;
19
21
  label: string;
@@ -52,10 +54,16 @@ interface ToolbarControlGroupProps {
52
54
  nestedDropdown?: boolean;
53
55
  /** Configure the nested dropdown menu inset without consumer ::part() CSS. */
54
56
  menuInset?: ToolbarControlGroupMenuInset;
55
- /** Keep an overlong row of actions inside the available width with horizontal scrolling. */
57
+ /** Keep an overlong row inside the available width by scrolling or wrapping. */
56
58
  overflow?: ToolbarControlGroupOverflow;
57
59
  /** Responsive visibility owned by the enclosing Toolbar container. */
58
60
  visibility?: ToolbarControlGroupVisibility;
61
+ /** Intrinsic (default), grow from a basis, or occupy a full wrapping row. */
62
+ sizing?: ToolbarControlGroupSizing;
63
+ /** Place this group at the end of its flex row in a wrapping Toolbar zone. */
64
+ placement?: ToolbarControlGroupPlacement;
65
+ /** CSS length used as the minimum width and flex basis for `sizing="grow"`; defaults to 19rem. */
66
+ growBasis?: string;
59
67
  /** Move this group into the work-area toolbar when its panel collapses. */
60
68
  relocateOnCollapse?: boolean;
61
69
  /** Add contrast behind photo-backed avatar content. */
@@ -72,6 +80,6 @@ interface ToolbarControlGroupProps {
72
80
  /** Native named-slot assignment when composed inside a web component. */
73
81
  slot?: string;
74
82
  }
75
- declare function ToolbarControlGroup({ children, label, className, expanded, single, appearance, tone, buttonAppearance, shape, size, density, content, focusRing, selectedChrome, selectedTone, nestedDropdown, menuInset, overflow, visibility, relocateOnCollapse, scrim, busy, busyLabel, avatarImage, slot, }: ToolbarControlGroupProps): kerfjs.SafeHtml;
83
+ declare function ToolbarControlGroup({ children, label, className, expanded, single, appearance, tone, buttonAppearance, shape, size, density, content, focusRing, selectedChrome, selectedTone, nestedDropdown, menuInset, overflow, visibility, sizing, placement, growBasis, relocateOnCollapse, scrim, busy, busyLabel, avatarImage, slot, }: ToolbarControlGroupProps): kerfjs.SafeHtml;
76
84
 
77
- export { ToolbarActionLink, type ToolbarActionLinkProps, ToolbarControlGroup, type ToolbarControlGroupAppearance, type ToolbarControlGroupButtonAppearance, type ToolbarControlGroupContent, type ToolbarControlGroupDensity, type ToolbarControlGroupFocusRing, type ToolbarControlGroupMenuInset, type ToolbarControlGroupOverflow, type ToolbarControlGroupProps, type ToolbarControlGroupSelectedChrome, type ToolbarControlGroupSelectedTone, type ToolbarControlGroupShape, type ToolbarControlGroupSize, type ToolbarControlGroupTone, type ToolbarControlGroupVisibility };
85
+ export { ToolbarActionLink, type ToolbarActionLinkProps, ToolbarControlGroup, type ToolbarControlGroupAppearance, type ToolbarControlGroupButtonAppearance, type ToolbarControlGroupContent, type ToolbarControlGroupDensity, type ToolbarControlGroupFocusRing, type ToolbarControlGroupMenuInset, type ToolbarControlGroupOverflow, type ToolbarControlGroupPlacement, type ToolbarControlGroupProps, type ToolbarControlGroupSelectedChrome, type ToolbarControlGroupSelectedTone, type ToolbarControlGroupShape, type ToolbarControlGroupSize, type ToolbarControlGroupSizing, type ToolbarControlGroupTone, type ToolbarControlGroupVisibility };
@@ -1,4 +1,5 @@
1
- export { ToolbarActionLink, ToolbarControlGroup } from './chunk-NXWE5S57.js';
1
+ export { ToolbarActionLink, ToolbarControlGroup } from './chunk-QJ5VFCW3.js';
2
+
2
3
 
3
4
 
4
5
  //# sourceMappingURL=toolbar-control-group.js.map
@@ -1,6 +1,6 @@
1
1
  import { wireWorkbench } from './chunk-TJK44RQC.js';
2
2
 
3
- import { wireScrollDividers } from './chunk-JCV4GXWB.js';
3
+ import { wireScrollDividers } from './chunk-6DFDTWGG.js';
4
4
 
5
5
 
6
6
  import { delegate } from 'kerfjs';
@@ -33,6 +33,7 @@ interface WireScrollDividersOptions {
33
33
  */
34
34
  targets?: readonly ScrollDividerTarget[];
35
35
  }
36
+ type Root = HTMLElement | Document;
36
37
  /**
37
38
  * Wire scroll dividers below `root`: a divider between pinned chrome and the
38
39
  * content that scrolls beside it shows only while content is scrolled away
@@ -60,10 +61,12 @@ interface WireScrollDividersOptions {
60
61
  *
61
62
  * Structure is re-read after every DOM change below root (a re-render that
62
63
  * drops the attributes gets them back before paint), scroll is tracked with
63
- * one capturing listener, and size changes of each scroller and its children
64
- * with a `ResizeObserver`. Returns a disposer that removes every attribute it
65
- * wrote. See `docs/23-app-layouts.md` §3.7.
64
+ * one capturing listener per registered root, and size changes of each
65
+ * scroller and its children with a `ResizeObserver`. Overlapping registrations
66
+ * share one attribute writer; each disposer removes its registration, and the
67
+ * final disposer removes the wiring-owned attributes. See
68
+ * `docs/23-app-layouts.md` §3.7.
66
69
  */
67
- declare function wireScrollDividers(root: HTMLElement | Document, { targets }?: WireScrollDividersOptions): () => void;
70
+ declare function wireScrollDividers(root: Root, { targets }?: WireScrollDividersOptions): () => void;
68
71
 
69
72
  export { type ScrollDividerTarget, type WireScrollDividersOptions, wireScrollDividers };
@@ -1,3 +1,3 @@
1
- export { wireScrollDividers } from './chunk-JCV4GXWB.js';
1
+ export { wireScrollDividers } from './chunk-6DFDTWGG.js';
2
2
 
3
3
  //# sourceMappingURL=wire-scroll-dividers.js.map
@@ -1,4 +1,4 @@
1
- export { wireTokenSearchFields } from './chunk-P4UXSYIJ.js';
1
+ export { wireTokenSearchFields } from './chunk-2ZOLX3IE.js';
2
2
 
3
3
 
4
4
 
package/dist/workbench.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Workbench } from './chunk-TGM424PI.js';
1
+ export { Workbench } from './chunk-H7IODXGY.js';
2
2
 
3
3
 
4
4
 
@@ -101,6 +101,13 @@ Navigation selects can use intrinsic `presentation="navigation"` plus
101
101
  `labelMaxWidth` for component-owned ellipsis. These props own the control's
102
102
  appearance; its parent continues to own outer placement.
103
103
 
104
+ Use `presentation="inline"` with a single-value `renderSelected` when the
105
+ selected content, such as a `Badge`, already provides the trigger chrome. The
106
+ closed combobox has no minimum height, inline padding, or border width, so the
107
+ rendered content defines its box. The Select still owns the focus ring,
108
+ accessible combobox name, and listbox interaction; keep `label` or `ariaLabel`
109
+ even when the selected content shows its own short text.
110
+
104
111
  Use `hint` for persistent supporting text below the control; use
105
112
  `placeholderText` only for the empty value shown inside the closed control.
106
113
  Kerf passes hint text through Web Awesome's form-control contract, which renders
@@ -346,6 +353,9 @@ workspace action in `end`; TabBar keeps the adjacent action immediately after
346
353
  the shrinkable/scrolling tabs and pins `end` at the far edge. Leading,
347
354
  trailing, and end actions remain visible and do not shrink. The component owns
348
355
  that geometry; applications must not override its anatomy to create the split.
356
+ `trailing` and `end` each accept one `ToolbarControlGroup` for grouped controls
357
+ or one standalone `wa-button` when a primary action needs its own Web Awesome
358
+ chrome. Do not add a wrapper or flex margins to position the action.
349
359
  `AppTab` provides compact 32px, segmented, truncating-label, and icon-only
350
360
  presentations. Icon-only tabs keep the required `name` as the tab button's
351
361
  accessible name while visually hiding the duplicate label. The default name
package/docs/catalog.md CHANGED
@@ -441,6 +441,9 @@ revealCatalogEntry(app, initial, { block: "center" });
441
441
  the preview (`scroll`), or stay pinned while the entry pane is tall enough and
442
442
  scroll with the preview when it is short (`auto`, the default) — so a short
443
443
  window or large text never squeezes the preview out.
444
+ The resource footer uses `ToolbarControlGroup overflow="wrap"`: whole links
445
+ move to another row when they do not fit, keeping Guidance and source labels
446
+ readable without horizontal scrolling.
444
447
  - **`sidebar`** configures the sidebar rail — it forwards to the Workbench's left
445
448
  rail: `size` (default 288px), `resizable` (`true` or `{ min, max }`),
446
449
  `separator`, `collapseMotion`, `presentation`, `responsiveOverlayAt` (default