@kerfjs/ui 5.0.0-beta.77 → 5.0.0-beta.79

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 (128) hide show
  1. package/README.md +9 -4
  2. package/ai/application-ui-diagnostic-ids-v1.json +4 -0
  3. package/ai/compile-time-contracts-v1.json +3 -3
  4. package/ai/component-catalog.json +152 -31
  5. package/ai/component-composition-rules.json +6 -14
  6. package/ai/component-composition.json +123 -29
  7. package/ai/components/README.md +1 -1
  8. package/ai/components/document-baseline.md +1 -1
  9. package/ai/components/nav-stack.md +6 -6
  10. package/ai/components/pane.md +3 -1
  11. package/ai/components/surface-scaffold.md +11 -2
  12. package/ai/components/{tab-scaffold.md → tab-navigator.md} +14 -14
  13. package/ai/components/token-search-field.md +1 -0
  14. package/ai/components/toolbar-control-group.md +2 -0
  15. package/ai/components/toolbar-text.md +2 -0
  16. package/ai/components/toolbar.md +6 -8
  17. package/ai/public-api-signatures-v1.md +68 -140
  18. package/ai/skill.md +15 -4
  19. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  20. package/dist/browser/nav-stack.js +2 -0
  21. package/dist/browser/split-view.js +2 -0
  22. package/dist/browser/tab-navigator.js +4 -0
  23. package/dist/catalog-resources.d.ts +3 -3
  24. package/dist/catalog.d.ts +3 -3
  25. package/dist/catalog.js +3 -3
  26. package/dist/{chunk-WJN3V2H5.js → chunk-2GOCOLQL.js} +18 -4
  27. package/dist/chunk-2GOCOLQL.js.map +1 -0
  28. package/dist/{chunk-QYXKMLHO.js → chunk-3CXRQAYT.js} +2 -2
  29. package/dist/chunk-3CXRQAYT.js.map +1 -0
  30. package/dist/{chunk-G4VKQP7B.js → chunk-3SXWV2IR.js} +5 -1
  31. package/dist/chunk-3SXWV2IR.js.map +1 -0
  32. package/dist/{chunk-VLPE6OPN.js → chunk-62VMNBV2.js} +6 -2
  33. package/dist/chunk-62VMNBV2.js.map +1 -0
  34. package/dist/{chunk-XIZRXI7N.js → chunk-A7DYEERU.js} +13 -1
  35. package/dist/chunk-A7DYEERU.js.map +1 -0
  36. package/dist/{chunk-6VQPLV3O.js → chunk-DSLRNR43.js} +9 -8
  37. package/dist/chunk-DSLRNR43.js.map +1 -0
  38. package/dist/{chunk-AOAW55JN.js → chunk-DXQZ3BEO.js} +4 -1
  39. package/dist/chunk-DXQZ3BEO.js.map +1 -0
  40. package/dist/chunk-IKCUPTR2.js +170 -0
  41. package/dist/chunk-IKCUPTR2.js.map +1 -0
  42. package/dist/{chunk-Z6PE5T7N.js → chunk-JL4BBZP4.js} +4 -3
  43. package/dist/chunk-JL4BBZP4.js.map +1 -0
  44. package/dist/collapsible-panel.js +2 -2
  45. package/dist/index.d.ts +1 -1
  46. package/dist/index.js +8 -8
  47. package/dist/nav-stack-B1Qc2e5q.d.ts +101 -0
  48. package/dist/nav-stack.d.ts +11 -93
  49. package/dist/nav-stack.js +5 -1
  50. package/dist/pane.d.ts +5 -2
  51. package/dist/pane.js +1 -1
  52. package/dist/split-view.d.ts +9 -4
  53. package/dist/split-view.js +7 -3
  54. package/dist/split-view.js.map +1 -1
  55. package/dist/styles/components/actions/toolbar/toolbar.css +7 -14
  56. package/dist/styles/components/actions/toolbar-control-group/toolbar-control-group.css +63 -13
  57. package/dist/styles/components/actions/toolbar-text/toolbar-text.css +8 -1
  58. package/dist/styles/components/forms/token-search-field/token-search-field.css +12 -1
  59. package/dist/styles/components/layout/pane/pane.css +18 -1
  60. package/dist/styles/components/navigation/nav-stack/nav-stack.css +6 -12
  61. package/dist/styles/components/navigation/tab-scaffold/tab-scaffold.css +18 -1
  62. package/dist/styles/components/surfaces/surface-scaffold/surface-scaffold.css +55 -0
  63. package/dist/styles/nav-stack.css +6 -12
  64. package/dist/styles/pane.css +18 -1
  65. package/dist/styles/surface-scaffold.css +55 -0
  66. package/dist/styles/{tab-scaffold.css → tab-navigator.css} +18 -1
  67. package/dist/styles/token-search-field.css +12 -1
  68. package/dist/styles/toolbar-control-group.css +63 -13
  69. package/dist/styles/toolbar-text.css +8 -1
  70. package/dist/styles/toolbar.css +7 -14
  71. package/dist/surface-scaffold-register.d.ts +4 -0
  72. package/dist/surface-scaffold-register.js +59 -0
  73. package/dist/surface-scaffold-register.js.map +1 -0
  74. package/dist/surface-scaffold.d.ts +10 -2
  75. package/dist/surface-scaffold.js +1 -1
  76. package/dist/{tab-scaffold.d.ts → tab-navigator.d.ts} +12 -10
  77. package/dist/{tab-scaffold.js → tab-navigator.js} +4 -3
  78. package/dist/tab-navigator.js.map +1 -0
  79. package/dist/token-search-field.js +1 -1
  80. package/dist/wire-catalog.js +1 -1
  81. package/dist/wire-scroll-dividers.d.ts +3 -3
  82. package/dist/wire-scroll-dividers.js +1 -1
  83. package/dist/wire-tab-navigator.d.ts +11 -0
  84. package/dist/{wire-tab-scaffold.js → wire-tab-navigator.js} +3 -3
  85. package/dist/wire-tab-navigator.js.map +1 -0
  86. package/dist/wire-token-search-fields.js +1 -1
  87. package/dist/wire-toolbar-visibility.js +1 -1
  88. package/dist/workbench.d.ts +5 -13
  89. package/dist/workbench.js +1 -1
  90. package/docs/app-layouts.md +44 -11
  91. package/docs/component-contract.md +9 -2
  92. package/docs/component-selection.md +17 -15
  93. package/docs/design/templates/token-search-field/empty-dark.svg +1 -1
  94. package/docs/design/templates/token-search-field/empty.svg +1 -1
  95. package/docs/design/templates/token-search-field-dark.svg +1 -1
  96. package/docs/design/templates/token-search-field.svg +1 -1
  97. package/docs/design/templates.md +1 -1
  98. package/docs/examples/application-ui-profile.json +4 -4
  99. package/docs/layout.md +31 -8
  100. package/docs/nav-stack.md +30 -18
  101. package/docs/recipes.md +6 -2
  102. package/docs/split-view.md +7 -4
  103. package/docs/surface-scaffold.md +46 -0
  104. package/docs/{tab-scaffold.md → tab-navigator.md} +83 -11
  105. package/docs/type-contracts.md +3 -3
  106. package/docs/ui-analyzer.md +5 -0
  107. package/docs/ui-doctor.md +33 -0
  108. package/docs/workbench.md +3 -2
  109. package/doctor/component-style-checks.mjs +457 -0
  110. package/doctor/index.mjs +43 -13
  111. package/llms.txt +18 -6
  112. package/package.json +16 -11
  113. package/ux-demo/recipes/list-detail-dialog.tsx +4 -0
  114. package/ux-demo/recipes/navigation-stack.tsx +2 -2
  115. package/dist/browser/tab-scaffold.js +0 -4
  116. package/dist/chunk-6VQPLV3O.js.map +0 -1
  117. package/dist/chunk-AOAW55JN.js.map +0 -1
  118. package/dist/chunk-G4VKQP7B.js.map +0 -1
  119. package/dist/chunk-QYXKMLHO.js.map +0 -1
  120. package/dist/chunk-VLPE6OPN.js.map +0 -1
  121. package/dist/chunk-WJN3V2H5.js.map +0 -1
  122. package/dist/chunk-XIZRXI7N.js.map +0 -1
  123. package/dist/chunk-Z4EPMX25.js +0 -123
  124. package/dist/chunk-Z4EPMX25.js.map +0 -1
  125. package/dist/chunk-Z6PE5T7N.js.map +0 -1
  126. package/dist/tab-scaffold.js.map +0 -1
  127. package/dist/wire-tab-scaffold.d.ts +0 -11
  128. package/dist/wire-tab-scaffold.js.map +0 -1
@@ -142,6 +142,10 @@
142
142
  its first and last items can always be scrolled clear of it. A header or
143
143
  footer already owns that edge. */
144
144
  .kui-pane__content {
145
+ /* Descendants can use these resolved insets to bleed decoration to the
146
+ pane edge while keeping their own content aligned with ordinary items. */
147
+ --kui-pane-content-inset-inline-start: var(--_kui-pane-safe-inline-start);
148
+ --kui-pane-content-inset-inline-end: var(--_kui-pane-safe-inline-end);
145
149
  --_kui-pane-content-block-start: var(--_kui-pane-safe-block-start);
146
150
  --_kui-pane-content-block-end: var(--_kui-pane-safe-block-end);
147
151
  min-width: 0;
@@ -154,10 +158,23 @@
154
158
  }
155
159
 
156
160
  .kui-pane > .kui-pane__content {
161
+ padding-inline: var(--kui-pane-content-inset-inline-start)
162
+ var(--kui-pane-content-inset-inline-end);
157
163
  padding-block: var(--_kui-pane-content-block-start)
158
164
  var(--_kui-pane-content-block-end);
159
165
  }
160
166
 
167
+ /* Add one outer gutter without changing the inherited item-margin token.
168
+ Nested Row, List, and Grid therefore keep their own default 8px insets. */
169
+ .kui-pane[data-deep-inset="true"] > .kui-pane__content {
170
+ --kui-pane-content-inset-inline-start: calc(
171
+ var(--_kui-pane-safe-inline-start) + var(--kui-space-xs)
172
+ );
173
+ --kui-pane-content-inset-inline-end: calc(
174
+ var(--_kui-pane-safe-inline-end) + var(--kui-space-xs)
175
+ );
176
+ }
177
+
161
178
  .kui-pane__header ~ .kui-pane__content {
162
179
  --_kui-pane-content-block-start: 0px;
163
180
  }
@@ -253,7 +270,7 @@
253
270
  --kui-edge-inset-inline-end: var(--_kui-workbench-content-edge-inline-end);
254
271
  }
255
272
 
256
- /* As the only child of a NavStack view or a TabScaffold scene, a Pane fills
273
+ /* As the only child of a NavStack view or a TabNavigator scene, a Pane fills
257
274
  it too, so its content owns the scroll and its header and footer stay
258
275
  pinned; the view or scene then never scrolls (it hands the Pane its
259
276
  safe-area edge context, which the Pane's slots apply). */
@@ -71,10 +71,6 @@
71
71
  background: var(--kui-color-surface);
72
72
  }
73
73
 
74
- .kui-nav-stack__header {
75
- min-width: 0;
76
- }
77
-
78
74
  .kui-nav-stack__viewport {
79
75
  --kui-edge-inset-block-start: var(--_kui-nav-stack-safe-block-start);
80
76
  --kui-edge-inset-block-end: var(--_kui-nav-stack-safe-block-end);
@@ -106,11 +102,9 @@
106
102
  inset: 0;
107
103
  }
108
104
 
109
- .kui-nav-stack__view[data-appearance="sunken"] {
110
- background: var(
111
- --kui-sunken-panel-background,
112
- var(--kui-color-surface-lowered)
113
- );
105
+ .kui-nav-stack__view:has(> [data-component="pane"]) {
106
+ display: grid;
107
+ overflow: hidden;
114
108
  }
115
109
 
116
110
  /* Each view is its region's scroll owner: block insets become padding inside
@@ -180,9 +174,9 @@
180
174
  }
181
175
 
182
176
  .kui-nav-stack__bottom {
183
- padding-block-end: var(--_kui-nav-stack-safe-block-end);
184
- padding-inline: var(--_kui-nav-stack-safe-inline-start)
185
- var(--_kui-nav-stack-safe-inline-end);
177
+ --kui-edge-inset-block-end: var(--_kui-nav-stack-safe-block-end);
178
+ --kui-edge-inset-inline-start: var(--_kui-nav-stack-safe-inline-start);
179
+ --kui-edge-inset-inline-end: var(--_kui-nav-stack-safe-inline-end);
186
180
  border-block-start: 1px solid
187
181
  var(--_kui-nav-stack-bottom-divider, transparent);
188
182
  background: var(--kui-color-surface);
@@ -73,6 +73,23 @@
73
73
  scroll-padding-block-start: var(--kui-edge-inset-block-start);
74
74
  }
75
75
 
76
+ /* A plain scene adds one outer gutter; a sole Pane or layout keeps ownership
77
+ of its own content and may opt into deepInset there. */
78
+ .kui-tab-scaffold__scene[data-deep-inset="true"]:not(
79
+ :has(
80
+ > :is(
81
+ [data-component="pane"],
82
+ [data-component="nav-stack"],
83
+ [data-component="split-view"],
84
+ [data-component="workbench"],
85
+ [data-component="tab-scaffold"]
86
+ ):only-child
87
+ )
88
+ ) {
89
+ padding-inline: calc(var(--kui-edge-inset-inline-start) + var(--kui-space-xs))
90
+ calc(var(--kui-edge-inset-inline-end) + var(--kui-space-xs));
91
+ }
92
+
76
93
  .kui-tab-scaffold__scene
77
94
  > :not(
78
95
  :is(
@@ -192,7 +209,7 @@
192
209
 
193
210
  /* As the only child of a Workbench region (its main area or a panel's
194
211
  content, which the Workbench marks with `data-workbench-main` /
195
- `data-workbench-panel-content`), a TabScaffold fills the region, so a
212
+ `data-workbench-panel-content`), a TabNavigator fills the region, so a
196
213
  composed toolbar's footer (or the app's own) sits at the region's bottom
197
214
  edge rather than under short content. */
198
215
  :is([data-workbench-main], [data-workbench-panel-content])
@@ -1,12 +1,67 @@
1
1
  .kui-dialog-surface > wa-dialog {
2
+ --_kui-dialog-surface-width: 35rem;
3
+ --_kui-dialog-surface-resolved-gutter: max(
4
+ 0px,
5
+ var(--_kui-dialog-surface-gutter, 1rem)
6
+ );
2
7
  --width: min(35rem, calc(100vw - 2rem));
3
8
  }
4
9
  .kui-dialog-surface[data-size="small"] > wa-dialog {
10
+ --_kui-dialog-surface-width: 25rem;
5
11
  --width: min(25rem, calc(100vw - 2rem));
6
12
  }
7
13
  .kui-dialog-surface[data-size="large"] > wa-dialog {
14
+ --_kui-dialog-surface-width: 50rem;
8
15
  --width: min(50rem, calc(100vw - 2rem));
9
16
  }
17
+ .kui-dialog-surface[data-presentation="modal"][data-preferred-width]
18
+ > wa-dialog {
19
+ --width: min(
20
+ var(--_kui-dialog-surface-preferred-width),
21
+ calc(100vw - 2rem)
22
+ );
23
+ }
24
+ .kui-dialog-surface[data-presentation="modal"][data-viewport-gutter]
25
+ > wa-dialog {
26
+ --width: min(
27
+ var(
28
+ --_kui-dialog-surface-preferred-width,
29
+ var(--_kui-dialog-surface-width)
30
+ ),
31
+ max(
32
+ 0px,
33
+ calc(
34
+ 100vw - var(--_kui-dialog-surface-resolved-gutter) -
35
+ var(--_kui-dialog-surface-resolved-gutter)
36
+ )
37
+ )
38
+ );
39
+ }
40
+ /* Web Awesome has a separate max-width clamp; setting --width alone cannot
41
+ provide an 8px phone gutter. Omitted props retain its legacy geometry. */
42
+ .kui-dialog-surface[data-presentation="modal"][data-viewport-gutter]
43
+ > wa-dialog::part(dialog) {
44
+ max-width: max(
45
+ 0px,
46
+ calc(
47
+ 100vw - var(--_kui-dialog-surface-resolved-gutter) -
48
+ var(--_kui-dialog-surface-resolved-gutter)
49
+ )
50
+ );
51
+ }
52
+ .kui-dialog-surface[data-presentation="modal"][data-max-height]
53
+ > wa-dialog::part(dialog) {
54
+ max-height: max(
55
+ 0px,
56
+ min(
57
+ var(--_kui-dialog-surface-max-height, 100dvh),
58
+ calc(
59
+ 100dvh - var(--_kui-dialog-surface-resolved-gutter) -
60
+ var(--_kui-dialog-surface-resolved-gutter)
61
+ )
62
+ )
63
+ );
64
+ }
10
65
  .kui-dialog-surface[data-body-inset="none"] > wa-dialog::part(body),
11
66
  .kui-dialog-surface[data-footer-inset="none"] > wa-dialog::part(footer) {
12
67
  padding: 0;
@@ -71,10 +71,6 @@
71
71
  background: var(--kui-color-surface);
72
72
  }
73
73
 
74
- .kui-nav-stack__header {
75
- min-width: 0;
76
- }
77
-
78
74
  .kui-nav-stack__viewport {
79
75
  --kui-edge-inset-block-start: var(--_kui-nav-stack-safe-block-start);
80
76
  --kui-edge-inset-block-end: var(--_kui-nav-stack-safe-block-end);
@@ -106,11 +102,9 @@
106
102
  inset: 0;
107
103
  }
108
104
 
109
- .kui-nav-stack__view[data-appearance="sunken"] {
110
- background: var(
111
- --kui-sunken-panel-background,
112
- var(--kui-color-surface-lowered)
113
- );
105
+ .kui-nav-stack__view:has(> [data-component="pane"]) {
106
+ display: grid;
107
+ overflow: hidden;
114
108
  }
115
109
 
116
110
  /* Each view is its region's scroll owner: block insets become padding inside
@@ -180,9 +174,9 @@
180
174
  }
181
175
 
182
176
  .kui-nav-stack__bottom {
183
- padding-block-end: var(--_kui-nav-stack-safe-block-end);
184
- padding-inline: var(--_kui-nav-stack-safe-inline-start)
185
- var(--_kui-nav-stack-safe-inline-end);
177
+ --kui-edge-inset-block-end: var(--_kui-nav-stack-safe-block-end);
178
+ --kui-edge-inset-inline-start: var(--_kui-nav-stack-safe-inline-start);
179
+ --kui-edge-inset-inline-end: var(--_kui-nav-stack-safe-inline-end);
186
180
  border-block-start: 1px solid
187
181
  var(--_kui-nav-stack-bottom-divider, transparent);
188
182
  background: var(--kui-color-surface);
@@ -142,6 +142,10 @@
142
142
  its first and last items can always be scrolled clear of it. A header or
143
143
  footer already owns that edge. */
144
144
  .kui-pane__content {
145
+ /* Descendants can use these resolved insets to bleed decoration to the
146
+ pane edge while keeping their own content aligned with ordinary items. */
147
+ --kui-pane-content-inset-inline-start: var(--_kui-pane-safe-inline-start);
148
+ --kui-pane-content-inset-inline-end: var(--_kui-pane-safe-inline-end);
145
149
  --_kui-pane-content-block-start: var(--_kui-pane-safe-block-start);
146
150
  --_kui-pane-content-block-end: var(--_kui-pane-safe-block-end);
147
151
  min-width: 0;
@@ -154,10 +158,23 @@
154
158
  }
155
159
 
156
160
  .kui-pane > .kui-pane__content {
161
+ padding-inline: var(--kui-pane-content-inset-inline-start)
162
+ var(--kui-pane-content-inset-inline-end);
157
163
  padding-block: var(--_kui-pane-content-block-start)
158
164
  var(--_kui-pane-content-block-end);
159
165
  }
160
166
 
167
+ /* Add one outer gutter without changing the inherited item-margin token.
168
+ Nested Row, List, and Grid therefore keep their own default 8px insets. */
169
+ .kui-pane[data-deep-inset="true"] > .kui-pane__content {
170
+ --kui-pane-content-inset-inline-start: calc(
171
+ var(--_kui-pane-safe-inline-start) + var(--kui-space-xs)
172
+ );
173
+ --kui-pane-content-inset-inline-end: calc(
174
+ var(--_kui-pane-safe-inline-end) + var(--kui-space-xs)
175
+ );
176
+ }
177
+
161
178
  .kui-pane__header ~ .kui-pane__content {
162
179
  --_kui-pane-content-block-start: 0px;
163
180
  }
@@ -253,7 +270,7 @@
253
270
  --kui-edge-inset-inline-end: var(--_kui-workbench-content-edge-inline-end);
254
271
  }
255
272
 
256
- /* As the only child of a NavStack view or a TabScaffold scene, a Pane fills
273
+ /* As the only child of a NavStack view or a TabNavigator scene, a Pane fills
257
274
  it too, so its content owns the scroll and its header and footer stay
258
275
  pinned; the view or scene then never scrolls (it hands the Pane its
259
276
  safe-area edge context, which the Pane's slots apply). */
@@ -1,12 +1,67 @@
1
1
  .kui-dialog-surface > wa-dialog {
2
+ --_kui-dialog-surface-width: 35rem;
3
+ --_kui-dialog-surface-resolved-gutter: max(
4
+ 0px,
5
+ var(--_kui-dialog-surface-gutter, 1rem)
6
+ );
2
7
  --width: min(35rem, calc(100vw - 2rem));
3
8
  }
4
9
  .kui-dialog-surface[data-size="small"] > wa-dialog {
10
+ --_kui-dialog-surface-width: 25rem;
5
11
  --width: min(25rem, calc(100vw - 2rem));
6
12
  }
7
13
  .kui-dialog-surface[data-size="large"] > wa-dialog {
14
+ --_kui-dialog-surface-width: 50rem;
8
15
  --width: min(50rem, calc(100vw - 2rem));
9
16
  }
17
+ .kui-dialog-surface[data-presentation="modal"][data-preferred-width]
18
+ > wa-dialog {
19
+ --width: min(
20
+ var(--_kui-dialog-surface-preferred-width),
21
+ calc(100vw - 2rem)
22
+ );
23
+ }
24
+ .kui-dialog-surface[data-presentation="modal"][data-viewport-gutter]
25
+ > wa-dialog {
26
+ --width: min(
27
+ var(
28
+ --_kui-dialog-surface-preferred-width,
29
+ var(--_kui-dialog-surface-width)
30
+ ),
31
+ max(
32
+ 0px,
33
+ calc(
34
+ 100vw - var(--_kui-dialog-surface-resolved-gutter) -
35
+ var(--_kui-dialog-surface-resolved-gutter)
36
+ )
37
+ )
38
+ );
39
+ }
40
+ /* Web Awesome has a separate max-width clamp; setting --width alone cannot
41
+ provide an 8px phone gutter. Omitted props retain its legacy geometry. */
42
+ .kui-dialog-surface[data-presentation="modal"][data-viewport-gutter]
43
+ > wa-dialog::part(dialog) {
44
+ max-width: max(
45
+ 0px,
46
+ calc(
47
+ 100vw - var(--_kui-dialog-surface-resolved-gutter) -
48
+ var(--_kui-dialog-surface-resolved-gutter)
49
+ )
50
+ );
51
+ }
52
+ .kui-dialog-surface[data-presentation="modal"][data-max-height]
53
+ > wa-dialog::part(dialog) {
54
+ max-height: max(
55
+ 0px,
56
+ min(
57
+ var(--_kui-dialog-surface-max-height, 100dvh),
58
+ calc(
59
+ 100dvh - var(--_kui-dialog-surface-resolved-gutter) -
60
+ var(--_kui-dialog-surface-resolved-gutter)
61
+ )
62
+ )
63
+ );
64
+ }
10
65
  .kui-dialog-surface[data-body-inset="none"] > wa-dialog::part(body),
11
66
  .kui-dialog-surface[data-footer-inset="none"] > wa-dialog::part(footer) {
12
67
  padding: 0;
@@ -73,6 +73,23 @@
73
73
  scroll-padding-block-start: var(--kui-edge-inset-block-start);
74
74
  }
75
75
 
76
+ /* A plain scene adds one outer gutter; a sole Pane or layout keeps ownership
77
+ of its own content and may opt into deepInset there. */
78
+ .kui-tab-scaffold__scene[data-deep-inset="true"]:not(
79
+ :has(
80
+ > :is(
81
+ [data-component="pane"],
82
+ [data-component="nav-stack"],
83
+ [data-component="split-view"],
84
+ [data-component="workbench"],
85
+ [data-component="tab-scaffold"]
86
+ ):only-child
87
+ )
88
+ ) {
89
+ padding-inline: calc(var(--kui-edge-inset-inline-start) + var(--kui-space-xs))
90
+ calc(var(--kui-edge-inset-inline-end) + var(--kui-space-xs));
91
+ }
92
+
76
93
  .kui-tab-scaffold__scene
77
94
  > :not(
78
95
  :is(
@@ -192,7 +209,7 @@
192
209
 
193
210
  /* As the only child of a Workbench region (its main area or a panel's
194
211
  content, which the Workbench marks with `data-workbench-main` /
195
- `data-workbench-panel-content`), a TabScaffold fills the region, so a
212
+ `data-workbench-panel-content`), a TabNavigator fills the region, so a
196
213
  composed toolbar's footer (or the app's own) sits at the region's bottom
197
214
  edge rather than under short content. */
198
215
  :is([data-workbench-main], [data-workbench-panel-content])
@@ -82,6 +82,7 @@
82
82
 
83
83
  .kui-token-search__editor {
84
84
  grid-column: 2;
85
+ grid-row: 1;
85
86
  min-width: var(--kui-token-search-editor-min-width, 0px);
86
87
  min-height: var(--kui-token-search-line-size);
87
88
  padding-block: calc((var(--kui-token-search-line-size) - 1.35em) / 2) 0;
@@ -104,10 +105,20 @@
104
105
  }
105
106
  }
106
107
 
107
- .kui-token-search__editor:empty::before {
108
+ .kui-token-search[data-placeholder-visible="true"]:has(
109
+ > .kui-token-search__editor
110
+ )::before {
111
+ grid-column: 2;
112
+ grid-row: 1;
113
+ min-width: 0;
114
+ padding-block: calc((var(--kui-token-search-line-size) - 1.35em) / 2) 0;
108
115
  color: var(--kui-color-text-quiet);
109
116
  content: attr(data-placeholder);
117
+ font-size: var(--kui-font-s);
118
+ line-height: 1.35;
119
+ overflow: hidden;
110
120
  pointer-events: none;
121
+ white-space: nowrap;
111
122
  }
112
123
 
113
124
  .kui-token-search__token {
@@ -80,6 +80,7 @@
80
80
  top margin, so it centers in the band by its own size. */
81
81
  :is(.kui-toolbar__leading, .kui-toolbar__center, .kui-toolbar__trailing)
82
82
  > .kui-toolbar-control-group {
83
+ align-self: flex-start;
83
84
  margin-block-start: max(
84
85
  0px,
85
86
  calc(
@@ -610,17 +611,23 @@
610
611
  wa-button,
611
612
  .kui-select,
612
613
  .kui-toolbar-action-link
613
- ):only-child
614
+ ):nth-child(1 of :where(:not([data-toolbar-visibility-state]))):where(
615
+ :nth-last-child(1 of :not([data-toolbar-visibility-state]))
616
+ )
614
617
  ):hover {
615
618
  background-color: var(--kui-toolbar-control-hover-background);
616
619
  }
617
620
 
618
621
  .kui-toolbar-control-group:not([data-single="true"]):has(
619
- > :is(button, wa-button, .kui-toolbar-action-link):only-child
622
+ > :is(button, wa-button, .kui-toolbar-action-link):nth-child(
623
+ 1 of :where(:not([data-toolbar-visibility-state]))
624
+ ):where(:nth-last-child(1 of :not([data-toolbar-visibility-state])))
620
625
  )
621
626
  > :is(button, wa-button, .kui-toolbar-action-link):hover,
622
627
  .kui-toolbar-control-group:not([data-single="true"]):has(
623
- > :is(button, wa-button):only-child
628
+ > :is(button, wa-button):nth-child(
629
+ 1 of :where(:not([data-toolbar-visibility-state]))
630
+ ):where(:nth-last-child(1 of :not([data-toolbar-visibility-state])))
624
631
  )
625
632
  > wa-button:hover::part(base) {
626
633
  border-color: transparent;
@@ -758,6 +765,7 @@
758
765
  lone control belongs to the outer group surface; in a group of choices the
759
766
  image belongs only to the selected highlight. */
760
767
  .kui-toolbar-control-group[data-content="avatar"] {
768
+ background-origin: border-box;
761
769
  background-position: center;
762
770
  background-repeat: no-repeat;
763
771
  background-size: contain;
@@ -765,29 +773,46 @@
765
773
 
766
774
  .kui-toolbar-control-group[data-content="avatar"]:is(
767
775
  [data-single="true"],
768
- :has(> :is(button, wa-button):only-child)
776
+ :has(
777
+ > :is(button, wa-button):nth-child(
778
+ 1 of :where(:not([data-toolbar-visibility-state]))
779
+ ):where(:nth-last-child(1 of :not([data-toolbar-visibility-state])))
780
+ )
769
781
  ) {
770
782
  background-image: var(--kui-toolbar-avatar-image);
771
783
  }
772
784
 
773
785
  .kui-toolbar-control-group[data-content="avatar"]:is(
774
786
  [data-single="true"],
775
- :has(> :is(button, wa-button):only-child)
787
+ :has(
788
+ > :is(button, wa-button):nth-child(
789
+ 1 of :where(:not([data-toolbar-visibility-state]))
790
+ ):where(:nth-last-child(1 of :not([data-toolbar-visibility-state])))
791
+ )
776
792
  )
777
793
  > :is(button, wa-button) {
778
794
  color: transparent;
779
795
  }
780
796
 
781
797
  .kui-toolbar-control-group[data-content="avatar"][data-single="false"]:not(
782
- :has(> :is(button, wa-button):only-child)
798
+ :has(
799
+ > :is(button, wa-button):nth-child(
800
+ 1 of :where(:not([data-toolbar-visibility-state]))
801
+ ):where(:nth-last-child(1 of :not([data-toolbar-visibility-state])))
802
+ )
783
803
  )
784
804
  > button[aria-pressed="true"],
785
805
  .kui-toolbar-control-group[data-content="avatar"][data-single="false"]:not(
786
- :has(> :is(button, wa-button):only-child)
806
+ :has(
807
+ > :is(button, wa-button):nth-child(
808
+ 1 of :where(:not([data-toolbar-visibility-state]))
809
+ ):where(:nth-last-child(1 of :not([data-toolbar-visibility-state])))
810
+ )
787
811
  )
788
812
  > wa-button[aria-pressed="true"]::part(base) {
789
813
  color: transparent;
790
814
  background-image: var(--kui-toolbar-avatar-image);
815
+ background-origin: border-box;
791
816
  background-position: center;
792
817
  background-repeat: no-repeat;
793
818
  background-size: contain;
@@ -798,7 +823,10 @@
798
823
 
799
824
  .kui-toolbar-control-group[data-single="true"][data-appearance="contained"][data-tile-tone="neutral"]:has(
800
825
  > svg[aria-hidden="true"]
801
- ):not(:has(> :not(svg[aria-hidden="true"])), :has(> svg ~ svg)) {
826
+ ):not(
827
+ :has(> :not(svg[aria-hidden="true"], [data-toolbar-visibility-state])),
828
+ :has(> svg ~ svg)
829
+ ) {
802
830
  background: var(--kui-color-neutral-fill-quiet);
803
831
  border-color: var(--kui-color-neutral-border-quiet);
804
832
  color: var(--kui-color-neutral-on-quiet);
@@ -806,7 +834,10 @@
806
834
 
807
835
  .kui-toolbar-control-group[data-single="true"][data-appearance="contained"][data-tile-tone="brand"]:has(
808
836
  > svg[aria-hidden="true"]
809
- ):not(:has(> :not(svg[aria-hidden="true"])), :has(> svg ~ svg)) {
837
+ ):not(
838
+ :has(> :not(svg[aria-hidden="true"], [data-toolbar-visibility-state])),
839
+ :has(> svg ~ svg)
840
+ ) {
810
841
  background: var(--kui-color-brand-fill-quiet);
811
842
  border-color: var(--kui-color-brand-border-quiet);
812
843
  color: var(--kui-color-brand-on-quiet);
@@ -814,7 +845,10 @@
814
845
 
815
846
  .kui-toolbar-control-group[data-single="true"][data-appearance="contained"][data-tile-tone="success"]:has(
816
847
  > svg[aria-hidden="true"]
817
- ):not(:has(> :not(svg[aria-hidden="true"])), :has(> svg ~ svg)) {
848
+ ):not(
849
+ :has(> :not(svg[aria-hidden="true"], [data-toolbar-visibility-state])),
850
+ :has(> svg ~ svg)
851
+ ) {
818
852
  background: var(--kui-color-success-fill-quiet);
819
853
  border-color: var(--kui-color-success-border-quiet);
820
854
  color: var(--kui-color-success-on-quiet);
@@ -822,7 +856,10 @@
822
856
 
823
857
  .kui-toolbar-control-group[data-single="true"][data-appearance="contained"][data-tile-tone="warning"]:has(
824
858
  > svg[aria-hidden="true"]
825
- ):not(:has(> :not(svg[aria-hidden="true"])), :has(> svg ~ svg)) {
859
+ ):not(
860
+ :has(> :not(svg[aria-hidden="true"], [data-toolbar-visibility-state])),
861
+ :has(> svg ~ svg)
862
+ ) {
826
863
  background: var(--kui-color-warning-fill-quiet);
827
864
  border-color: var(--kui-color-warning-border-quiet);
828
865
  color: var(--kui-color-warning-on-quiet);
@@ -830,12 +867,25 @@
830
867
 
831
868
  .kui-toolbar-control-group[data-single="true"][data-appearance="contained"][data-tile-tone="danger"]:has(
832
869
  > svg[aria-hidden="true"]
833
- ):not(:has(> :not(svg[aria-hidden="true"])), :has(> svg ~ svg)) {
870
+ ):not(
871
+ :has(> :not(svg[aria-hidden="true"], [data-toolbar-visibility-state])),
872
+ :has(> svg ~ svg)
873
+ ) {
834
874
  background: var(--kui-color-danger-fill-quiet);
835
875
  border-color: var(--kui-color-danger-border-quiet);
836
876
  color: var(--kui-color-danger-on-quiet);
837
877
  }
838
878
  .kui-toolbar-control-group[data-toolbar-width-hidden="true"],
839
- .kui-toolbar-control-group__busy-status[data-toolbar-width-hidden="true"] {
879
+ .kui-toolbar-control-group__busy-status[data-toolbar-width-hidden="true"],
880
+ .kui-toolbar-control-group:has(
881
+ > [data-toolbar-visibility-state][data-toolbar-width-hidden="true"]
882
+ ),
883
+ .kui-toolbar-control-group__busy-status:has(
884
+ > [data-toolbar-visibility-state][data-toolbar-width-hidden="true"]
885
+ ) {
886
+ display: none;
887
+ }
888
+ .kui-toolbar-control-group > [data-toolbar-visibility-state],
889
+ .kui-toolbar-control-group__busy-status > [data-toolbar-visibility-state] {
840
890
  display: none;
841
891
  }
@@ -39,6 +39,7 @@ button.kui-toolbar-text:focus-visible {
39
39
  heights. */
40
40
  :is(.kui-toolbar__leading, .kui-toolbar__center, .kui-toolbar__trailing)
41
41
  > .kui-toolbar-text {
42
+ align-self: flex-start;
42
43
  height: auto;
43
44
  min-height: var(--_kui-toolbar-band);
44
45
  }
@@ -159,6 +160,12 @@ button.kui-toolbar-text[data-tone="dark"]:hover {
159
160
  line-clamp: none;
160
161
  max-height: calc(var(--kui-toolbar-text-max-lines) * 1.25em);
161
162
  }
162
- .kui-toolbar-text[data-toolbar-width-hidden="true"] {
163
+ .kui-toolbar-text[data-toolbar-width-hidden="true"],
164
+ .kui-toolbar-text:has(
165
+ > [data-toolbar-visibility-state][data-toolbar-width-hidden="true"]
166
+ ) {
167
+ display: none;
168
+ }
169
+ .kui-toolbar-text > [data-toolbar-visibility-state] {
163
170
  display: none;
164
171
  }
@@ -150,19 +150,11 @@
150
150
  );
151
151
  }
152
152
 
153
- /* The control band. Every zone reserves one group-height row at the top of
154
- the toolbar, and each item is centered in that band by its own size, not by
155
- its siblings: a group or title shorter than the band takes half the
156
- difference as a top margin, and anything taller (a wrapped title, a
157
- multi-line search, a second trailing row) starts at the band's top and grows
158
- down. A growing item therefore never moves the other items or its own top.
159
- Centering the zones in the toolbar row instead dropped every control to the
160
- middle of a two-line title. The band is resolved here, on the toolbar, so a
161
- compact group's own smaller group size never redefines it.
162
- `--_kui-toolbar-band` is context the toolbar provides: a ToolbarControlGroup
163
- and a ToolbarText each center themselves in it from their own stylesheets
164
- (toolbar-control-group.css, toolbar-text.css). A direct primary wa-button in
165
- trailing is centered here without altering its Web Awesome chrome. */
153
+ /* Every zone reserves a group-height control band. Direct custom content
154
+ centers against its zone's height by default. ToolbarText,
155
+ ToolbarControlGroup, and standalone wa-button keep their own first-band
156
+ placement, so taller siblings do not move their controls off that axis.
157
+ `--_kui-toolbar-band` is context those components use for that placement. */
166
158
  .kui-toolbar {
167
159
  --_kui-toolbar-band: var(--kui-toolbar-group-size, calc(2px + 2.625rem));
168
160
  }
@@ -175,7 +167,7 @@
175
167
  min-height: var(--_kui-toolbar-band);
176
168
  padding-inline: var(--kui-toolbar-zone-padding-inline, 0px);
177
169
  box-sizing: border-box;
178
- align-items: flex-start;
170
+ align-items: center;
179
171
  gap: var(--kui-toolbar-gap, 0.5rem);
180
172
  }
181
173
 
@@ -243,6 +235,7 @@
243
235
  0px,
244
236
  calc((var(--_kui-toolbar-band) - var(--wa-form-control-height)) / 2)
245
237
  );
238
+ align-self: flex-start;
246
239
  flex: 0 0 auto;
247
240
  }
248
241
 
@@ -0,0 +1,4 @@
1
+ /** Importing this module registers wa-dialog and repairs wrapped native names. */
2
+ declare const surfaceScaffoldElementsRegistered = true;
3
+
4
+ export { surfaceScaffoldElementsRegistered };