@kerfjs/ui 5.0.0-beta.50 → 5.0.0-beta.51
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 +29 -5
- package/ai/compile-time-contracts-v1.json +5 -2
- package/ai/component-catalog-v2.d.ts +19 -1
- package/ai/component-catalog-v2.json +842 -127
- package/ai/component-catalog-v2.schema.json +33 -1
- package/ai/component-catalog.json +603 -126
- package/ai/component-catalog.schema.json +21 -1
- package/ai/public-api-signatures-v1.md +201 -29
- package/ai/skill.md +12 -9
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/analyzer/index.mjs +105 -35
- package/dist/app-tab.js +1 -1
- package/dist/catalog-resources.d.ts +1 -1
- package/dist/catalog.d.ts +28 -5
- package/dist/catalog.js +66 -25
- package/dist/catalog.js.map +1 -1
- package/dist/{chunk-COUPLRZG.js → chunk-5FZZMIMD.js} +3 -3
- package/dist/{chunk-COUPLRZG.js.map → chunk-5FZZMIMD.js.map} +1 -1
- package/dist/{chunk-DARTMI5Z.js → chunk-5PMGQDG7.js} +2 -2
- package/dist/{chunk-DARTMI5Z.js.map → chunk-5PMGQDG7.js.map} +1 -1
- package/dist/{chunk-V6RZWDII.js → chunk-7GUQYHKA.js} +19 -2
- package/dist/chunk-7GUQYHKA.js.map +1 -0
- package/dist/{chunk-ZNZ2JDBW.js → chunk-7IUSV4XG.js} +1 -1
- package/dist/chunk-7IUSV4XG.js.map +1 -0
- package/dist/{chunk-ELRMBQEC.js → chunk-AEPXGCNF.js} +17 -2
- package/dist/chunk-AEPXGCNF.js.map +1 -0
- package/dist/{chunk-5CE64WGC.js → chunk-D547PH4L.js} +3 -3
- package/dist/{chunk-5CE64WGC.js.map → chunk-D547PH4L.js.map} +1 -1
- package/dist/{chunk-S6ZTTTV7.js → chunk-DVZCMMB3.js} +3 -3
- package/dist/{chunk-S6ZTTTV7.js.map → chunk-DVZCMMB3.js.map} +1 -1
- package/dist/chunk-EKYZCRCX.js +256 -0
- package/dist/chunk-EKYZCRCX.js.map +1 -0
- package/dist/{chunk-3V75EQIP.js → chunk-JM53SMVF.js} +3 -3
- package/dist/{chunk-3V75EQIP.js.map → chunk-JM53SMVF.js.map} +1 -1
- package/dist/{chunk-2WMSE4MK.js → chunk-JMGKM7RK.js} +2 -2
- package/dist/{chunk-2WMSE4MK.js.map → chunk-JMGKM7RK.js.map} +1 -1
- package/dist/{chunk-2YOUUEWR.js → chunk-KX7DP2GO.js} +4 -4
- package/dist/{chunk-2YOUUEWR.js.map → chunk-KX7DP2GO.js.map} +1 -1
- package/dist/{chunk-OL4TC3U2.js → chunk-MO56ZZLG.js} +6 -2
- package/dist/chunk-MO56ZZLG.js.map +1 -0
- package/dist/{chunk-OQI7RCRP.js → chunk-MTM43SJO.js} +7 -1
- package/dist/chunk-MTM43SJO.js.map +1 -0
- package/dist/{chunk-ZSYLBVWG.js → chunk-NMGTHYW3.js} +3 -3
- package/dist/{chunk-ZSYLBVWG.js.map → chunk-NMGTHYW3.js.map} +1 -1
- package/dist/{chunk-AQSKJ6U6.js → chunk-NZXWU4R5.js} +21 -2
- package/dist/chunk-NZXWU4R5.js.map +1 -0
- package/dist/{chunk-DJKWFYAA.js → chunk-O3RCCSQJ.js} +3 -3
- package/dist/{chunk-DJKWFYAA.js.map → chunk-O3RCCSQJ.js.map} +1 -1
- package/dist/{chunk-UMGY5JSP.js → chunk-S4QRSBFI.js} +22 -2
- package/dist/chunk-S4QRSBFI.js.map +1 -0
- package/dist/{chunk-KKNK3JUT.js → chunk-UBH743HV.js} +5 -5
- package/dist/chunk-UBH743HV.js.map +1 -0
- package/dist/{chunk-54HM36IQ.js → chunk-ULCDZTWL.js} +2 -2
- package/dist/{chunk-54HM36IQ.js.map → chunk-ULCDZTWL.js.map} +1 -1
- package/dist/{chunk-SIU2AC5W.js → chunk-UPZ6EEJN.js} +3 -3
- package/dist/{chunk-SIU2AC5W.js.map → chunk-UPZ6EEJN.js.map} +1 -1
- package/dist/collapsible-panel.d.ts +1 -1
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/css-values.d.ts +39 -3
- package/dist/css-values.js +1 -1
- package/dist/grid.d.ts +15 -1
- package/dist/grid.js +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +19 -19
- package/dist/list-action-row.js +1 -1
- package/dist/list-header.js +1 -1
- package/dist/list-item.js +1 -1
- package/dist/list.d.ts +21 -2
- package/dist/list.js +2 -1
- package/dist/nav-stack.js +1 -1
- package/dist/pane.d.ts +17 -2
- package/dist/pane.js +1 -1
- package/dist/row.d.ts +19 -1
- package/dist/row.js +2 -1
- package/dist/segmented-control.js +1 -1
- package/dist/select.d.ts +13 -3
- package/dist/select.js +1 -1
- package/dist/skeleton.js +1 -1
- package/dist/spacer.js +1 -1
- package/dist/split-view.js +1 -1
- package/dist/state-banner.js +1 -1
- package/dist/styles/catalog/components/catalog-example-stack.css +4 -1
- package/dist/styles/catalog/components/catalog-example.css +145 -0
- package/dist/styles/collapsible-panel.css +132 -4
- package/dist/styles/document.css +23 -0
- package/dist/styles/foundation.css +21 -7
- package/dist/styles/grid.css +10 -0
- package/dist/styles/list-header.css +45 -0
- package/dist/styles/list-inset-control.css +8 -1
- package/dist/styles/list-item.css +6 -0
- package/dist/styles/list.css +11 -0
- package/dist/styles/nav-stack.css +89 -2
- package/dist/styles/pane.css +86 -1
- package/dist/styles/resizable-region.css +93 -5
- package/dist/styles/row.css +10 -0
- package/dist/styles/select.css +39 -4
- package/dist/styles/split-view.css +107 -1
- package/dist/styles/tab-scaffold.css +64 -1
- package/dist/styles/text.css +6 -0
- package/dist/styles/toolbar-control-group.css +90 -11
- package/dist/styles/toolbar-text.css +4 -1
- package/dist/styles/toolbar.css +130 -38
- package/dist/styles/webawesome.css +48 -2
- package/dist/styles/workbench.css +136 -4
- package/dist/text.d.ts +4 -3
- package/dist/text.js +1 -1
- package/dist/toolbar-text.js +1 -1
- package/dist/toolbar.d.ts +24 -3
- package/dist/toolbar.js +1 -1
- package/dist/{types-CzgSrFXP.d.ts → types-CEsieBZi.d.ts} +6 -1
- package/dist/value-table.js +1 -1
- package/dist/wire-resizable-regions.js +1 -1
- package/dist/wire-sidebar.d.ts +18 -3
- package/dist/wire-sidebar.js +95 -14
- package/dist/wire-sidebar.js.map +1 -1
- package/docs/accessibility.md +45 -8
- package/docs/app-layouts.md +73 -0
- package/docs/catalog.md +23 -2
- package/docs/collapsible-panel.md +81 -8
- package/docs/component-contract.md +28 -9
- package/docs/component-integration.md +9 -4
- package/docs/component-selection.md +25 -6
- package/docs/design/templates/list/stack-dark.svg +1 -1
- package/docs/design/templates/list/stack.svg +1 -1
- package/docs/design/templates/list-dark.svg +1 -1
- package/docs/design/templates/list-header/action-dark.svg +1 -1
- package/docs/design/templates/list-header/action.svg +1 -1
- package/docs/design/templates/list-header/count-dark.svg +1 -1
- package/docs/design/templates/list-header/count.svg +1 -1
- package/docs/design/templates/list-header/inline-action-dark.svg +1 -1
- package/docs/design/templates/list-header/inline-action.svg +1 -1
- package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -1
- package/docs/design/templates/list-header/toggle-expanded.svg +1 -1
- package/docs/design/templates/list-header-dark.svg +1 -1
- package/docs/design/templates/list-header.svg +1 -1
- package/docs/design/templates/list.svg +1 -1
- package/docs/design/templates/state-banner/info-badge-dark.svg +1 -1
- package/docs/design/templates/state-banner/info-badge.svg +1 -1
- package/docs/design/templates/state-banner-dark.svg +1 -1
- package/docs/design/templates/state-banner.svg +1 -1
- package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -1
- package/docs/design/templates/toolbar/title-and-actions.svg +1 -1
- package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -1
- package/docs/design/templates/toolbar-control-group/with-text.svg +1 -1
- package/docs/design/templates/toolbar-control-group-dark.svg +1 -1
- package/docs/design/templates/toolbar-control-group.svg +1 -1
- package/docs/design/templates/toolbar-dark.svg +1 -1
- package/docs/design/templates/toolbar-text/default-dark.svg +1 -1
- package/docs/design/templates/toolbar-text/default.svg +1 -1
- package/docs/design/templates/toolbar-text/large-dark.svg +1 -1
- package/docs/design/templates/toolbar-text/large.svg +1 -1
- package/docs/design/templates/toolbar-text/small-dark.svg +1 -1
- package/docs/design/templates/toolbar-text/small.svg +1 -1
- package/docs/design/templates/toolbar-text-dark.svg +1 -1
- package/docs/design/templates/toolbar-text.svg +1 -1
- package/docs/design/templates/toolbar.svg +1 -1
- package/docs/document-baseline.md +31 -0
- package/docs/layout.md +86 -21
- package/docs/nav-stack.md +8 -0
- package/docs/recipes.md +78 -43
- package/docs/split-view.md +8 -0
- package/docs/tab-scaffold.md +4 -2
- package/docs/type-contracts.md +21 -17
- package/docs/ui-analyzer.md +19 -0
- package/docs/ui-evaluator.md +17 -0
- package/docs/ux-demo.md +4 -4
- package/docs/webawesome-theme.md +20 -2
- package/docs/workbench.md +20 -1
- package/evaluator/index.mjs +73 -8
- package/llms.txt +32 -14
- package/package.json +4 -2
- package/ux-demo/recipes/app-shell.tsx +209 -178
- package/ux-demo/recipes/collapsible-sidebar.tsx +188 -159
- package/ux-demo/recipes/compact-toolbar.tsx +48 -35
- package/ux-demo/recipes/composer-form.tsx +85 -79
- package/ux-demo/recipes/list-detail-dialog.tsx +124 -142
- package/ux-demo/recipes/list-workspace-states.tsx +83 -83
- package/ux-demo/recipes/loaders.ts +5 -2
- package/ux-demo/recipes/loading-inspector.tsx +157 -160
- package/ux-demo/recipes/navigation-sidebar.tsx +111 -109
- package/ux-demo/recipes/navigation-stack.tsx +50 -49
- package/ux-demo/recipes/types.ts +14 -0
- package/ux-demo/recipes/workspace-header.tsx +73 -56
- package/dist/chunk-AQSKJ6U6.js.map +0 -1
- package/dist/chunk-ELRMBQEC.js.map +0 -1
- package/dist/chunk-J3EE6XWD.js +0 -115
- package/dist/chunk-J3EE6XWD.js.map +0 -1
- package/dist/chunk-KKNK3JUT.js.map +0 -1
- package/dist/chunk-OL4TC3U2.js.map +0 -1
- package/dist/chunk-OQI7RCRP.js.map +0 -1
- package/dist/chunk-UMGY5JSP.js.map +0 -1
- package/dist/chunk-V6RZWDII.js.map +0 -1
- package/dist/chunk-ZNZ2JDBW.js.map +0 -1
- package/ux-demo/recipes/app-shell.css +0 -87
- package/ux-demo/recipes/collapsible-sidebar.css +0 -83
- package/ux-demo/recipes/compact-toolbar.css +0 -35
- package/ux-demo/recipes/composer-form.css +0 -19
- package/ux-demo/recipes/list-detail-dialog.css +0 -42
- package/ux-demo/recipes/list-workspace-states.css +0 -30
- package/ux-demo/recipes/loading-inspector.css +0 -7
- package/ux-demo/recipes/navigation-sidebar.css +0 -12
- package/ux-demo/recipes/navigation-stack.css +0 -12
- package/ux-demo/recipes/recipe-root.css +0 -67
- package/ux-demo/recipes/recipe-root.tsx +0 -87
- package/ux-demo/recipes/workspace-header.css +0 -7
package/docs/type-contracts.md
CHANGED
|
@@ -11,22 +11,22 @@ public-signature artifact.
|
|
|
11
11
|
|
|
12
12
|
## Strengthened contracts
|
|
13
13
|
|
|
14
|
-
| ID | Compile-time guarantee
|
|
15
|
-
| ---------- |
|
|
16
|
-
| `KUI-T001` | `ListHeader` is a passive heading, a fully named/icon-bearing trailing action, or a controlled disclosure with `action` + `expanded`. Props ignored by the selected mode are rejected.
|
|
17
|
-
| `KUI-T002` | `Select` has a visible `label` or an `ariaLabel`.
|
|
18
|
-
| `KUI-T003` | A literal `Select.value` belongs to its literal `choices`.
|
|
19
|
-
| `KUI-T004` | A literal `SegmentedControl.value` belongs to its literal `choices`.
|
|
20
|
-
| `KUI-T005` | `expanded`, `expandAction`, and `expandLabel` exist only on `TokenSearchField({ collapsible: true })`.
|
|
21
|
-
| `KUI-T006` | `TokenSearchEditorAttributes` accepts application `data-*` metadata but rejects component-owned identity, morph, count, and placeholder attributes.
|
|
22
|
-
| `KUI-T007` | `ToolbarText.maxLines` requires `wrap: true`; it is never silently ignored in typed code.
|
|
23
|
-
| `KUI-T008` | A literal `TabScaffold.active` id belongs to its literal `tabs`.
|
|
24
|
-
| `KUI-T009` | Adjacent-token keyboard removal requires `onRemoveToken`; disabling removal rejects the now-meaningless callback.
|
|
25
|
-
| `KUI-T010` | Finite public variants have named exported union types, including divider sides, tab activation, banner urgency, and all AppTab, TabBar, ToolbarControlGroup, and Select presentation axes; the convenience root barrel re-exports them.
|
|
26
|
-
| `KUI-T011` | Semantic component zones use the recursive `KerfUiContent` type: `SafeHtml`, runtime-empty booleans/nullish values, and readonly nested arrays are valid; arbitrary strings, numbers, and signals are rejected. Explicit text positions such as `ListInsetText` retain their text exception.
|
|
27
|
-
| `KUI-T012` | `List.gap` accepts finite `UiSpaceName` shorthands or a complete branded `CssLength`; raw strings and non-standalone `CssLengthExpression` arithmetic are rejected. `calc(plus(...))` promotes a typed expression to a complete value.
|
|
28
|
-
| `KUI-T013` | CSS-valued props preserve property grammar: `List.flex` uses `CssFlex`, `Skeleton` dimensions use `CssSize`/`CssLength`, and choice icons use `
|
|
29
|
-
| `KUI-T014` | Stable single-root visual components accept the explicit native `slot` attribute. Multi-root `ResizableRegion` and `CollapsiblePanel` remain excluded because no single returned element can own the assignment, and other arbitrary native attributes remain rejected.
|
|
14
|
+
| ID | Compile-time guarantee |
|
|
15
|
+
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
16
|
+
| `KUI-T001` | `ListHeader` is a passive heading, a fully named/icon-bearing trailing action, or a controlled disclosure with `action` + `expanded`. Props ignored by the selected mode are rejected. |
|
|
17
|
+
| `KUI-T002` | `Select` has a visible `label` or an `ariaLabel`. |
|
|
18
|
+
| `KUI-T003` | A literal `Select.value` belongs to its literal `choices`. |
|
|
19
|
+
| `KUI-T004` | A literal `SegmentedControl.value` belongs to its literal `choices`. |
|
|
20
|
+
| `KUI-T005` | `expanded`, `expandAction`, and `expandLabel` exist only on `TokenSearchField({ collapsible: true })`. |
|
|
21
|
+
| `KUI-T006` | `TokenSearchEditorAttributes` accepts application `data-*` metadata but rejects component-owned identity, morph, count, and placeholder attributes. |
|
|
22
|
+
| `KUI-T007` | `ToolbarText.maxLines` requires `wrap: true`; it is never silently ignored in typed code. |
|
|
23
|
+
| `KUI-T008` | A literal `TabScaffold.active` id belongs to its literal `tabs`. |
|
|
24
|
+
| `KUI-T009` | Adjacent-token keyboard removal requires `onRemoveToken`; disabling removal rejects the now-meaningless callback. |
|
|
25
|
+
| `KUI-T010` | Finite public variants have named exported union types, including divider sides, tab activation, banner urgency, and all AppTab, TabBar, ToolbarControlGroup, and Select presentation axes; the convenience root barrel re-exports them. |
|
|
26
|
+
| `KUI-T011` | Semantic component zones use the recursive `KerfUiContent` type: `SafeHtml`, runtime-empty booleans/nullish values, and readonly nested arrays are valid; arbitrary strings, numbers, and signals are rejected. Explicit text positions such as `ListInsetText` retain their text exception. |
|
|
27
|
+
| `KUI-T012` | `List.gap` accepts finite `UiSpaceName` shorthands or a complete branded `CssLength`; raw strings and non-standalone `CssLengthExpression` arithmetic are rejected. `calc(plus(...))` promotes a typed expression to a complete value. |
|
|
28
|
+
| `KUI-T013` | CSS-valued props preserve property grammar: `List.flex` uses `CssFlex`, `Skeleton` dimensions use `CssSize`/`CssLength`, and choice icons use `CssForegroundColor` (foreground tokens via `uiColor()` or `foregroundColorVar()`; fill aliases such as `uiColor('success')` are rejected); row declaration strings are absent. |
|
|
29
|
+
| `KUI-T014` | Stable single-root visual components accept the explicit native `slot` attribute. Multi-root `ResizableRegion` and `CollapsiblePanel` remain excluded because no single returned element can own the assignment, and other arbitrary native attributes remain rejected. |
|
|
30
30
|
|
|
31
31
|
`KerfUiContent` lets conditionals and mapped component collections be direct
|
|
32
32
|
siblings without an otherwise-unnecessary `Fragment`:
|
|
@@ -120,7 +120,11 @@ move errors into casts without making the integration safer.
|
|
|
120
120
|
`gap="0.25rem"` with `gap={rem(0.25)}` and wrap sums with `calc(plus(...))`.
|
|
121
121
|
- Replace raw `List.flex` shorthands with `flex(grow, shrink, basis)` or a finite
|
|
122
122
|
keyword; replace raw Skeleton dimensions with `px`/`rem`/`em`/`pct` builders;
|
|
123
|
-
and replace raw choice colors with
|
|
123
|
+
and replace raw choice colors with a foreground token such as
|
|
124
|
+
`uiColor('success-on-quiet')` or an app-owned `foregroundColorVar()`.
|
|
125
|
+
`SelectChoice.color` rejects fill aliases (`uiColor('success')`) and
|
|
126
|
+
unqualified `colorVar()` values because a fill paints a nearly invisible
|
|
127
|
+
icon.
|
|
124
128
|
- Remove `style` from `ListItem` and `ListActionRow`; use `className`, public
|
|
125
129
|
tokens, and cataloged props. These breaking cleanups land before 5.0 stable.
|
|
126
130
|
|
package/docs/ui-analyzer.md
CHANGED
|
@@ -17,6 +17,25 @@ composition catalog by `package:id`, parses literal JavaScript/TypeScript
|
|
|
17
17
|
component calls, TSX/JSX, and CSS, and reports portable repository-relative
|
|
18
18
|
locations.
|
|
19
19
|
|
|
20
|
+
An imported component name is resolved to a catalog entry by `package:id`, not
|
|
21
|
+
by display name: several entries share one (the Kerf `Select` and the Web
|
|
22
|
+
Awesome `wa-select` are both "Select"), so the analyzer joins each composition
|
|
23
|
+
entry to its selection-catalog public exports and import subpaths and picks
|
|
24
|
+
the entry that the import actually names. That keeps the Kerf component's
|
|
25
|
+
CSS-value contracts (`KUI-L013`–`KUI-L017`) in force for `Select` and
|
|
26
|
+
`Skeleton`.
|
|
27
|
+
|
|
28
|
+
Only component exports resolve to an entry. A selection-catalog
|
|
29
|
+
`publicExports` list also carries the helpers a component's props consume
|
|
30
|
+
(`Select` ships `uiColor`, `List` ships `px`, `rem`, and `flex`), and a helper
|
|
31
|
+
never inherits its entry's contracts, so `uiColor({ choices: [...] })` is not
|
|
32
|
+
checked as a `Select` call. A component export is one whose name starts with
|
|
33
|
+
an uppercase letter, the same rule JSX uses to tell a component tag from an
|
|
34
|
+
intrinsic element; `eslint-plugin-kerfjs` applies the identical rule, and the
|
|
35
|
+
package's catalog check fails if a cataloged render function (a value
|
|
36
|
+
returning `SafeHtml`) is lowercase or any other runtime value is uppercase.
|
|
37
|
+
Third-party catalogs should follow the same naming convention.
|
|
38
|
+
|
|
20
39
|
Analysis is scoped per source file. Each TSX/JSX file resolves package,
|
|
21
40
|
workspace, and parent-to-child directory profiles from its own location, then
|
|
22
41
|
follows its relative CSS imports (including nested CSS `@import`s). Stylesheet
|
package/docs/ui-evaluator.md
CHANGED
|
@@ -61,6 +61,23 @@ shared container and `data-kui-align-edge` on two or more elements whose logical
|
|
|
61
61
|
start edges must align. Use `data-kui-scroll-scope` only for an application-owned
|
|
62
62
|
scope that is not a `.kui-pane`.
|
|
63
63
|
|
|
64
|
+
Target size (`KUI-B050`) measures the area the pointer can actually reach, not
|
|
65
|
+
just the border box. When a control's box is under 44 × 44, the evaluator
|
|
66
|
+
hit-tests outward from its center with `elementFromPoint`, so a transparent hit
|
|
67
|
+
layer (a positioned `::before`/`::after` that receives pointer events, as on the
|
|
68
|
+
`ListHeader` action) counts toward the target, while a pseudo-element with
|
|
69
|
+
`pointer-events: none`, a clipping ancestor, or an overlapping neighbor does
|
|
70
|
+
not. Where the probe reaches the viewport edge it mirrors the opposite side's
|
|
71
|
+
reach; a control whose center is off-screen or covered keeps its border box.
|
|
72
|
+
The diagnostic evidence reports the measured `width`/`height` and the border
|
|
73
|
+
`box`.
|
|
74
|
+
|
|
75
|
+
Compact density is a documented exception. Inside `[data-density="compact"]` —
|
|
76
|
+
the compact `List`/`ListHeader` family, whose rows are 36px tall — a target
|
|
77
|
+
still needs the full 44px width but only the 36px row height, because a taller
|
|
78
|
+
hit layer would reach into the neighboring row. The evidence's `required` field
|
|
79
|
+
names the floor that applied (`44×44`, or `44×36` in compact density).
|
|
80
|
+
|
|
64
81
|
Accessible names follow ARIA/native naming inputs, including labels, referenced
|
|
65
82
|
content with `aria-hidden` descendants removed, and native input values.
|
|
66
83
|
Geometry checks use each catalog entry's explicit `boundaries.rootClass`; the
|
package/docs/ux-demo.md
CHANGED
|
@@ -25,13 +25,13 @@ deterministic state, and semantic layout owners from the [recipe guide](./recipe
|
|
|
25
25
|
- The master/detail shell groups first-party routes by category with production `ListHeader` and `ListItem` components. Catalog entries can supply short reusable trailing tags; the Web Awesome projection uses them to label exactly the 15 discouraged choices. The 70 ecosystem components live in a separate `Web Awesome` disclosure with seven subgroups, so they remain discoverable without being presented as first-class `@kerfjs/ui` exports. Direct Web Awesome routes open the disclosure and reveal the selected row at wide sizes; narrow layouts keep the expanded list in document flow rather than introducing a competing nested scroller.
|
|
26
26
|
- The shell itself uses `@kerfjs/ui/layout.css`: sidebars, details, previews, dialogs, and resize specimens share unpadded panes plus self-contained content items. Its sidebar identity uses the Kerf logo beside a vertically centered title, with supporting copy in its own aligned row; the current-view heading is also a toolbar. Collapsing the catalog removes the pane completely and moves its restore action to the main toolbar's leading edge instead of leaving an icon-only rail. The selected view description remains inset below the page toolbar. The checkerboard belongs to the preview scroll owner rather than a viewport-height stage or nested card, and one explicitly repeated SVG tile keeps the pattern continuous through below-fold content. A lightly separated footer keeps live status above compact source, guidance, and relationship groups. The focused `ResizableRegion` specimen stretches its surface through the available stage height and reports committed width in that shared status footer; narrow layouts retain local horizontal access when the pane is resized wider than the stage, and the split remains readable at 200% root scaling. Geometry coverage checks wide, intermediate, narrow, and 200% zoom layouts.
|
|
27
27
|
- The composer-form recipe demonstrates one coherent visible form surface with toolbar title/supporting-copy hierarchy, fields and actions on the shared 8px control gutter, and 24px major rhythm. Its conditional error or success `StateBanner` is the only nested semantic surface. Reset synchronizes the upgraded Web Awesome fields' live value properties with their empty controlled attributes and announces `Draft reset`; browser coverage preserves behavior and verifies wide, narrow, dark, validation, success, reset, 200% zoom, and forced-colors states.
|
|
28
|
-
- The list-detail dialog recipe
|
|
28
|
+
- The list-detail dialog recipe composes `DialogSurface`, the dialog's own labeled header and close control, `SplitView`, and footer actions. Its `SplitView` sits flush in the dialog body, both panes open with a `ListHeader` on one shared line, the dialog title and header text share the 17px text edge, the value table keeps the 8px outer margin, and the trailing actions keep the 16px footer gutter. Compact devices get a full-screen sheet with a list-to-detail drill-down. Browser geometry coverage protects those relationships at wide and narrow widths.
|
|
29
29
|
- Catalog-only brand marks, preview dimensions, checkerboard tiles, and the compound display-settings control retain local geometry because they are specimen chrome or intrinsic control anatomy rather than reusable application spacing roles.
|
|
30
30
|
- The menu composition route demonstrates toolbar/content/footer anatomy, 24px major gaps, 8/1/8 child geometry, the full-width `ListHeader` count-or-badge/action split, logical-end 44px action targets with 18px visuals, and 44px row/header/toolbar targets. Its one chevron is a production 18px `DisclosureArrow` inside a controlled Tools header that actually reveals and hides content; ordinary Projects navigation has no false disclosure affordance. Browser assertions cover stable naming, expanded/content transitions, visual rotation, node identity, reduced motion, RTL alignment and containment, and wide, narrow, dark, and 200% layouts. The focused ListHeader route separately shows the shared neutral count pill for Attachments, Notes (including zero), and Duplicates plus a non-count legacy badge, full-width logical-end actions, and no disclosure without content.
|
|
31
31
|
- The `DisclosureArrow` route renders the production 18px root-scaled default without a catalog-only size override. Its two native buttons independently control the default right-to-down chevron and a recognizable right-facing replacement arrow with left-to-up custom directions; both use shortest-path rotation and their names stay stable while `aria-expanded` communicates state. Browser coverage verifies the custom clockwise path, pointer and native keyboard activation, focus, narrow and 200%-zoom stacking with contained labels, consumer sizing, and the independent `.5` Web Awesome glyph scale retained by Kerf `Select`.
|
|
32
32
|
- A detail with relationships renders one content-fitted `Components` footer selector: `Uses` links to direct dependencies and `Used by` links to reverse dependents. Its popup owns the standard surface inset so headings and even long component names stay clear of the menu border. Choosing either navigates to that component's demo. The relationship group is absent when both sets are empty; no duplicate summary is rendered.
|
|
33
|
-
-
|
|
34
|
-
- Scenarios use deterministic data and cover real variants, long content, disabled state, selection, progress, feedback, overlays, media, helpers, and stateful interactions. Individual Web Awesome action, form, layout, navigation, feedback, media, and helper routes provide focused theme specimens without a redundant aggregate route; ListItem and ListHeader demonstrate typed domain metadata, protected native button/disclosure semantics, and a native popover trigger relationship without product props; the Headers composition demonstrates direct toolbar headings with an extra-large title, optional supporting copy, and grouped icon/actions; the Select route verifies that option icons survive unrelated Kerf rerenders and selected slot content follows value changes; the Animation route exposes preset, easing, duration, playback-rate, and transport controls with live lifecycle status; observer routes provide user-driven intersection, mutation, and resize events with live results; ToolbarControlGroup exposes all eight Hot Sheet 2 variants, loads the Web Awesome registrations needed by its popup specimen, and preserves the upgraded dropdown's managed light-DOM children across Kerf rerenders; the Toolbar route composes a collapsible TokenSearchField inside a group, animates between the empty iconic and complete field states, stays open while populated, and focuses the revealed editor; SegmentedControl covers toolbar, rounded-rectangle, pill, equal-width, and disabled presentations; TokenSearchField covers editable ordered chips, pointer and keyboard removal, caret-preserving controlled deletion, editing, clearing, free text, disabled state, and fixed first-line alignment while content wraps; StateBanner exposes every built-in tone with tone-tinted badges plus a scoped override; the Application tabs composition
|
|
33
|
+
- Focused demos ship no local stylesheets, inline styles, or styling-only class names. They compose Kerf components first, Web Awesome surfaces where Kerf has no equivalent, and ordinary semantic HTML for the remainder. The catalog-owned `CatalogExample.viewport` contract supplies the few specimen constraints needed to demonstrate layout behavior. Recipes follow the same rule: they ship no stylesheets, inline styles, or styling-only classes, and the catalog frames each one in the `CatalogExample` viewport its exported `presentation` declares (full-width application arrangements span the canvas measure; narrower recipes sit in the centered example column). Demo-only CSS is limited to the document-shell `style.css`, which carries no recipe rules. Decorative chrome and Web Awesome controls share the same semantic system palette instead of carrying a separate demo identity.
|
|
34
|
+
- Scenarios use deterministic data and cover real variants, long content, disabled state, selection, progress, feedback, overlays, media, helpers, and stateful interactions. Individual Web Awesome action, form, layout, navigation, feedback, media, and helper routes provide focused theme specimens without a redundant aggregate route; ListItem and ListHeader demonstrate typed domain metadata, protected native button/disclosure semantics, and a native popover trigger relationship without product props; the Headers composition demonstrates direct toolbar headings with an extra-large title, optional supporting copy, and grouped icon/actions; the Select route verifies that option icons survive unrelated Kerf rerenders and selected slot content follows value changes; the Animation route exposes preset, easing, duration, playback-rate, and transport controls with live lifecycle status; observer routes provide user-driven intersection, mutation, and resize events with live results; ToolbarControlGroup exposes all eight Hot Sheet 2 variants, loads the Web Awesome registrations needed by its popup specimen, and preserves the upgraded dropdown's managed light-DOM children across Kerf rerenders; the Toolbar route composes a collapsible TokenSearchField inside a group, animates between the empty iconic and complete field states, stays open while populated, and focuses the revealed editor; SegmentedControl covers toolbar, rounded-rectangle, pill, equal-width, and disabled presentations; TokenSearchField covers editable ordered chips, pointer and keyboard removal, caret-preserving controlled deletion, editing, clearing, free text, disabled state, and fixed first-line alignment while content wraps; StateBanner exposes every built-in tone with tone-tinted badges plus a scoped override; the Application tabs composition uses a Web Awesome card with semantic header/footer slots and Kerf `Text` while demonstrating overflow, edge autoscroll, and controlled pointer/keyboard reordering.
|
|
35
35
|
- The ToolbarControlGroup route also demonstrates the public compact/tight,
|
|
36
36
|
mixed-content, filled-selection, nested-dropdown, and avatar/scrim contracts
|
|
37
37
|
added for consumers that previously restyled group descendants. The compact
|
|
@@ -42,7 +42,7 @@ deterministic state, and semantic layout owners from the [recipe guide](./recipe
|
|
|
42
42
|
paints only the pressed selection, with contain fitting in both cases. Its
|
|
43
43
|
collapsible-search specimen follows the selected group shape with a
|
|
44
44
|
concentric inner radius in both collapsed and expanded states.
|
|
45
|
-
- Recipe ownership notes are hidden by default. A page-toolbar toggle reveals
|
|
45
|
+
- Recipe ownership notes are hidden by default. A page-toolbar toggle reveals each recipe's note as its `CatalogExample` note above the framed specimen, so instructional copy never covers the composition.
|
|
46
46
|
- Settings exercise light/dark, increased contrast, and reduced motion without changing component code. The theme action starts from the operating system's effective color scheme, always names the appearance it will switch to, and installs an explicit light or dark override when activated; contrast and reduced motion expose their independent preferences through `aria-pressed`.
|
|
47
47
|
- The footer action log is an `aria-live` region, making interactions visible to both people and browser tests.
|
|
48
48
|
- The focused Toast route calls Web Awesome's documented programmatic stack API and notes that Hot Sheet 2 still uses its own app-level toast implementation; the catalog demonstrates ecosystem support without implying current product adoption.
|
package/docs/webawesome-theme.md
CHANGED
|
@@ -54,12 +54,30 @@ pointer targets. Override `--kui-wa-carousel-icon-size`,
|
|
|
54
54
|
`--kui-wa-carousel-dot-hit-size` on a carousel or containing scope when a
|
|
55
55
|
product needs different geometry.
|
|
56
56
|
|
|
57
|
+
Code text uses Kerf's named monospace stack, `--kui-font-mono`
|
|
58
|
+
(`ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono",
|
|
59
|
+
monospace`), and the theme points `--wa-font-family-code` at it. Web Awesome's
|
|
60
|
+
own `ui-monospace, monospace` renders the generic face (Courier on macOS) in
|
|
61
|
+
Chromium, which does not recognize `ui-monospace`; because the generic
|
|
62
|
+
`monospace` ends any stack, Kerf's token owns the stack rather than appending
|
|
63
|
+
fallbacks after Web Awesome's. Override `--kui-font-mono` to change code text in
|
|
64
|
+
both Kerf and Web Awesome components.
|
|
65
|
+
|
|
57
66
|
Form fields carry the same content-item inset as the Kerf primitives: a 1px
|
|
58
67
|
border with 8px inside it (`--wa-form-control-border-width`,
|
|
59
68
|
`--wa-form-control-padding-block`, and `--wa-form-control-padding-inline` are set
|
|
60
69
|
to the `--kui-layout-item-border-width` / `--kui-layout-item-padding` values), so
|
|
61
|
-
|
|
62
|
-
|
|
70
|
+
the value sits 9px in from the field edge. Default-size single-line controls
|
|
71
|
+
share Kerf's 44px control height — the height of a Kerf `Select`, a toolbar
|
|
72
|
+
group, and a list row — so a `wa-input` or `wa-button` sits flush beside a Kerf
|
|
73
|
+
`Select`. The theme sets `--wa-form-control-height` to `2.75em` (44px at the
|
|
74
|
+
16px default) on Button, Color Picker, Input, Known Date, Number Input, Radio
|
|
75
|
+
Group, Select, Textarea (its minimum height), and Time Input, so `size="large"`
|
|
76
|
+
scales proportionally while `size="small"` keeps Web Awesome's compact secondary
|
|
77
|
+
height. The token is scoped to those controls rather than the root because Web
|
|
78
|
+
Awesome also derives tag, copy-button, and toast geometry from it. Buttons
|
|
79
|
+
inside a `ToolbarControlGroup` keep the group's 40px (32px compact) control
|
|
80
|
+
height. Each field's top label is inset by that same border +
|
|
63
81
|
padding (9px) so it lines up with the value inside the field, and is styled
|
|
64
82
|
exactly like a `ListHeader` label — uppercase, `--kui-font-xs`, weight 650, quiet
|
|
65
83
|
foreground. This applies to every free field that exposes a top label
|
package/docs/workbench.md
CHANGED
|
@@ -12,6 +12,12 @@ import { Workbench } from "@kerfjs/ui/workbench";
|
|
|
12
12
|
import "@kerfjs/ui/workbench.css";
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
+
A top-level `Workbench` needs a definite containing height. Import the opt-in
|
|
16
|
+
`@kerfjs/ui/document.css` baseline and add `.kui-app-root` to the direct mount
|
|
17
|
+
container, or provide an equivalent definite height in application-owned
|
|
18
|
+
layout. The component intentionally uses `height: 100%` rather than `100dvh` so
|
|
19
|
+
it can also be embedded. See [Document baseline](document-baseline.md).
|
|
20
|
+
|
|
15
21
|
## State lives in the app
|
|
16
22
|
|
|
17
23
|
`Workbench` is declarative and the collapse is **pure CSS** — no wire. The app
|
|
@@ -90,7 +96,10 @@ with state-derived props:
|
|
|
90
96
|
```
|
|
91
97
|
|
|
92
98
|
`wireResizableRegions` marks the active region with `data-resizing` and the
|
|
93
|
-
package CSS suppresses content motion during pointer resize.
|
|
99
|
+
package CSS suppresses content motion during pointer resize. It applies the
|
|
100
|
+
live size to both the track and the slide-motion content, so content fills the
|
|
101
|
+
region throughout a drag, including any safe-area edge extent, and a later
|
|
102
|
+
collapse slides it out at the resized width. A collapsed,
|
|
94
103
|
overlay, or hidden region is not resizeable. Together these policies replace
|
|
95
104
|
app CSS for separator suppression, instant-track/composited-content collapse,
|
|
96
105
|
popup overflow, mobile overlay/hidden replacement, resize-transition guards,
|
|
@@ -110,6 +119,16 @@ must classify public application selectors. Prefer the component props and two
|
|
|
110
119
|
size tokens before selecting internal anatomy, and do not target its data
|
|
111
120
|
attributes or descendant tags as styling contracts.
|
|
112
121
|
|
|
122
|
+
## Safe areas
|
|
123
|
+
|
|
124
|
+
Each rail and the drawer grows by the unsafe inset of the screen edge it docks
|
|
125
|
+
to, so its surface and separator paint through while its content keeps the
|
|
126
|
+
configured size and is padded for the edges it touches. The main area pads for
|
|
127
|
+
the edges it reaches, inside its scroller: an expanded inline rail or drawer
|
|
128
|
+
takes that edge away, and collapsing it (or presenting it as an overlay) hands
|
|
129
|
+
the edge back. A region whose only child is a `Pane` or layout lets that child
|
|
130
|
+
own the insets. See [Choosing an app layout › Safe areas](app-layouts.md#safe-areas).
|
|
131
|
+
|
|
113
132
|
## How the collapse animates
|
|
114
133
|
|
|
115
134
|
Collapsing snaps the panel's flex track to zero in a single reflow (so the work
|
package/evaluator/index.mjs
CHANGED
|
@@ -336,6 +336,50 @@ async function inspectPage(page, geometryContracts) {
|
|
|
336
336
|
return null;
|
|
337
337
|
};
|
|
338
338
|
|
|
339
|
+
const hitExtent = (element, rect) => {
|
|
340
|
+
const root = element.getRootNode();
|
|
341
|
+
const probe = root.elementFromPoint ? root : document;
|
|
342
|
+
const inViewport = (x, y) =>
|
|
343
|
+
x >= 0 && y >= 0 && x < innerWidth && y < innerHeight;
|
|
344
|
+
const owns = (x, y) => {
|
|
345
|
+
const hit = probe.elementFromPoint(x, y);
|
|
346
|
+
return !!hit && (hit === element || element.contains(hit));
|
|
347
|
+
};
|
|
348
|
+
const x = rect.left + rect.width / 2;
|
|
349
|
+
const y = rect.top + rect.height / 2;
|
|
350
|
+
if (!inViewport(x, y) || !owns(x, y)) return null;
|
|
351
|
+
// Walk out in 1px steps (no further than the 44px goal needs), then
|
|
352
|
+
// refine the last step in quarter pixels; the reach is the last owned
|
|
353
|
+
// sample, so it never overstates the target. A walk stopped by
|
|
354
|
+
// the viewport edge cannot see the rest of the layer, so it is marked
|
|
355
|
+
// and mirrored from the opposite side (hit layers are symmetric insets).
|
|
356
|
+
const reach = (dx, dy) => {
|
|
357
|
+
const at = (distance) => [x + dx * distance, y + dy * distance];
|
|
358
|
+
let owned = 0;
|
|
359
|
+
while (owned < 24) {
|
|
360
|
+
const point = at(owned + 1);
|
|
361
|
+
if (!inViewport(...point)) return { distance: owned, clipped: true };
|
|
362
|
+
if (!owns(...point)) break;
|
|
363
|
+
owned += 1;
|
|
364
|
+
}
|
|
365
|
+
if (owned >= 24) return { distance: owned, clipped: false };
|
|
366
|
+
while (owns(...at(owned + 0.25))) owned += 0.25;
|
|
367
|
+
return { distance: owned, clipped: false };
|
|
368
|
+
};
|
|
369
|
+
const span = (first, second) =>
|
|
370
|
+
first.clipped && second.clipped
|
|
371
|
+
? first.distance + second.distance
|
|
372
|
+
: first.clipped
|
|
373
|
+
? 2 * second.distance
|
|
374
|
+
: second.clipped
|
|
375
|
+
? 2 * first.distance
|
|
376
|
+
: first.distance + second.distance;
|
|
377
|
+
return {
|
|
378
|
+
width: span(reach(-1, 0), reach(1, 0)),
|
|
379
|
+
height: span(reach(0, -1), reach(0, 1)),
|
|
380
|
+
};
|
|
381
|
+
};
|
|
382
|
+
|
|
339
383
|
for (const element of interactives) {
|
|
340
384
|
const target = selector(element);
|
|
341
385
|
const rect = element.getBoundingClientRect();
|
|
@@ -495,14 +539,35 @@ async function inspectPage(page, geometryContracts) {
|
|
|
495
539
|
'button,input:not([type="hidden"]),select,textarea,[role]',
|
|
496
540
|
) &&
|
|
497
541
|
(rect.width < 43.5 || rect.height < 43.5)
|
|
498
|
-
)
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
542
|
+
) {
|
|
543
|
+
// The border box understates a control whose pointer target is
|
|
544
|
+
// extended by a transparent hit layer (a positioned ::before/::after
|
|
545
|
+
// that receives pointer events). Hit-test outward from the center to
|
|
546
|
+
// measure the area the pointer can actually reach; a probe that finds
|
|
547
|
+
// no hit (off-screen, covered center) keeps the border box.
|
|
548
|
+
const hit = hitExtent(element, rect);
|
|
549
|
+
const width = Math.max(rect.width, hit?.width ?? 0);
|
|
550
|
+
const height = Math.max(rect.height, hit?.height ?? 0);
|
|
551
|
+
// Compact density is a deliberate trade-off: its rows are 36px tall,
|
|
552
|
+
// and a taller hit layer would reach into the neighboring row. Inside
|
|
553
|
+
// `[data-density="compact"]` a target still needs the full 44px width
|
|
554
|
+
// but only the 36px compact row height.
|
|
555
|
+
const compact = element.closest('[data-density="compact"]') !== null;
|
|
556
|
+
const requiredHeight = compact ? 36 : 44;
|
|
557
|
+
if (width < 43.5 || height < requiredHeight - 0.5)
|
|
558
|
+
diagnostics.push({
|
|
559
|
+
code: 'KUI-B050',
|
|
560
|
+
selector: target,
|
|
561
|
+
message: `Hit target is ${width.toFixed(1)}×${height.toFixed(1)}px; expected at least 44×${requiredHeight}px${compact ? ' (compact density)' : ''}.`,
|
|
562
|
+
repair: repair.target,
|
|
563
|
+
evidence: {
|
|
564
|
+
width,
|
|
565
|
+
height,
|
|
566
|
+
box: { width: rect.width, height: rect.height },
|
|
567
|
+
required: { width: 44, height: requiredHeight },
|
|
568
|
+
},
|
|
569
|
+
});
|
|
570
|
+
}
|
|
506
571
|
}
|
|
507
572
|
|
|
508
573
|
const parse = (value) => {
|
package/llms.txt
CHANGED
|
@@ -34,7 +34,9 @@ the folder modules, and CSS only imports their owner stylesheets.
|
|
|
34
34
|
when app-owned components must participate in selection or alignment.
|
|
35
35
|
Load the [Composition catalog v2](./ai/component-catalog-v2.json) to
|
|
36
36
|
mechanically evaluate parents, contexts, zones/cardinality, children, state,
|
|
37
|
-
wiring
|
|
37
|
+
wiring (including the wiring-owned `stateAttributes` an app must never
|
|
38
|
+
render or remove), responsive/layout/accessibility rules, and public
|
|
39
|
+
boundaries. V1
|
|
38
40
|
remains compatible; v2 joins catalogs by `package:id`. Consumer v2 catalogs
|
|
39
41
|
use [the v2 extension schema](./ai/component-catalog-extension-v2.schema.json).
|
|
40
42
|
Load [compile-time contracts](./ai/compile-time-contracts-v1.json) for stable
|
|
@@ -70,7 +72,9 @@ the folder modules, and CSS only imports their owner stylesheets.
|
|
|
70
72
|
[catalog-authoring.json](./ai/catalog-authoring.json), then follow its
|
|
71
73
|
authoritative [Catalog demo authoring contract](./docs/catalog.md#catalog-demo-authoring-contract).
|
|
72
74
|
Use its component/composition/recipe taxonomy and functional-group,
|
|
73
|
-
importance, alphabetical-tie, and recipes-last ordering policy.
|
|
75
|
+
importance, alphabetical-tie, and recipes-last ordering policy. Focused
|
|
76
|
+
demos and recipes use public components plus `CatalogExample.viewport`,
|
|
77
|
+
never local stylesheets, inline styles, or styling-only classes.
|
|
74
78
|
5. **Apply the rules below and in** [skill.md](./ai/skill.md).
|
|
75
79
|
6. **Before calling an integration complete**, run
|
|
76
80
|
[`kerf-ui-doctor`](./docs/ui-doctor.md). Its portable JSON report merges
|
|
@@ -103,6 +107,11 @@ the folder modules, and CSS only imports their owner stylesheets.
|
|
|
103
107
|
own the geometry (8px inline margin + 1px border + 8px padding). Do not add a
|
|
104
108
|
container padding on top of a content-item's own margin — pick one owner. Use
|
|
105
109
|
`.kui-content` for 24px major vertical rhythm.
|
|
110
|
+
- **Opt into document globals explicitly.** Import `@kerfjs/ui/document.css`
|
|
111
|
+
once for border-box sizing, token-backed body/link presentation, and zero body
|
|
112
|
+
margin. Put `.kui-app-root` on the one direct mount container only when a
|
|
113
|
+
percentage-height shell needs the provided `html` → `body` → app-root height
|
|
114
|
+
chain. The baseline is not part of `styles.css` or component browser imports.
|
|
106
115
|
- **Use `Row` for horizontal and `List` for vertical layout.** Both expose
|
|
107
116
|
physical `hAlign`/`vAlign` props and typed gaps. Row defaults to left/full,
|
|
108
117
|
an `xs` gap, and no wrapping; List retains full/top and zero-gap defaults.
|
|
@@ -117,13 +126,19 @@ the folder modules, and CSS only imports their owner stylesheets.
|
|
|
117
126
|
shorthand (`gap="xs"`, `gap="m"`) or a complete `CssLength` from the CSS-free
|
|
118
127
|
`@kerfjs/ui/css-values` builders; raw CSS strings are rejected. Use `flex()`
|
|
119
128
|
for List flex, typed lengths for Skeleton geometry, and
|
|
120
|
-
`uiColor()
|
|
129
|
+
foreground colors for choice icons: `uiColor()` with an `*-on-*`/text token
|
|
130
|
+
or `foregroundColorVar()`; fill aliases such as `uiColor('success')` do not
|
|
131
|
+
type-check. These brands are intentionally
|
|
121
132
|
not interchangeable; rows use classes/tokens/props rather than raw `style`.
|
|
122
133
|
- **Use `Grid` for a fixed positive count of equal-width columns.** It uses
|
|
123
134
|
zero-minimum fractional tracks, so intrinsic content cannot make one column
|
|
124
135
|
wider than its peers. The app owns responsive count changes; use custom CSS
|
|
125
136
|
grid for asymmetric/intrinsic tracks and `ResizableRegion` for adjustable
|
|
126
137
|
boundaries. `Grid.gap` and `Grid.flex` use the same typed grammars as Row.
|
|
138
|
+
- **Give a layout root `fill`, not a frame `Pane`.** A Row, List, or Grid that
|
|
139
|
+
is the sole layout root of a definite-height parent takes its full height
|
|
140
|
+
with `fill` and carries safe `data-*` markers through `rootAttributes`.
|
|
141
|
+
Inside a flex layout use `flex` instead.
|
|
127
142
|
- **Keep Web Awesome on the shared inset tiers.** `webawesome.css` uses
|
|
128
143
|
`--kui-wa-control-inset` (8px controls/items) and
|
|
129
144
|
`--kui-wa-surface-margin` / `--kui-wa-surface-inset` (8px around/inside
|
|
@@ -173,22 +188,25 @@ the folder modules, and CSS only imports their owner stylesheets.
|
|
|
173
188
|
need a Web Awesome feature, chiefly the `slot="trigger"` button of a `wa-dropdown`
|
|
174
189
|
popup menu. A toolbar popup menu is a `single` `ToolbarControlGroup` around a
|
|
175
190
|
`wa-dropdown` (its `slot="trigger"` `wa-button` is the toolbar button, kept under
|
|
176
|
-
`data-morph-skip-children`).
|
|
177
|
-
and
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
191
|
+
`data-morph-skip-children`). Let the group size the trigger from its icon,
|
|
192
|
+
localized text, and caret; do not force a dropdown or button width. Compact
|
|
193
|
+
mixed groups keep standard item padding and raised selected chrome without an
|
|
194
|
+
internal separator; the selected item paints over the outer border. For an
|
|
195
|
+
avatar control, set `content="avatar"` and `avatarImage` on the group instead of
|
|
196
|
+
inserting an `img`; a lone control paints the group and a multi-button group
|
|
197
|
+
paints only its pressed highlight.
|
|
181
198
|
- **Use one direct toolbar composition for panel/dialog/page headings.** Put an
|
|
182
199
|
optional icon in a `ToolbarControlGroup`, an extra-large `ToolbarText` directly
|
|
183
200
|
in the leading zone, and actions in a trailing group. Supporting copy is
|
|
184
201
|
app-owned content below. Do not create a private heading wrapper or restyle the
|
|
185
202
|
toolbar.
|
|
186
|
-
- **Use `Text` for ordinary semantic headings and
|
|
187
|
-
title zones.** Omit `variant` for the default `p`,
|
|
188
|
-
the document outline
|
|
203
|
+
- **Use `Text` for ordinary semantic headings, paragraphs, and inline secondary
|
|
204
|
+
text outside toolbar title zones.** Omit `variant` for the default `p`, pass
|
|
205
|
+
`h1`–`h6` based on the document outline, or use `variant="span"` inside a row,
|
|
206
|
+
label, or table cell without adding box geometry. Independently compose `tone="quiet|danger"`,
|
|
189
207
|
`size="compact"`, and `font="monospace"` for supporting, error, compact, and
|
|
190
208
|
code roles instead of global utility classes. It passes native attributes
|
|
191
|
-
through
|
|
209
|
+
through; block variants own the standard transparent border plus item padding, while `span` owns none. Keep
|
|
192
210
|
toolbar titles on `ToolbarText` and list-aligned bare prose on `ListInsetText`.
|
|
193
211
|
- **Space by the five-step scale, by relationship not by eye.** `0`
|
|
194
212
|
`--kui-space-none`, `4px` `--kui-space-2xs`, `8px` `--kui-space-xs` (inside a
|
|
@@ -279,7 +297,7 @@ tree-shakeable, declarative with `wire…` helpers, each with a companion CSS im
|
|
|
279
297
|
`@kerfjs/ui/device-class`. For a standalone collapsible rail/drawer outside a full
|
|
280
298
|
shell, `@kerfjs/ui/collapsible-panel` (`CollapsiblePanel`, `CollapsiblePanelToggle`)
|
|
281
299
|
|
|
282
|
-
- `@kerfjs/ui/wire-sidebar` (`wireSidebar`: toggle, focus, compact overlay, persistence).
|
|
300
|
+
- `@kerfjs/ui/wire-sidebar` (`wireSidebar`: toggle, focus, compact overlay, persistence; a compact overlay starts closed and opens only on a user action, and `inlineCollapsed` declares a panel's inline default).
|
|
283
301
|
`@kerfjs/ui/catalog` is another opt-in shell — a
|
|
284
302
|
`Catalog` component + `wireCatalog` helper for building a component-gallery catalog
|
|
285
303
|
(collapsible category sidebar + preview stage + resources footer, with an opt-in
|
|
@@ -300,7 +318,7 @@ shell, `@kerfjs/ui/collapsible-panel` (`CollapsiblePanel`, `CollapsiblePanelTogg
|
|
|
300
318
|
- [component-contract.md](./docs/component-contract.md): what a component owns vs. what the app owns.
|
|
301
319
|
- [accessibility.md](./docs/accessibility.md): keyboard and ARIA contracts per component.
|
|
302
320
|
- [recipes.md](./docs/recipes.md): production compositions (app shell, list-detail dialog, composer form, …) as copyable references.
|
|
303
|
-
- [app-layouts.md](./docs/app-layouts.md): choosing `NavStack`/`SplitView`/`Workbench`/`TabScaffold` by data + interaction + device, and dialog presentation.
|
|
321
|
+
- [app-layouts.md](./docs/app-layouts.md): choosing `NavStack`/`SplitView`/`Workbench`/`TabScaffold` by data + interaction + device, and dialog presentation, plus the safe-area model (surfaces paint through unsafe areas; content pads only the edges it reaches; `Pane.safeAreaEdges` for app-owned arrangements, `Toolbar.safeAreaEdges` for an app bar or bottom bar at a screen edge).
|
|
304
322
|
- [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.
|
|
305
323
|
- [component-catalog.json](./ai/component-catalog.json) + [component-catalog-extension.schema.json](./ai/component-catalog-extension.schema.json) + [catalog-authoring.json](./ai/catalog-authoring.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 selection facts, a reusable app-component extension contract, Catalog authoring discovery, and exact signatures.
|
|
306
324
|
- [compile-time-contracts-v1.json](./ai/compile-time-contracts-v1.json) + [type-contracts.md](./docs/type-contracts.md): stable compile diagnostics, packed-declaration proof, migrations, and explicit non-goals.
|
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.51",
|
|
4
4
|
"description": "Accessible, composable UI primitives for kerf applications.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -292,6 +292,7 @@
|
|
|
292
292
|
"import": "./dist/index.js"
|
|
293
293
|
},
|
|
294
294
|
"./foundation.css": "./dist/styles/foundation.css",
|
|
295
|
+
"./document.css": "./dist/styles/document.css",
|
|
295
296
|
"./layout.css": "./dist/styles/layout.css",
|
|
296
297
|
"./webawesome.css": "./dist/styles/webawesome.css",
|
|
297
298
|
"./styles.css": "./dist/styles/styles.css",
|
|
@@ -351,7 +352,8 @@
|
|
|
351
352
|
"scripts": {
|
|
352
353
|
"build": "tsup && node ../scripts/clean-dist-output.mjs dist && node scripts/build-css.mjs && node scripts/build-browser-entries.mjs",
|
|
353
354
|
"dev": "npm run build && vite --config ux-demo/vite.config.ts",
|
|
354
|
-
"demo:
|
|
355
|
+
"demo:bundle": "npm run build && vite build --config ux-demo/vite.config.ts",
|
|
356
|
+
"demo:build": "npm run demo:bundle && node scripts/check-demo-bundle.mjs",
|
|
355
357
|
"demo:serve": "vite preview --config ux-demo/vite.config.ts",
|
|
356
358
|
"test:e2e:serve": "npm run check:catalog && npm run check:demo-conformance && npm run demo:build && npm run demo:serve",
|
|
357
359
|
"format": "prettier --write . --ignore-unknown",
|