@kerfjs/ui 5.0.0-beta.17 → 5.0.0-beta.18
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 +108 -79
- package/ai/component-catalog-extension.schema.json +79 -0
- package/ai/component-catalog.json +499 -0
- package/ai/component-catalog.schema.json +15 -0
- package/ai/public-api-signatures-v1.md +67 -31
- package/ai/skill.md +58 -49
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/dist/app-tab.d.ts +1 -1
- package/dist/app-tab.js +1 -1
- package/dist/catalog.d.ts +10 -3
- package/dist/catalog.js +279 -90
- package/dist/catalog.js.map +1 -1
- package/dist/chunk-43FUQH35.js +83 -0
- package/dist/chunk-43FUQH35.js.map +1 -0
- package/dist/{chunk-YGN7OMLT.js → chunk-4TRDV6RL.js} +2 -2
- package/dist/chunk-4TRDV6RL.js.map +1 -0
- package/dist/chunk-6ETZKKAE.js +38 -0
- package/dist/chunk-6ETZKKAE.js.map +1 -0
- package/dist/chunk-6WTETUZ6.js +21 -0
- package/dist/chunk-6WTETUZ6.js.map +1 -0
- package/dist/chunk-7L6EHUMV.js +31 -0
- package/dist/chunk-7L6EHUMV.js.map +1 -0
- package/dist/chunk-BBRXX6PF.js +108 -0
- package/dist/chunk-BBRXX6PF.js.map +1 -0
- package/dist/chunk-DPDBVKNA.js +113 -0
- package/dist/chunk-DPDBVKNA.js.map +1 -0
- package/dist/chunk-ELSJX4W7.js +68 -0
- package/dist/chunk-ELSJX4W7.js.map +1 -0
- package/dist/{chunk-6NLRBSVX.js → chunk-ENVTNLYC.js} +125 -68
- package/dist/chunk-ENVTNLYC.js.map +1 -0
- package/dist/{chunk-AHQI52QO.js → chunk-FEY65TBV.js} +6 -2
- package/dist/chunk-FEY65TBV.js.map +1 -0
- package/dist/chunk-JTHUXDN2.js +58 -0
- package/dist/chunk-JTHUXDN2.js.map +1 -0
- package/dist/chunk-LPOMRC4C.js +25 -0
- package/dist/chunk-LPOMRC4C.js.map +1 -0
- package/dist/chunk-NENBUYX5.js +79 -0
- package/dist/chunk-NENBUYX5.js.map +1 -0
- package/dist/{chunk-XXMOARTH.js → chunk-NVWXKU37.js} +57 -16
- package/dist/chunk-NVWXKU37.js.map +1 -0
- package/dist/chunk-PIDTEQ3U.js +105 -0
- package/dist/chunk-PIDTEQ3U.js.map +1 -0
- package/dist/chunk-PX3YSS5C.js +32 -0
- package/dist/chunk-PX3YSS5C.js.map +1 -0
- package/dist/chunk-PZQVSDLH.js +61 -0
- package/dist/chunk-PZQVSDLH.js.map +1 -0
- package/dist/chunk-QIRXYKCE.js +113 -0
- package/dist/chunk-QIRXYKCE.js.map +1 -0
- package/dist/chunk-QO55FN2Y.js +20 -0
- package/dist/chunk-QO55FN2Y.js.map +1 -0
- package/dist/chunk-QQFJMRIB.js +45 -0
- package/dist/chunk-QQFJMRIB.js.map +1 -0
- package/dist/chunk-S3HKPI7I.js +218 -0
- package/dist/chunk-S3HKPI7I.js.map +1 -0
- package/dist/{chunk-WXMGNX2Y.js → chunk-S3PCZ7NV.js} +2 -2
- package/dist/chunk-S3PCZ7NV.js.map +1 -0
- package/dist/{chunk-7BR3DO2A.js → chunk-SRSJO5QE.js} +13 -4
- package/dist/chunk-SRSJO5QE.js.map +1 -0
- package/dist/chunk-U5IFGQCD.js +117 -0
- package/dist/chunk-U5IFGQCD.js.map +1 -0
- package/dist/{chunk-56RJXPHG.js → chunk-Y6LYKFXY.js} +1 -1
- package/dist/{chunk-56RJXPHG.js.map → chunk-Y6LYKFXY.js.map} +1 -1
- package/dist/chunk-ZK2G3VR5.js +35 -0
- package/dist/chunk-ZK2G3VR5.js.map +1 -0
- package/dist/chunk-ZVI5YST2.js +41 -0
- package/dist/chunk-ZVI5YST2.js.map +1 -0
- package/dist/collapsible-panel.d.ts +2 -2
- package/dist/collapsible-panel.js +47 -6
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/device-class.js +33 -5
- package/dist/device-class.js.map +1 -1
- package/dist/disclosure-arrow.js +1 -1
- package/dist/empty-state.d.ts +1 -1
- package/dist/empty-state.js +1 -1
- package/dist/floating-toolbar.d.ts +1 -1
- package/dist/floating-toolbar.js +1 -1
- package/dist/index.js +25 -25
- package/dist/list-action-row.d.ts +1 -1
- package/dist/list-action-row.js +1 -1
- package/dist/list-header.d.ts +1 -1
- package/dist/list-header.js +1 -1
- package/dist/list-inset-control.d.ts +1 -1
- package/dist/list-inset-control.js +1 -1
- package/dist/list-inset-text.d.ts +1 -1
- package/dist/list-inset-text.js +1 -1
- package/dist/list-item.d.ts +1 -1
- package/dist/list-item.js +1 -1
- package/dist/loading-spinner.js +1 -1
- package/dist/nav-stack.d.ts +1 -1
- package/dist/nav-stack.js +1 -1
- package/dist/panel-header.d.ts +1 -1
- package/dist/panel-header.js +1 -1
- package/dist/resizable-region.d.ts +1 -1
- package/dist/resizable-region.js +1 -1
- package/dist/segmented-control.js +1 -1
- package/dist/select.d.ts +1 -1
- package/dist/select.js +1 -1
- package/dist/skeleton.d.ts +1 -1
- package/dist/skeleton.js +1 -1
- package/dist/split-view.d.ts +1 -1
- package/dist/split-view.js +70 -10
- package/dist/split-view.js.map +1 -1
- package/dist/state-banner.d.ts +1 -1
- package/dist/state-banner.js +1 -1
- package/dist/styles/catalog.css +26 -0
- package/dist/tab-bar.d.ts +1 -1
- package/dist/tab-bar.js +1 -1
- package/dist/tab-scaffold.d.ts +1 -1
- package/dist/tab-scaffold.js +43 -8
- package/dist/tab-scaffold.js.map +1 -1
- package/dist/token-search-field.js +1 -1
- package/dist/toolbar-control-group.d.ts +1 -1
- package/dist/toolbar-control-group.js +1 -1
- package/dist/toolbar-text.js +1 -1
- package/dist/toolbar.d.ts +1 -1
- package/dist/toolbar.js +1 -1
- package/dist/value-table.d.ts +2 -2
- package/dist/value-table.js +1 -1
- package/dist/wire-catalog.d.ts +31 -2
- package/dist/wire-catalog.js +203 -8
- package/dist/wire-catalog.js.map +1 -1
- package/dist/wire-nav-stack.js +22 -7
- package/dist/wire-nav-stack.js.map +1 -1
- package/dist/wire-resizable-regions.d.ts +1 -1
- package/dist/wire-resizable-regions.js +1 -1
- package/dist/wire-sidebar.js +52 -41
- package/dist/wire-sidebar.js.map +1 -1
- package/dist/wire-tab-bars.js +1 -1
- package/dist/wire-tab-scaffold.js +9 -4
- package/dist/wire-tab-scaffold.js.map +1 -1
- package/dist/wire-token-search-fields.d.ts +1 -1
- package/dist/wire-token-search-fields.js +1 -1
- package/dist/workbench.d.ts +1 -1
- package/dist/workbench.js +56 -9
- package/dist/workbench.js.map +1 -1
- package/docs/app-layouts.md +7 -7
- package/docs/catalog.md +108 -24
- package/docs/collapsible-panel.md +38 -11
- package/docs/component-contract.md +30 -2
- package/docs/component-selection.md +71 -63
- package/docs/design/templates.md +1 -1
- package/docs/design-philosophy.md +5 -5
- package/docs/device-class.md +8 -8
- package/docs/examples/command-palette-adapter.tsx +67 -17
- package/docs/examples/component-catalog-extension.json +45 -0
- package/docs/layout.md +19 -19
- package/docs/nav-stack.md +15 -6
- package/docs/recipes.md +4 -4
- package/docs/split-view.md +3 -3
- package/docs/tab-scaffold.md +16 -7
- package/docs/webawesome-theme.md +8 -8
- package/docs/workbench.md +18 -5
- package/llms.txt +20 -14
- package/package.json +6 -4
- package/ux-demo/recipes/app-shell.tsx +206 -10
- package/ux-demo/recipes/collapsible-sidebar.tsx +167 -44
- package/ux-demo/recipes/compact-toolbar.tsx +114 -12
- package/ux-demo/recipes/composer-form.tsx +106 -18
- package/ux-demo/recipes/list-detail-dialog.tsx +144 -8
- package/ux-demo/recipes/list-workspace-states.tsx +165 -8
- package/ux-demo/recipes/loaders.ts +5 -2
- package/ux-demo/recipes/loading-inspector.tsx +124 -41
- package/ux-demo/recipes/mount-recipe.ts +27 -6
- package/ux-demo/recipes/navigation-sidebar.tsx +120 -9
- package/ux-demo/recipes/navigation-stack.tsx +61 -19
- package/ux-demo/recipes/types.ts +3 -1
- package/ux-demo/recipes/workspace-header.tsx +57 -2
- package/dist/chunk-2Z5TWHKQ.js +0 -34
- package/dist/chunk-2Z5TWHKQ.js.map +0 -1
- package/dist/chunk-37T3VNIZ.js +0 -19
- package/dist/chunk-37T3VNIZ.js.map +0 -1
- package/dist/chunk-55DATV3A.js +0 -10
- package/dist/chunk-55DATV3A.js.map +0 -1
- package/dist/chunk-5ATCDSQS.js +0 -42
- package/dist/chunk-5ATCDSQS.js.map +0 -1
- package/dist/chunk-5E2HVJ33.js +0 -10
- package/dist/chunk-5E2HVJ33.js.map +0 -1
- package/dist/chunk-6NLRBSVX.js.map +0 -1
- package/dist/chunk-7BR3DO2A.js.map +0 -1
- package/dist/chunk-7JB7VPRI.js +0 -34
- package/dist/chunk-7JB7VPRI.js.map +0 -1
- package/dist/chunk-7LDCTU7D.js +0 -134
- package/dist/chunk-7LDCTU7D.js.map +0 -1
- package/dist/chunk-AHQI52QO.js.map +0 -1
- package/dist/chunk-AQNKJRFH.js +0 -79
- package/dist/chunk-AQNKJRFH.js.map +0 -1
- package/dist/chunk-AVZHJN6C.js +0 -14
- package/dist/chunk-AVZHJN6C.js.map +0 -1
- package/dist/chunk-B24C4A6T.js +0 -22
- package/dist/chunk-B24C4A6T.js.map +0 -1
- package/dist/chunk-CH4SQ6H5.js +0 -39
- package/dist/chunk-CH4SQ6H5.js.map +0 -1
- package/dist/chunk-DAFFDO33.js +0 -14
- package/dist/chunk-DAFFDO33.js.map +0 -1
- package/dist/chunk-I7INRJO4.js +0 -17
- package/dist/chunk-I7INRJO4.js.map +0 -1
- package/dist/chunk-L4OKFDJY.js +0 -24
- package/dist/chunk-L4OKFDJY.js.map +0 -1
- package/dist/chunk-M5JRI6MN.js +0 -27
- package/dist/chunk-M5JRI6MN.js.map +0 -1
- package/dist/chunk-RNPGFQ33.js +0 -10
- package/dist/chunk-RNPGFQ33.js.map +0 -1
- package/dist/chunk-VPCTCUED.js +0 -10
- package/dist/chunk-VPCTCUED.js.map +0 -1
- package/dist/chunk-WRTAQ7BZ.js +0 -23
- package/dist/chunk-WRTAQ7BZ.js.map +0 -1
- package/dist/chunk-WVPYVDXY.js +0 -15
- package/dist/chunk-WVPYVDXY.js.map +0 -1
- package/dist/chunk-WXMGNX2Y.js.map +0 -1
- package/dist/chunk-XXMOARTH.js.map +0 -1
- package/dist/chunk-YGN7OMLT.js.map +0 -1
- package/dist/chunk-ZQQ6P4SV.js +0 -20
- package/dist/chunk-ZQQ6P4SV.js.map +0 -1
package/docs/nav-stack.md
CHANGED
|
@@ -8,9 +8,9 @@ a `NavStack` with one entry**. It is one of the opt-in app layouts (see
|
|
|
8
8
|
Import the component and its companion stylesheet:
|
|
9
9
|
|
|
10
10
|
```ts
|
|
11
|
-
import { NavStack, type NavStackView } from
|
|
12
|
-
import { wireNavStack } from
|
|
13
|
-
import
|
|
11
|
+
import { NavStack, type NavStackView } from "@kerfjs/ui/nav-stack";
|
|
12
|
+
import { wireNavStack } from "@kerfjs/ui/wire-nav-stack";
|
|
13
|
+
import "@kerfjs/ui/nav-stack.css";
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
## State lives in the app
|
|
@@ -20,16 +20,25 @@ stack as a `signal<NavStackView[]>`, `NavStack({ views })` renders it, and
|
|
|
20
20
|
`wireNavStack` animates the transitions.
|
|
21
21
|
|
|
22
22
|
```tsx
|
|
23
|
-
const views = signal<NavStackView[]>([
|
|
23
|
+
const views = signal<NavStackView[]>([
|
|
24
|
+
{ key: "inbox", title: "Inbox", content: <InboxView /> },
|
|
25
|
+
]);
|
|
24
26
|
|
|
25
27
|
// render inside mount():
|
|
26
28
|
<NavStack id="mail" label="Mail" views={views.value} />;
|
|
27
29
|
|
|
28
30
|
// once, after first render:
|
|
29
|
-
const dispose = wireNavStack(root, {
|
|
31
|
+
const dispose = wireNavStack(root, {
|
|
32
|
+
onBack: () => {
|
|
33
|
+
views.value = views.value.slice(0, -1);
|
|
34
|
+
},
|
|
35
|
+
});
|
|
30
36
|
|
|
31
37
|
// push / pop by editing the signal:
|
|
32
|
-
views.value = [
|
|
38
|
+
views.value = [
|
|
39
|
+
...views.value,
|
|
40
|
+
{ key: id, title: "Message", content: <MessageView id={id} /> },
|
|
41
|
+
];
|
|
33
42
|
```
|
|
34
43
|
|
|
35
44
|
`NavStack` renders every entry stacked, the last one active and the rest kept
|
package/docs/recipes.md
CHANGED
|
@@ -14,12 +14,12 @@ the public `onCommit` callback, retains every disposer, and returns one
|
|
|
14
14
|
idempotent disposer:
|
|
15
15
|
|
|
16
16
|
```ts
|
|
17
|
-
import { createRecipe } from
|
|
18
|
-
import { mountRecipe } from
|
|
17
|
+
import { createRecipe } from "./navigation-sidebar.js";
|
|
18
|
+
import { mountRecipe } from "./mount-recipe.js";
|
|
19
19
|
|
|
20
|
-
const root = document.querySelector<HTMLElement>(
|
|
20
|
+
const root = document.querySelector<HTMLElement>("#navigation")!;
|
|
21
21
|
const stopRecipe = mountRecipe(root, createRecipe(announce));
|
|
22
|
-
window.addEventListener(
|
|
22
|
+
window.addEventListener("pagehide", stopRecipe, { once: true });
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
The adapter is delivered as reference source, not a new package runtime export.
|
package/docs/split-view.md
CHANGED
|
@@ -6,9 +6,9 @@ on compact ones. One of the opt-in app layouts (see
|
|
|
6
6
|
[`../../docs/23-app-layouts.md`](../../docs/23-app-layouts.md)).
|
|
7
7
|
|
|
8
8
|
```ts
|
|
9
|
-
import { SplitView } from
|
|
10
|
-
import { deviceClass } from
|
|
11
|
-
import
|
|
9
|
+
import { SplitView } from "@kerfjs/ui/split-view";
|
|
10
|
+
import { deviceClass } from "@kerfjs/ui/device-class";
|
|
11
|
+
import "@kerfjs/ui/split-view.css";
|
|
12
12
|
// plus nav-stack.css when the compact path is reachable, and
|
|
13
13
|
// wireResizableRegions / wireNavStack for the interactive behavior.
|
|
14
14
|
```
|
package/docs/tab-scaffold.md
CHANGED
|
@@ -7,9 +7,9 @@ opt-in app layouts (see [`../../docs/23-app-layouts.md`](../../docs/23-app-layou
|
|
|
7
7
|
It is distinct from `TabBar` (document-oriented, reorderable strips).
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
|
-
import { TabScaffold } from
|
|
11
|
-
import { wireTabScaffold } from
|
|
12
|
-
import
|
|
10
|
+
import { TabScaffold } from "@kerfjs/ui/tab-scaffold";
|
|
11
|
+
import { wireTabScaffold } from "@kerfjs/ui/wire-tab-scaffold";
|
|
12
|
+
import "@kerfjs/ui/tab-scaffold.css";
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Controlled selection
|
|
@@ -19,20 +19,29 @@ The app owns the active tab (a signal); `TabScaffold` renders every tab's scene
|
|
|
19
19
|
clicks.
|
|
20
20
|
|
|
21
21
|
```tsx
|
|
22
|
-
const active = signal(
|
|
22
|
+
const active = signal("home");
|
|
23
23
|
|
|
24
24
|
<TabScaffold
|
|
25
25
|
id="app"
|
|
26
26
|
label="Sections"
|
|
27
27
|
active={active.value}
|
|
28
28
|
tabs={[
|
|
29
|
-
{ id:
|
|
30
|
-
{
|
|
29
|
+
{ id: "home", label: "Home", icon: <HomeIcon />, content: <HomeStack /> },
|
|
30
|
+
{
|
|
31
|
+
id: "search",
|
|
32
|
+
label: "Search",
|
|
33
|
+
icon: <SearchIcon />,
|
|
34
|
+
content: <SearchStack />,
|
|
35
|
+
},
|
|
31
36
|
]}
|
|
32
37
|
/>;
|
|
33
38
|
|
|
34
39
|
// once, after first render:
|
|
35
|
-
const dispose = wireTabScaffold(root, {
|
|
40
|
+
const dispose = wireTabScaffold(root, {
|
|
41
|
+
onSelect: (id) => {
|
|
42
|
+
active.value = id;
|
|
43
|
+
},
|
|
44
|
+
});
|
|
36
45
|
```
|
|
37
46
|
|
|
38
47
|
Each `TabScaffoldTab` has an `id`, `label`, optional `icon`, and `content`. The
|
package/docs/webawesome-theme.md
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
free components and the Kerf/Hot Sheet 2 design system.
|
|
5
5
|
|
|
6
6
|
```ts
|
|
7
|
-
import type {} from
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
7
|
+
import type {} from "@kerfjs/ui/webawesome";
|
|
8
|
+
import "@kerfjs/ui/webawesome.css";
|
|
9
|
+
import "@awesome.me/webawesome/dist/components/button/button.js";
|
|
10
|
+
import "@awesome.me/webawesome/dist/components/input/input.js";
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
The type-only package import augments `kerfjs/jsx-runtime` with the 70
|
|
@@ -138,12 +138,12 @@ subtree, or for one instance after the theme import:
|
|
|
138
138
|
|
|
139
139
|
```css
|
|
140
140
|
:root {
|
|
141
|
-
--wa-tooltip-arrow-size: .375rem;
|
|
142
|
-
--kui-wa-popover-arrow-size: .375rem;
|
|
141
|
+
--wa-tooltip-arrow-size: 0.375rem;
|
|
142
|
+
--kui-wa-popover-arrow-size: 0.375rem;
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
.pointed-popover {
|
|
146
|
-
--arrow-size: .5rem;
|
|
146
|
+
--arrow-size: 0.5rem;
|
|
147
147
|
}
|
|
148
148
|
```
|
|
149
149
|
|
|
@@ -244,7 +244,7 @@ smallest subtree that needs a different identity:
|
|
|
244
244
|
:root {
|
|
245
245
|
--wa-color-brand-fill-loud: #7540a8;
|
|
246
246
|
--wa-color-focus: #7540a8;
|
|
247
|
-
--wa-form-control-border-radius: .5rem;
|
|
247
|
+
--wa-form-control-border-radius: 0.5rem;
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
.billing-workspace {
|
package/docs/workbench.md
CHANGED
|
@@ -8,8 +8,8 @@ sidebar. One of the opt-in app layouts (see
|
|
|
8
8
|
desktop-class devices.
|
|
9
9
|
|
|
10
10
|
```ts
|
|
11
|
-
import { Workbench } from
|
|
12
|
-
import
|
|
11
|
+
import { Workbench } from "@kerfjs/ui/workbench";
|
|
12
|
+
import "@kerfjs/ui/workbench.css";
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## State lives in the app
|
|
@@ -25,9 +25,22 @@ const navCollapsed = signal(false);
|
|
|
25
25
|
id="studio"
|
|
26
26
|
label="Studio"
|
|
27
27
|
main={<Editor />}
|
|
28
|
-
leftRail={{
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
leftRail={{
|
|
29
|
+
content: <Navigator />,
|
|
30
|
+
label: "Navigator",
|
|
31
|
+
collapsed: navCollapsed.value,
|
|
32
|
+
size: 280,
|
|
33
|
+
}}
|
|
34
|
+
rightRail={{
|
|
35
|
+
content: <Inspector />,
|
|
36
|
+
label: "Inspector",
|
|
37
|
+
collapsed: inspectorCollapsed.value,
|
|
38
|
+
}}
|
|
39
|
+
bottomDrawer={{
|
|
40
|
+
content: <Console />,
|
|
41
|
+
label: "Console",
|
|
42
|
+
collapsed: consoleCollapsed.value,
|
|
43
|
+
}}
|
|
31
44
|
/>;
|
|
32
45
|
```
|
|
33
46
|
|
package/llms.txt
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
> generate correct, good-looking kerf UI — it is not a catalog to browse.
|
|
7
7
|
|
|
8
8
|
```bash
|
|
9
|
-
npm install kerfjs @kerfjs/ui
|
|
9
|
+
npm install kerfjs @kerfjs/ui # kerfjs is a peer; Web Awesome is an optional peer
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
Import each component from its own subpath (`@kerfjs/ui/list-item`, `@kerfjs/ui/toolbar`,
|
|
@@ -22,15 +22,18 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
|
|
|
22
22
|
[public-api-signatures-v1.md](./ai/public-api-signatures-v1.md) (real prop names,
|
|
23
23
|
callback shapes, disposer return types).
|
|
24
24
|
3. **For exhaustive, structured facts** (ids, exports, variants, `publicClasses`,
|
|
25
|
-
relationships, side effects) load the
|
|
25
|
+
relationships, side effects, and geometry ownership) load the
|
|
26
26
|
[Machine-readable component catalog](./ai/component-catalog.json) — the
|
|
27
|
-
canonical checked-in source; its schema is alongside it.
|
|
27
|
+
canonical checked-in source; its schema is alongside it. Also load the
|
|
28
|
+
consuming application's catalog extension when present; generate one from the
|
|
29
|
+
[Consumer catalog extension schema](./ai/component-catalog-extension.schema.json)
|
|
30
|
+
when app-owned components must participate in selection or alignment.
|
|
28
31
|
4. **Apply the rules below and in** [skill.md](./ai/skill.md).
|
|
29
32
|
|
|
30
33
|
## Core rules (do the right thing)
|
|
31
34
|
|
|
32
35
|
- **Reach for the primitive, not for CSS.** The package is built to look right
|
|
33
|
-
|
|
36
|
+
_unstyled_. Before adding `padding`, `margin`, `width`, `height`, `border`,
|
|
34
37
|
`background`, a wrapper card, or a decoration, check whether the component, the
|
|
35
38
|
pane, or the content-item already owns it — it almost always does. Prefer a
|
|
36
39
|
component prop or a `--kui-*` token; write CSS only for genuinely new structure,
|
|
@@ -69,7 +72,7 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
|
|
|
69
72
|
popup menu. A toolbar popup menu is a `single` `ToolbarControlGroup` around a
|
|
70
73
|
`wa-dropdown` (its `slot="trigger"` `wa-button` is the toolbar button, kept under
|
|
71
74
|
`data-morph-skip-children`).
|
|
72
|
-
- **`PanelHeader` is
|
|
75
|
+
- **`PanelHeader` is _the_ panel/dialog/page heading.** A plain toolbar with an
|
|
73
76
|
optional bordered icon group, an extra-large `ToolbarText` title, the trailing
|
|
74
77
|
controls you pass, and an optional subtitle below — do not hand-build a heading
|
|
75
78
|
row or restyle a toolbar into one.
|
|
@@ -90,7 +93,7 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
|
|
|
90
93
|
- **App state is domain/persisted; helpers own only ephemeral mechanics.** Keep
|
|
91
94
|
navigation stacks, tab selection and order, pane sizes, and `collapsed`/`expanded`
|
|
92
95
|
disclosure flags in the app — they are data or persisted layout, and the app reads
|
|
93
|
-
them to render. The `wire…` helpers own the
|
|
96
|
+
them to render. The `wire…` helpers own the _ephemeral_ parts: `wireNavStack` the
|
|
94
97
|
push/pop animation, `wireTabBars` the overflow autoscroll and drag preview,
|
|
95
98
|
`wireResizableRegions` the live drag preview; they report committed changes via
|
|
96
99
|
callbacks. The one richer case is `wireTokenSearchFields`, which manages the
|
|
@@ -128,13 +131,16 @@ tree-shakeable, declarative with `wire…` helpers, each with a companion CSS im
|
|
|
128
131
|
`NavStack`, `SplitView`, `Workbench`, `TabScaffold`, driven by `deviceClass()` from
|
|
129
132
|
`@kerfjs/ui/device-class`. For a standalone collapsible rail/drawer outside a full
|
|
130
133
|
shell, `@kerfjs/ui/collapsible-panel` (`CollapsiblePanel`, `CollapsiblePanelToggle`)
|
|
131
|
-
|
|
132
|
-
`@kerfjs/ui/
|
|
133
|
-
`
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
|
|
135
|
+
- `@kerfjs/ui/wire-sidebar` (`wireSidebar`: toggle, focus, compact overlay, persistence).
|
|
136
|
+
`@kerfjs/ui/catalog` is another opt-in shell — a
|
|
137
|
+
`Catalog` component + `wireCatalog` helper for building a component-gallery catalog
|
|
138
|
+
(collapsible category sidebar + preview stage + resources footer, with an opt-in
|
|
139
|
+
transparent-bound and margin geometry overlay plus focus-preserving active-row
|
|
140
|
+
reveal for long desktop sidebars) from your own
|
|
141
|
+
entries; controlled/stateless like the layouts. `@kerfjs/ui/webawesome` is a
|
|
142
|
+
type-only boundary for `wa-*` JSX; `@kerfjs/ui/select/register` and the CSS are the
|
|
143
|
+
declared side effects.
|
|
138
144
|
|
|
139
145
|
## Reference
|
|
140
146
|
|
|
@@ -146,5 +152,5 @@ declared side effects.
|
|
|
146
152
|
- [recipes.md](./docs/recipes.md): production compositions (app shell, list-detail dialog, composer form, …) as copyable references.
|
|
147
153
|
- [app-layouts.md](./docs/app-layouts.md): choosing `NavStack`/`SplitView`/`Workbench`/`TabScaffold` by data + interaction + device, and dialog presentation.
|
|
148
154
|
- [webawesome-theme.md](./docs/webawesome-theme.md): the optional Web Awesome theme; catalog coverage means themed-and-supported, not preferred (prefer the Kerf primitive when one exists). The UX sidebar visibly tags superseded and exceptional Web Awesome choices as `Discouraged`; Popup remains an available conditional positioning primitive.
|
|
149
|
-
- [component-catalog.json](./ai/component-catalog.json) + [public-api-signatures-v1.md](./ai/public-api-signatures-v1.md) + [webawesome-jsx-signatures-v1.md](./ai/webawesome-jsx-signatures-v1.md): machine-readable facts and exact signatures.
|
|
155
|
+
- [component-catalog.json](./ai/component-catalog.json) + [component-catalog-extension.schema.json](./ai/component-catalog-extension.schema.json) + [public-api-signatures-v1.md](./ai/public-api-signatures-v1.md) + [webawesome-jsx-signatures-v1.md](./ai/webawesome-jsx-signatures-v1.md): machine-readable facts, a reusable app-component extension contract, and exact signatures.
|
|
150
156
|
- [README.md](./README.md): package overview and the component subpath table.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kerfjs/ui",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.18",
|
|
4
4
|
"description": "Accessible, composable UI primitives for kerf applications.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -272,8 +272,9 @@
|
|
|
272
272
|
"dev": "npm run build && vite --config ux-demo/vite.config.ts",
|
|
273
273
|
"demo:build": "npm run build && vite build --config ux-demo/vite.config.ts && node scripts/check-demo-bundle.mjs",
|
|
274
274
|
"demo:serve": "vite preview --config ux-demo/vite.config.ts",
|
|
275
|
+
"format": "prettier --write . --ignore-unknown",
|
|
275
276
|
"format:css": "prettier --write \"src/**/*.css\" \"ux-demo/**/*.css\"",
|
|
276
|
-
"check:format": "prettier --check
|
|
277
|
+
"check:format": "prettier --check . --ignore-unknown",
|
|
277
278
|
"catalog:sync": "node scripts/sync-component-catalog.mjs",
|
|
278
279
|
"check:catalog": "node scripts/sync-component-catalog.mjs --check && node scripts/check-component-catalog.mjs",
|
|
279
280
|
"check:recipes": "node scripts/check-recipes.mjs",
|
|
@@ -285,14 +286,15 @@
|
|
|
285
286
|
"ai:regressions:record": "node scripts/record-ai-regression-run.mjs",
|
|
286
287
|
"ai:regressions:score": "node scripts/score-ai-regression.mjs",
|
|
287
288
|
"check:guidance": "node scripts/check-decision-guidance.mjs",
|
|
288
|
-
"lint": "eslint src tests ux-demo docs/examples --max-warnings 0",
|
|
289
|
+
"lint:eslint": "eslint src tests ux-demo docs/examples --max-warnings 0",
|
|
290
|
+
"lint": "npm run lint:eslint && npm run check:format",
|
|
289
291
|
"typecheck": "node node_modules/typescript7/bin/tsc --noEmit",
|
|
290
292
|
"test": "npm run test:unit && npm run test:bundle",
|
|
291
293
|
"test:unit": "vitest run tests/unit --coverage",
|
|
292
294
|
"test:bundle": "npm run build && vitest run tests/bundle",
|
|
293
295
|
"test:consumer-types": "npm run build && node node_modules/typescript7/bin/tsc -p tests/consumer-types/webawesome/tsconfig.json",
|
|
294
296
|
"test:e2e": "npm run demo:build && playwright test",
|
|
295
|
-
"check": "npm run check:
|
|
297
|
+
"check": "npm run check:catalog && npm run check:recipes && npm run check:guidance && npm run check:ai-regressions && npm run lint && npm run typecheck && npm test && npm run test:consumer-types && npm run check:ai-signatures && npm run demo:build && npm run check:design-templates && npm pack --dry-run",
|
|
296
298
|
"prepublishOnly": "npm run check",
|
|
297
299
|
"check:design-templates": "node scripts/check-design-templates.mjs",
|
|
298
300
|
"check:design-templates:drift": "node scripts/check-design-templates-drift.mjs",
|
|
@@ -19,14 +19,210 @@ export const createRecipe: RecipeFactory = (announce) => {
|
|
|
19
19
|
const selected = signal('inbox');
|
|
20
20
|
const navigationSize = signal(224);
|
|
21
21
|
const inspectorSize = signal(240);
|
|
22
|
-
const responsivePane = signal<'content' | 'navigation' | 'inspector'>(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
22
|
+
const responsivePane = signal<'content' | 'navigation' | 'inspector'>(
|
|
23
|
+
'content',
|
|
24
|
+
);
|
|
25
|
+
const render = () => (
|
|
26
|
+
<section
|
|
27
|
+
class="kui-recipe recipe-shell kui-recipe__surface kui-layout"
|
|
28
|
+
data-recipe="recipe-app-shell"
|
|
29
|
+
data-responsive-pane={responsivePane.value}
|
|
30
|
+
>
|
|
31
|
+
<Toolbar
|
|
32
|
+
label="Atlas workspace"
|
|
33
|
+
leading={
|
|
34
|
+
<ToolbarControlGroup appearance="borderless" single>
|
|
35
|
+
<ToolbarText text="Atlas" />
|
|
36
|
+
</ToolbarControlGroup>
|
|
37
|
+
}
|
|
38
|
+
trailing={
|
|
39
|
+
<div class="recipe-shell__toolbar-actions">
|
|
40
|
+
<ToolbarControlGroup
|
|
41
|
+
className="recipe-shell__responsive-controls"
|
|
42
|
+
appearance="borderless"
|
|
43
|
+
label="Workspace panes"
|
|
44
|
+
>
|
|
45
|
+
<button
|
|
46
|
+
type="button"
|
|
47
|
+
aria-label="Show navigation"
|
|
48
|
+
aria-controls="recipe-shell-navigation"
|
|
49
|
+
aria-pressed={String(responsivePane.value === 'navigation')}
|
|
50
|
+
data-action="recipe-action"
|
|
51
|
+
data-recipe-command="show-navigation"
|
|
52
|
+
>
|
|
53
|
+
<LucideIcon icon={Folder} name="folder" />
|
|
54
|
+
</button>
|
|
55
|
+
<button
|
|
56
|
+
type="button"
|
|
57
|
+
aria-label="Show content"
|
|
58
|
+
aria-controls="recipe-shell-content"
|
|
59
|
+
aria-pressed={String(responsivePane.value === 'content')}
|
|
60
|
+
data-action="recipe-action"
|
|
61
|
+
data-recipe-command="show-content"
|
|
62
|
+
>
|
|
63
|
+
<LucideIcon icon={Inbox} name="inbox" />
|
|
64
|
+
</button>
|
|
65
|
+
<button
|
|
66
|
+
type="button"
|
|
67
|
+
aria-label="Show inspector"
|
|
68
|
+
aria-controls="recipe-shell-inspector"
|
|
69
|
+
aria-pressed={String(responsivePane.value === 'inspector')}
|
|
70
|
+
data-action="recipe-action"
|
|
71
|
+
data-recipe-command="show-inspector"
|
|
72
|
+
>
|
|
73
|
+
<LucideIcon icon={Settings} name="settings" />
|
|
74
|
+
</button>
|
|
75
|
+
</ToolbarControlGroup>
|
|
76
|
+
<ToolbarControlGroup
|
|
77
|
+
appearance="borderless"
|
|
78
|
+
label="Workspace controls"
|
|
79
|
+
>
|
|
80
|
+
<button
|
|
81
|
+
type="button"
|
|
82
|
+
aria-label="Notifications"
|
|
83
|
+
data-action="recipe-action"
|
|
84
|
+
data-recipe-command="notify"
|
|
85
|
+
>
|
|
86
|
+
<LucideIcon icon={Bell} name="bell" />
|
|
87
|
+
</button>
|
|
88
|
+
<button
|
|
89
|
+
type="button"
|
|
90
|
+
aria-label="Settings"
|
|
91
|
+
data-action="recipe-action"
|
|
92
|
+
data-recipe-command="settings"
|
|
93
|
+
>
|
|
94
|
+
<LucideIcon icon={Settings} name="settings" />
|
|
95
|
+
</button>
|
|
96
|
+
</ToolbarControlGroup>
|
|
97
|
+
</div>
|
|
98
|
+
}
|
|
99
|
+
/>
|
|
100
|
+
<div class="recipe-shell__body">
|
|
101
|
+
<div id="recipe-shell-navigation" class="recipe-shell__nav-region">
|
|
102
|
+
<ResizableRegion
|
|
103
|
+
id="recipe-navigation"
|
|
104
|
+
label="Navigation"
|
|
105
|
+
size={navigationSize.value}
|
|
106
|
+
min={180}
|
|
107
|
+
max={320}
|
|
108
|
+
>
|
|
109
|
+
<aside class="recipe-shell__nav kui-pane">
|
|
110
|
+
<ListHeader label="Workspace" />
|
|
111
|
+
<nav
|
|
112
|
+
class="recipe-shell__nav-list kui-pane__content kui-content"
|
|
113
|
+
aria-label="Workspace"
|
|
114
|
+
>
|
|
115
|
+
<section>
|
|
116
|
+
<ListItem
|
|
117
|
+
action="recipe-action"
|
|
118
|
+
itemId="inbox"
|
|
119
|
+
label="Inbox"
|
|
120
|
+
icon={<LucideIcon icon={Inbox} name="inbox" />}
|
|
121
|
+
selected={selected.value === 'inbox'}
|
|
122
|
+
/>
|
|
123
|
+
<ListItem
|
|
124
|
+
action="recipe-action"
|
|
125
|
+
itemId="projects"
|
|
126
|
+
label="Projects with a deliberately wrapping title"
|
|
127
|
+
icon={<LucideIcon icon={Folder} name="folder" />}
|
|
128
|
+
selected={selected.value === 'projects'}
|
|
129
|
+
multiline
|
|
130
|
+
/>
|
|
131
|
+
</section>
|
|
132
|
+
</nav>
|
|
133
|
+
</aside>
|
|
134
|
+
</ResizableRegion>
|
|
135
|
+
</div>
|
|
136
|
+
<main id="recipe-shell-content" class="recipe-shell__main kui-pane">
|
|
137
|
+
<PanelHeader
|
|
138
|
+
title={
|
|
139
|
+
selected.value === 'inbox' ? 'Inbox triage' : 'Active projects'
|
|
140
|
+
}
|
|
141
|
+
titleId="recipe-shell-main-title"
|
|
142
|
+
actions={
|
|
143
|
+
<button
|
|
144
|
+
class="kui-recipe__button"
|
|
145
|
+
data-primary="true"
|
|
146
|
+
type="button"
|
|
147
|
+
data-action="recipe-action"
|
|
148
|
+
data-recipe-command="new"
|
|
149
|
+
>
|
|
150
|
+
New task
|
|
151
|
+
</button>
|
|
152
|
+
}
|
|
153
|
+
/>
|
|
154
|
+
<div class="recipe-shell__main-body kui-pane__content kui-content">
|
|
155
|
+
<p class="kui-recipe__ownership kui-content-item">
|
|
156
|
+
Recipe owns pane geometry and one scroll owner per pane. The app
|
|
157
|
+
owns routing, data, pane visibility, sizes, and persistence.
|
|
158
|
+
</p>
|
|
159
|
+
<div class="recipe-shell__cards">
|
|
160
|
+
{[
|
|
161
|
+
'Release accessibility audit',
|
|
162
|
+
'Prepare tablet navigation',
|
|
163
|
+
'Review stale-data states',
|
|
164
|
+
'Confirm package boundaries',
|
|
165
|
+
].map((title) => (
|
|
166
|
+
<article class="recipe-shell__card kui-content-item">
|
|
167
|
+
<strong>{title}</strong>
|
|
168
|
+
<p class="kui-recipe__muted">
|
|
169
|
+
Assigned to the interface systems team · due this week
|
|
170
|
+
</p>
|
|
171
|
+
</article>
|
|
172
|
+
))}
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
</main>
|
|
176
|
+
<div id="recipe-shell-inspector" class="recipe-shell__inspector-region">
|
|
177
|
+
<ResizableRegion
|
|
178
|
+
id="recipe-inspector"
|
|
179
|
+
label="Inspector"
|
|
180
|
+
size={inspectorSize.value}
|
|
181
|
+
min={200}
|
|
182
|
+
max={360}
|
|
183
|
+
edge="start"
|
|
184
|
+
>
|
|
185
|
+
<aside class="recipe-shell__inspector kui-pane">
|
|
186
|
+
<PanelHeader
|
|
187
|
+
title="Inspector"
|
|
188
|
+
titleId="recipe-shell-inspector-title"
|
|
189
|
+
/>
|
|
190
|
+
<div class="recipe-shell__inspector-body kui-pane__content kui-content">
|
|
191
|
+
<ValueTable label="Selected task">
|
|
192
|
+
<ValueTableRow label="Status" value="In review" />
|
|
193
|
+
<ValueTableRow label="Owner" value="Mara Chen" />
|
|
194
|
+
<ValueTableRow label="Priority" value="High" />
|
|
195
|
+
</ValueTable>
|
|
196
|
+
</div>
|
|
197
|
+
</aside>
|
|
198
|
+
</ResizableRegion>
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
</section>
|
|
202
|
+
);
|
|
203
|
+
return {
|
|
204
|
+
render,
|
|
205
|
+
action(command, element) {
|
|
206
|
+
const pane = command.match(
|
|
207
|
+
/^show-(navigation|content|inspector)$/,
|
|
208
|
+
)?.[1] as typeof responsivePane.value | undefined;
|
|
209
|
+
if (pane) responsivePane.value = pane;
|
|
210
|
+
const id = element.dataset.itemId;
|
|
211
|
+
if (id) selected.value = id;
|
|
212
|
+
announce(
|
|
213
|
+
id
|
|
214
|
+
? `Opened ${id}`
|
|
215
|
+
: pane
|
|
216
|
+
? `Showing ${pane}`
|
|
217
|
+
: command === 'new'
|
|
218
|
+
? 'New task requested'
|
|
219
|
+
: `${command} requested`,
|
|
220
|
+
);
|
|
221
|
+
},
|
|
222
|
+
resize(id, size) {
|
|
223
|
+
if (id === 'recipe-navigation') navigationSize.value = size;
|
|
224
|
+
if (id === 'recipe-inspector') inspectorSize.value = size;
|
|
225
|
+
announce(`${id} resized to ${size}px`);
|
|
226
|
+
},
|
|
227
|
+
};
|
|
32
228
|
};
|