@kerfjs/ui 5.0.0-beta.55 → 5.0.0-beta.56
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.
- package/README.md +12 -10
- package/ai/compile-time-contracts-v1.json +2 -2
- package/ai/component-catalog-v2.json +149 -39
- package/ai/component-catalog.json +202 -51
- package/ai/public-api-signatures-v1.md +439 -97
- package/ai/skill.md +43 -40
- package/ai/webawesome-jsx-signatures-v1.md +8 -2
- package/dist/app-tab.js +1 -1
- package/dist/badge.d.ts +35 -7
- package/dist/badge.js +1 -1
- package/dist/browser/content-item.js +3 -0
- package/dist/browser/select.js +1 -0
- package/dist/catalog-resources.d.ts +12 -1
- package/dist/catalog.d.ts +14 -3
- package/dist/catalog.js +52 -43
- package/dist/catalog.js.map +1 -1
- package/dist/{chunk-WZ2GLEY4.js → chunk-2G2ZJQYK.js} +2 -14
- package/dist/chunk-2G2ZJQYK.js.map +1 -0
- package/dist/{chunk-D7GWXIAS.js → chunk-5I7QGQVT.js} +1 -1
- package/dist/chunk-5I7QGQVT.js.map +1 -0
- package/dist/{chunk-RNRUVPJ3.js → chunk-63ZWBGE3.js} +3 -2
- package/dist/chunk-63ZWBGE3.js.map +1 -0
- package/dist/{chunk-44IG7PFV.js → chunk-6CINWX2E.js} +3 -3
- package/dist/{chunk-44IG7PFV.js.map → chunk-6CINWX2E.js.map} +1 -1
- package/dist/{chunk-C2FAYFDE.js → chunk-AGXQQFKZ.js} +2 -2
- package/dist/{chunk-C2FAYFDE.js.map → chunk-AGXQQFKZ.js.map} +1 -1
- package/dist/{chunk-ATHXW6RP.js → chunk-AHEG27M7.js} +2 -2
- package/dist/{chunk-ATHXW6RP.js.map → chunk-AHEG27M7.js.map} +1 -1
- package/dist/{chunk-7GUQYHKA.js → chunk-AK67F6QN.js} +4 -1
- package/dist/chunk-AK67F6QN.js.map +1 -0
- package/dist/chunk-BFPBS5Y4.js +250 -0
- package/dist/chunk-BFPBS5Y4.js.map +1 -0
- package/dist/{chunk-5OLVUEND.js → chunk-DG6G5EPF.js} +4 -6
- package/dist/chunk-DG6G5EPF.js.map +1 -0
- package/dist/{chunk-MTM43SJO.js → chunk-G33XC2NB.js} +1 -1
- package/dist/chunk-G33XC2NB.js.map +1 -0
- package/dist/{chunk-TZ5IHWB2.js → chunk-K6UNVKDK.js} +3 -3
- package/dist/{chunk-TZ5IHWB2.js.map → chunk-K6UNVKDK.js.map} +1 -1
- package/dist/{chunk-HMQ2ZDGG.js → chunk-KROD7KZK.js} +3 -2
- package/dist/chunk-KROD7KZK.js.map +1 -0
- package/dist/{chunk-5NDQABWK.js → chunk-M7QV3IHH.js} +3 -1
- package/dist/chunk-M7QV3IHH.js.map +1 -0
- package/dist/{chunk-RNZAKSME.js → chunk-MA6Z6EIM.js} +3 -3
- package/dist/{chunk-RNZAKSME.js.map → chunk-MA6Z6EIM.js.map} +1 -1
- package/dist/chunk-MA73TA6D.js +42 -0
- package/dist/chunk-MA73TA6D.js.map +1 -0
- package/dist/{chunk-ZMBU522F.js → chunk-MEY33VWB.js} +2 -2
- package/dist/{chunk-ZMBU522F.js.map → chunk-MEY33VWB.js.map} +1 -1
- package/dist/{chunk-T22EM4ET.js → chunk-MOBRFZH3.js} +81 -31
- package/dist/chunk-MOBRFZH3.js.map +1 -0
- package/dist/chunk-MP2GDBQZ.js +50 -0
- package/dist/chunk-MP2GDBQZ.js.map +1 -0
- package/dist/{chunk-3NBL3OUQ.js → chunk-NAPE7WUS.js} +2 -2
- package/dist/chunk-NAPE7WUS.js.map +1 -0
- package/dist/{chunk-BSKEH3UC.js → chunk-NBYTIVHS.js} +2 -2
- package/dist/{chunk-BSKEH3UC.js.map → chunk-NBYTIVHS.js.map} +1 -1
- package/dist/chunk-O3EXIBEZ.js +114 -0
- package/dist/chunk-O3EXIBEZ.js.map +1 -0
- package/dist/{chunk-R754MHXX.js → chunk-PK4N5QTO.js} +7 -6
- package/dist/chunk-PK4N5QTO.js.map +1 -0
- package/dist/{chunk-EAX2GSS4.js → chunk-QQOTQTDD.js} +51 -20
- package/dist/chunk-QQOTQTDD.js.map +1 -0
- package/dist/{chunk-LZXQVUGN.js → chunk-T4UZTNZ4.js} +4 -4
- package/dist/{chunk-LZXQVUGN.js.map → chunk-T4UZTNZ4.js.map} +1 -1
- package/dist/{chunk-N7FHFNT6.js → chunk-V65EOWNF.js} +33 -5
- package/dist/chunk-V65EOWNF.js.map +1 -0
- package/dist/{chunk-GUIHMIT2.js → chunk-VNPQDCQZ.js} +3 -3
- package/dist/{chunk-GUIHMIT2.js.map → chunk-VNPQDCQZ.js.map} +1 -1
- package/dist/{chunk-5I22LMCV.js → chunk-VZOFZPSO.js} +2 -2
- package/dist/chunk-VZOFZPSO.js.map +1 -0
- package/dist/{chunk-4BIMLITI.js → chunk-WLG6SSNT.js} +5 -3
- package/dist/chunk-WLG6SSNT.js.map +1 -0
- package/dist/{chunk-NE5JAOQS.js → chunk-WOUF7YXM.js} +3 -3
- package/dist/{chunk-NE5JAOQS.js.map → chunk-WOUF7YXM.js.map} +1 -1
- package/dist/collapsible-panel.d.ts +14 -3
- package/dist/collapsible-panel.js +13 -16
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/content-item.d.ts +46 -0
- package/dist/content-item.js +4 -0
- package/dist/content-item.js.map +1 -0
- package/dist/css-values.d.ts +5 -11
- package/dist/css-values.js +1 -1
- package/dist/disclosure-arrow.d.ts +4 -1
- package/dist/disclosure-arrow.js +1 -1
- package/dist/floating-toolbar.d.ts +17 -6
- package/dist/floating-toolbar.js +1 -1
- package/dist/grid.js +1 -1
- package/dist/help-tags-register.d.ts +13 -0
- package/dist/help-tags-register.js +9 -0
- package/dist/help-tags-register.js.map +1 -0
- package/dist/index.d.ts +6 -5
- package/dist/index.js +27 -26
- package/dist/list-action-row.js +1 -1
- package/dist/list-header.d.ts +14 -1
- package/dist/list-header.js +1 -1
- package/dist/list-inset-control.d.ts +1 -1
- package/dist/list-inset-control.js +1 -1
- package/dist/list-inset-text.d.ts +3 -10
- package/dist/list-inset-text.js +1 -1
- package/dist/list-item.js +1 -1
- package/dist/list.d.ts +10 -3
- package/dist/list.js +1 -1
- package/dist/nav-stack.d.ts +38 -5
- package/dist/nav-stack.js +4 -1
- package/dist/pane.d.ts +20 -2
- package/dist/pane.js +1 -1
- package/dist/{panel-toolbar-BFQxFITu.d.ts → panel-toolbar-C8sF-YZC.d.ts} +12 -1
- package/dist/popup-menu-register.js +3 -2
- package/dist/popup-menu-register.js.map +1 -1
- package/dist/popup-menu.js +1 -1
- package/dist/row.d.ts +1 -1
- package/dist/row.js +1 -1
- package/dist/select-register.js +70 -3
- package/dist/select-register.js.map +1 -1
- package/dist/select.d.ts +46 -8
- package/dist/select.js +2 -1
- package/dist/{divider-sides-BzB6rphT.d.ts → sides-BPSWde0A.d.ts} +1 -3
- package/dist/skeleton.js +1 -1
- package/dist/spacer.js +1 -1
- package/dist/split-view.d.ts +31 -3
- package/dist/split-view.js +33 -5
- package/dist/split-view.js.map +1 -1
- package/dist/state-banner.js +1 -1
- package/dist/styles/badge.css +13 -0
- package/dist/styles/catalog/components/catalog-example.css +1 -1
- package/dist/styles/catalog/components/catalog-stage.css +1 -1
- package/dist/styles/collapsible-panel.css +192 -39
- package/dist/styles/content-item.css +30 -0
- package/dist/styles/floating-toolbar.css +5 -0
- package/dist/styles/foundation.css +28 -19
- package/dist/styles/layout.css +1 -21
- package/dist/styles/list-action-row.css +13 -1
- package/dist/styles/list-inset-text.css +1 -2
- package/dist/styles/list-item.css +14 -1
- package/dist/styles/list.css +1 -1
- package/dist/styles/nav-stack.css +29 -64
- package/dist/styles/pane.css +33 -1
- package/dist/styles/popup-menu.css +78 -0
- package/dist/styles/resizable-region.css +53 -10
- package/dist/styles/select.css +39 -12
- package/dist/styles/split-view.css +21 -25
- package/dist/styles/tab-scaffold.css +36 -14
- package/dist/styles/text.css +1 -1
- package/dist/styles/token-search-field.css +4 -4
- package/dist/styles/toolbar-control-group.css +31 -12
- package/dist/styles/toolbar.css +14 -5
- package/dist/styles/value-table.css +19 -2
- package/dist/styles/webawesome.css +3 -1
- package/dist/styles/workbench.css +134 -31
- package/dist/tab-scaffold.d.ts +35 -1
- package/dist/tab-scaffold.js +50 -16
- package/dist/tab-scaffold.js.map +1 -1
- package/dist/token-search-field.d.ts +4 -2
- package/dist/token-search-field.js +1 -1
- package/dist/toolbar-text.js +1 -1
- package/dist/toolbar.d.ts +12 -4
- package/dist/toolbar.js +1 -1
- package/dist/{types-D6vzj-VT.d.ts → types-DXAGogOS.d.ts} +39 -6
- package/dist/value-table.js +1 -1
- package/dist/webawesome.d.ts +7 -1
- package/dist/wire-catalog.d.ts +12 -1
- package/dist/wire-catalog.js +10 -2
- package/dist/wire-catalog.js.map +1 -1
- package/dist/wire-token-search-fields.js +1 -1
- package/dist/workbench.d.ts +59 -22
- package/dist/workbench.js +1 -1
- package/docs/accessibility.md +116 -7
- package/docs/app-layouts.md +9 -7
- package/docs/catalog.md +17 -3
- package/docs/collapsible-panel.md +26 -7
- package/docs/component-contract.md +36 -10
- package/docs/component-selection.md +41 -40
- package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
- package/docs/design/templates/empty-state/with-action.svg +1 -1
- package/docs/design/templates/empty-state-dark.svg +1 -1
- package/docs/design/templates/empty-state.svg +1 -1
- package/docs/design/templates/list/compact-dark.svg +1 -1
- package/docs/design/templates/list/compact.svg +1 -1
- package/docs/design/templates/list/stack-dark.svg +1 -1
- package/docs/design/templates/list/stack.svg +1 -1
- package/docs/design/templates/list-action-row/default-dark.svg +1 -1
- package/docs/design/templates/list-action-row/default.svg +1 -1
- package/docs/design/templates/list-action-row/selected-dark.svg +1 -1
- package/docs/design/templates/list-action-row/selected.svg +1 -1
- package/docs/design/templates/list-action-row-dark.svg +1 -1
- package/docs/design/templates/list-action-row.svg +1 -1
- package/docs/design/templates/list-dark.svg +1 -1
- package/docs/design/templates/list-item/default-dark.svg +1 -1
- package/docs/design/templates/list-item/default.svg +1 -1
- package/docs/design/templates/list-item/selected-dark.svg +1 -1
- package/docs/design/templates/list-item/selected.svg +1 -1
- package/docs/design/templates/list-item/trailing-dark.svg +1 -1
- package/docs/design/templates/list-item/trailing.svg +1 -1
- package/docs/design/templates/list-item-dark.svg +1 -1
- package/docs/design/templates/list-item.svg +1 -1
- package/docs/design/templates/list.svg +1 -1
- package/docs/design/templates/value-table/details-dark.svg +1 -1
- package/docs/design/templates/value-table/details.svg +1 -1
- package/docs/design/templates/value-table-dark.svg +1 -1
- package/docs/design/templates/value-table.svg +1 -1
- package/docs/design-philosophy.md +1 -1
- package/docs/examples/command-palette-adapter.tsx +3 -2
- package/docs/layout.md +69 -29
- package/docs/nav-stack.md +45 -1
- package/docs/recipes.md +4 -3
- package/docs/split-view.md +46 -2
- package/docs/tab-scaffold.md +50 -1
- package/docs/type-contracts.md +17 -17
- package/docs/ux-demo.md +2 -2
- package/docs/webawesome-theme.md +1 -2
- package/docs/workbench.md +45 -9
- package/llms.txt +32 -4
- package/package.json +13 -2
- package/ux-demo/recipes/collapsible-sidebar.tsx +3 -2
- package/ux-demo/recipes/navigation-sidebar.tsx +3 -2
- package/ux-demo/recipes/navigation-stack.tsx +3 -2
- package/dist/chunk-3NBL3OUQ.js.map +0 -1
- package/dist/chunk-4BIMLITI.js.map +0 -1
- package/dist/chunk-5I22LMCV.js.map +0 -1
- package/dist/chunk-5NDQABWK.js.map +0 -1
- package/dist/chunk-5OLVUEND.js.map +0 -1
- package/dist/chunk-7GUQYHKA.js.map +0 -1
- package/dist/chunk-D7GWXIAS.js.map +0 -1
- package/dist/chunk-DQA5FMOX.js +0 -85
- package/dist/chunk-DQA5FMOX.js.map +0 -1
- package/dist/chunk-EAX2GSS4.js.map +0 -1
- package/dist/chunk-HMQ2ZDGG.js.map +0 -1
- package/dist/chunk-MTM43SJO.js.map +0 -1
- package/dist/chunk-N7FHFNT6.js.map +0 -1
- package/dist/chunk-R754MHXX.js.map +0 -1
- package/dist/chunk-RNRUVPJ3.js.map +0 -1
- package/dist/chunk-T22EM4ET.js.map +0 -1
- package/dist/chunk-WZ2GLEY4.js.map +0 -1
- package/dist/chunk-XD7DWYXG.js +0 -34
- package/dist/chunk-XD7DWYXG.js.map +0 -1
|
@@ -317,7 +317,12 @@
|
|
|
317
317
|
padding-inline: 0;
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
-
|
|
320
|
+
/* `standard` keeps each menu's own standard inset: a raw wa-dropdown takes the
|
|
321
|
+
8px surface inset, while a PopupMenu keeps the Select listbox inset it
|
|
322
|
+
shares (popup-menu.css). The explicit compact and list-zero choices apply to
|
|
323
|
+
every nested menu. */
|
|
324
|
+
.kui-toolbar-control-group[data-menu-inset="standard"]
|
|
325
|
+
wa-dropdown:not([data-component="popup-menu"])::part(menu) {
|
|
321
326
|
padding: var(--kui-wa-surface-inset, 0.5rem);
|
|
322
327
|
}
|
|
323
328
|
.kui-toolbar-control-group[data-menu-inset="compact"] wa-dropdown::part(menu) {
|
|
@@ -478,35 +483,49 @@
|
|
|
478
483
|
|
|
479
484
|
/* With per-control rings, a composed Select paints its own ring even when it
|
|
480
485
|
was told the group owns it: nothing else would show focus. It matches the
|
|
481
|
-
sibling controls' ring and offset.
|
|
486
|
+
sibling controls' ring and offset. While its listbox is open the popup shows
|
|
487
|
+
focus instead, so the trigger ring stays off, as a PopupMenu trigger's does. */
|
|
482
488
|
.kui-toolbar-control-group[data-focus-ring="control"]
|
|
483
|
-
> wa-select:focus-within::part(combobox) {
|
|
489
|
+
> wa-select:not([open]):focus-within::part(combobox) {
|
|
484
490
|
outline: var(--kui-focus-ring);
|
|
485
491
|
outline-offset: 1px;
|
|
486
492
|
}
|
|
487
493
|
|
|
488
|
-
.kui-toolbar-control-group[data-focus-ring="outline"]:focus-within
|
|
494
|
+
.kui-toolbar-control-group[data-focus-ring="outline"]:focus-within:not(
|
|
495
|
+
:where(:has(wa-select[open], wa-dropdown[open]))
|
|
496
|
+
) {
|
|
489
497
|
outline: var(--kui-focus-ring);
|
|
490
498
|
outline-offset: 1px;
|
|
491
499
|
}
|
|
492
500
|
|
|
493
|
-
.kui-toolbar-control-group[data-focus-ring="halo"]:focus-within
|
|
501
|
+
.kui-toolbar-control-group[data-focus-ring="halo"]:focus-within:not(
|
|
502
|
+
:where(:has(wa-select[open], wa-dropdown[open]))
|
|
503
|
+
) {
|
|
494
504
|
border-color: var(--kui-color-text-link);
|
|
495
505
|
box-shadow: 0 0 0 3px
|
|
496
506
|
color-mix(in srgb, var(--kui-color-text-link) 22%, transparent);
|
|
497
507
|
}
|
|
498
508
|
|
|
499
|
-
/*
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
509
|
+
/* A group-owned ring (outline or halo) is off while a Select listbox or a
|
|
510
|
+
PopupMenu inside the group is open: the open popup shows focus, as the
|
|
511
|
+
per-control Select and PopupMenu triggers already do, and the ring returns
|
|
512
|
+
when the popup closes with focus still in the group. The exclusion sits in
|
|
513
|
+
a forgiving :where(), so an engine without :has() keeps the ring.
|
|
514
|
+
|
|
515
|
+
Chromium and WebKit do not propagate :focus-within from a focused
|
|
516
|
+
light-DOM child through a host's popup shadow tree, so a focused light-DOM
|
|
517
|
+
descendant also owns the group ring. Kept as separate rules so an engine
|
|
518
|
+
without :has() keeps the :focus-within ring. */
|
|
519
|
+
.kui-toolbar-control-group[data-focus-ring="outline"]:has(:focus):not(
|
|
520
|
+
:where(:has(wa-select[open], wa-dropdown[open]))
|
|
521
|
+
) {
|
|
505
522
|
outline: var(--kui-focus-ring);
|
|
506
523
|
outline-offset: 1px;
|
|
507
524
|
}
|
|
508
525
|
|
|
509
|
-
.kui-toolbar-control-group[data-focus-ring="halo"]:has(:focus)
|
|
526
|
+
.kui-toolbar-control-group[data-focus-ring="halo"]:has(:focus):not(
|
|
527
|
+
:where(:has(wa-select[open], wa-dropdown[open]))
|
|
528
|
+
) {
|
|
510
529
|
border-color: var(--kui-color-text-link);
|
|
511
530
|
box-shadow: 0 0 0 3px
|
|
512
531
|
color-mix(in srgb, var(--kui-color-text-link) 22%, transparent);
|
package/dist/styles/toolbar.css
CHANGED
|
@@ -5,7 +5,11 @@
|
|
|
5
5
|
box-sizing: border-box;
|
|
6
6
|
color: var(--kui-color-text);
|
|
7
7
|
background: transparent;
|
|
8
|
-
|
|
8
|
+
/* The center track's minimum is `auto`, not 0, so it resolves to the center
|
|
9
|
+
zone's own min-width (its content width, below): when the zones do not all
|
|
10
|
+
fit, the auto leading track is what shrinks and its title truncates, and
|
|
11
|
+
the center group never overflows its track onto the leading identity. */
|
|
12
|
+
grid-template-columns: auto 1fr auto;
|
|
9
13
|
align-items: start;
|
|
10
14
|
gap: var(--kui-toolbar-gap, 0.5rem);
|
|
11
15
|
container: kui-toolbar / inline-size;
|
|
@@ -103,28 +107,28 @@
|
|
|
103
107
|
.kui-toolbar[divider-sides*="t"] {
|
|
104
108
|
--_kui-toolbar-divider-top: var(
|
|
105
109
|
--kui-toolbar-divider-color,
|
|
106
|
-
var(--kui-color-border)
|
|
110
|
+
var(--kui-color-neutral-border-normal)
|
|
107
111
|
);
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
.kui-toolbar[divider-sides*="r"] {
|
|
111
115
|
--_kui-toolbar-divider-right: var(
|
|
112
116
|
--kui-toolbar-divider-color,
|
|
113
|
-
var(--kui-color-border)
|
|
117
|
+
var(--kui-color-neutral-border-normal)
|
|
114
118
|
);
|
|
115
119
|
}
|
|
116
120
|
|
|
117
121
|
.kui-toolbar[divider-sides*="b"] {
|
|
118
122
|
--_kui-toolbar-divider-bottom: var(
|
|
119
123
|
--kui-toolbar-divider-color,
|
|
120
|
-
var(--kui-color-border)
|
|
124
|
+
var(--kui-color-neutral-border-normal)
|
|
121
125
|
);
|
|
122
126
|
}
|
|
123
127
|
|
|
124
128
|
.kui-toolbar[divider-sides*="l"] {
|
|
125
129
|
--_kui-toolbar-divider-left: var(
|
|
126
130
|
--kui-toolbar-divider-color,
|
|
127
|
-
var(--kui-color-border)
|
|
131
|
+
var(--kui-color-neutral-border-normal)
|
|
128
132
|
);
|
|
129
133
|
}
|
|
130
134
|
|
|
@@ -190,6 +194,11 @@
|
|
|
190
194
|
}
|
|
191
195
|
|
|
192
196
|
.kui-toolbar__center {
|
|
197
|
+
/* The center content never compresses below its own width (a group cannot
|
|
198
|
+
shrink or clip its controls). The track above takes this as its minimum, so
|
|
199
|
+
the leading identity gives way first, the way a platform toolbar truncates
|
|
200
|
+
its title before it overlaps the centered controls. */
|
|
201
|
+
min-width: min-content;
|
|
193
202
|
justify-content: center;
|
|
194
203
|
grid-column: 2;
|
|
195
204
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
.kui-value-table {
|
|
2
2
|
--kui-value-table-background: var(--kui-color-surface-lowered);
|
|
3
|
-
--kui-value-table-border: var(--kui-color-border);
|
|
3
|
+
--kui-value-table-border: var(--kui-color-neutral-border-normal);
|
|
4
4
|
--_kui-value-table-icon-size: var(--kui-value-table-icon-size, 1.5rem);
|
|
5
5
|
display: grid;
|
|
6
6
|
margin-block: 0;
|
|
@@ -22,7 +22,14 @@
|
|
|
22
22
|
padding-block: 0.5rem;
|
|
23
23
|
padding-inline: var(--_kui-value-table-inline-padding);
|
|
24
24
|
box-sizing: border-box;
|
|
25
|
-
|
|
25
|
+
/* Two content-sized tracks share the free space equally, and each stops
|
|
26
|
+
growing once its content fits. A short value keeps its whole width and a
|
|
27
|
+
long label takes the rest (ending a word that still does not fit in an
|
|
28
|
+
ellipsis); a short label keeps its width beside a long, wrapping value;
|
|
29
|
+
when both are long they split the row. A `1fr` value track would get
|
|
30
|
+
nothing until the label reached its full width, starving the value to 0px
|
|
31
|
+
beside a long single-word label. */
|
|
32
|
+
grid-template-columns: minmax(0, auto) minmax(0, auto);
|
|
26
33
|
align-items: center;
|
|
27
34
|
gap: var(--kui-layout-item-gap, 0.5rem);
|
|
28
35
|
}
|
|
@@ -42,7 +49,12 @@
|
|
|
42
49
|
}
|
|
43
50
|
.kui-value-table__row dt {
|
|
44
51
|
display: flex;
|
|
52
|
+
/* The label hugs its content (up to its column) rather than stretching, so
|
|
53
|
+
its box does not change with the value's width — a placeholder row keeps
|
|
54
|
+
the live row's label geometry beside its skeleton value. */
|
|
55
|
+
max-width: 100%;
|
|
45
56
|
min-width: 0;
|
|
57
|
+
justify-self: start;
|
|
46
58
|
color: var(--kui-color-text-quiet);
|
|
47
59
|
align-items: center;
|
|
48
60
|
gap: var(--kui-layout-item-gap, 0.5rem);
|
|
@@ -60,6 +72,11 @@
|
|
|
60
72
|
}
|
|
61
73
|
.kui-value-table__label {
|
|
62
74
|
min-width: 0;
|
|
75
|
+
overflow: hidden;
|
|
76
|
+
/* A multi-word label wraps at spaces; a single word wider than the label
|
|
77
|
+
column (a long component or file name) ends in an ellipsis instead of
|
|
78
|
+
running under the value. */
|
|
79
|
+
text-overflow: ellipsis;
|
|
63
80
|
}
|
|
64
81
|
.kui-value-table__row dd {
|
|
65
82
|
display: flex;
|
|
@@ -499,7 +499,9 @@
|
|
|
499
499
|
padding-inline: var(--kui-wa-control-inset) !important;
|
|
500
500
|
}
|
|
501
501
|
|
|
502
|
-
|
|
502
|
+
/* A PopupMenu item owns the Select option geometry instead (popup-menu.css),
|
|
503
|
+
so a command menu and a value list draw identical rows. */
|
|
504
|
+
wa-dropdown-item:not([data-component="popup-menu"] > *) {
|
|
503
505
|
padding-inline: var(--kui-wa-control-inset) !important;
|
|
504
506
|
}
|
|
505
507
|
|
|
@@ -55,14 +55,14 @@
|
|
|
55
55
|
--_kui-workbench-rail-safe-inset: var(--_kui-workbench-safe-inline-start);
|
|
56
56
|
--kui-edge-inset-inline-start: var(--_kui-workbench-safe-inline-start);
|
|
57
57
|
--kui-edge-inset-inline-end: 0px;
|
|
58
|
-
border-inline-end: 1px solid var(--kui-color-border);
|
|
58
|
+
border-inline-end: 1px solid var(--kui-color-neutral-border-normal);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
.kui-workbench__rail--right {
|
|
62
62
|
--_kui-workbench-rail-safe-inset: var(--_kui-workbench-safe-inline-end);
|
|
63
63
|
--kui-edge-inset-inline-start: 0px;
|
|
64
64
|
--kui-edge-inset-inline-end: var(--_kui-workbench-safe-inline-end);
|
|
65
|
-
border-inline-start: 1px solid var(--kui-color-border);
|
|
65
|
+
border-inline-start: 1px solid var(--kui-color-neutral-border-normal);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
.kui-workbench__rail[data-collapsed="true"] {
|
|
@@ -157,30 +157,32 @@
|
|
|
157
157
|
var(--kui-edge-inset-block-end);
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
.
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
160
|
+
/* Every other child sees a cleared context. The exemption is tested on the
|
|
161
|
+
child itself, never as `region:not(:has(…)) > *`: a `:has()` before a
|
|
162
|
+
universal child makes each child of the region re-check the region's
|
|
163
|
+
`:has()` on every DOM change (~46ms per restyle for 1000 rows in Chromium).
|
|
164
|
+
SplitView, NavStack, TabScaffold, and CollapsiblePanel content use the same
|
|
165
|
+
shape. */
|
|
166
|
+
.kui-workbench__main
|
|
167
|
+
> :not(
|
|
168
|
+
:is(
|
|
169
|
+
[data-component="pane"],
|
|
170
|
+
[data-component="nav-stack"],
|
|
171
|
+
[data-component="split-view"],
|
|
172
|
+
[data-component="workbench"],
|
|
173
|
+
[data-component="tab-scaffold"]
|
|
174
|
+
):only-child
|
|
175
|
+
),
|
|
176
|
+
.kui-workbench__panel-content
|
|
177
|
+
> :not(
|
|
178
|
+
:is(
|
|
179
|
+
[data-component="pane"],
|
|
180
|
+
[data-component="nav-stack"],
|
|
181
|
+
[data-component="split-view"],
|
|
182
|
+
[data-component="workbench"],
|
|
183
|
+
[data-component="tab-scaffold"]
|
|
184
|
+
):only-child
|
|
185
|
+
) {
|
|
184
186
|
--kui-edge-inset-block-start: 0px;
|
|
185
187
|
--kui-edge-inset-block-end: 0px;
|
|
186
188
|
--kui-edge-inset-inline-start: 0px;
|
|
@@ -213,7 +215,7 @@
|
|
|
213
215
|
flex: 0 0 var(--_kui-workbench-drawer-extent);
|
|
214
216
|
min-height: 0;
|
|
215
217
|
overflow: hidden;
|
|
216
|
-
border-block-start: 1px solid var(--kui-color-border);
|
|
218
|
+
border-block-start: 1px solid var(--kui-color-neutral-border-normal);
|
|
217
219
|
background: var(--kui-color-surface);
|
|
218
220
|
}
|
|
219
221
|
|
|
@@ -387,10 +389,64 @@
|
|
|
387
389
|
display: none;
|
|
388
390
|
}
|
|
389
391
|
|
|
390
|
-
/*
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
392
|
+
/* An expanded panel lets exactly the handle's outer half through its clip, so
|
|
393
|
+
the hit target straddles the separator like a ResizableRegion handle does
|
|
394
|
+
and the grip is drawn centered on the separator line. Collapsing drops the
|
|
395
|
+
extension again before the content slides out. Engines that can extend a
|
|
396
|
+
clip past the panel's edge do it with `overflow-clip-margin`; the rest
|
|
397
|
+
(WebKit) clip with a `clip-path` that reaches past the panel's edges. That
|
|
398
|
+
also makes the panel a stacking context, so the panel stacks at the
|
|
399
|
+
handle's own level to keep the handle's outer half above the work area
|
|
400
|
+
beside it. The clip and the stacking level sit at low specificity, so a
|
|
401
|
+
responsive overlay presentation (below) replaces both. */
|
|
402
|
+
@supports not (overflow-clip-margin: 10px) {
|
|
403
|
+
.kui-workbench__rail[data-resizable="true"][data-presentation="inline"]:not(
|
|
404
|
+
[data-collapsed="true"],
|
|
405
|
+
[data-content-overflow="visible"]
|
|
406
|
+
),
|
|
407
|
+
.kui-workbench__drawer[data-resizable="true"][data-presentation="inline"]:not(
|
|
408
|
+
[data-collapsed="true"],
|
|
409
|
+
[data-content-overflow="visible"]
|
|
410
|
+
) {
|
|
411
|
+
overflow: visible;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.kui-workbench__rail:where(
|
|
415
|
+
[data-resizable="true"][data-presentation="inline"]:not(
|
|
416
|
+
[data-collapsed="true"],
|
|
417
|
+
[data-content-overflow="visible"]
|
|
418
|
+
)
|
|
419
|
+
) {
|
|
420
|
+
z-index: 3;
|
|
421
|
+
clip-path: inset(0 -10px);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
.kui-workbench__drawer:where(
|
|
425
|
+
[data-resizable="true"][data-presentation="inline"]:not(
|
|
426
|
+
[data-collapsed="true"],
|
|
427
|
+
[data-content-overflow="visible"]
|
|
428
|
+
)
|
|
429
|
+
) {
|
|
430
|
+
z-index: 3;
|
|
431
|
+
clip-path: inset(-10px 0 0);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.kui-workbench__rail--left[data-resizable="true"][data-presentation="inline"]
|
|
435
|
+
> .kui-workbench__handle {
|
|
436
|
+
inset-inline-end: -10px;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.kui-workbench__rail--right[data-resizable="true"][data-presentation="inline"]
|
|
440
|
+
> .kui-workbench__handle {
|
|
441
|
+
inset-inline-start: -10px;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.kui-workbench__drawer[data-resizable="true"][data-presentation="inline"]
|
|
445
|
+
> .kui-workbench__handle {
|
|
446
|
+
inset-block-start: -10px;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
394
450
|
@supports (overflow-clip-margin: 10px) {
|
|
395
451
|
.kui-workbench__rail[data-resizable="true"]:not(
|
|
396
452
|
[data-collapsed="true"],
|
|
@@ -542,6 +598,7 @@
|
|
|
542
598
|
max-width: var(--kui-workbench-overlay-max-width, 85vw);
|
|
543
599
|
inset-block: 0;
|
|
544
600
|
box-shadow: var(--kui-shadow-l);
|
|
601
|
+
clip-path: none;
|
|
545
602
|
}
|
|
546
603
|
|
|
547
604
|
.kui-workbench__rail--left[data-responsive-overlay-at="narrow"] {
|
|
@@ -592,6 +649,7 @@
|
|
|
592
649
|
inset-inline: 0;
|
|
593
650
|
inset-block-end: 0;
|
|
594
651
|
box-shadow: var(--kui-shadow-l);
|
|
652
|
+
clip-path: none;
|
|
595
653
|
}
|
|
596
654
|
|
|
597
655
|
.kui-workbench__drawer[data-responsive-overlay-at="narrow"][data-collapsed="true"] {
|
|
@@ -626,6 +684,7 @@
|
|
|
626
684
|
max-width: var(--kui-workbench-overlay-max-width, 85vw);
|
|
627
685
|
inset-block: 0;
|
|
628
686
|
box-shadow: var(--kui-shadow-l);
|
|
687
|
+
clip-path: none;
|
|
629
688
|
}
|
|
630
689
|
|
|
631
690
|
.kui-workbench__rail--left[data-responsive-overlay-at="compact"] {
|
|
@@ -676,6 +735,7 @@
|
|
|
676
735
|
inset-inline: 0;
|
|
677
736
|
inset-block-end: 0;
|
|
678
737
|
box-shadow: var(--kui-shadow-l);
|
|
738
|
+
clip-path: none;
|
|
679
739
|
}
|
|
680
740
|
|
|
681
741
|
.kui-workbench__drawer[data-responsive-overlay-at="compact"][data-collapsed="true"] {
|
|
@@ -721,6 +781,8 @@
|
|
|
721
781
|
from this point instead of adding its own inset on top. */
|
|
722
782
|
--kui-floating-toolbar-inset: 0px;
|
|
723
783
|
position: absolute;
|
|
784
|
+
/* Hidden while an open rail overlay covers the work area (see below). */
|
|
785
|
+
visibility: var(--_kui-floating-covered, inherit);
|
|
724
786
|
z-index: var(
|
|
725
787
|
--kui-workbench-restore-z,
|
|
726
788
|
calc(var(--kui-workbench-overlay-z, 41) - 2)
|
|
@@ -788,6 +850,47 @@
|
|
|
788
850
|
);
|
|
789
851
|
}
|
|
790
852
|
|
|
853
|
+
/* An open rail overlay — static or a responsive one whose breakpoint applies —
|
|
854
|
+
covers the work area, so the work area's floating controls (a
|
|
855
|
+
FloatingToolbar in main, the drawer's restore corner, the other rail's
|
|
856
|
+
restore corner) are hidden, not merely stacked beneath it: they never paint
|
|
857
|
+
over the overlay whatever stacking context an app puts them in, and hidden
|
|
858
|
+
they leave the tab order and the accessibility tree. They come back as the
|
|
859
|
+
overlay closes. The flag is set on the rail's siblings only (never on the
|
|
860
|
+
open rail), so the overlay's own floating controls stay, and it is read by
|
|
861
|
+
FloatingToolbar and the layouts' restore corners. A direct child
|
|
862
|
+
resolves the Workbench's own container query, never a nested one's. */
|
|
863
|
+
.kui-workbench:has(
|
|
864
|
+
> .kui-workbench__rail[data-presentation="overlay"]:not(
|
|
865
|
+
[data-collapsed="true"]
|
|
866
|
+
)
|
|
867
|
+
)
|
|
868
|
+
> :is(.kui-workbench__center, .kui-workbench__restore) {
|
|
869
|
+
--_kui-floating-covered: hidden;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
@container kui-workbench (max-width: 44rem) {
|
|
873
|
+
.kui-workbench:has(
|
|
874
|
+
> .kui-workbench__rail[data-responsive-overlay-at="narrow"][data-presentation="inline"]:not(
|
|
875
|
+
[data-collapsed="true"]
|
|
876
|
+
)
|
|
877
|
+
)
|
|
878
|
+
> :is(.kui-workbench__center, .kui-workbench__restore) {
|
|
879
|
+
--_kui-floating-covered: hidden;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
@container kui-workbench (max-width: 28rem) {
|
|
884
|
+
.kui-workbench:has(
|
|
885
|
+
> .kui-workbench__rail[data-responsive-overlay-at="compact"][data-presentation="inline"]:not(
|
|
886
|
+
[data-collapsed="true"]
|
|
887
|
+
)
|
|
888
|
+
)
|
|
889
|
+
> :is(.kui-workbench__center, .kui-workbench__restore) {
|
|
890
|
+
--_kui-floating-covered: hidden;
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
791
894
|
@media (prefers-reduced-motion: reduce) {
|
|
792
895
|
.kui-workbench__panel-content {
|
|
793
896
|
transition: none;
|
package/dist/tab-scaffold.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SafeHtml } from 'kerfjs';
|
|
2
2
|
import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
|
|
3
3
|
|
|
4
|
-
interface
|
|
4
|
+
interface TabScaffoldTabBase<Id extends string> {
|
|
5
5
|
id: Id;
|
|
6
6
|
label: string;
|
|
7
7
|
/** Decorative icon shown above the label in the bottom bar. */
|
|
@@ -9,6 +9,40 @@ interface TabScaffoldTab<Id extends string = string> {
|
|
|
9
9
|
/** The tab's content — typically a `NavStack` so each tab keeps its own stack. */
|
|
10
10
|
content: KerfUiContent;
|
|
11
11
|
}
|
|
12
|
+
/** A tab with an optional count or short-status badge. */
|
|
13
|
+
interface TabScaffoldTabCountBadge {
|
|
14
|
+
/**
|
|
15
|
+
* Optional count or short status shown as a solid danger `Badge` at the
|
|
16
|
+
* top-trailing corner of the tab icon (the iOS tab-bar badge). Omitted, `''`,
|
|
17
|
+
* or non-finite numbers render no badge. The visual badge is `aria-hidden`;
|
|
18
|
+
* its meaning reaches assistive technology through `badgeLabel`.
|
|
19
|
+
*
|
|
20
|
+
* Pass `true` instead for the text-free dot (new content without a count).
|
|
21
|
+
*/
|
|
22
|
+
badge?: string | number;
|
|
23
|
+
/**
|
|
24
|
+
* Localized phrase folded into the tab's accessible name as
|
|
25
|
+
* `"<label>, <badgeLabel>"` (for example `"3 unread"` → `"Inbox, 3 unread"`).
|
|
26
|
+
* Defaults to the badge text itself. Ignored when no badge renders.
|
|
27
|
+
*/
|
|
28
|
+
badgeLabel?: string;
|
|
29
|
+
}
|
|
30
|
+
/** A tab with the text-free dot badge (new content without a count). */
|
|
31
|
+
interface TabScaffoldTabDotBadge {
|
|
32
|
+
/**
|
|
33
|
+
* `true` shows a solid danger dot `Badge` at the top-trailing corner of the
|
|
34
|
+
* tab icon — the iOS tab-bar dot for new content without a count.
|
|
35
|
+
*/
|
|
36
|
+
badge: true;
|
|
37
|
+
/**
|
|
38
|
+
* Required localized phrase folded into the tab's accessible name as
|
|
39
|
+
* `"<label>, <badgeLabel>"` (for example `"New activity"` →
|
|
40
|
+
* `"Feed, New activity"`). A dot has no text, so this is its only meaning.
|
|
41
|
+
*/
|
|
42
|
+
badgeLabel: string;
|
|
43
|
+
}
|
|
44
|
+
/** One bottom-bar destination: its label, optional icon and badge, and content. */
|
|
45
|
+
type TabScaffoldTab<Id extends string = string> = TabScaffoldTabBase<Id> & (TabScaffoldTabCountBadge | TabScaffoldTabDotBadge);
|
|
12
46
|
interface TabScaffoldProps<Id extends string = string> {
|
|
13
47
|
id: string;
|
|
14
48
|
/** Accessible name for the tab bar. */
|
package/dist/tab-scaffold.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { Badge } from './chunk-MP2GDBQZ.js';
|
|
1
2
|
import { jsxs, jsx } from 'kerfjs/jsx-runtime';
|
|
2
3
|
|
|
3
|
-
// src/tab-scaffold.tsx
|
|
4
4
|
function TabScaffold({
|
|
5
5
|
id,
|
|
6
6
|
label,
|
|
@@ -28,25 +28,59 @@ function TabScaffold({
|
|
|
28
28
|
children: tab.content
|
|
29
29
|
}
|
|
30
30
|
)) }),
|
|
31
|
-
/* @__PURE__ */ jsx("nav", { class: "kui-tab-scaffold__bar", role: "tablist", "aria-label": label, children: tabs.map((tab) =>
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
31
|
+
/* @__PURE__ */ jsx("nav", { class: "kui-tab-scaffold__bar", role: "tablist", "aria-label": label, children: tabs.map((tab) => {
|
|
32
|
+
const dot = tab.badge === true;
|
|
33
|
+
const badgeText = dot ? void 0 : normalizeBadge(tab.badge);
|
|
34
|
+
const hasBadge = dot || badgeText !== void 0;
|
|
35
|
+
const badge = hasBadge && /* @__PURE__ */ jsx(
|
|
36
|
+
"span",
|
|
37
|
+
{
|
|
38
|
+
class: "kui-tab-scaffold__tab-badge",
|
|
39
|
+
"data-badge-kind": dot ? "dot" : "text",
|
|
40
|
+
children: badgeText === void 0 ? /* @__PURE__ */ jsx(Badge, { tone: "danger", size: "dot", ariaHidden: true }) : /* @__PURE__ */ jsx(
|
|
41
|
+
Badge,
|
|
42
|
+
{
|
|
43
|
+
tone: "danger",
|
|
44
|
+
appearance: "solid",
|
|
45
|
+
size: "compact",
|
|
46
|
+
ariaHidden: true,
|
|
47
|
+
children: badgeText
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
const badgeLabel = hasBadge ? tab.badgeLabel?.trim() || badgeText : void 0;
|
|
53
|
+
return /* @__PURE__ */ jsxs(
|
|
54
|
+
"button",
|
|
55
|
+
{
|
|
56
|
+
type: "button",
|
|
57
|
+
class: "kui-tab-scaffold__tab",
|
|
58
|
+
role: "tab",
|
|
59
|
+
"data-tab-scaffold-tab": tab.id,
|
|
60
|
+
"aria-selected": String(tab.id === active),
|
|
61
|
+
tabindex: tab.id === active ? "0" : "-1",
|
|
62
|
+
"aria-label": badgeLabel === void 0 ? void 0 : `${tab.label}, ${badgeLabel}`,
|
|
63
|
+
"data-has-badge": hasBadge ? "true" : void 0,
|
|
64
|
+
children: [
|
|
65
|
+
tab.icon ? /* @__PURE__ */ jsxs("span", { class: "kui-tab-scaffold__tab-icon", "aria-hidden": "true", children: [
|
|
66
|
+
tab.icon,
|
|
67
|
+
badge
|
|
68
|
+
] }) : badge,
|
|
69
|
+
/* @__PURE__ */ jsx("span", { class: "kui-tab-scaffold__tab-label", children: tab.label })
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
}) })
|
|
46
74
|
]
|
|
47
75
|
}
|
|
48
76
|
);
|
|
49
77
|
}
|
|
78
|
+
function normalizeBadge(badge) {
|
|
79
|
+
if (typeof badge === "number")
|
|
80
|
+
return Number.isFinite(badge) ? String(badge) : void 0;
|
|
81
|
+
if (typeof badge === "string" && badge.trim()) return badge.trim();
|
|
82
|
+
return void 0;
|
|
83
|
+
}
|
|
50
84
|
|
|
51
85
|
export { TabScaffold };
|
|
52
86
|
|
package/dist/tab-scaffold.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tab-scaffold.tsx"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"sources":["../src/tab-scaffold.tsx"],"names":[],"mappings":"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","file":"tab-scaffold.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { Badge } from './badge.js';\nimport type { KerfUiContent } from './semantic-content.js';\n\ninterface TabScaffoldTabBase<Id extends 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\n/** A tab with an optional count or short-status badge. */\ninterface TabScaffoldTabCountBadge {\n /**\n * Optional count or short status shown as a solid danger `Badge` at the\n * top-trailing corner of the tab icon (the iOS tab-bar badge). Omitted, `''`,\n * or non-finite numbers render no badge. The visual badge is `aria-hidden`;\n * its meaning reaches assistive technology through `badgeLabel`.\n *\n * Pass `true` instead for the text-free dot (new content without a count).\n */\n badge?: string | number;\n /**\n * Localized phrase folded into the tab's accessible name as\n * `\"<label>, <badgeLabel>\"` (for example `\"3 unread\"` → `\"Inbox, 3 unread\"`).\n * Defaults to the badge text itself. Ignored when no badge renders.\n */\n badgeLabel?: string;\n}\n\n/** A tab with the text-free dot badge (new content without a count). */\ninterface TabScaffoldTabDotBadge {\n /**\n * `true` shows a solid danger dot `Badge` at the top-trailing corner of the\n * tab icon — the iOS tab-bar dot for new content without a count.\n */\n badge: true;\n /**\n * Required localized phrase folded into the tab's accessible name as\n * `\"<label>, <badgeLabel>\"` (for example `\"New activity\"` →\n * `\"Feed, New activity\"`). A dot has no text, so this is its only meaning.\n */\n badgeLabel: string;\n}\n\n/** One bottom-bar destination: its label, optional icon and badge, and content. */\nexport type TabScaffoldTab<Id extends string = string> =\n TabScaffoldTabBase<Id> & (TabScaffoldTabCountBadge | TabScaffoldTabDotBadge);\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 const dot = tab.badge === true;\n const badgeText = dot ? undefined : normalizeBadge(tab.badge);\n const hasBadge = dot || badgeText !== undefined;\n const badge = hasBadge && (\n <span\n class=\"kui-tab-scaffold__tab-badge\"\n data-badge-kind={dot ? 'dot' : 'text'}\n >\n {badgeText === undefined ? (\n <Badge tone=\"danger\" size=\"dot\" ariaHidden />\n ) : (\n <Badge\n tone=\"danger\"\n appearance=\"solid\"\n size=\"compact\"\n ariaHidden\n >\n {badgeText}\n </Badge>\n )}\n </span>\n );\n // A dot has no text fallback: without a usable badgeLabel (reachable\n // only from untyped callers) the tab keeps its plain accessible name.\n const badgeLabel = hasBadge\n ? tab.badgeLabel?.trim() || badgeText\n : undefined;\n return (\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 aria-label={\n badgeLabel === undefined\n ? undefined\n : `${tab.label}, ${badgeLabel}`\n }\n data-has-badge={hasBadge ? 'true' : undefined}\n >\n {tab.icon ? (\n <span class=\"kui-tab-scaffold__tab-icon\" aria-hidden=\"true\">\n {tab.icon}\n {badge}\n </span>\n ) : (\n badge\n )}\n <span class=\"kui-tab-scaffold__tab-label\">{tab.label}</span>\n </button>\n );\n })}\n </nav>\n </section>\n );\n}\n\nfunction normalizeBadge(\n badge: string | number | undefined,\n): string | undefined {\n if (typeof badge === 'number')\n return Number.isFinite(badge) ? String(badge) : undefined;\n if (typeof badge === 'string' && badge.trim()) return badge.trim();\n return undefined;\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { SafeHtml } from 'kerfjs';
|
|
2
2
|
import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
|
|
3
3
|
|
|
4
4
|
interface TokenSearchToken {
|
|
@@ -41,6 +41,8 @@ interface TokenSearchFieldBaseProps {
|
|
|
41
41
|
removeAction?: string;
|
|
42
42
|
clearAction?: string;
|
|
43
43
|
clearLabel?: string;
|
|
44
|
+
/** Icon for the clear button. Default: the Lucide `x` glyph token chips also use. */
|
|
45
|
+
clearIcon?: SafeHtml;
|
|
44
46
|
className?: string;
|
|
45
47
|
editorAttributes?: TokenSearchEditorAttributes;
|
|
46
48
|
/** Native named-slot assignment when composed inside a web component. */
|
|
@@ -64,7 +66,7 @@ interface TokenSearchFieldValue {
|
|
|
64
66
|
query: string;
|
|
65
67
|
tokens: TokenSearchToken[];
|
|
66
68
|
}
|
|
67
|
-
declare function TokenSearchField({ id, label, query, tokens, revision, placeholder, tokenPlaceholder, disabled, autofocus, collapsible, expanded, expandAction, expandLabel, leading, trailing, presentation, editAction, removeAction, clearAction, clearLabel, className, editorAttributes, slot, }: TokenSearchFieldProps):
|
|
69
|
+
declare function TokenSearchField({ id, label, query, tokens, revision, placeholder, tokenPlaceholder, disabled, autofocus, collapsible, expanded, expandAction, expandLabel, leading, trailing, presentation, editAction, removeAction, clearAction, clearLabel, clearIcon, className, editorAttributes, slot, }: TokenSearchFieldProps): SafeHtml;
|
|
68
70
|
/** Read editable text and ordered token offsets from a rendered TokenSearchField editor. */
|
|
69
71
|
declare function readTokenSearchField(editor: HTMLElement, knownTokens?: readonly TokenSearchToken[]): TokenSearchFieldValue;
|
|
70
72
|
/** Focus an editor and place its caret at a text offset, skipping atomic token chips. */
|
package/dist/toolbar-text.js
CHANGED