@kerfjs/ui 5.0.0-beta.77 → 5.0.0-beta.78
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 +3 -0
- package/ai/application-ui-diagnostic-ids-v1.json +3 -0
- package/ai/component-catalog.json +121 -9
- package/ai/component-composition.json +102 -6
- package/ai/components/nav-stack.md +3 -3
- package/ai/components/surface-scaffold.md +11 -2
- package/ai/components/toolbar-control-group.md +2 -0
- package/ai/components/toolbar-text.md +2 -0
- package/ai/components/toolbar.md +2 -0
- package/ai/public-api-signatures-v1.md +49 -121
- package/ai/skill.md +11 -1
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/dist/browser/nav-stack.js +2 -0
- package/dist/browser/split-view.js +2 -0
- package/dist/catalog-resources.d.ts +3 -3
- package/dist/catalog.d.ts +3 -3
- package/dist/catalog.js +3 -3
- package/dist/{chunk-WJN3V2H5.js → chunk-2GOCOLQL.js} +18 -4
- package/dist/chunk-2GOCOLQL.js.map +1 -0
- package/dist/{chunk-XIZRXI7N.js → chunk-A7DYEERU.js} +13 -1
- package/dist/chunk-A7DYEERU.js.map +1 -0
- package/dist/{chunk-6VQPLV3O.js → chunk-DSLRNR43.js} +9 -8
- package/dist/chunk-DSLRNR43.js.map +1 -0
- package/dist/{chunk-AOAW55JN.js → chunk-DXQZ3BEO.js} +4 -1
- package/dist/chunk-DXQZ3BEO.js.map +1 -0
- package/dist/chunk-IKCUPTR2.js +170 -0
- package/dist/chunk-IKCUPTR2.js.map +1 -0
- package/dist/{chunk-Z6PE5T7N.js → chunk-JL4BBZP4.js} +4 -3
- package/dist/chunk-JL4BBZP4.js.map +1 -0
- package/dist/collapsible-panel.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -5
- package/dist/nav-stack-B1Qc2e5q.d.ts +101 -0
- package/dist/nav-stack.d.ts +11 -93
- package/dist/nav-stack.js +5 -1
- package/dist/pane.d.ts +5 -2
- package/dist/pane.js +1 -1
- package/dist/split-view.d.ts +9 -4
- package/dist/split-view.js +7 -3
- package/dist/split-view.js.map +1 -1
- package/dist/styles/components/actions/toolbar-control-group/toolbar-control-group.css +60 -13
- package/dist/styles/components/actions/toolbar-text/toolbar-text.css +7 -1
- package/dist/styles/components/layout/pane/pane.css +7 -0
- package/dist/styles/components/navigation/nav-stack/nav-stack.css +6 -12
- package/dist/styles/components/navigation/tab-scaffold/tab-scaffold.css +17 -0
- package/dist/styles/components/surfaces/surface-scaffold/surface-scaffold.css +55 -0
- package/dist/styles/nav-stack.css +6 -12
- package/dist/styles/pane.css +7 -0
- package/dist/styles/surface-scaffold.css +55 -0
- package/dist/styles/tab-scaffold.css +17 -0
- package/dist/styles/toolbar-control-group.css +60 -13
- package/dist/styles/toolbar-text.css +7 -1
- package/dist/surface-scaffold-register.d.ts +4 -0
- package/dist/surface-scaffold-register.js +59 -0
- package/dist/surface-scaffold-register.js.map +1 -0
- package/dist/surface-scaffold.d.ts +10 -2
- package/dist/surface-scaffold.js +1 -1
- package/dist/tab-scaffold.d.ts +2 -0
- package/dist/tab-scaffold.js +1 -0
- package/dist/tab-scaffold.js.map +1 -1
- package/dist/wire-toolbar-visibility.js +1 -1
- package/dist/workbench.d.ts +5 -13
- package/dist/workbench.js +1 -1
- package/docs/component-contract.md +8 -1
- package/docs/component-selection.md +1 -1
- package/docs/layout.md +20 -0
- package/docs/nav-stack.md +30 -18
- package/docs/recipes.md +5 -1
- package/docs/split-view.md +7 -4
- package/docs/surface-scaffold.md +46 -0
- package/docs/tab-scaffold.md +57 -0
- package/docs/ui-doctor.md +23 -0
- package/docs/workbench.md +3 -2
- package/doctor/component-style-checks.mjs +224 -0
- package/doctor/index.mjs +42 -13
- package/llms.txt +10 -0
- package/package.json +7 -2
- package/ux-demo/recipes/list-detail-dialog.tsx +4 -0
- package/ux-demo/recipes/navigation-stack.tsx +2 -2
- package/dist/chunk-6VQPLV3O.js.map +0 -1
- package/dist/chunk-AOAW55JN.js.map +0 -1
- package/dist/chunk-WJN3V2H5.js.map +0 -1
- package/dist/chunk-XIZRXI7N.js.map +0 -1
- package/dist/chunk-Z4EPMX25.js +0 -123
- package/dist/chunk-Z4EPMX25.js.map +0 -1
- package/dist/chunk-Z6PE5T7N.js.map +0 -1
|
@@ -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-
|
|
110
|
-
|
|
111
|
-
|
|
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
|
-
|
|
184
|
-
|
|
185
|
-
|
|
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);
|
package/dist/styles/pane.css
CHANGED
|
@@ -158,6 +158,13 @@
|
|
|
158
158
|
var(--_kui-pane-content-block-end);
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
/* Add one outer gutter without changing the inherited item-margin token.
|
|
162
|
+
Nested Row, List, and Grid therefore keep their own default 8px insets. */
|
|
163
|
+
.kui-pane[data-deep-inset="true"] > .kui-pane__content {
|
|
164
|
+
padding-inline: calc(var(--_kui-pane-safe-inline-start) + var(--kui-space-xs))
|
|
165
|
+
calc(var(--_kui-pane-safe-inline-end) + var(--kui-space-xs));
|
|
166
|
+
}
|
|
167
|
+
|
|
161
168
|
.kui-pane__header ~ .kui-pane__content {
|
|
162
169
|
--_kui-pane-content-block-start: 0px;
|
|
163
170
|
}
|
|
@@ -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(
|
|
@@ -610,17 +610,23 @@
|
|
|
610
610
|
wa-button,
|
|
611
611
|
.kui-select,
|
|
612
612
|
.kui-toolbar-action-link
|
|
613
|
-
):
|
|
613
|
+
):nth-child(1 of :where(:not([data-toolbar-visibility-state]))):where(
|
|
614
|
+
:nth-last-child(1 of :not([data-toolbar-visibility-state]))
|
|
615
|
+
)
|
|
614
616
|
):hover {
|
|
615
617
|
background-color: var(--kui-toolbar-control-hover-background);
|
|
616
618
|
}
|
|
617
619
|
|
|
618
620
|
.kui-toolbar-control-group:not([data-single="true"]):has(
|
|
619
|
-
> :is(button, wa-button, .kui-toolbar-action-link):
|
|
621
|
+
> :is(button, wa-button, .kui-toolbar-action-link):nth-child(
|
|
622
|
+
1 of :where(:not([data-toolbar-visibility-state]))
|
|
623
|
+
):where(:nth-last-child(1 of :not([data-toolbar-visibility-state])))
|
|
620
624
|
)
|
|
621
625
|
> :is(button, wa-button, .kui-toolbar-action-link):hover,
|
|
622
626
|
.kui-toolbar-control-group:not([data-single="true"]):has(
|
|
623
|
-
> :is(button, wa-button):
|
|
627
|
+
> :is(button, wa-button):nth-child(
|
|
628
|
+
1 of :where(:not([data-toolbar-visibility-state]))
|
|
629
|
+
):where(:nth-last-child(1 of :not([data-toolbar-visibility-state])))
|
|
624
630
|
)
|
|
625
631
|
> wa-button:hover::part(base) {
|
|
626
632
|
border-color: transparent;
|
|
@@ -765,25 +771,41 @@
|
|
|
765
771
|
|
|
766
772
|
.kui-toolbar-control-group[data-content="avatar"]:is(
|
|
767
773
|
[data-single="true"],
|
|
768
|
-
:has(
|
|
774
|
+
:has(
|
|
775
|
+
> :is(button, wa-button):nth-child(
|
|
776
|
+
1 of :where(:not([data-toolbar-visibility-state]))
|
|
777
|
+
):where(:nth-last-child(1 of :not([data-toolbar-visibility-state])))
|
|
778
|
+
)
|
|
769
779
|
) {
|
|
770
780
|
background-image: var(--kui-toolbar-avatar-image);
|
|
771
781
|
}
|
|
772
782
|
|
|
773
783
|
.kui-toolbar-control-group[data-content="avatar"]:is(
|
|
774
784
|
[data-single="true"],
|
|
775
|
-
:has(
|
|
785
|
+
:has(
|
|
786
|
+
> :is(button, wa-button):nth-child(
|
|
787
|
+
1 of :where(:not([data-toolbar-visibility-state]))
|
|
788
|
+
):where(:nth-last-child(1 of :not([data-toolbar-visibility-state])))
|
|
789
|
+
)
|
|
776
790
|
)
|
|
777
791
|
> :is(button, wa-button) {
|
|
778
792
|
color: transparent;
|
|
779
793
|
}
|
|
780
794
|
|
|
781
795
|
.kui-toolbar-control-group[data-content="avatar"][data-single="false"]:not(
|
|
782
|
-
:has(
|
|
796
|
+
:has(
|
|
797
|
+
> :is(button, wa-button):nth-child(
|
|
798
|
+
1 of :where(:not([data-toolbar-visibility-state]))
|
|
799
|
+
):where(:nth-last-child(1 of :not([data-toolbar-visibility-state])))
|
|
800
|
+
)
|
|
783
801
|
)
|
|
784
802
|
> button[aria-pressed="true"],
|
|
785
803
|
.kui-toolbar-control-group[data-content="avatar"][data-single="false"]:not(
|
|
786
|
-
:has(
|
|
804
|
+
:has(
|
|
805
|
+
> :is(button, wa-button):nth-child(
|
|
806
|
+
1 of :where(:not([data-toolbar-visibility-state]))
|
|
807
|
+
):where(:nth-last-child(1 of :not([data-toolbar-visibility-state])))
|
|
808
|
+
)
|
|
787
809
|
)
|
|
788
810
|
> wa-button[aria-pressed="true"]::part(base) {
|
|
789
811
|
color: transparent;
|
|
@@ -798,7 +820,10 @@
|
|
|
798
820
|
|
|
799
821
|
.kui-toolbar-control-group[data-single="true"][data-appearance="contained"][data-tile-tone="neutral"]:has(
|
|
800
822
|
> svg[aria-hidden="true"]
|
|
801
|
-
):not(
|
|
823
|
+
):not(
|
|
824
|
+
:has(> :not(svg[aria-hidden="true"], [data-toolbar-visibility-state])),
|
|
825
|
+
:has(> svg ~ svg)
|
|
826
|
+
) {
|
|
802
827
|
background: var(--kui-color-neutral-fill-quiet);
|
|
803
828
|
border-color: var(--kui-color-neutral-border-quiet);
|
|
804
829
|
color: var(--kui-color-neutral-on-quiet);
|
|
@@ -806,7 +831,10 @@
|
|
|
806
831
|
|
|
807
832
|
.kui-toolbar-control-group[data-single="true"][data-appearance="contained"][data-tile-tone="brand"]:has(
|
|
808
833
|
> svg[aria-hidden="true"]
|
|
809
|
-
):not(
|
|
834
|
+
):not(
|
|
835
|
+
:has(> :not(svg[aria-hidden="true"], [data-toolbar-visibility-state])),
|
|
836
|
+
:has(> svg ~ svg)
|
|
837
|
+
) {
|
|
810
838
|
background: var(--kui-color-brand-fill-quiet);
|
|
811
839
|
border-color: var(--kui-color-brand-border-quiet);
|
|
812
840
|
color: var(--kui-color-brand-on-quiet);
|
|
@@ -814,7 +842,10 @@
|
|
|
814
842
|
|
|
815
843
|
.kui-toolbar-control-group[data-single="true"][data-appearance="contained"][data-tile-tone="success"]:has(
|
|
816
844
|
> svg[aria-hidden="true"]
|
|
817
|
-
):not(
|
|
845
|
+
):not(
|
|
846
|
+
:has(> :not(svg[aria-hidden="true"], [data-toolbar-visibility-state])),
|
|
847
|
+
:has(> svg ~ svg)
|
|
848
|
+
) {
|
|
818
849
|
background: var(--kui-color-success-fill-quiet);
|
|
819
850
|
border-color: var(--kui-color-success-border-quiet);
|
|
820
851
|
color: var(--kui-color-success-on-quiet);
|
|
@@ -822,7 +853,10 @@
|
|
|
822
853
|
|
|
823
854
|
.kui-toolbar-control-group[data-single="true"][data-appearance="contained"][data-tile-tone="warning"]:has(
|
|
824
855
|
> svg[aria-hidden="true"]
|
|
825
|
-
):not(
|
|
856
|
+
):not(
|
|
857
|
+
:has(> :not(svg[aria-hidden="true"], [data-toolbar-visibility-state])),
|
|
858
|
+
:has(> svg ~ svg)
|
|
859
|
+
) {
|
|
826
860
|
background: var(--kui-color-warning-fill-quiet);
|
|
827
861
|
border-color: var(--kui-color-warning-border-quiet);
|
|
828
862
|
color: var(--kui-color-warning-on-quiet);
|
|
@@ -830,12 +864,25 @@
|
|
|
830
864
|
|
|
831
865
|
.kui-toolbar-control-group[data-single="true"][data-appearance="contained"][data-tile-tone="danger"]:has(
|
|
832
866
|
> svg[aria-hidden="true"]
|
|
833
|
-
):not(
|
|
867
|
+
):not(
|
|
868
|
+
:has(> :not(svg[aria-hidden="true"], [data-toolbar-visibility-state])),
|
|
869
|
+
:has(> svg ~ svg)
|
|
870
|
+
) {
|
|
834
871
|
background: var(--kui-color-danger-fill-quiet);
|
|
835
872
|
border-color: var(--kui-color-danger-border-quiet);
|
|
836
873
|
color: var(--kui-color-danger-on-quiet);
|
|
837
874
|
}
|
|
838
875
|
.kui-toolbar-control-group[data-toolbar-width-hidden="true"],
|
|
839
|
-
.kui-toolbar-control-group__busy-status[data-toolbar-width-hidden="true"]
|
|
876
|
+
.kui-toolbar-control-group__busy-status[data-toolbar-width-hidden="true"],
|
|
877
|
+
.kui-toolbar-control-group:has(
|
|
878
|
+
> [data-toolbar-visibility-state][data-toolbar-width-hidden="true"]
|
|
879
|
+
),
|
|
880
|
+
.kui-toolbar-control-group__busy-status:has(
|
|
881
|
+
> [data-toolbar-visibility-state][data-toolbar-width-hidden="true"]
|
|
882
|
+
) {
|
|
883
|
+
display: none;
|
|
884
|
+
}
|
|
885
|
+
.kui-toolbar-control-group > [data-toolbar-visibility-state],
|
|
886
|
+
.kui-toolbar-control-group__busy-status > [data-toolbar-visibility-state] {
|
|
840
887
|
display: none;
|
|
841
888
|
}
|
|
@@ -159,6 +159,12 @@ button.kui-toolbar-text[data-tone="dark"]:hover {
|
|
|
159
159
|
line-clamp: none;
|
|
160
160
|
max-height: calc(var(--kui-toolbar-text-max-lines) * 1.25em);
|
|
161
161
|
}
|
|
162
|
-
.kui-toolbar-text[data-toolbar-width-hidden="true"]
|
|
162
|
+
.kui-toolbar-text[data-toolbar-width-hidden="true"],
|
|
163
|
+
.kui-toolbar-text:has(
|
|
164
|
+
> [data-toolbar-visibility-state][data-toolbar-width-hidden="true"]
|
|
165
|
+
) {
|
|
166
|
+
display: none;
|
|
167
|
+
}
|
|
168
|
+
.kui-toolbar-text > [data-toolbar-visibility-state] {
|
|
163
169
|
display: none;
|
|
164
170
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import WaDialog from '@awesome.me/webawesome/dist/components/dialog/dialog.js';
|
|
2
|
+
|
|
3
|
+
// src/components/surfaces/surface-scaffold/register/surface-scaffold-register.ts
|
|
4
|
+
|
|
5
|
+
// src/components/surfaces/surface-scaffold/internal/install-dialog-label.ts
|
|
6
|
+
var installed = /* @__PURE__ */ new WeakSet();
|
|
7
|
+
var observed = /* @__PURE__ */ new WeakSet();
|
|
8
|
+
var ownedNames = /* @__PURE__ */ new WeakMap();
|
|
9
|
+
function installDialogLabel(prototype) {
|
|
10
|
+
if (installed.has(prototype)) return;
|
|
11
|
+
installed.add(prototype);
|
|
12
|
+
const target = prototype;
|
|
13
|
+
const update = target.update;
|
|
14
|
+
target.update = function(changed) {
|
|
15
|
+
update.call(this, changed);
|
|
16
|
+
if (!this.parentElement?.classList.contains("kui-dialog-surface")) return;
|
|
17
|
+
if (!observed.has(this)) {
|
|
18
|
+
observed.add(this);
|
|
19
|
+
new MutationObserver(() => syncDialogLabel(this)).observe(this, {
|
|
20
|
+
attributes: true,
|
|
21
|
+
attributeFilter: ["aria-label"]
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
syncDialogLabel(this);
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function syncDialogLabel(host) {
|
|
28
|
+
if (!host.parentElement?.classList.contains("kui-dialog-surface")) return;
|
|
29
|
+
const panel = host.dialog;
|
|
30
|
+
if (!panel) return;
|
|
31
|
+
const previous = ownedNames.get(panel);
|
|
32
|
+
const externalName = ["aria-label", "aria-labelledby"].some((attribute2) => {
|
|
33
|
+
const value2 = panel.getAttribute(attribute2);
|
|
34
|
+
return value2 !== null && !(previous?.attribute === attribute2 && previous.value === value2);
|
|
35
|
+
});
|
|
36
|
+
if (externalName) {
|
|
37
|
+
if (previous && panel.getAttribute(previous.attribute) === previous.value)
|
|
38
|
+
panel.removeAttribute(previous.attribute);
|
|
39
|
+
ownedNames.delete(panel);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const explicit = host.getAttribute("aria-label")?.trim();
|
|
43
|
+
const title = host.shadowRoot?.getElementById("title");
|
|
44
|
+
const attribute = !explicit && !host.withoutHeader && title ? "aria-labelledby" : "aria-label";
|
|
45
|
+
const value = attribute === "aria-labelledby" ? "title" : explicit || host.label;
|
|
46
|
+
if (previous && previous.attribute !== attribute)
|
|
47
|
+
panel.removeAttribute(previous.attribute);
|
|
48
|
+
if (panel.getAttribute(attribute) !== value)
|
|
49
|
+
panel.setAttribute(attribute, value);
|
|
50
|
+
ownedNames.set(panel, { attribute, value });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/components/surfaces/surface-scaffold/register/surface-scaffold-register.ts
|
|
54
|
+
installDialogLabel(WaDialog.prototype);
|
|
55
|
+
var surfaceScaffoldElementsRegistered = true;
|
|
56
|
+
|
|
57
|
+
export { surfaceScaffoldElementsRegistered };
|
|
58
|
+
|
|
59
|
+
//# sourceMappingURL=surface-scaffold-register.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/surfaces/surface-scaffold/internal/install-dialog-label.ts","../src/components/surfaces/surface-scaffold/register/surface-scaffold-register.ts"],"names":["attribute","value"],"mappings":";;;;;AAOA,IAAM,SAAA,uBAAgB,OAAA,EAAgB;AACtC,IAAM,QAAA,uBAAe,OAAA,EAAqB;AAC1C,IAAM,UAAA,uBAAiB,OAAA,EAGrB;AAGK,SAAS,mBAAmB,SAAA,EAAyB;AAC1D,EAAA,IAAI,SAAA,CAAU,GAAA,CAAI,SAAS,CAAA,EAAG;AAC9B,EAAA,SAAA,CAAU,IAAI,SAAS,CAAA;AACvB,EAAA,MAAM,MAAA,GAAS,SAAA;AACf,EAAA,MAAM,SAAS,MAAA,CAAO,MAAA;AACtB,EAAA,MAAA,CAAO,MAAA,GAAS,SAA6B,OAAA,EAAwB;AACnE,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,OAAO,CAAA;AACzB,IAAA,IAAI,CAAC,IAAA,CAAK,aAAA,EAAe,SAAA,CAAU,QAAA,CAAS,oBAAoB,CAAA,EAAG;AACnE,IAAA,IAAI,CAAC,QAAA,CAAS,GAAA,CAAI,IAAI,CAAA,EAAG;AACvB,MAAA,QAAA,CAAS,IAAI,IAAI,CAAA;AACjB,MAAA,IAAI,iBAAiB,MAAM,eAAA,CAAgB,IAAI,CAAC,CAAA,CAAE,QAAQ,IAAA,EAAM;AAAA,QAC9D,UAAA,EAAY,IAAA;AAAA,QACZ,eAAA,EAAiB,CAAC,YAAY;AAAA,OAC/B,CAAA;AAAA,IACH;AACA,IAAA,eAAA,CAAgB,IAAI,CAAA;AAAA,EACtB,CAAA;AACF;AAEA,SAAS,gBAAgB,IAAA,EAAyB;AAChD,EAAA,IAAI,CAAC,IAAA,CAAK,aAAA,EAAe,SAAA,CAAU,QAAA,CAAS,oBAAoB,CAAA,EAAG;AACnE,EAAA,MAAM,QAAQ,IAAA,CAAK,MAAA;AACnB,EAAA,IAAI,CAAC,KAAA,EAAO;AACZ,EAAA,MAAM,QAAA,GAAW,UAAA,CAAW,GAAA,CAAI,KAAK,CAAA;AACrC,EAAA,MAAM,eAAe,CAAC,YAAA,EAAc,iBAAiB,CAAA,CAAE,IAAA,CAAK,CAACA,UAAAA,KAAc;AACzE,IAAA,MAAMC,MAAAA,GAAQ,KAAA,CAAM,YAAA,CAAaD,UAAS,CAAA;AAC1C,IAAA,OACEC,WAAU,IAAA,IACV,EAAE,UAAU,SAAA,KAAcD,UAAAA,IAAa,SAAS,KAAA,KAAUC,MAAAA,CAAAA;AAAA,EAE9D,CAAC,CAAA;AACD,EAAA,IAAI,YAAA,EAAc;AAChB,IAAA,IAAI,YAAY,KAAA,CAAM,YAAA,CAAa,QAAA,CAAS,SAAS,MAAM,QAAA,CAAS,KAAA;AAClE,MAAA,KAAA,CAAM,eAAA,CAAgB,SAAS,SAAS,CAAA;AAC1C,IAAA,UAAA,CAAW,OAAO,KAAK,CAAA;AACvB,IAAA;AAAA,EACF;AACA,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,YAAA,CAAa,YAAY,GAAG,IAAA,EAAK;AACvD,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,UAAA,EAAY,cAAA,CAAe,OAAO,CAAA;AACrD,EAAA,MAAM,YACJ,CAAC,QAAA,IAAY,CAAC,IAAA,CAAK,aAAA,IAAiB,QAChC,iBAAA,GACA,YAAA;AACN,EAAA,MAAM,KAAA,GACJ,SAAA,KAAc,iBAAA,GAAoB,OAAA,GAAU,YAAY,IAAA,CAAK,KAAA;AAC/D,EAAA,IAAI,QAAA,IAAY,SAAS,SAAA,KAAc,SAAA;AACrC,IAAA,KAAA,CAAM,eAAA,CAAgB,SAAS,SAAS,CAAA;AAC1C,EAAA,IAAI,KAAA,CAAM,YAAA,CAAa,SAAS,CAAA,KAAM,KAAA;AACpC,IAAA,KAAA,CAAM,YAAA,CAAa,WAAW,KAAK,CAAA;AACrC,EAAA,UAAA,CAAW,GAAA,CAAI,KAAA,EAAO,EAAE,SAAA,EAAW,OAAO,CAAA;AAC5C;;;AC7DA,kBAAA,CAAmB,SAAS,SAAS,CAAA;AAG9B,IAAM,iCAAA,GAAoC","file":"surface-scaffold-register.js","sourcesContent":["interface NamedDialog extends HTMLElement {\n dialog?: HTMLDialogElement;\n label: string;\n withoutHeader: boolean;\n update(changed: unknown): void;\n}\n\nconst installed = new WeakSet<object>();\nconst observed = new WeakSet<HTMLElement>();\nconst ownedNames = new WeakMap<\n HTMLElement,\n { attribute: string; value: string }\n>();\n\n/** Repair Web Awesome's missing native dialog name before its first modal open. */\nexport function installDialogLabel(prototype: object): void {\n if (installed.has(prototype)) return;\n installed.add(prototype);\n const target = prototype as NamedDialog;\n const update = target.update;\n target.update = function (this: NamedDialog, changed: unknown): void {\n update.call(this, changed);\n if (!this.parentElement?.classList.contains('kui-dialog-surface')) return;\n if (!observed.has(this)) {\n observed.add(this);\n new MutationObserver(() => syncDialogLabel(this)).observe(this, {\n attributes: true,\n attributeFilter: ['aria-label'],\n });\n }\n syncDialogLabel(this);\n };\n}\n\nfunction syncDialogLabel(host: NamedDialog): void {\n if (!host.parentElement?.classList.contains('kui-dialog-surface')) return;\n const panel = host.dialog;\n if (!panel) return;\n const previous = ownedNames.get(panel);\n const externalName = ['aria-label', 'aria-labelledby'].some((attribute) => {\n const value = panel.getAttribute(attribute);\n return (\n value !== null &&\n !(previous?.attribute === attribute && previous.value === value)\n );\n });\n if (externalName) {\n if (previous && panel.getAttribute(previous.attribute) === previous.value)\n panel.removeAttribute(previous.attribute);\n ownedNames.delete(panel);\n return;\n }\n const explicit = host.getAttribute('aria-label')?.trim();\n const title = host.shadowRoot?.getElementById('title');\n const attribute =\n !explicit && !host.withoutHeader && title\n ? 'aria-labelledby'\n : 'aria-label';\n const value =\n attribute === 'aria-labelledby' ? 'title' : explicit || host.label;\n if (previous && previous.attribute !== attribute)\n panel.removeAttribute(previous.attribute);\n if (panel.getAttribute(attribute) !== value)\n panel.setAttribute(attribute, value);\n ownedNames.set(panel, { attribute, value });\n}\n","import WaDialog from '@awesome.me/webawesome/dist/components/dialog/dialog.js';\n\nimport { installDialogLabel } from '../internal/install-dialog-label.js';\n\ninstallDialogLabel(WaDialog.prototype);\n\n/** Importing this module registers wa-dialog and repairs wrapped native names. */\nexport const surfaceScaffoldElementsRegistered = true;\n"]}
|
|
@@ -1,21 +1,29 @@
|
|
|
1
1
|
import * as kerfjs from 'kerfjs';
|
|
2
2
|
import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
|
|
3
|
+
import { CssLength } from './css-values.js';
|
|
3
4
|
|
|
4
5
|
type DialogSurfaceSize = 'small' | 'medium' | 'large';
|
|
5
6
|
type DialogSurfacePresentation = 'modal' | 'side-sheet' | 'fullscreen';
|
|
6
7
|
type SurfaceInset = 'none' | 'compact' | 'comfortable';
|
|
8
|
+
type DialogSurfaceMaxHeight = CssLength | 'viewport';
|
|
7
9
|
interface DialogSurfaceProps {
|
|
8
10
|
children: KerfUiContent;
|
|
9
11
|
size?: DialogSurfaceSize;
|
|
10
12
|
presentation?: DialogSurfacePresentation;
|
|
13
|
+
/** Modal preferred width. Takes precedence over size, within the viewport cap. */
|
|
14
|
+
preferredWidth?: CssLength;
|
|
11
15
|
bodyInset?: SurfaceInset;
|
|
12
16
|
footerInset?: SurfaceInset;
|
|
17
|
+
/** Modal edge clearance. Omit to retain Web Awesome's default viewport cap. */
|
|
18
|
+
viewportGutter?: CssLength;
|
|
19
|
+
/** Modal height cap, bounded by the dynamic viewport minus both gutters. */
|
|
20
|
+
maxHeight?: DialogSurfaceMaxHeight;
|
|
13
21
|
className?: string;
|
|
14
22
|
/** Native named-slot assignment when composed inside a web component. */
|
|
15
23
|
slot?: string;
|
|
16
24
|
}
|
|
17
25
|
/** Configure recurring Web Awesome dialog geometry without consumer ::part() CSS. */
|
|
18
|
-
declare function DialogSurface({ children, size, presentation, bodyInset, footerInset, className, slot, }: DialogSurfaceProps): kerfjs.SafeHtml;
|
|
26
|
+
declare function DialogSurface({ children, size, presentation, preferredWidth, bodyInset, footerInset, viewportGutter, maxHeight, className, slot, }: DialogSurfaceProps): kerfjs.SafeHtml;
|
|
19
27
|
type PopupSurfaceInset = 'standard' | 'compact' | 'list-zero';
|
|
20
28
|
interface PopupSurfaceProps {
|
|
21
29
|
children: KerfUiContent;
|
|
@@ -27,4 +35,4 @@ interface PopupSurfaceProps {
|
|
|
27
35
|
/** Configure recurring Web Awesome dropdown-menu geometry without consumer ::part() CSS. */
|
|
28
36
|
declare function PopupSurface({ children, inset, className, slot, }: PopupSurfaceProps): kerfjs.SafeHtml;
|
|
29
37
|
|
|
30
|
-
export { DialogSurface, type DialogSurfacePresentation, type DialogSurfaceProps, type DialogSurfaceSize, PopupSurface, type PopupSurfaceInset, type PopupSurfaceProps, type SurfaceInset };
|
|
38
|
+
export { DialogSurface, type DialogSurfaceMaxHeight, type DialogSurfacePresentation, type DialogSurfaceProps, type DialogSurfaceSize, PopupSurface, type PopupSurfaceInset, type PopupSurfaceProps, type SurfaceInset };
|
package/dist/surface-scaffold.js
CHANGED
package/dist/tab-scaffold.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ interface TabScaffoldTabBase<Id extends string> {
|
|
|
11
11
|
content: KerfUiContent;
|
|
12
12
|
/** Background of this scene's scrolling work surface. */
|
|
13
13
|
appearance?: PaneAppearance;
|
|
14
|
+
/** Add an extra 8px inline gutter to a plain scene's scrolling content. */
|
|
15
|
+
deepInset?: boolean;
|
|
14
16
|
}
|
|
15
17
|
/** A tab with an optional count or short-status badge. */
|
|
16
18
|
interface TabScaffoldTabCountBadge {
|
package/dist/tab-scaffold.js
CHANGED
|
@@ -27,6 +27,7 @@ function TabScaffold({
|
|
|
27
27
|
"data-tab-scaffold-scene": tab.id,
|
|
28
28
|
"data-active": String(tab.id === active),
|
|
29
29
|
"data-appearance": tab.appearance === "sunken" ? "sunken" : void 0,
|
|
30
|
+
"data-deep-inset": tab.deepInset ? "true" : void 0,
|
|
30
31
|
"aria-hidden": String(tab.id !== active),
|
|
31
32
|
children: tab.content
|
|
32
33
|
}
|
package/dist/tab-scaffold.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/navigation/tab-scaffold/tab-scaffold.tsx"],"names":[],"mappings":"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","file":"tab-scaffold.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport type { KerfUiContent } from '../../../shared/content/semantic-content.js';\nimport { Badge } from '../../feedback/badge/badge.js';\nimport type { PaneAppearance } from '../../layout/pane/pane.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 /** Background of this scene's scrolling work surface. */\n appearance?: PaneAppearance;\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 /**\n * The line over the tab bar, where it meets the active scene. `scroll`\n * (default) shows it only while more of the scene's content lies below —\n * never at the scroll end or when the content fits — once\n * `wireScrollDividers` (`@kerfjs/ui/wire-scroll-dividers`) is wired above\n * the scaffold; unwired, it does not show. `always` shows it without the\n * wiring; `none` never, even when wired. The line is the bar's own 1px top\n * border, so no state moves the bar or a tab.\n */\n chromeDividers?: 'scroll' | 'always' | 'none';\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 chromeDividers = 'scroll',\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 data-chrome-dividers={\n chromeDividers === 'always' || chromeDividers === 'none'\n ? chromeDividers\n : undefined\n }\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 data-appearance={tab.appearance === 'sunken' ? 'sunken' : undefined}\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
|
+
{"version":3,"sources":["../src/components/navigation/tab-scaffold/tab-scaffold.tsx"],"names":[],"mappings":"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","file":"tab-scaffold.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport type { KerfUiContent } from '../../../shared/content/semantic-content.js';\nimport { Badge } from '../../feedback/badge/badge.js';\nimport type { PaneAppearance } from '../../layout/pane/pane.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 /** Background of this scene's scrolling work surface. */\n appearance?: PaneAppearance;\n /** Add an extra 8px inline gutter to a plain scene's scrolling content. */\n deepInset?: boolean;\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 /**\n * The line over the tab bar, where it meets the active scene. `scroll`\n * (default) shows it only while more of the scene's content lies below —\n * never at the scroll end or when the content fits — once\n * `wireScrollDividers` (`@kerfjs/ui/wire-scroll-dividers`) is wired above\n * the scaffold; unwired, it does not show. `always` shows it without the\n * wiring; `none` never, even when wired. The line is the bar's own 1px top\n * border, so no state moves the bar or a tab.\n */\n chromeDividers?: 'scroll' | 'always' | 'none';\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 chromeDividers = 'scroll',\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 data-chrome-dividers={\n chromeDividers === 'always' || chromeDividers === 'none'\n ? chromeDividers\n : undefined\n }\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 data-appearance={tab.appearance === 'sunken' ? 'sunken' : undefined}\n data-deep-inset={tab.deepInset ? 'true' : undefined}\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"]}
|
package/dist/workbench.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { SafeHtml } from 'kerfjs';
|
|
2
2
|
import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
|
|
3
|
+
import { b as NavPane, N as NavStackProps } from './nav-stack-B1Qc2e5q.js';
|
|
3
4
|
import { ListConfig } from './list.js';
|
|
4
|
-
import { NavStackProps } from './nav-stack.js';
|
|
5
5
|
import { PaneConfig } from './pane.js';
|
|
6
6
|
import { ResizableRegionSeparator, ResizableRegionCollapseMotion, ResizableRegionContentOverflow, ResizableRegionPresentation, ResizableRegionRestorePosition } from './resizable-region.js';
|
|
7
|
-
import { a as PanelToolbar,
|
|
7
|
+
import { a as PanelToolbar, c as PanelBottomToolbar, b as PanelChromePlacement, d as PanelToggle } from './panel-toolbar-CL9tYOkh.js';
|
|
8
8
|
import { ToolbarConfig } from './toolbar.js';
|
|
9
|
+
import './toolbar-text.js';
|
|
10
|
+
import './css-values.js';
|
|
9
11
|
import './flex-alignment-4ms8ZbV8.js';
|
|
10
12
|
import './sides-BPSWde0A.js';
|
|
11
|
-
import './css-values.js';
|
|
12
|
-
import './toolbar-text.js';
|
|
13
13
|
import './lucide-icon.js';
|
|
14
14
|
import 'lucide';
|
|
15
15
|
|
|
@@ -131,19 +131,11 @@ interface WorkbenchPanelBase {
|
|
|
131
131
|
restorePosition?: ResizableRegionRestorePosition;
|
|
132
132
|
}
|
|
133
133
|
/** The original static panel body: one toolbar, optional fixed chrome, and one Pane. */
|
|
134
|
-
interface WorkbenchStaticPanel extends WorkbenchPanelBase {
|
|
135
|
-
content: KerfUiContent;
|
|
134
|
+
interface WorkbenchStaticPanel extends WorkbenchPanelBase, NavPane<WorkbenchPanelToolbar, WorkbenchPanelBottomToolbar> {
|
|
136
135
|
/** The composed toolbar; marked groups and its toggle relocate on collapse. */
|
|
137
136
|
toolbar?: WorkbenchPanelToolbar;
|
|
138
|
-
header?: KerfUiContent;
|
|
139
|
-
headerList?: ListConfig;
|
|
140
137
|
headerPlacement?: WorkbenchChromePlacement;
|
|
141
|
-
footer?: KerfUiContent;
|
|
142
|
-
footerList?: ListConfig;
|
|
143
|
-
bottomToolbar?: WorkbenchPanelBottomToolbar;
|
|
144
138
|
footerPlacement?: WorkbenchChromePlacement;
|
|
145
|
-
/** Configuration for the static toolbar panel's Pane. */
|
|
146
|
-
pane?: PaneConfig;
|
|
147
139
|
navStack?: never;
|
|
148
140
|
}
|
|
149
141
|
/** A panel whose active NavStack view supplies the toolbar, fixed header, and scroll body. */
|
package/dist/workbench.js
CHANGED
|
@@ -890,7 +890,14 @@ leave the item visible under this width policy. Server-rendered content is visib
|
|
|
890
890
|
until wiring runs; without browser observers, initial wiring and window resize
|
|
891
891
|
still update it. Probe context and lengths are reconciled only when their CSSOM
|
|
892
892
|
values change, so unrelated DOM observers can redraw without feeding an ongoing
|
|
893
|
-
mutation loop.
|
|
893
|
+
mutation loop. Probes are helper-owned imperative nodes preserved across Kerf
|
|
894
|
+
rerenders, preventing repeated probe creation and resize/DOM observer churn.
|
|
895
|
+
Invisible preserved state children keep actual CSS visibility stable while a render
|
|
896
|
+
removes transient parent markers, so post-render geometry measurements cannot
|
|
897
|
+
feed a show/hide render loop. These children never enter layout, focus or the
|
|
898
|
+
accessible tree. Toolbar replacement or deliberate internal-node removal is
|
|
899
|
+
still repaired. Dispose to
|
|
900
|
+
remove measurement probes and restore prior markers.
|
|
894
901
|
|
|
895
902
|
Hidden controls leave layout and keyboard navigation. A hidden busy group also
|
|
896
903
|
hides only its own adjacent busy status. Keep primary actions always available;
|