@kerfjs/ui 5.0.0-beta.61 → 5.0.0-beta.62
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/ai/component-catalog.json +12 -5
- package/ai/component-composition.json +8 -1
- package/ai/components/pane.md +3 -2
- package/ai/components/select.md +1 -0
- package/ai/components/toolbar-text.md +2 -1
- package/ai/public-api-signatures-v1.md +27 -11
- package/ai/skill.md +3 -1
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/dist/catalog.js +3 -3
- package/dist/{chunk-TEYARRAK.js → chunk-4MG3KXJM.js} +4 -1
- package/dist/chunk-4MG3KXJM.js.map +1 -0
- package/dist/{chunk-NYL63PSD.js → chunk-ENGVYQPG.js} +4 -3
- package/dist/chunk-ENGVYQPG.js.map +1 -0
- package/dist/{chunk-5PESG2VP.js → chunk-KYDDCJXU.js} +4 -3
- package/dist/chunk-KYDDCJXU.js.map +1 -0
- package/dist/{chunk-MERWRTBG.js → chunk-N2DRU35S.js} +1 -1
- package/dist/chunk-N2DRU35S.js.map +1 -0
- package/dist/{chunk-EZVNC4J6.js → chunk-OD2VXAPL.js} +4 -1
- package/dist/chunk-OD2VXAPL.js.map +1 -0
- package/dist/{chunk-N3GKMPDW.js → chunk-RKTTF3L4.js} +3 -1
- package/dist/chunk-RKTTF3L4.js.map +1 -0
- package/dist/{chunk-C4OYOKWX.js → chunk-UA6JW52D.js} +36 -2
- package/dist/chunk-UA6JW52D.js.map +1 -0
- package/dist/{chunk-3SXMEK3B.js → chunk-V3DX3K65.js} +1 -1
- package/dist/chunk-V3DX3K65.js.map +1 -0
- package/dist/{chunk-Y74NWGQW.js → chunk-X6ADHJNI.js} +45 -20
- package/dist/chunk-X6ADHJNI.js.map +1 -0
- package/dist/collapsible-panel.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -6
- package/dist/nav-stack.d.ts +3 -1
- package/dist/nav-stack.js +1 -1
- package/dist/pane.d.ts +8 -3
- package/dist/pane.js +1 -1
- package/dist/select.d.ts +2 -0
- package/dist/select.js +1 -1
- package/dist/split-view.d.ts +1 -1
- package/dist/split-view.js +1 -1
- package/dist/styles/app-tab.css +84 -0
- package/dist/styles/nav-stack.css +13 -0
- package/dist/styles/pane.css +33 -0
- package/dist/styles/resizable-region.css +9 -0
- package/dist/styles/select.css +15 -0
- package/dist/styles/split-view.css +6 -0
- package/dist/styles/tab-bar.css +3 -0
- package/dist/styles/tab-scaffold.css +13 -0
- package/dist/styles/toolbar-text.css +15 -6
- package/dist/styles/toolbar.css +7 -0
- package/dist/styles/workbench.css +117 -93
- package/dist/tab-bar.d.ts +6 -2
- package/dist/tab-bar.js +1 -1
- package/dist/tab-scaffold.d.ts +3 -0
- package/dist/tab-scaffold.js +1 -0
- package/dist/tab-scaffold.js.map +1 -1
- package/dist/toolbar-text.d.ts +1 -1
- package/dist/toolbar-text.js +1 -1
- package/dist/toolbar.d.ts +2 -2
- package/dist/toolbar.js +1 -1
- package/dist/wire-tab-bars.js +1 -1
- package/dist/workbench.js +1 -1
- package/docs/collapsible-panel.md +4 -3
- package/docs/component-selection.md +27 -8
- package/docs/layout.md +31 -0
- package/docs/nav-stack.md +5 -0
- package/docs/split-view.md +5 -0
- package/docs/sunken-panel.md +8 -1
- package/docs/tab-scaffold.md +5 -0
- package/docs/webawesome-theme.md +36 -6
- package/docs/workbench.md +22 -10
- package/llms.txt +4 -0
- package/package.json +1 -1
- package/dist/chunk-3SXMEK3B.js.map +0 -1
- package/dist/chunk-5PESG2VP.js.map +0 -1
- package/dist/chunk-C4OYOKWX.js.map +0 -1
- package/dist/chunk-EZVNC4J6.js.map +0 -1
- package/dist/chunk-MERWRTBG.js.map +0 -1
- package/dist/chunk-N3GKMPDW.js.map +0 -1
- package/dist/chunk-NYL63PSD.js.map +0 -1
- package/dist/chunk-TEYARRAK.js.map +0 -1
- package/dist/chunk-Y74NWGQW.js.map +0 -1
|
@@ -582,7 +582,8 @@
|
|
|
582
582
|
"useWhen": [
|
|
583
583
|
"An application column needs shared header, content, and optional footer organization with exactly one scrolling content owner.",
|
|
584
584
|
"A pane boundary needs an opt-in separator on any combination of logical sides.",
|
|
585
|
-
"Pinned chrome needs a divider from the scrolling content only while content is scrolled beneath it (wireScrollDividers)."
|
|
585
|
+
"Pinned chrome needs a divider from the scrolling content only while content is scrolled beneath it (wireScrollDividers).",
|
|
586
|
+
"A lowered background must cover the scrolling work viewport and blank space after short content without a second scroll container (appearance: sunken)."
|
|
586
587
|
],
|
|
587
588
|
"avoidWhen": [
|
|
588
589
|
"Do not use Pane as a padded card or add a competing scroll owner around its content slot.",
|
|
@@ -602,7 +603,8 @@
|
|
|
602
603
|
"which logical boundaries show separators",
|
|
603
604
|
"which sides may compensate for device safe areas in an app-owned arrangement (safeAreaEdges)",
|
|
604
605
|
"responsive placement and visibility",
|
|
605
|
-
"whether the chrome dividers follow the scroll, always show, or never show (chromeDividers)"
|
|
606
|
+
"whether the chrome dividers follow the scroll, always show, or never show (chromeDividers)",
|
|
607
|
+
"default or sunken scrolling work surface (appearance)"
|
|
606
608
|
],
|
|
607
609
|
"variants": [
|
|
608
610
|
"content only",
|
|
@@ -667,7 +669,9 @@
|
|
|
667
669
|
"--kui-edge-inset-inline-end",
|
|
668
670
|
"--kui-edge-inset-inline-start",
|
|
669
671
|
"--kui-pane-separator-color",
|
|
670
|
-
"--kui-pane-separator-width"
|
|
672
|
+
"--kui-pane-separator-width",
|
|
673
|
+
"--kui-pane-chrome-background",
|
|
674
|
+
"--kui-sunken-panel-background"
|
|
671
675
|
],
|
|
672
676
|
"links": {
|
|
673
677
|
"catalogRoute": "?component=pane",
|
|
@@ -1850,7 +1854,7 @@
|
|
|
1850
1854
|
],
|
|
1851
1855
|
"avoidWhen": [
|
|
1852
1856
|
"Do not omit headingLevel when the text is the page or section heading.",
|
|
1853
|
-
"
|
|
1857
|
+
"Large, default, and small are intentionally quiet toolbar identity text and have no tone option. Use xlarge-fixed for a normal-color toolbar heading at the fixed font-l step; use Text with an h2-h6 variant for a content subsection title, or ListHeader for a list or menu section."
|
|
1854
1858
|
],
|
|
1855
1859
|
"alternatives": [
|
|
1856
1860
|
{
|
|
@@ -1870,6 +1874,7 @@
|
|
|
1870
1874
|
],
|
|
1871
1875
|
"variants": [
|
|
1872
1876
|
"xlarge",
|
|
1877
|
+
"xlarge-fixed (fixed font-l heading)",
|
|
1873
1878
|
"large",
|
|
1874
1879
|
"default",
|
|
1875
1880
|
"small",
|
|
@@ -3601,7 +3606,8 @@
|
|
|
3601
3606
|
"overflow dividers on each side with tabs scrolled out of view (wired by wireScrollDividers)"
|
|
3602
3607
|
],
|
|
3603
3608
|
"accessibility": [
|
|
3604
|
-
"Keep exactly one selected tab at tabindex 0 and preserve the wiring keyboard model."
|
|
3609
|
+
"Keep exactly one selected tab at tabindex 0 and preserve the wiring keyboard model.",
|
|
3610
|
+
"Call wireTabBars for keyboard focus and selection, including the pinned leading tab's WebKit RTL scroll correction."
|
|
3605
3611
|
],
|
|
3606
3612
|
"geometry": {
|
|
3607
3613
|
"margin": "none",
|
|
@@ -4152,6 +4158,7 @@
|
|
|
4152
4158
|
"form, toolbar-borderless, or navigation presentation",
|
|
4153
4159
|
"default or compact size",
|
|
4154
4160
|
"label or icon-only selected presentation",
|
|
4161
|
+
"optional caret-free round icon-only trigger",
|
|
4155
4162
|
"select- or group-owned focus ring",
|
|
4156
4163
|
"label maximum width and truncation",
|
|
4157
4164
|
"fit-content, max-content, or fill trigger width",
|
|
@@ -589,6 +589,11 @@
|
|
|
589
589
|
"id": "whether the chrome dividers follow the scroll, always show, or never show (chromeDividers)",
|
|
590
590
|
"owner": "application",
|
|
591
591
|
"required": false
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
"id": "default or sunken scrolling work surface (appearance)",
|
|
595
|
+
"owner": "application",
|
|
596
|
+
"required": false
|
|
592
597
|
}
|
|
593
598
|
],
|
|
594
599
|
"wiring": {
|
|
@@ -645,7 +650,9 @@
|
|
|
645
650
|
"--kui-edge-inset-inline-end",
|
|
646
651
|
"--kui-edge-inset-inline-start",
|
|
647
652
|
"--kui-pane-separator-color",
|
|
648
|
-
"--kui-pane-separator-width"
|
|
653
|
+
"--kui-pane-separator-width",
|
|
654
|
+
"--kui-pane-chrome-background",
|
|
655
|
+
"--kui-sunken-panel-background"
|
|
649
656
|
]
|
|
650
657
|
},
|
|
651
658
|
"diagnostics": [],
|
package/ai/components/pane.md
CHANGED
|
@@ -13,6 +13,7 @@ Organize a sidebar, main area, inspector, or dialog column into fixed vertical h
|
|
|
13
13
|
- An application column needs shared header, content, and optional footer organization with exactly one scrolling content owner.
|
|
14
14
|
- A pane boundary needs an opt-in separator on any combination of logical sides.
|
|
15
15
|
- Pinned chrome needs a divider from the scrolling content only while content is scrolled beneath it (wireScrollDividers).
|
|
16
|
+
- A lowered background must cover the scrolling work viewport and blank space after short content without a second scroll container (appearance: sunken).
|
|
16
17
|
|
|
17
18
|
**Not when:**
|
|
18
19
|
|
|
@@ -60,7 +61,7 @@ Zones (a zone is bound to JSX only through its listed prop; never assume the zon
|
|
|
60
61
|
|
|
61
62
|
## State and wiring
|
|
62
63
|
|
|
63
|
-
**The app owns:** root and content semantics; accessible labels; header, content, and footer children; which logical boundaries show separators; which sides may compensate for device safe areas in an app-owned arrangement (safeAreaEdges); responsive placement and visibility; whether the chrome dividers follow the scroll, always show, or never show (chromeDividers).
|
|
64
|
+
**The app owns:** root and content semantics; accessible labels; header, content, and footer children; which logical boundaries show separators; which sides may compensate for device safe areas in an app-owned arrangement (safeAreaEdges); responsive placement and visibility; whether the chrome dividers follow the scroll, always show, or never show (chromeDividers); default or sunken scrolling work surface (appearance).
|
|
64
65
|
|
|
65
66
|
**Wiring:** `wireScrollDividers` is optional.
|
|
66
67
|
|
|
@@ -89,7 +90,7 @@ Public class hooks (select for layout placement only, never to change the compon
|
|
|
89
90
|
|
|
90
91
|
Never put `kui-pane`, `kui-pane__content`, `kui-pane__footer`, `kui-pane__header`, `kui-pane__toolbar` on an element you write; render `Pane` instead (`KUI-L103`).
|
|
91
92
|
|
|
92
|
-
Public tokens it reads: `--kui-edge-inset-block-end`, `--kui-edge-inset-block-start`, `--kui-edge-inset-inline-end`, `--kui-edge-inset-inline-start`, `--kui-pane-separator-color`, `--kui-pane-separator-width`. Set a token only where its public contract allows; prefer a prop.
|
|
93
|
+
Public tokens it reads: `--kui-edge-inset-block-end`, `--kui-edge-inset-block-start`, `--kui-edge-inset-inline-end`, `--kui-edge-inset-inline-start`, `--kui-pane-separator-color`, `--kui-pane-separator-width`, `--kui-pane-chrome-background`, `--kui-sunken-panel-background`. Set a token only where its public contract allows; prefer a prop.
|
|
93
94
|
|
|
94
95
|
Everything else is internal: `kerf-ui-analyze` reports private or unknown `.kui-*` selectors (`KUI-L001`, `KUI-L010`), unknown or private tokens (`KUI-L002`, `KUI-L012`), and any application rule that restyles the component, forced dimensions included (`KUI-L019`).
|
|
95
96
|
|
package/ai/components/select.md
CHANGED
|
@@ -46,6 +46,7 @@ Exact prop names and types: [`@kerfjs/ui/select`](../public-api-signatures-v1.md
|
|
|
46
46
|
- form, toolbar-borderless, or navigation presentation
|
|
47
47
|
- default or compact size
|
|
48
48
|
- label or icon-only selected presentation
|
|
49
|
+
- optional caret-free round icon-only trigger
|
|
49
50
|
- select- or group-owned focus ring
|
|
50
51
|
- label maximum width and truncation
|
|
51
52
|
- fit-content, max-content, or fill trigger width
|
|
@@ -13,7 +13,7 @@ Extra-large through extra-small toolbar identity text.
|
|
|
13
13
|
**Not when:**
|
|
14
14
|
|
|
15
15
|
- Do not omit headingLevel when the text is the page or section heading.
|
|
16
|
-
-
|
|
16
|
+
- Large, default, and small are intentionally quiet toolbar identity text and have no tone option. Use xlarge-fixed for a normal-color toolbar heading at the fixed font-l step; use Text with an h2-h6 variant for a content subsection title, or ListHeader for a list or menu section.
|
|
17
17
|
|
|
18
18
|
**Alternatives:**
|
|
19
19
|
|
|
@@ -33,6 +33,7 @@ Exact prop names and types: [`@kerfjs/ui/toolbar-text`](../public-api-signatures
|
|
|
33
33
|
**Variants (configure, do not restyle):**
|
|
34
34
|
|
|
35
35
|
- xlarge
|
|
36
|
+
- xlarge-fixed (fixed font-l heading)
|
|
36
37
|
- large
|
|
37
38
|
- default
|
|
38
39
|
- small
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Public API signatures for the UI authoring corpus
|
|
2
2
|
|
|
3
|
-
Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.
|
|
3
|
+
Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.62` and `kerfjs@5.0.0-beta.62`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
|
|
4
4
|
|
|
5
5
|
## `@kerfjs/ui/css-values`
|
|
6
6
|
|
|
@@ -160,8 +160,8 @@ interface ToolbarProps {
|
|
|
160
160
|
* then draws its facing side the same way.
|
|
161
161
|
*/
|
|
162
162
|
dividerSides?: Sides;
|
|
163
|
-
/**
|
|
164
|
-
centerAlign?: 'center' | 'stretch';
|
|
163
|
+
/** `balanced` gives both side zones equal tracks, centering the middle zone on the toolbar even if only one side has controls. */
|
|
164
|
+
centerAlign?: 'center' | 'stretch' | 'balanced';
|
|
165
165
|
/**
|
|
166
166
|
* Component-owned responsive layout; applications choose the policy rather
|
|
167
167
|
* than restyling toolbar internals. Under every policy the trailing zone
|
|
@@ -210,7 +210,7 @@ export { Sides, Toolbar, type ToolbarConfig, type ToolbarProps };
|
|
|
210
210
|
```ts
|
|
211
211
|
import * as kerfjs from 'kerfjs';
|
|
212
212
|
|
|
213
|
-
type ToolbarTextSize = 'xlarge' | 'large' | 'default' | 'small' | 'xsmall';
|
|
213
|
+
type ToolbarTextSize = 'xlarge' | 'xlarge-fixed' | 'large' | 'default' | 'small' | 'xsmall';
|
|
214
214
|
/** ARIA heading level for a title exposed as a heading landmark. */
|
|
215
215
|
type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
|
216
216
|
interface ToolbarTextBaseProps {
|
|
@@ -1024,6 +1024,8 @@ type TabActivation = 'automatic' | 'manual';
|
|
|
1024
1024
|
type TabBarAllocation = 'intrinsic' | 'fill';
|
|
1025
1025
|
type TabBarPresentation = 'rail' | 'segmented' | 'inspector';
|
|
1026
1026
|
type TabBarTrailingPlacement = 'separate' | 'adjacent';
|
|
1027
|
+
/** Tablist width where segmented AppTabs switch to icon-only. */
|
|
1028
|
+
type TabBarIconOnlyAt = 'wide' | 'narrow' | 'compact';
|
|
1027
1029
|
interface TabBarProps {
|
|
1028
1030
|
id: string;
|
|
1029
1031
|
label: string;
|
|
@@ -1047,15 +1049,17 @@ interface TabBarProps {
|
|
|
1047
1049
|
allocation?: TabBarAllocation;
|
|
1048
1050
|
/** Named strip chrome for application rails, segmented tabs, or inspectors. */
|
|
1049
1051
|
presentation?: TabBarPresentation;
|
|
1052
|
+
/** Switch segmented AppTabs to icon-only at tablist widths of 832, 704, or 448px. Each tab needs a leading icon. */
|
|
1053
|
+
iconOnlyAt?: TabBarIconOnlyAt;
|
|
1050
1054
|
/** Keep a trailing action beside the final tab or at the far edge of the bar. */
|
|
1051
1055
|
trailingPlacement?: TabBarTrailingPlacement;
|
|
1052
1056
|
/** Native named-slot assignment when composed inside a web component. */
|
|
1053
1057
|
slot?: string;
|
|
1054
1058
|
}
|
|
1055
1059
|
/** Render a controlled tab strip. The application owns selection, order, and persistence. */
|
|
1056
|
-
declare function TabBar({ id, label, children, leading, trailing, end, className, activation, allocation, presentation, trailingPlacement, slot, }: TabBarProps): kerfjs.SafeHtml;
|
|
1060
|
+
declare function TabBar({ id, label, children, leading, trailing, end, className, activation, allocation, presentation, iconOnlyAt, trailingPlacement, slot, }: TabBarProps): kerfjs.SafeHtml;
|
|
1057
1061
|
|
|
1058
|
-
export { type TabActivation, TabBar, type TabBarAllocation, type TabBarPresentation, type TabBarProps, type TabBarTrailingPlacement };
|
|
1062
|
+
export { type TabActivation, TabBar, type TabBarAllocation, type TabBarIconOnlyAt, type TabBarPresentation, type TabBarProps, type TabBarTrailingPlacement };
|
|
1059
1063
|
```
|
|
1060
1064
|
|
|
1061
1065
|
## `@kerfjs/ui/wire-tab-bars`
|
|
@@ -1175,10 +1179,10 @@ export { type ScrollDividerTarget, type WireScrollDividersOptions, wireScrollDiv
|
|
|
1175
1179
|
|
|
1176
1180
|
```ts
|
|
1177
1181
|
import * as kerfjs from 'kerfjs';
|
|
1182
|
+
import { PaneAppearance } from './pane.js';
|
|
1178
1183
|
import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
|
|
1179
1184
|
import { ToolbarConfig } from './toolbar.js';
|
|
1180
1185
|
import { ToolbarTextSize, HeadingLevel } from './toolbar-text.js';
|
|
1181
|
-
import './pane.js';
|
|
1182
1186
|
import './sides-BPSWde0A.js';
|
|
1183
1187
|
|
|
1184
1188
|
/**
|
|
@@ -1189,6 +1193,8 @@ interface NavStackView {
|
|
|
1189
1193
|
/** Stable identity for keyed reconcile and transition direction. */
|
|
1190
1194
|
key: string;
|
|
1191
1195
|
content: KerfUiContent;
|
|
1196
|
+
/** Background of this view's scrolling work surface. */
|
|
1197
|
+
appearance?: PaneAppearance;
|
|
1192
1198
|
/** Title shown in the top toolbar for this view. */
|
|
1193
1199
|
title?: string;
|
|
1194
1200
|
/** Leading groups for this view's top toolbar, after the back control and before the title. */
|
|
@@ -1294,8 +1300,8 @@ import * as kerfjs from 'kerfjs';
|
|
|
1294
1300
|
import { NavStackProps, NavStackView } from './nav-stack.js';
|
|
1295
1301
|
import { ResizableRegionProps } from './resizable-region.js';
|
|
1296
1302
|
import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
|
|
1297
|
-
import './toolbar.js';
|
|
1298
1303
|
import './pane.js';
|
|
1304
|
+
import './toolbar.js';
|
|
1299
1305
|
import './sides-BPSWde0A.js';
|
|
1300
1306
|
import './toolbar-text.js';
|
|
1301
1307
|
import './css-values.js';
|
|
@@ -1393,6 +1399,7 @@ type PaneRootAttributes = Readonly<Record<`data-${string}`, string | undefined>
|
|
|
1393
1399
|
'data-safe-area-inline-end'?: never;
|
|
1394
1400
|
'data-chrome-placement'?: never;
|
|
1395
1401
|
'data-chrome-dividers'?: never;
|
|
1402
|
+
'data-appearance'?: never;
|
|
1396
1403
|
}>;
|
|
1397
1404
|
/** How a Pane's header and footer relate to its scrolling content. */
|
|
1398
1405
|
type PaneChromePlacement = 'fixed' | 'auto';
|
|
@@ -1402,6 +1409,8 @@ type PaneChromePlacement = 'fixed' | 'auto';
|
|
|
1402
1409
|
* chrome, as `wireScrollDividers` reports; `always`; or `none`.
|
|
1403
1410
|
*/
|
|
1404
1411
|
type PaneChromeDividers = 'scroll' | 'always' | 'none';
|
|
1412
|
+
/** Background treatment of the Pane's scrolling work surface. */
|
|
1413
|
+
type PaneAppearance = 'default' | 'sunken';
|
|
1405
1414
|
interface PaneProps {
|
|
1406
1415
|
/** Optional fixed chrome above the scrolling content, arranged vertically. */
|
|
1407
1416
|
header?: KerfUiContent;
|
|
@@ -1427,6 +1436,8 @@ interface PaneProps {
|
|
|
1427
1436
|
* The line is drawn inside the chrome, so no state moves the content.
|
|
1428
1437
|
*/
|
|
1429
1438
|
chromeDividers?: PaneChromeDividers;
|
|
1439
|
+
/** Paint the scrolling work surface with the shared lowered-surface color. */
|
|
1440
|
+
appearance?: PaneAppearance;
|
|
1430
1441
|
/** Root semantics. Defaults to `div`. */
|
|
1431
1442
|
element?: PaneElement;
|
|
1432
1443
|
/** Scrolling content semantics. Defaults to `div`. */
|
|
@@ -1461,16 +1472,16 @@ interface PaneProps {
|
|
|
1461
1472
|
* or a CollapsiblePanel) forwards, so the app configures that pane instead of
|
|
1462
1473
|
* styling it. An omitted or `undefined` field keeps the composite's default.
|
|
1463
1474
|
*/
|
|
1464
|
-
type PaneConfig = Pick<PaneProps, 'contentElement' | 'contentLabel' | 'separators' | 'safeAreaEdges' | 'chromeDividers'>;
|
|
1475
|
+
type PaneConfig = Pick<PaneProps, 'contentElement' | 'contentLabel' | 'separators' | 'safeAreaEdges' | 'chromeDividers' | 'appearance'>;
|
|
1465
1476
|
/**
|
|
1466
1477
|
* An unpadded application column with optional fixed header/footer slots and one
|
|
1467
1478
|
* scrolling vertical content owner. Separator lines are independently opt-in on
|
|
1468
1479
|
* each logical edge, so the same component works as a sidebar, main area,
|
|
1469
1480
|
* inspector, or dialog column.
|
|
1470
1481
|
*/
|
|
1471
|
-
declare function Pane({ header, children, footer, chromePlacement, chromeDividers, element, contentElement, separators, safeAreaEdges, id, label, contentLabel, className, headerClassName, contentClassName, footerClassName, rootAttributes, slot, }: PaneProps): kerfjs.SafeHtml;
|
|
1482
|
+
declare function Pane({ header, children, footer, chromePlacement, chromeDividers, appearance, element, contentElement, separators, safeAreaEdges, id, label, contentLabel, className, headerClassName, contentClassName, footerClassName, rootAttributes, slot, }: PaneProps): kerfjs.SafeHtml;
|
|
1472
1483
|
|
|
1473
|
-
export { Pane, type PaneChromeDividers, type PaneChromePlacement, type PaneConfig, type PaneContentElement, type PaneElement, type PaneProps, type PaneSeparatorSide };
|
|
1484
|
+
export { Pane, type PaneAppearance, type PaneChromeDividers, type PaneChromePlacement, type PaneConfig, type PaneContentElement, type PaneElement, type PaneProps, type PaneSeparatorSide };
|
|
1474
1485
|
```
|
|
1475
1486
|
|
|
1476
1487
|
## `@kerfjs/ui/workbench`
|
|
@@ -2035,6 +2046,7 @@ export { type SidebarStorage, type WireSidebarOptions, type WireSidebarPanel, wi
|
|
|
2035
2046
|
|
|
2036
2047
|
```ts
|
|
2037
2048
|
import { SafeHtml } from 'kerfjs';
|
|
2049
|
+
import { PaneAppearance } from './pane.js';
|
|
2038
2050
|
import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
|
|
2039
2051
|
|
|
2040
2052
|
interface TabScaffoldTabBase<Id extends string> {
|
|
@@ -2044,6 +2056,8 @@ interface TabScaffoldTabBase<Id extends string> {
|
|
|
2044
2056
|
icon?: SafeHtml;
|
|
2045
2057
|
/** The tab's content — typically a `NavStack` so each tab keeps its own stack. */
|
|
2046
2058
|
content: KerfUiContent;
|
|
2059
|
+
/** Background of this scene's scrolling work surface. */
|
|
2060
|
+
appearance?: PaneAppearance;
|
|
2047
2061
|
}
|
|
2048
2062
|
/** A tab with an optional count or short-status badge. */
|
|
2049
2063
|
interface TabScaffoldTabCountBadge {
|
|
@@ -2608,6 +2622,8 @@ interface SelectBaseProps<Value extends string = string> {
|
|
|
2608
2622
|
size?: SelectSize;
|
|
2609
2623
|
/** Closed trigger width; omit to keep the presentation's default. */
|
|
2610
2624
|
triggerWidth?: SelectTriggerWidth;
|
|
2625
|
+
/** Show the disclosure caret (default); omit it for a compact icon-only trigger. */
|
|
2626
|
+
caret?: boolean;
|
|
2611
2627
|
/** Let an enclosing ToolbarControlGroup paint the composed focus ring. */
|
|
2612
2628
|
focusRingOwner?: SelectFocusRingOwner;
|
|
2613
2629
|
/** Maximum closed-control label width in CSS pixels before ellipsis. */
|
package/ai/skill.md
CHANGED
|
@@ -195,7 +195,7 @@ Hard rules:
|
|
|
195
195
|
4. Wire `data-action` hooks from one stable root with `delegate()` or `delegateActions()` and retain disposers.
|
|
196
196
|
5. Configure components through their typed props; components own their own styles (see "Components own their styles; configure, never override" above). Use the opinionated `--kui-color-*` semantic ramps for theming, not to reshape a component. Use `pop` only for attractive non-status emphasis such as featured, novel, or celebratory content; never substitute it for info, success, warning, or danger. Set a theme token only at the narrowest useful scope, and never where an equivalent prop exists. `publicClasses` exist for diagnostics, tooling, tests, and package-owned composition, not application styling. Never target a Kerf or Web Awesome component from application CSS; add missing configuration to the owner.
|
|
197
197
|
6. `Select` is pure until the app explicitly imports `@kerfjs/ui/select/register`; once registered, an icon-only `Select` (and, via `@kerfjs/ui/popup-menu/register`, an icon-only `PopupMenu`) shows an `aria-hidden` help tag repeating its accessible name (and a Select's current choice) on hover and keyboard focus, hidden while its popup is open — never add a `title` or your own tooltip to these triggers. The same installer tags an icon-only `<button>` or link in a `ToolbarControlGroup` named by `aria-label` (no visible text, no `title`); a toolbar with such buttons but no registered Select or PopupMenu imports `@kerfjs/ui/help-tags/register` once. Name those buttons with `aria-label`, not `title`: a `title` keeps the browser tooltip and skips the tag. Do not import Web Awesome's full registration bundle. When an app writes direct `wa-*` JSX, add `import type {} from '@kerfjs/ui/webawesome'` for the catalog-supported intrinsic-element declarations, import the CSS-only `@kerfjs/ui/webawesome.css` theme once, and keep importing individual Web Awesome component modules so their JavaScript remains tree-shakeable. The type boundary emits no code and registers nothing. Pass icon-bearing `choices` and `renderSelected` content normally: `Select` preserves its slotted option icons across Kerf rerenders and keys selected content by the controlled value, so app wrappers must not add competing morph-control attributes. Give it a visible `label` or an `ariaLabel` for a visually hidden name; the nonempty visible label takes precedence and the package names the actual shadow combobox, including `renderSelected`, without adding label geometry. Use `hint` for persistent supporting text below the control and `placeholderText` only for the empty value inside the closed control; loading placeholders retain the hint. For any number of choices set `multiple` with an array `value`: the popup stays open while choices toggle and closes on an outside press or Escape, the closed control summarizes the chosen labels, and `change` reports the value array; do not add app code to keep it open or to render tags. For a toolbar filter menu, add `selectedPresentation="icon-only"` plus a fixed `triggerIcon` (such as a funnel `LucideIcon`): the trigger shows that icon, a count badge while any choice is chosen, and ends its accessible name with the chosen labels ("Filter by label: Bug, Docs"); do not render your own count badge or rewrite the name. When testing name or description, target the element with the `combobox` role rather than the `wa-select` wrapper. Web Awesome's hint attribute and explicit hint slot both describe that shadow combobox across supported engines; do not add an `aria-description` mirror or application shadow-DOM patch.
|
|
198
|
-
7. Decorative icons are hidden; controls are named; focus is visible; state never relies on color alone; reduced motion and increased contrast remain usable. `DisclosureArrow` defaults to an 18px root-scaled visual; size it with its typed `size` prop (`size={remify(24)}`); it never becomes the interaction or accessible-name owner. Put it in an owning native control with a stable accessible name and controlled `aria-expanded`. `ListHeader` toggle mode supplies it when `actionIcon` is omitted, but the app must reveal matching content; a custom icon replaces it. Author replacement icon content facing right before its configured direction transform is applied. Direction changes take the shortest rotation path, with counterclockwise chosen for a 180-degree closed-to-open tie. Kerf `Select` separately keeps its intrinsic Web Awesome expand glyph at `--kui-disclosure-icon-scale: .5
|
|
198
|
+
7. Decorative icons are hidden; controls are named; focus is visible; state never relies on color alone; reduced motion and increased contrast remain usable. `DisclosureArrow` defaults to an 18px root-scaled visual; size it with its typed `size` prop (`size={remify(24)}`); it never becomes the interaction or accessible-name owner. Put it in an owning native control with a stable accessible name and controlled `aria-expanded`. `ListHeader` toggle mode supplies it when `actionIcon` is omitted, but the app must reveal matching content; a custom icon replaces it. Author replacement icon content facing right before its configured direction transform is applied. Direction changes take the shortest rotation path, with counterclockwise chosen for a 180-degree closed-to-open tie. Kerf `Select` separately keeps its intrinsic Web Awesome expand glyph at `--kui-disclosure-icon-scale: .5`; an icon-only toolbar Select may set `caret={false}` for a round trigger while preserving its help tag and keyboard listbox.
|
|
199
199
|
8. `ResizableRegion` uses `wireResizableRegions()` for Arrow, Shift+Arrow, Home/End, and pointer behavior. The app owns size persistence. `handleIcon` replaces decorative dormant glyph content only. Set `responsiveFillAt="narrow"` or `"compact"` when a responsive composition exposes the pane as its only inline track; the component fills that track and hides its dormant separator. For compact overlays, set `presentation="overlay"` and the overlay maximum variables. A lone child (normally a `Pane`) fills the region and owns scrolling; several children stack at natural height. Do not add descendant width/height overrides.
|
|
200
200
|
9. Use controlled `SegmentedControl` for a small exclusive choice set. Select `appearance="toolbar"` when nesting it inside `ToolbarControlGroup`; use rounded or pill shapes for standalone contexts. The package derives inset hover/selection radii from the owning outer shape through `--kui-layout-highlight-inset`; do not restyle an inner highlight to an independent radius. Handle its action, update `value`, keep meaningful choice labels, and preserve every enabled native button in sequential Tab order.
|
|
201
201
|
10. Compose `AppTab` inside controlled `TabBar`; call `wireTabBars()` once and retain its disposer. It owns same-bar drag mechanics, including proximity-based horizontal edge autoscroll, while the app applies `onReorder` and owns order, selection, panels, close policy, routing, and persistence. For a tab-local action followed by a separately pinned workspace action, set `trailingPlacement="adjacent"`, put the local action in `trailing`, and the workspace action in `end`; TabBar owns the shrinking/scrolling tabs and fixed action geometry, so do not add descendant flex overrides. Arrow/Home/End select on move by default and restore focus by bar/tab identity when controlled activation replaces the strip; pass `activation: 'manual'` (or `TabBar activation="manual"` per strip) so arrow keys move focus only and the user selects with Enter/Space/click — use it when selecting a tab is a heavy action. Use runtime-filtered `rootAttributes` for domain metadata and keep an optional `closeIcon` decorative and noninteractive.
|
|
@@ -209,6 +209,8 @@ Hard rules:
|
|
|
209
209
|
16. Keep a visible collapsible pane's collapse control in its own toolbar. When hidden, move its restore control into the adjacent main toolbar on the corresponding logical edge: leading for an inline-start sidebar and trailing for an inline-end inspector. Collapse the pane completely; do not preserve an empty icon-only rail.
|
|
210
210
|
16a. Dividers between pinned chrome and scrolling content are scroll state, not decoration: a `Toolbar` draws none by default (`dividerSides` is for a permanent edge only). Call `wireScrollDividers(appRoot)` from `@kerfjs/ui/wire-scroll-dividers` once and retain its disposer; every `Pane` then draws the line under its header only while content is scrolled beneath it and over its footer only while more content lies below (never when the content fits), every `NavStack`'s top chrome and bottom toolbar and every `TabScaffold` bar do the same around the active view or scene (keyed on whatever actually scrolls there, including a sole `Pane`'s content), and every `TabBar` marks each side of its strip with tabs scrolled out of view. Configure a pane with `chromeDividers` (`scroll` default, `always`, `none`, also via `PaneConfig`), and a `NavStack` or `TabScaffold` with its own `chromeDividers` (same values: `always` draws the chrome lines without the wiring, `none` never, even when wired; a `SplitView` forwards it through `compactStack`); a `toolbarConfig.dividerSides` edge stays the Toolbar's own. Name app-owned chrome by id in `targets`. The wiring writes only `data-scroll-overflow` / `data-scroll-divider` state; never write a border onto a component to show a divider.
|
|
211
211
|
17. The only direct children of a `Toolbar` zone (`leading`/`center`/`trailing`) are `ToolbarText` (identity/title text) and `ToolbarControlGroup`; never drop bare buttons, inputs, links, or arbitrary markup straight into a zone. Put identity/title text directly in the zone as `ToolbarText`; wrap interactive controls and icon tiles in `ToolbarControlGroup`. `SegmentedControl`, `Select`, a collapsible `TokenSearchField`, and Web Awesome controls all live inside a group. Configure zone behavior with `Toolbar.centerAlign` and its `responsive` / `responsiveAt` policy instead of selecting toolbar zone classes. No policy clips an action: trailing (and stacked center) zones wrap whole groups onto another row, and the center zone never compresses below its content (a leading title too long for the row truncates with an ellipsis instead), so never hide or shrink a toolbar control to make it fit; use `responsive="wrap"` for a heading whose title must stay whole, and move genuinely lower-priority commands into an app-owned "More" popup menu. For an ordinary icon/action control inside a group, use a plain `<button>` (the group styles `> button` fully) — that is the default; reach for `wa-button` only when you need a Web Awesome feature. A popup menu in a toolbar is a `PopupMenu` (`@kerfjs/ui/popup-menu`, registered once via `@kerfjs/ui/popup-menu/register`) in a `single` group with `nestedDropdown` and a `menuInset`: give it typed `items` (commands with `action`s, `heading`s, `divider`s) and a trigger `icon` plus visible `text` or an accessible `label`; never hand-write `wa-dropdown` / `wa-dropdown-item` markup for a menu. Let the group size that trigger from its icon, localized text, and caret; do not force a width on the menu or button. Nothing wraps inside a group: an icon sits beside its label on one row and a group's controls never break onto a second line — the group sizes to its content, so if it does not fit, the toolbar's `responsive` policy relocates whole groups. A `ToolbarText` is one line ending in an ellipsis by default; opt into `wrap` (capped by `maxLines`) or `ellipsis={false}` deliberately. Inside a group, a `Select` or `PopupMenu` trigger drops its focus ring while its popup is open (the open popup and its current row show where focus is) and the ring returns when the popup closes; a ring follows the control's shape (a pill for an icon-and-caret trigger, a circle for a compact icon button) — set `focusRingOwner="group"` on a Select whose group paints the composed ring, and never add CSS to show, hide, or reshape a ring. For a compact mixed group, keep the standard item padding and raised selected chrome; the selected item paints over the outer border without an internal separator. For an avatar control, set `content="avatar"` and `avatarImage` on the group instead of inserting an `img`: a lone control paints the contained image on the outer group and a multi-button group paints it only on the pressed selection highlight. Compose panel/dialog/page headings with a direct extra-large `ToolbarText`, optional grouped icon, grouped trailing controls, and app-owned supporting copy below. A non-interactive heading icon is an icon tile: put the `LucideIcon` directly in its `ToolbarControlGroup` (it takes an icon button's 40px slot and centers), never inside a `<button>` that does nothing. A group remains 44px outside (`calc(2px + remify(42px))`) when its border/background are transparent; use 8px between groups and inside items. Each zone item sits in the toolbar's top 44px control band, centered by its own size; a taller item (a wrapped title, a second trailing row) starts at the band's top and grows down without moving the others, so a wrapped `ToolbarText` keeps trailing controls beside its first line — do not add alignment CSS for this. Split dormant and interactive regions: `ListHeader` fills the available inline width by default; set `width="content"` to shrink-wrap while retaining its normal geometry, or `inline` when it belongs in surrounding text without outer margin, border, or padding. It keeps its label and mutually exclusive semantic count or non-count `badge` together, with an independent logical-end action unless disclosure mode makes the title cluster the button. Its action visual defaults to 18px through `--kui-list-header-action-icon-size` inside a fitted 36px hover square whose transparent hit layer keeps the pointer target at least 44px (44px wide by the 36px row in `density="compact"`); never shrink the target to match the visual, and never force the button to 44px. Pass every non-negative safe-integer section quantity through `count` with a localized full spoken `countLabel`; never concatenate it into `label` or put a number in `badge`. `ListItem.trailing` is dormant; use `ListActionRow` when primary and trailing actions need sibling native buttons. Its `label`, `icon`, and `trailingActionIcon` slots are also dormant and cannot contain controls. Let panes relocate at narrow widths instead of shrinking targets. Dividers are chrome and earn their place: a `Toolbar` draws none by default, and the line between pinned chrome and scrolling content comes from scroll state (rule 16a), so never add a border, a permanent `dividerSides`, or a margin to fake or adjust one.
|
|
212
|
+
For a toolbar heading that must remain at the 20px `--kui-font-l` step, use `ToolbarText size="xlarge-fixed"`; `xlarge` retains the responsive page-title clamp. Pass `headingLevel` when it is a section landmark.
|
|
213
|
+
|
|
212
214
|
18. When a recurring concept has no matching export or production recipe, keep its semantics in a thin application adapter while reusing the public layout vocabulary. The composer recipe uses one visible form surface, toolbar title/supporting-copy ids, shared 8px field/action gutters, 24px major rhythm, and a conditional StateBanner as its only nested semantic surface; do not turn every section into a card or double-inset intrinsically bordered controls. For multi-line banner copy use `copyLayout="stacked"`; use `actionPlacement="below"` for an action on its own trailing row. The application-local `../docs/examples/command-palette-adapter.tsx` is reference source for one such missing concept, not an `@kerfjs/ui` runtime export or catalog recipe. The application owns its registration, ranking, history, permissions, availability, shortcut policy, focus policy, dispatch, and copy. If a missing concept recurs across products, open an upstream component or recipe request.
|
|
213
215
|
|
|
214
216
|
For compact `Select` triggers, set `triggerWidth` to `fit-content`, `max-content`,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Web Awesome JSX signatures for the UI authoring corpus
|
|
2
2
|
|
|
3
|
-
Generated from the emitted `@kerfjs/ui@5.0.0-beta.
|
|
3
|
+
Generated from the emitted `@kerfjs/ui@5.0.0-beta.62` declaration boundary. Import `@kerfjs/ui/webawesome` for type effects when authoring direct `wa-*` JSX. The module emits no runtime behavior and does not register custom elements.
|
|
4
4
|
|
|
5
5
|
```ts
|
|
6
6
|
import { KerfCustomElement } from 'kerfjs/jsx-runtime';
|
package/dist/catalog.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Workbench } from './chunk-
|
|
1
|
+
import { Workbench } from './chunk-X6ADHJNI.js';
|
|
2
2
|
|
|
3
3
|
import { PopupMenu } from './chunk-VCBTX62E.js';
|
|
4
4
|
|
|
@@ -9,7 +9,7 @@ import { ListInsetText } from './chunk-DG6G5EPF.js';
|
|
|
9
9
|
import { ListItem } from './chunk-SWVW56CV.js';
|
|
10
10
|
import { List } from './chunk-NAPE7WUS.js';
|
|
11
11
|
|
|
12
|
-
import { ToolbarText } from './chunk-
|
|
12
|
+
import { ToolbarText } from './chunk-V3DX3K65.js';
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
|
|
@@ -19,7 +19,7 @@ import { ToolbarText } from './chunk-3SXMEK3B.js';
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
import { ToolbarControlGroup, ToolbarActionLink } from './chunk-7JUBXOIV.js';
|
|
22
|
-
import { Toolbar } from './chunk-
|
|
22
|
+
import { Toolbar } from './chunk-N2DRU35S.js';
|
|
23
23
|
import { LucideIcon } from './chunk-4R777DUZ.js';
|
|
24
24
|
import { filterDataAttributes } from './chunk-SRSJO5QE.js';
|
|
25
25
|
|
|
@@ -22,6 +22,7 @@ function Select(props) {
|
|
|
22
22
|
presentation = "form",
|
|
23
23
|
size = "default",
|
|
24
24
|
triggerWidth,
|
|
25
|
+
caret = true,
|
|
25
26
|
focusRingOwner = "select",
|
|
26
27
|
labelMaxWidth,
|
|
27
28
|
slot
|
|
@@ -42,6 +43,7 @@ function Select(props) {
|
|
|
42
43
|
"data-presentation": presentation,
|
|
43
44
|
"data-size": size,
|
|
44
45
|
"data-trigger-width": triggerWidth,
|
|
46
|
+
"data-caret": caret ? void 0 : "false",
|
|
45
47
|
"data-selected-presentation": selectedPresentation,
|
|
46
48
|
"data-focus-ring-owner": focusRingOwner,
|
|
47
49
|
"aria-busy": "true",
|
|
@@ -127,6 +129,7 @@ function Select(props) {
|
|
|
127
129
|
"data-presentation": presentation,
|
|
128
130
|
"data-size": size,
|
|
129
131
|
"data-trigger-width": triggerWidth,
|
|
132
|
+
"data-caret": caret ? void 0 : "false",
|
|
130
133
|
"data-selected-presentation": selectedPresentation,
|
|
131
134
|
"data-focus-ring-owner": focusRingOwner,
|
|
132
135
|
name,
|
|
@@ -213,4 +216,4 @@ function Select(props) {
|
|
|
213
216
|
|
|
214
217
|
export { Select };
|
|
215
218
|
|
|
216
|
-
//# sourceMappingURL=chunk-
|
|
219
|
+
//# sourceMappingURL=chunk-4MG3KXJM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/select.tsx"],"names":[],"mappings":"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","file":"chunk-4MG3KXJM.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { Badge } from './badge.js';\nimport { type CssForegroundColor, em } from './css-values.js';\nimport { LucideIcon, type LucideNode } from './lucide-icon.js';\nimport type { KerfUiContent } from './semantic-content.js';\nimport { Skeleton } from './skeleton.js';\n\nexport interface SelectChoice<Value extends string = string> {\n value: Value;\n label: string;\n icon?: LucideNode;\n iconName?: string;\n /**\n * Foreground color for the optional icon: a semantic foreground token such\n * as `uiColor('success-on-quiet')`, or an application-owned\n * `foregroundColorVar('--app-icon-color')`. Fill tokens such as\n * `uiColor('success-fill-quiet')` are pale background tints and do not\n * type-check.\n */\n color?: CssForegroundColor;\n group?: string;\n /** Keep an unavailable choice visible but prevent selection. */\n disabled?: boolean;\n /** Optional explanation exposed as the disabled option's native tooltip. */\n disabledReason?: string;\n /**\n * Draw a divider between this choice and the previous choice in the same\n * list. A group boundary is already a separator, so the first choice of a\n * group (or of the whole menu) never draws a second one.\n */\n separatorBefore?: boolean;\n}\n\ntype SelectAccessibleName =\n { label: string; ariaLabel?: string } | { label?: never; ariaLabel: string };\n\nexport type SelectPresentation = 'form' | 'toolbar-borderless' | 'navigation';\nexport type SelectSize = 'default' | 'compact';\nexport type SelectSelectedPresentation = 'label' | 'icon-only';\nexport type SelectFocusRingOwner = 'select' | 'group';\nexport type SelectTriggerWidth = 'fit-content' | 'max-content' | 'fill';\n\ninterface SelectBaseProps<Value extends string = string> {\n name: string;\n choices: readonly SelectChoice<Value>[];\n className?: string;\n /** Empty-value hint text shown in the closed control (the native select placeholder). */\n placeholderText?: string;\n /** Supporting text shown below the control and associated with its combobox. */\n hint?: string;\n disabled?: boolean;\n fitMenu?: boolean;\n /** Render as an unanimated loading skeleton: the label above a static, empty control box. */\n placeholder?: boolean;\n /** Form (default), borderless toolbar, or intrinsic navigation chrome. */\n presentation?: SelectPresentation;\n size?: SelectSize;\n /** Closed trigger width; omit to keep the presentation's default. */\n triggerWidth?: SelectTriggerWidth;\n /** Show the disclosure caret (default); omit it for a compact icon-only trigger. */\n caret?: boolean;\n /** Let an enclosing ToolbarControlGroup paint the composed focus ring. */\n focusRingOwner?: SelectFocusRingOwner;\n /** Maximum closed-control label width in CSS pixels before ellipsis. */\n labelMaxWidth?: number;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\n/** One chosen value (the default). */\nexport interface SelectSingleValueProps<Value extends string = string> {\n multiple?: false;\n value: NoInfer<Value>;\n renderSelected?: (choice: SelectChoice<Value>) => SafeHtml;\n /** Show only the selected choice icon while retaining the Select's accessible name. */\n selectedPresentation?: SelectSelectedPresentation;\n triggerIcon?: never;\n selectAllLabel?: never;\n clearLabel?: never;\n}\n\n/**\n * Any number of chosen values. The popup stays open while the person toggles\n * choices and closes on an outside click, Escape, or focus leaving; the closed\n * control summarizes the chosen labels in choice order.\n */\nexport interface SelectMultipleLabelProps<Value extends string = string> {\n multiple: true;\n value: readonly NoInfer<Value>[];\n renderSelected?: never;\n selectedPresentation?: 'label';\n triggerIcon?: never;\n /** Opt in to a footer action that selects every enabled choice. */\n selectAllLabel?: string;\n /** Opt in to a footer action that clears the current selection. */\n clearLabel?: string;\n}\n\n/**\n * A multiple Select drawn as an icon-only toolbar trigger, such as a\n * \"Filter by label\" funnel. No single choice is selected, so the trigger shows\n * a fixed `triggerIcon` naming the menu's purpose; while any choice is chosen\n * a count badge sits beside it, and the combobox's accessible name ends with\n * the chosen labels in choice order.\n */\nexport interface SelectMultipleIconProps<Value extends string = string> {\n multiple: true;\n value: readonly NoInfer<Value>[];\n renderSelected?: never;\n selectedPresentation: 'icon-only';\n /**\n * The trigger's fixed icon, typically a `LucideIcon` naming the menu's\n * purpose (a funnel for a filter), independent of the selection.\n */\n triggerIcon: KerfUiContent;\n /** Opt in to a footer action that selects every enabled choice. */\n selectAllLabel?: string;\n /** Opt in to a footer action that clears the current selection. */\n clearLabel?: string;\n}\n\nexport type SelectMultipleValueProps<Value extends string = string> =\n SelectMultipleLabelProps<Value> | SelectMultipleIconProps<Value>;\n\nexport type SelectProps<Value extends string = string> =\n SelectBaseProps<Value> &\n SelectAccessibleName &\n (SelectSingleValueProps<Value> | SelectMultipleValueProps<Value>);\n\n// The closed wa-select's disclosure glyph: Web Awesome's system `chevron-down`,\n// Font Awesome Free 7.0.0 by @fontawesome (https://fontawesome.com), licensed\n// CC BY 4.0 (https://fontawesome.com/license/free). The placeholder draws the\n// same path so the loading box matches the live control without registering\n// Web Awesome.\nfunction SelectChevron() {\n return (\n <svg viewBox=\"0 0 448 512\" aria-hidden=\"true\">\n <path d=\"M201.4 406.6c12.5 12.5 32.8 12.5 45.3 0l192-192c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L224 338.7 54.6 169.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l192 192z\"></path>\n </svg>\n );\n}\n\nexport function Select<Value extends string>(props: SelectProps<Value>) {\n const {\n name,\n label,\n ariaLabel,\n choices,\n className = '',\n placeholderText,\n hint,\n disabled = false,\n fitMenu = false,\n placeholder = false,\n presentation = 'form',\n size = 'default',\n triggerWidth,\n caret = true,\n focusRingOwner = 'select',\n labelMaxWidth,\n slot,\n } = props;\n const multiple = props.multiple === true;\n const values: readonly Value[] = props.multiple ? props.value : [props.value];\n const renderSelected = props.multiple ? undefined : props.renderSelected;\n const selectedPresentation: SelectSelectedPresentation =\n props.selectedPresentation ?? 'label';\n // A multiple icon-only trigger shows a fixed icon naming the menu's\n // purpose instead of a selected choice's icon.\n const iconTrigger =\n props.multiple && props.selectedPresentation === 'icon-only';\n const triggerIcon = iconTrigger ? props.triggerIcon : undefined;\n if (placeholder) {\n return (\n <div\n class={`kui-select kui-select--placeholder ${className}`.trim()}\n data-component=\"select\"\n data-placeholder=\"true\"\n data-presentation={presentation}\n data-size={size}\n data-trigger-width={triggerWidth}\n data-caret={caret ? undefined : 'false'}\n data-selected-presentation={selectedPresentation}\n data-focus-ring-owner={focusRingOwner}\n aria-busy=\"true\"\n style={\n labelMaxWidth === undefined\n ? undefined\n : `--kui-select-label-max-width:${labelMaxWidth}px`\n }\n slot={slot}\n >\n {label && <span class=\"kui-select__placeholder-label\">{label}</span>}\n <span\n class=\"kui-select__placeholder-box\"\n aria-label={ariaLabel}\n role=\"img\"\n >\n <Skeleton width={em(10)} />\n <span class=\"kui-select__placeholder-chevron\" aria-hidden=\"true\">\n <SelectChevron />\n </span>\n </span>\n {hint && <span class=\"kui-select__placeholder-hint\">{hint}</span>}\n </div>\n );\n }\n // A multiple Select summarizes its choices in the display text instead of\n // leading with one selected icon.\n const selected = multiple\n ? undefined\n : choices.find((choice) => choice.value === values[0] && !choice.disabled);\n const chosenCount = iconTrigger\n ? choices.filter(\n (choice) => !choice.disabled && values.includes(choice.value),\n ).length\n : 0;\n const icon = (choice: SelectChoice<Value>, selectedIcon = false) => (\n <span\n data-key={`${name}:${choice.value}:${selectedIcon ? 'selected' : 'option'}`}\n data-morph-skip\n slot=\"start\"\n class={`kui-select__icon${selectedIcon ? ' kui-select__icon--selected' : ''}`}\n style={choice.color ? `color:${choice.color}` : undefined}\n >\n {choice.icon ? (\n <LucideIcon\n icon={choice.icon}\n name={\n choice.iconName ?? choice.label.toLowerCase().replaceAll(' ', '-')\n }\n />\n ) : null}\n </span>\n );\n const option = (choice: SelectChoice<Value>, index: number) => (\n <>\n {/* Web Awesome sets the divider's role and aria-orientation on its\n host once, so a template that omits them would lose them to the\n next kerf re-render's morph for good. Render them explicitly, with\n the orientation it reflects (see the wa-select note below). */}\n {choice.separatorBefore && index > 0 && (\n <wa-divider\n orientation=\"horizontal\"\n role=\"separator\"\n aria-orientation=\"horizontal\"\n ></wa-divider>\n )}\n <wa-option\n value={choice.value}\n selected={multiple && !choice.disabled && values.includes(choice.value)}\n disabled={choice.disabled}\n title={choice.disabled ? choice.disabledReason : undefined}\n >\n {choice.icon ? icon(choice) : null}\n {choice.label}\n </wa-option>\n </>\n );\n const groups = [\n ...new Set(\n choices\n .map((choice) => choice.group)\n .filter((group): group is string => Boolean(group)),\n ),\n ];\n const ungrouped = choices.filter((choice) => !choice.group);\n // Web Awesome names its shadow combobox from the label, not the host's\n // aria-label. Keep ariaLabel-only names available without visible chrome.\n // A multiple Select's value is its selected options (the value attribute\n // holds only one string), kept in sync by @kerfjs/ui/select/register.\n // size/appearance/placement are Web Awesome's defaults, which it reflects\n // onto the host; rendering them keeps a re-render's morph from stripping\n // them and forcing a Lit update to put them back.\n return (\n <wa-select\n size=\"m\"\n appearance=\"outlined\"\n placement=\"bottom\"\n class={`kui-select${renderSelected ? ' kui-select--custom-selected' : ''}${fitMenu ? ' kui-select--fit-menu' : ''}${!label ? ' kui-select--label-hidden' : ''} ${className}`.trim()}\n data-component=\"select\"\n data-presentation={presentation}\n data-size={size}\n data-trigger-width={triggerWidth}\n data-caret={caret ? undefined : 'false'}\n data-selected-presentation={selectedPresentation}\n data-focus-ring-owner={focusRingOwner}\n name={name}\n label={label || ariaLabel}\n aria-label={ariaLabel}\n multiple={multiple}\n value={multiple ? undefined : values[0]}\n placeholder={placeholderText}\n hint={hint}\n disabled={disabled}\n style={\n labelMaxWidth === undefined\n ? undefined\n : `--kui-select-label-max-width:${labelMaxWidth}px`\n }\n slot={slot}\n >\n {iconTrigger && (\n <>\n {/* The accessible name ends with the chosen labels, which\n @kerfjs/ui/select/register writes into the summary. */}\n <span slot=\"label\" data-key={`${name}:trigger-label`}>\n {label || ariaLabel}\n <span class=\"kui-select__name-summary\" data-morph-skip></span>\n </span>\n <span\n data-key={`${name}:trigger-icon`}\n slot=\"start\"\n class=\"kui-select__icon kui-select__icon--selected kui-select__trigger-icon\"\n >\n {triggerIcon}\n </span>\n {chosenCount > 0 && (\n <Badge slot=\"end\" tone=\"brand\" size=\"compact\" ariaHidden>\n {chosenCount}\n </Badge>\n )}\n </>\n )}\n {selected &&\n (renderSelected ? (\n <span\n data-key={`${name}:${values[0]}:custom-selected`}\n slot=\"start\"\n class=\"kui-select__custom-selected\"\n >\n <span class=\"kui-select__custom-selected-content\">\n {renderSelected(selected)}\n </span>\n </span>\n ) : selected.icon ? (\n icon(selected, true)\n ) : null)}\n {ungrouped.map(option)}\n {groups.map((group, index) => (\n <div\n class={`kui-select__group${index > 0 || ungrouped.length > 0 ? ' kui-select__group--separated' : ''}`}\n role=\"group\"\n aria-label={group}\n >\n <span class=\"kui-select__group-title\">{group}</span>\n {choices.filter((choice) => choice.group === group).map(option)}\n </div>\n ))}\n {props.multiple && (props.selectAllLabel || props.clearLabel) && (\n <div\n class=\"kui-select__actions\"\n role=\"group\"\n aria-label={label || ariaLabel}\n >\n {props.selectAllLabel && (\n <button\n class=\"kui-select__action\"\n type=\"button\"\n data-select-action=\"all\"\n >\n {props.selectAllLabel}\n </button>\n )}\n {props.clearLabel && (\n <button\n class=\"kui-select__action\"\n type=\"button\"\n data-select-action=\"clear\"\n >\n {props.clearLabel}\n </button>\n )}\n </div>\n )}\n </wa-select>\n );\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { Pane } from './chunk-
|
|
1
|
+
import { Pane } from './chunk-OD2VXAPL.js';
|
|
2
2
|
import { isRelocatableGroup, ToolbarControlGroup } from './chunk-7JUBXOIV.js';
|
|
3
|
-
import { Toolbar } from './chunk-
|
|
3
|
+
import { Toolbar } from './chunk-N2DRU35S.js';
|
|
4
4
|
import { LucideIcon } from './chunk-4R777DUZ.js';
|
|
5
5
|
import { PanelLeftOpen, PanelLeftClose, PanelRightOpen, PanelRightClose, PanelBottomOpen, PanelBottomClose } from 'lucide';
|
|
6
6
|
import { jsx, jsxs, Fragment } from 'kerfjs/jsx-runtime';
|
|
@@ -67,6 +67,7 @@ function composedPanelBody({
|
|
|
67
67
|
separators: pane?.separators,
|
|
68
68
|
safeAreaEdges: pane?.safeAreaEdges,
|
|
69
69
|
chromeDividers: pane?.chromeDividers,
|
|
70
|
+
appearance: pane?.appearance,
|
|
70
71
|
children: content
|
|
71
72
|
}
|
|
72
73
|
);
|
|
@@ -92,4 +93,4 @@ function relocatedPanelGroups(toolbar, side, collapsed, attributes) {
|
|
|
92
93
|
|
|
93
94
|
export { collapsiblePanelToggleIcon, composedPanelBody, relocatedPanelGroups };
|
|
94
95
|
|
|
95
|
-
//# sourceMappingURL=chunk-
|
|
96
|
+
//# sourceMappingURL=chunk-ENGVYQPG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/panel-toolbar.tsx"],"names":[],"mappings":"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","file":"chunk-ENGVYQPG.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\nimport {\n PanelBottomClose,\n PanelBottomOpen,\n PanelLeftClose,\n PanelLeftOpen,\n PanelRightClose,\n PanelRightOpen,\n} from 'lucide';\n\nimport { LucideIcon } from './lucide-icon.js';\nimport { Pane, type PaneConfig } from './pane.js';\nimport { isRelocatableGroup } from './panel-toolbar-group.js';\nimport type { KerfUiContent } from './semantic-content.js';\nimport { Toolbar, type ToolbarConfig } from './toolbar.js';\nimport { ToolbarControlGroup } from './toolbar-control-group.js';\n\n/** Which edge a collapsible panel docks to. */\nexport type PanelSide = 'left' | 'right' | 'bottom';\n\n/**\n * The standard collapse/expand icon for a panel `side` and `collapsed` state,\n * so every app's sidebars and drawers use one recognizable convention:\n * `PanelLeft*` for a left rail, `PanelRight*` for a right rail, `PanelBottom*`\n * for a bottom drawer — the `Close` glyph while open, the `Open` glyph while\n * collapsed. Exposed so an app can render its own toggle affordance.\n */\nexport function collapsiblePanelToggleIcon(\n side: PanelSide,\n collapsed: boolean,\n): { icon: Parameters<typeof LucideIcon>[0]['icon']; name: string } {\n if (side === 'left')\n return collapsed\n ? { icon: PanelLeftOpen, name: 'panel-left-open' }\n : { icon: PanelLeftClose, name: 'panel-left-close' };\n if (side === 'right')\n return collapsed\n ? { icon: PanelRightOpen, name: 'panel-right-open' }\n : { icon: PanelRightClose, name: 'panel-right-close' };\n return collapsed\n ? { icon: PanelBottomOpen, name: 'panel-bottom-open' }\n : { icon: PanelBottomClose, name: 'panel-bottom-close' };\n}\n\n/**\n * The standard collapse toggle a panel toolbar renders. The app handles the\n * button's `data-action` and flips its own `collapsed` flag.\n */\nexport interface PanelToggle {\n /** The `data-action` the toggle button carries. */\n action: string;\n /** The panel's short name, for the accessible \"Show …\" / \"Hide …\" label. */\n name: string;\n /** Accessible label while the panel is collapsed. Defaults to `Show {name}`. */\n showLabel?: string;\n /** Accessible label while the panel is open. Defaults to `Hide {name}`. */\n hideLabel?: string;\n}\n\n/**\n * A collapsible panel's top toolbar, composed so its groups follow the\n * panel's open state.\n *\n * - `title` precedes the `leading` zone. Groups may appear in any of the\n * `leading`, `center`, and `trailing` zones while the panel is open.\n * - Groups marked `relocateOnCollapse` move to the work area's toolbar while\n * the panel is collapsed, preserving their order across the three zones.\n * - `toggle` is always the last group: in the panel's toolbar while it is\n * open, and right after the relocated groups in the work area's toolbar\n * while it is collapsed.\n *\n * Relocated content renders in both places while the panel is collapsed (the\n * panel's copy is inert), so give it no `id`s. Pass groups directly or in\n * arrays so their render-time annotation remains available to the panel.\n *\n * The toolbar's configuration (`dividerSides`, `centerAlign`, `responsive`,\n * `responsiveAt`, `safeAreaEdges`) forwards to its `Toolbar`. It draws no\n * divider of its own: the panel's `Pane` draws the line under it while the\n * content is scrolled (its `chromeDividers`, wired by `wireScrollDividers`).\n */\nexport interface PanelToolbar extends ToolbarConfig {\n /** Accessible name of the panel's toolbar. */\n label: string;\n title?: KerfUiContent;\n leading?: KerfUiContent;\n center?: KerfUiContent;\n trailing?: KerfUiContent;\n toggle?: PanelToggle;\n}\n\n/** Owner-specific attributes a toggle button carries (its wiring hooks). */\nexport type PanelToggleAttributes = Readonly<Record<string, string>>;\n\n/** The standard toggle, alone in a borderless group. */\nexport function panelToggleGroup(\n side: PanelSide,\n toggle: PanelToggle,\n collapsed: boolean,\n attributes: PanelToggleAttributes,\n): SafeHtml {\n const glyph = collapsiblePanelToggleIcon(side, collapsed);\n return (\n <ToolbarControlGroup label={toggle.name} appearance=\"borderless\" single>\n <button\n type=\"button\"\n {...attributes}\n data-action={toggle.action}\n aria-expanded={String(!collapsed)}\n aria-label={\n collapsed\n ? (toggle.showLabel ?? `Show ${toggle.name}`)\n : (toggle.hideLabel ?? `Hide ${toggle.name}`)\n }\n >\n <LucideIcon icon={glyph.icon} name={glyph.name} />\n </button>\n </ToolbarControlGroup>\n );\n}\n\n/**\n * The panel's own toolbar: content keeps its chosen zones and the toggle trails.\n */\nexport function composedPanelToolbar(\n toolbar: PanelToolbar,\n side: PanelSide,\n collapsed: boolean,\n attributes: PanelToggleAttributes,\n): SafeHtml {\n return (\n <Toolbar\n label={toolbar.label}\n dividerSides={toolbar.dividerSides}\n centerAlign={toolbar.centerAlign}\n responsive={toolbar.responsive}\n responsiveAt={toolbar.responsiveAt}\n safeAreaEdges={toolbar.safeAreaEdges}\n center={toolbar.center}\n leading={\n <>\n {toolbar.title}\n {toolbar.leading}\n </>\n }\n trailing={\n <>\n {toolbar.trailing}\n {toolbar.toggle\n ? panelToggleGroup(side, toolbar.toggle, collapsed, attributes)\n : null}\n </>\n }\n />\n );\n}\n\n/**\n * A toolbar panel's body: its content in a `Pane` under its composed toolbar,\n * with its optional `footer` below. The panel's `pane` configuration forwards\n * to that `Pane`; an omitted or `undefined` field keeps the `Pane` default.\n */\nexport function composedPanelBody({\n toolbar,\n side,\n collapsed,\n attributes,\n pane,\n footer,\n content,\n}: {\n toolbar: PanelToolbar;\n side: PanelSide;\n collapsed: boolean;\n attributes: PanelToggleAttributes;\n pane: PaneConfig | undefined;\n footer: KerfUiContent;\n content: KerfUiContent;\n}): SafeHtml {\n return (\n <Pane\n header={composedPanelToolbar(toolbar, side, collapsed, attributes)}\n footer={footer}\n contentElement={pane?.contentElement}\n contentLabel={pane?.contentLabel}\n separators={pane?.separators}\n safeAreaEdges={pane?.safeAreaEdges}\n chromeDividers={pane?.chromeDividers}\n appearance={pane?.appearance}\n >\n {content}\n </Pane>\n );\n}\n\n/**\n * The groups a collapsed panel hands to the work area, in zone order, then its\n * toggle. Empty while the panel is open or has no toolbar.\n */\nexport function relocatedPanelGroups(\n toolbar: PanelToolbar | undefined,\n side: PanelSide,\n collapsed: boolean,\n attributes: PanelToggleAttributes,\n): KerfUiContent[] {\n if (!collapsed || !toolbar) return [];\n const groups: KerfUiContent[] = [];\n const collect = (content: KerfUiContent): void => {\n if (Array.isArray(content)) {\n for (const item of content) collect(item);\n } else if (isRelocatableGroup(content)) {\n groups.push(content);\n }\n };\n collect(toolbar.leading);\n collect(toolbar.center);\n collect(toolbar.trailing);\n return [\n ...groups,\n toolbar.toggle\n ? panelToggleGroup(side, toolbar.toggle, true, attributes)\n : null,\n ].filter((group) => group !== undefined && group !== null && group !== false);\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ToolbarText } from './chunk-
|
|
1
|
+
import { ToolbarText } from './chunk-V3DX3K65.js';
|
|
2
2
|
import { ToolbarControlGroup } from './chunk-7JUBXOIV.js';
|
|
3
|
-
import { Toolbar } from './chunk-
|
|
3
|
+
import { Toolbar } from './chunk-N2DRU35S.js';
|
|
4
4
|
import { LucideIcon } from './chunk-4R777DUZ.js';
|
|
5
5
|
import { ChevronLeft } from 'lucide';
|
|
6
6
|
import { jsxs, jsx, Fragment } from 'kerfjs/jsx-runtime';
|
|
@@ -100,6 +100,7 @@ function NavStack({
|
|
|
100
100
|
"data-key": view.key,
|
|
101
101
|
"data-nav-key": view.key,
|
|
102
102
|
"data-nav-active": String(index === topIndex),
|
|
103
|
+
"data-appearance": view.appearance === "sunken" ? "sunken" : void 0,
|
|
103
104
|
"aria-hidden": String(index !== topIndex),
|
|
104
105
|
children: view.content
|
|
105
106
|
}
|
|
@@ -112,4 +113,4 @@ function NavStack({
|
|
|
112
113
|
|
|
113
114
|
export { NavStack };
|
|
114
115
|
|
|
115
|
-
//# sourceMappingURL=chunk-
|
|
116
|
+
//# sourceMappingURL=chunk-KYDDCJXU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/nav-stack.tsx"],"names":[],"mappings":"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","file":"chunk-KYDDCJXU.js","sourcesContent":["import { ChevronLeft } from 'lucide';\n\nimport { LucideIcon } from './lucide-icon.js';\nimport type { PaneAppearance } from './pane.js';\nimport type { KerfUiContent } from './semantic-content.js';\nimport { Toolbar, type ToolbarConfig } from './toolbar.js';\nimport { ToolbarControlGroup } from './toolbar-control-group.js';\nimport {\n type HeadingLevel,\n ToolbarText,\n type ToolbarTextSize,\n} from './toolbar-text.js';\n\n/**\n * One entry in a {@link NavStack}. The app owns the stack as an array (usually a\n * signal); `NavStack` renders it and `wireNavStack` animates the transitions.\n */\nexport interface NavStackView {\n /** Stable identity for keyed reconcile and transition direction. */\n key: string;\n content: KerfUiContent;\n /** Background of this view's scrolling work surface. */\n appearance?: PaneAppearance;\n /** Title shown in the top toolbar for this view. */\n title?: string;\n /** Leading groups for this view's top toolbar, after the back control and before the title. */\n leading?: KerfUiContent;\n /** Center content for this view's top toolbar (placed per `toolbarConfig.centerAlign`). */\n center?: KerfUiContent;\n /** Trailing actions for this view's top toolbar. */\n toolbar?: KerfUiContent;\n /** Bottom toolbar for this view. Cross-fades with the top chrome on navigation. */\n bottomToolbar?: KerfUiContent;\n}\n\n/**\n * The top toolbar's configuration. Its `ToolbarConfig` forwards to the real\n * `Toolbar` the stack renders; by default that toolbar draws no divider and\n * claims the top and side safe-area edges the stack still touches.\n */\nexport interface NavStackToolbarConfig extends ToolbarConfig {\n /** Accessible name of the top toolbar (default: none). */\n label?: string;\n /** Size of the view title's `ToolbarText` (default `large`). */\n titleSize?: ToolbarTextSize;\n /** Expose the view title as a heading at this level (default: a plain span). */\n headingLevel?: HeadingLevel;\n}\n\nexport interface NavStackProps {\n id: string;\n /** Accessible name for the stack region. */\n label: string;\n /** The stack, root first; the last entry is the active top view. */\n views: NavStackView[];\n /** Accessible label for the icon-only back control (default \"Back\"). */\n backLabel?: string;\n /** The back control's icon (default a chevron-left `LucideIcon`). */\n backIcon?: KerfUiContent;\n /**\n * Visible text beside the back icon, such as the previous view's title\n * (default: icon only). When set, the text names the control and\n * `backLabel` is not used.\n */\n backText?: string;\n /** The top toolbar's configuration, forwarded to its `Toolbar`. */\n toolbarConfig?: NavStackToolbarConfig;\n /** Hide the top toolbar entirely (rare — a fully custom-chrome view). */\n hideToolbar?: boolean;\n /** Optional persistent bottom toolbar used when the active view does not provide one. */\n bottomToolbar?: KerfUiContent;\n /**\n * The line under the top chrome and over the bottom toolbar, where they\n * meet the active view. `scroll` (default) shows the chrome's line only\n * while the view's content is scrolled beneath it, and the bottom\n * toolbar's only while more content lies below — never when the content\n * fits — once `wireScrollDividers` (`@kerfjs/ui/wire-scroll-dividers`) is\n * wired above the stack; unwired, neither shows. `always` shows both\n * without the wiring; `none` neither, even when wired. The line is drawn\n * inside the chrome, so no state moves the chrome or the content. A\n * `toolbarConfig.dividerSides` edge is the Toolbar's own and is unaffected.\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\nconst DEFAULT_SAFE_AREA_EDGES = [\n 'block-start',\n 'inline-start',\n 'inline-end',\n] as const;\n\n/**\n * A navigation stack (iOS-style push/pop). Renders every entry stacked, the last\n * one active; `@kerfjs/ui/wire-nav-stack`'s `wireNavStack` slides the content and\n * cross-fades the chrome across a change. Its top chrome is a real `Toolbar`: the\n * back control and title lead, the active view's `leading` / `center` / `toolbar`\n * content fills the zones, and `toolbarConfig` configures it. A single-pane\n * layout is a `NavStack` with one entry. See `docs/23-app-layouts.md` §3.1.\n */\nexport function NavStack({\n id,\n label,\n views,\n backLabel = 'Back',\n backIcon,\n backText,\n toolbarConfig = {},\n hideToolbar = false,\n bottomToolbar,\n chromeDividers = 'scroll',\n className = '',\n slot,\n}: NavStackProps) {\n const topIndex = views.length - 1;\n const top = views[topIndex];\n const canPop = views.length > 1;\n return (\n <section\n class={`kui-nav-stack ${className}`.trim()}\n id={id}\n data-component=\"nav-stack\"\n data-nav-stack-id={id}\n data-depth={String(views.length)}\n data-chrome-dividers={\n chromeDividers === 'always' || chromeDividers === 'none'\n ? chromeDividers\n : undefined\n }\n aria-label={label}\n slot={slot}\n >\n {!hideToolbar && (\n <div class=\"kui-nav-stack__chrome\" data-nav-stack-chrome>\n <Toolbar\n label={toolbarConfig.label}\n dividerSides={toolbarConfig.dividerSides}\n centerAlign={toolbarConfig.centerAlign}\n responsive={toolbarConfig.responsive}\n responsiveAt={toolbarConfig.responsiveAt}\n safeAreaEdges={\n toolbarConfig.safeAreaEdges ?? DEFAULT_SAFE_AREA_EDGES\n }\n leading={\n <>\n {canPop && (\n <ToolbarControlGroup\n appearance=\"borderless\"\n shape=\"rounded\"\n content={backText ? 'mixed' : 'icon'}\n single\n >\n <button\n type=\"button\"\n class=\"kui-nav-stack__back\"\n data-nav-back\n aria-label={backText ? undefined : backLabel}\n >\n {backIcon ?? (\n <LucideIcon\n icon={ChevronLeft}\n name=\"chevron-left\"\n className=\"kui-nav-stack__back-icon\"\n />\n )}\n {backText ? <span>{backText}</span> : null}\n </button>\n </ToolbarControlGroup>\n )}\n {top?.leading}\n <ToolbarText\n text={top?.title ?? ''}\n size={toolbarConfig.titleSize ?? 'large'}\n headingLevel={toolbarConfig.headingLevel}\n fill\n />\n </>\n }\n center={top?.center}\n trailing={top?.toolbar}\n />\n </div>\n )}\n <div class=\"kui-nav-stack__viewport\" data-nav-stack-viewport>\n {views.map((view, index) => (\n <article\n class=\"kui-nav-stack__view\"\n data-key={view.key}\n data-nav-key={view.key}\n data-nav-active={String(index === topIndex)}\n data-appearance={\n view.appearance === 'sunken' ? 'sunken' : undefined\n }\n aria-hidden={String(index !== topIndex)}\n >\n {view.content}\n </article>\n ))}\n </div>\n {(top?.bottomToolbar ?? bottomToolbar) && (\n <footer class=\"kui-nav-stack__bottom\" data-nav-stack-bottom>\n {top?.bottomToolbar ?? bottomToolbar}\n </footer>\n )}\n </section>\n );\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/toolbar.tsx"],"names":[],"mappings":";;;AAoEA,IAAM,KAAA,GAAQ,CACZ,KAAA,EACA,IAAA,KACI,OAAO,QAAA,CAAS,IAAI,IAAI,MAAA,GAAS,MAAA;AAEhC,SAAS,OAAA,CAAQ;AAAA,EACtB,OAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EACA,KAAA;AAAA,EACA,YAAA,GAAe,EAAA;AAAA,EACf,WAAA,GAAc,QAAA;AAAA,EACd,UAAA,GAAa,MAAA;AAAA,EACb,YAAA,GAAe,QAAA;AAAA,EACf,aAAA;AAAA,EACA,SAAA,GAAY,EAAA;AAAA,EACZ;AACF,CAAA,EAAiB;AACf,EAAA,uBACE,IAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,CAAA,YAAA,EAAe,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,MACvC,gBAAA,EAAe,SAAA;AAAA,MACf,iBAAe,YAAA,IAAgB,MAAA;AAAA,MAC/B,iBAAA,EAAiB,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAC,CAAA;AAAA,MACvC,mBAAA,EAAmB,WAAA;AAAA,MACnB,iBAAA,EAAiB,UAAA;AAAA,MACjB,oBAAA,EAAoB,YAAA;AAAA,MACpB,4BAAA,EAA4B,KAAA,CAAM,aAAA,EAAe,aAAa,CAAA;AAAA,MAC9D,0BAAA,EAA0B,KAAA,CAAM,aAAA,EAAe,WAAW,CAAA;AAAA,MAC1D,6BAAA,EAA6B,KAAA,CAAM,aAAA,EAAe,cAAc,CAAA;AAAA,MAChE,2BAAA,EAA2B,KAAA,CAAM,aAAA,EAAe,YAAY,CAAA;AAAA,MAC5D,YAAA,EAAY,KAAA;AAAA,MACZ,IAAA;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,sBAAA,EAAwB,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,wBAC3C,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,qBAAA,EAAuB,QAAA,EAAA,MAAA,EAAO,CAAA;AAAA,wBACzC,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,uBAAA,EAAyB,QAAA,EAAA,QAAA,EAAS;AAAA;AAAA;AAAA,GAC/C;AAEJ","file":"chunk-N2DRU35S.js","sourcesContent":["import type { PaneSeparatorSide } from './pane.js';\nimport type { KerfUiContent } from './semantic-content.js';\nimport type { Sides } from './sides.js';\n\nexport interface ToolbarProps {\n leading?: KerfUiContent;\n center?: KerfUiContent;\n trailing?: KerfUiContent;\n label?: string;\n /**\n * Physical divider edges in canonical top/right/bottom/left order, drawn\n * always. Defaults to none: a toolbar pinned over or under scrolling content\n * gets its divider from the scroll state instead — a `Pane` draws the line\n * between its chrome and content while content is scrolled away beneath it,\n * and `wireScrollDividers` `targets` can name a toolbar as chrome, which\n * then draws its facing side the same way.\n */\n dividerSides?: Sides;\n /** `balanced` gives both side zones equal tracks, centering the middle zone on the toolbar even if only one side has controls. */\n centerAlign?: 'center' | 'stretch' | 'balanced';\n /**\n * Component-owned responsive layout; applications choose the policy rather\n * than restyling toolbar internals. Under every policy the trailing zone\n * wraps its groups instead of clipping an action, and the center zone keeps\n * its whole content width: when the zones do not fit one row, the leading\n * title truncates with an ellipsis rather than the center overlapping it.\n * - `none` keeps one row; the leading identity truncates first.\n * - `stack` stacks the zones at `responsiveAt`, wrapping stacked control\n * groups onto further rows.\n * - `wrap` keeps one row while every zone fits at its natural width, and\n * otherwise moves the trailing zone below a whole leading identity.\n * - `center-priority` gives an expanded center control the full row.\n * - `trailing-priority` moves an expanded trailing control to a full row\n * below the leading identity at `responsiveAt`.\n */\n responsive?:\n 'none' | 'stack' | 'wrap' | 'center-priority' | 'trailing-priority';\n /** Container width at which `stack` or `trailing-priority` activates. */\n responsiveAt?: 'compact' | 'narrow';\n /**\n * Screen edges this toolbar claims for device safe-area compensation, for an\n * app bar or bottom bar that sits directly at a screen edge rather than in a\n * Pane header or footer. Each listed side pads by the inset its surrounding\n * layout reports through `--kui-edge-inset-*`, or the full device inset when\n * nothing routes that edge, while the toolbar's box and dividers paint\n * through. Omitted, the toolbar pads only the inline edges an owner such as\n * a Pane header hands it, and never a block edge.\n */\n safeAreaEdges?: readonly PaneSeparatorSide[];\n className?: string;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\n/**\n * A toolbar's configuration, apart from its content: the props a composite\n * that renders a `Toolbar` for the app (a Workbench or CollapsiblePanel\n * toolbar) forwards, so the app configures that toolbar instead of styling it.\n */\nexport type ToolbarConfig = Pick<\n ToolbarProps,\n | 'dividerSides'\n | 'centerAlign'\n | 'responsive'\n | 'responsiveAt'\n | 'safeAreaEdges'\n>;\n\nconst claim = (\n edges: readonly PaneSeparatorSide[] | undefined,\n side: PaneSeparatorSide,\n) => (edges?.includes(side) ? 'true' : undefined);\n\nexport function Toolbar({\n leading,\n center,\n trailing,\n label,\n dividerSides = '',\n centerAlign = 'center',\n responsive = 'none',\n responsiveAt = 'narrow',\n safeAreaEdges,\n className = '',\n slot,\n}: ToolbarProps) {\n return (\n <header\n class={`kui-toolbar ${className}`.trim()}\n data-component=\"toolbar\"\n divider-sides={dividerSides || undefined}\n data-has-center={String(Boolean(center))}\n data-center-align={centerAlign}\n data-responsive={responsive}\n data-responsive-at={responsiveAt}\n data-safe-area-block-start={claim(safeAreaEdges, 'block-start')}\n data-safe-area-block-end={claim(safeAreaEdges, 'block-end')}\n data-safe-area-inline-start={claim(safeAreaEdges, 'inline-start')}\n data-safe-area-inline-end={claim(safeAreaEdges, 'inline-end')}\n aria-label={label}\n slot={slot}\n >\n <div class=\"kui-toolbar__leading\">{leading}</div>\n <div class=\"kui-toolbar__center\">{center}</div>\n <div class=\"kui-toolbar__trailing\">{trailing}</div>\n </header>\n );\n}\n\nexport type { Sides } from './sides.js';\n"]}
|