@kerfjs/ui 5.0.0-beta.55 → 5.0.0-beta.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -10
- package/ai/compile-time-contracts-v1.json +2 -2
- package/ai/component-catalog-v2.json +149 -39
- package/ai/component-catalog.json +202 -51
- package/ai/public-api-signatures-v1.md +439 -97
- package/ai/skill.md +43 -40
- package/ai/webawesome-jsx-signatures-v1.md +8 -2
- package/dist/app-tab.js +1 -1
- package/dist/badge.d.ts +35 -7
- package/dist/badge.js +1 -1
- package/dist/browser/content-item.js +3 -0
- package/dist/browser/select.js +1 -0
- package/dist/catalog-resources.d.ts +12 -1
- package/dist/catalog.d.ts +14 -3
- package/dist/catalog.js +52 -43
- package/dist/catalog.js.map +1 -1
- package/dist/{chunk-WZ2GLEY4.js → chunk-2G2ZJQYK.js} +2 -14
- package/dist/chunk-2G2ZJQYK.js.map +1 -0
- package/dist/{chunk-D7GWXIAS.js → chunk-5I7QGQVT.js} +1 -1
- package/dist/chunk-5I7QGQVT.js.map +1 -0
- package/dist/{chunk-RNRUVPJ3.js → chunk-63ZWBGE3.js} +3 -2
- package/dist/chunk-63ZWBGE3.js.map +1 -0
- package/dist/{chunk-44IG7PFV.js → chunk-6CINWX2E.js} +3 -3
- package/dist/{chunk-44IG7PFV.js.map → chunk-6CINWX2E.js.map} +1 -1
- package/dist/{chunk-C2FAYFDE.js → chunk-AGXQQFKZ.js} +2 -2
- package/dist/{chunk-C2FAYFDE.js.map → chunk-AGXQQFKZ.js.map} +1 -1
- package/dist/{chunk-ATHXW6RP.js → chunk-AHEG27M7.js} +2 -2
- package/dist/{chunk-ATHXW6RP.js.map → chunk-AHEG27M7.js.map} +1 -1
- package/dist/{chunk-7GUQYHKA.js → chunk-AK67F6QN.js} +4 -1
- package/dist/chunk-AK67F6QN.js.map +1 -0
- package/dist/chunk-BFPBS5Y4.js +250 -0
- package/dist/chunk-BFPBS5Y4.js.map +1 -0
- package/dist/{chunk-5OLVUEND.js → chunk-DG6G5EPF.js} +4 -6
- package/dist/chunk-DG6G5EPF.js.map +1 -0
- package/dist/{chunk-MTM43SJO.js → chunk-G33XC2NB.js} +1 -1
- package/dist/chunk-G33XC2NB.js.map +1 -0
- package/dist/{chunk-TZ5IHWB2.js → chunk-K6UNVKDK.js} +3 -3
- package/dist/{chunk-TZ5IHWB2.js.map → chunk-K6UNVKDK.js.map} +1 -1
- package/dist/{chunk-HMQ2ZDGG.js → chunk-KROD7KZK.js} +3 -2
- package/dist/chunk-KROD7KZK.js.map +1 -0
- package/dist/{chunk-5NDQABWK.js → chunk-M7QV3IHH.js} +3 -1
- package/dist/chunk-M7QV3IHH.js.map +1 -0
- package/dist/{chunk-RNZAKSME.js → chunk-MA6Z6EIM.js} +3 -3
- package/dist/{chunk-RNZAKSME.js.map → chunk-MA6Z6EIM.js.map} +1 -1
- package/dist/chunk-MA73TA6D.js +42 -0
- package/dist/chunk-MA73TA6D.js.map +1 -0
- package/dist/{chunk-ZMBU522F.js → chunk-MEY33VWB.js} +2 -2
- package/dist/{chunk-ZMBU522F.js.map → chunk-MEY33VWB.js.map} +1 -1
- package/dist/{chunk-T22EM4ET.js → chunk-MOBRFZH3.js} +81 -31
- package/dist/chunk-MOBRFZH3.js.map +1 -0
- package/dist/chunk-MP2GDBQZ.js +50 -0
- package/dist/chunk-MP2GDBQZ.js.map +1 -0
- package/dist/{chunk-3NBL3OUQ.js → chunk-NAPE7WUS.js} +2 -2
- package/dist/chunk-NAPE7WUS.js.map +1 -0
- package/dist/{chunk-BSKEH3UC.js → chunk-NBYTIVHS.js} +2 -2
- package/dist/{chunk-BSKEH3UC.js.map → chunk-NBYTIVHS.js.map} +1 -1
- package/dist/chunk-O3EXIBEZ.js +114 -0
- package/dist/chunk-O3EXIBEZ.js.map +1 -0
- package/dist/{chunk-R754MHXX.js → chunk-PK4N5QTO.js} +7 -6
- package/dist/chunk-PK4N5QTO.js.map +1 -0
- package/dist/{chunk-EAX2GSS4.js → chunk-QQOTQTDD.js} +51 -20
- package/dist/chunk-QQOTQTDD.js.map +1 -0
- package/dist/{chunk-LZXQVUGN.js → chunk-T4UZTNZ4.js} +4 -4
- package/dist/{chunk-LZXQVUGN.js.map → chunk-T4UZTNZ4.js.map} +1 -1
- package/dist/{chunk-N7FHFNT6.js → chunk-V65EOWNF.js} +33 -5
- package/dist/chunk-V65EOWNF.js.map +1 -0
- package/dist/{chunk-GUIHMIT2.js → chunk-VNPQDCQZ.js} +3 -3
- package/dist/{chunk-GUIHMIT2.js.map → chunk-VNPQDCQZ.js.map} +1 -1
- package/dist/{chunk-5I22LMCV.js → chunk-VZOFZPSO.js} +2 -2
- package/dist/chunk-VZOFZPSO.js.map +1 -0
- package/dist/{chunk-4BIMLITI.js → chunk-WLG6SSNT.js} +5 -3
- package/dist/chunk-WLG6SSNT.js.map +1 -0
- package/dist/{chunk-NE5JAOQS.js → chunk-WOUF7YXM.js} +3 -3
- package/dist/{chunk-NE5JAOQS.js.map → chunk-WOUF7YXM.js.map} +1 -1
- package/dist/collapsible-panel.d.ts +14 -3
- package/dist/collapsible-panel.js +13 -16
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/content-item.d.ts +46 -0
- package/dist/content-item.js +4 -0
- package/dist/content-item.js.map +1 -0
- package/dist/css-values.d.ts +5 -11
- package/dist/css-values.js +1 -1
- package/dist/disclosure-arrow.d.ts +4 -1
- package/dist/disclosure-arrow.js +1 -1
- package/dist/floating-toolbar.d.ts +17 -6
- package/dist/floating-toolbar.js +1 -1
- package/dist/grid.js +1 -1
- package/dist/help-tags-register.d.ts +13 -0
- package/dist/help-tags-register.js +9 -0
- package/dist/help-tags-register.js.map +1 -0
- package/dist/index.d.ts +6 -5
- package/dist/index.js +27 -26
- package/dist/list-action-row.js +1 -1
- package/dist/list-header.d.ts +14 -1
- package/dist/list-header.js +1 -1
- package/dist/list-inset-control.d.ts +1 -1
- package/dist/list-inset-control.js +1 -1
- package/dist/list-inset-text.d.ts +3 -10
- package/dist/list-inset-text.js +1 -1
- package/dist/list-item.js +1 -1
- package/dist/list.d.ts +10 -3
- package/dist/list.js +1 -1
- package/dist/nav-stack.d.ts +38 -5
- package/dist/nav-stack.js +4 -1
- package/dist/pane.d.ts +20 -2
- package/dist/pane.js +1 -1
- package/dist/{panel-toolbar-BFQxFITu.d.ts → panel-toolbar-C8sF-YZC.d.ts} +12 -1
- package/dist/popup-menu-register.js +3 -2
- package/dist/popup-menu-register.js.map +1 -1
- package/dist/popup-menu.js +1 -1
- package/dist/row.d.ts +1 -1
- package/dist/row.js +1 -1
- package/dist/select-register.js +70 -3
- package/dist/select-register.js.map +1 -1
- package/dist/select.d.ts +46 -8
- package/dist/select.js +2 -1
- package/dist/{divider-sides-BzB6rphT.d.ts → sides-BPSWde0A.d.ts} +1 -3
- package/dist/skeleton.js +1 -1
- package/dist/spacer.js +1 -1
- package/dist/split-view.d.ts +31 -3
- package/dist/split-view.js +33 -5
- package/dist/split-view.js.map +1 -1
- package/dist/state-banner.js +1 -1
- package/dist/styles/badge.css +13 -0
- package/dist/styles/catalog/components/catalog-example.css +1 -1
- package/dist/styles/catalog/components/catalog-stage.css +1 -1
- package/dist/styles/collapsible-panel.css +192 -39
- package/dist/styles/content-item.css +30 -0
- package/dist/styles/floating-toolbar.css +5 -0
- package/dist/styles/foundation.css +28 -19
- package/dist/styles/layout.css +1 -21
- package/dist/styles/list-action-row.css +13 -1
- package/dist/styles/list-inset-text.css +1 -2
- package/dist/styles/list-item.css +14 -1
- package/dist/styles/list.css +1 -1
- package/dist/styles/nav-stack.css +29 -64
- package/dist/styles/pane.css +33 -1
- package/dist/styles/popup-menu.css +78 -0
- package/dist/styles/resizable-region.css +53 -10
- package/dist/styles/select.css +39 -12
- package/dist/styles/split-view.css +21 -25
- package/dist/styles/tab-scaffold.css +36 -14
- package/dist/styles/text.css +1 -1
- package/dist/styles/token-search-field.css +4 -4
- package/dist/styles/toolbar-control-group.css +31 -12
- package/dist/styles/toolbar.css +14 -5
- package/dist/styles/value-table.css +19 -2
- package/dist/styles/webawesome.css +3 -1
- package/dist/styles/workbench.css +134 -31
- package/dist/tab-scaffold.d.ts +35 -1
- package/dist/tab-scaffold.js +50 -16
- package/dist/tab-scaffold.js.map +1 -1
- package/dist/token-search-field.d.ts +4 -2
- package/dist/token-search-field.js +1 -1
- package/dist/toolbar-text.js +1 -1
- package/dist/toolbar.d.ts +12 -4
- package/dist/toolbar.js +1 -1
- package/dist/{types-D6vzj-VT.d.ts → types-DXAGogOS.d.ts} +39 -6
- package/dist/value-table.js +1 -1
- package/dist/webawesome.d.ts +7 -1
- package/dist/wire-catalog.d.ts +12 -1
- package/dist/wire-catalog.js +10 -2
- package/dist/wire-catalog.js.map +1 -1
- package/dist/wire-token-search-fields.js +1 -1
- package/dist/workbench.d.ts +59 -22
- package/dist/workbench.js +1 -1
- package/docs/accessibility.md +116 -7
- package/docs/app-layouts.md +9 -7
- package/docs/catalog.md +17 -3
- package/docs/collapsible-panel.md +26 -7
- package/docs/component-contract.md +36 -10
- package/docs/component-selection.md +41 -40
- package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
- package/docs/design/templates/empty-state/with-action.svg +1 -1
- package/docs/design/templates/empty-state-dark.svg +1 -1
- package/docs/design/templates/empty-state.svg +1 -1
- package/docs/design/templates/list/compact-dark.svg +1 -1
- package/docs/design/templates/list/compact.svg +1 -1
- package/docs/design/templates/list/stack-dark.svg +1 -1
- package/docs/design/templates/list/stack.svg +1 -1
- package/docs/design/templates/list-action-row/default-dark.svg +1 -1
- package/docs/design/templates/list-action-row/default.svg +1 -1
- package/docs/design/templates/list-action-row/selected-dark.svg +1 -1
- package/docs/design/templates/list-action-row/selected.svg +1 -1
- package/docs/design/templates/list-action-row-dark.svg +1 -1
- package/docs/design/templates/list-action-row.svg +1 -1
- package/docs/design/templates/list-dark.svg +1 -1
- package/docs/design/templates/list-item/default-dark.svg +1 -1
- package/docs/design/templates/list-item/default.svg +1 -1
- package/docs/design/templates/list-item/selected-dark.svg +1 -1
- package/docs/design/templates/list-item/selected.svg +1 -1
- package/docs/design/templates/list-item/trailing-dark.svg +1 -1
- package/docs/design/templates/list-item/trailing.svg +1 -1
- package/docs/design/templates/list-item-dark.svg +1 -1
- package/docs/design/templates/list-item.svg +1 -1
- package/docs/design/templates/list.svg +1 -1
- package/docs/design/templates/value-table/details-dark.svg +1 -1
- package/docs/design/templates/value-table/details.svg +1 -1
- package/docs/design/templates/value-table-dark.svg +1 -1
- package/docs/design/templates/value-table.svg +1 -1
- package/docs/design-philosophy.md +1 -1
- package/docs/examples/command-palette-adapter.tsx +3 -2
- package/docs/layout.md +69 -29
- package/docs/nav-stack.md +45 -1
- package/docs/recipes.md +4 -3
- package/docs/split-view.md +46 -2
- package/docs/tab-scaffold.md +50 -1
- package/docs/type-contracts.md +17 -17
- package/docs/ux-demo.md +2 -2
- package/docs/webawesome-theme.md +1 -2
- package/docs/workbench.md +45 -9
- package/llms.txt +32 -4
- package/package.json +13 -2
- package/ux-demo/recipes/collapsible-sidebar.tsx +3 -2
- package/ux-demo/recipes/navigation-sidebar.tsx +3 -2
- package/ux-demo/recipes/navigation-stack.tsx +3 -2
- package/dist/chunk-3NBL3OUQ.js.map +0 -1
- package/dist/chunk-4BIMLITI.js.map +0 -1
- package/dist/chunk-5I22LMCV.js.map +0 -1
- package/dist/chunk-5NDQABWK.js.map +0 -1
- package/dist/chunk-5OLVUEND.js.map +0 -1
- package/dist/chunk-7GUQYHKA.js.map +0 -1
- package/dist/chunk-D7GWXIAS.js.map +0 -1
- package/dist/chunk-DQA5FMOX.js +0 -85
- package/dist/chunk-DQA5FMOX.js.map +0 -1
- package/dist/chunk-EAX2GSS4.js.map +0 -1
- package/dist/chunk-HMQ2ZDGG.js.map +0 -1
- package/dist/chunk-MTM43SJO.js.map +0 -1
- package/dist/chunk-N7FHFNT6.js.map +0 -1
- package/dist/chunk-R754MHXX.js.map +0 -1
- package/dist/chunk-RNRUVPJ3.js.map +0 -1
- package/dist/chunk-T22EM4ET.js.map +0 -1
- package/dist/chunk-WZ2GLEY4.js.map +0 -1
- package/dist/chunk-XD7DWYXG.js +0 -34
- package/dist/chunk-XD7DWYXG.js.map +0 -1
package/docs/layout.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Import `Pane` from `@kerfjs/ui/pane`. Browser-aware bundlers receive its CSS
|
|
4
4
|
automatically; other consumers can import `@kerfjs/ui/pane.css`. Import
|
|
5
|
-
`@kerfjs/ui/layout.css` as well when using the
|
|
6
|
-
layout classes
|
|
5
|
+
`@kerfjs/ui/layout.css` as well when using the `.kui-content` stack and control
|
|
6
|
+
layout classes; place `ContentItem` children from `@kerfjs/ui/content-item`. The vocabulary deliberately describes structure rather than
|
|
7
7
|
location: the same pane can be placed anywhere.
|
|
8
8
|
|
|
9
9
|
## Anatomy
|
|
@@ -29,10 +29,17 @@ top toolbar followed by secondary toolbar or status rows. A main area or dialog
|
|
|
29
29
|
often omits the footer; a navigation pane commonly uses all three. Fixed chrome
|
|
30
30
|
stays outside `.kui-pane__content`, which is the pane's only scroll owner.
|
|
31
31
|
|
|
32
|
+
Tall fixed chrome can leave a short pane no room for its content (a small
|
|
33
|
+
window, or text at 200%). `chromePlacement="auto"` keeps the header and footer
|
|
34
|
+
pinned while the pane is at least 480px (30rem, so it scales with the text
|
|
35
|
+
size) tall, and below that lets the whole pane scroll as one column, header,
|
|
36
|
+
content, and footer together, so the content keeps its natural height. The
|
|
37
|
+
default `fixed` always pins them.
|
|
38
|
+
|
|
32
39
|
Pass any combination of logical sides to `separators`: `block-start`,
|
|
33
40
|
`block-end`, `inline-start`, and `inline-end`. Every line is off by default and
|
|
34
41
|
each enabled side uses `--kui-pane-separator-width` (1px) and
|
|
35
|
-
`--kui-pane-separator-color` (`--kui-color-border`). Logical sides keep pane
|
|
42
|
+
`--kui-pane-separator-color` (`--kui-color-neutral-border-normal`). Logical sides keep pane
|
|
36
43
|
boundaries correct in both left-to-right and right-to-left layouts.
|
|
37
44
|
|
|
38
45
|
A pane is safe-area aware. Its background and separators paint through a
|
|
@@ -45,18 +52,8 @@ same logical sides as `separators`; all four by default, `[]` to opt out). See
|
|
|
45
52
|
|
|
46
53
|
`.kui-content` is a vertical stack with a 24px gap between major children.
|
|
47
54
|
Sections may contain adjacent `ListItem` rows without adding another major gap.
|
|
48
|
-
Ordinary surface-like children
|
|
49
|
-
geometry
|
|
50
|
-
|
|
51
|
-
- 8px inline margin from the pane edge
|
|
52
|
-
- 1px border, transparent by default
|
|
53
|
-
- 8px internal padding and 8px internal gap
|
|
54
|
-
- `calc(1px + remify(11px))`, or 12px, rounded corners
|
|
55
|
-
|
|
56
|
-
Use `.kui-content-item--pill` for the 22px pill radius expressed as
|
|
57
|
-
`calc(1px + remify(21px))`. Consumers can make a content item visible without
|
|
58
|
-
changing its geometry by setting `--kui-content-item-border` and
|
|
59
|
-
`--kui-content-item-background`.
|
|
55
|
+
Ordinary surface-like children are `ContentItem`s and own their complete
|
|
56
|
+
geometry (see [Content items](#content-items)).
|
|
60
57
|
|
|
61
58
|
Nested selection and hover highlights stay concentric and match their owning
|
|
62
59
|
control's shape. Their inner radius is the outer radius minus the full inset,
|
|
@@ -72,20 +69,63 @@ inline gutter instead of nesting them inside another padded content item. A
|
|
|
72
69
|
conditional `StateBanner` remains visibly distinct because it communicates
|
|
73
70
|
semantic status.
|
|
74
71
|
|
|
72
|
+
## Content items
|
|
73
|
+
|
|
74
|
+
Render an ordinary surface-like `.kui-content` child with `ContentItem` from
|
|
75
|
+
`@kerfjs/ui/content-item` (browser-aware bundlers receive its CSS automatically;
|
|
76
|
+
`@kerfjs/ui/layout.css` and `@kerfjs/ui/content-item.css` both deliver it). It
|
|
77
|
+
owns its complete geometry:
|
|
78
|
+
|
|
79
|
+
- 8px inline margin from the pane edge
|
|
80
|
+
- 1px border, transparent by default
|
|
81
|
+
- 8px internal padding
|
|
82
|
+
- `calc(1px + remify(11px))`, or 12px, rounded corners
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
import { ContentItem } from "@kerfjs/ui/content-item";
|
|
86
|
+
|
|
87
|
+
<Pane label="Inspector">
|
|
88
|
+
<ContentItem>{details}</ContentItem>
|
|
89
|
+
<ContentItem frame="framed">{pendingChanges}</ContentItem>
|
|
90
|
+
<ContentItem shape="pill">{summary}</ContentItem>
|
|
91
|
+
</Pane>;
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`frame="framed"` paints the standard neutral border in the 1px the item always
|
|
95
|
+
reserves, so framed and unframed items share the same geometry. Frame an item
|
|
96
|
+
only when it marks a real distinction and must read as visibly bounded; do not
|
|
97
|
+
frame it to make it "look contained". `shape="pill"` selects the 22px pill
|
|
98
|
+
radius expressed as `calc(1px + remify(21px))`. There is deliberately no filled
|
|
99
|
+
variant: a lowered, filled surface is `SunkenPanel`, and bare text that only
|
|
100
|
+
needs to align with neighboring items is `ListInsetText`. Safe `data-*`
|
|
101
|
+
metadata goes in `rootAttributes`. Pass `ariaLabel` only for a distinct named
|
|
102
|
+
region (`role="region"`), and `focusTarget` to make the item a programmatic
|
|
103
|
+
focus target (`tabindex="-1"`), for example a NavStack view's `data-nav-focus`
|
|
104
|
+
target.
|
|
105
|
+
|
|
106
|
+
The rendered classes — `.kui-content-item`, `.kui-content-item--framed`, and
|
|
107
|
+
`.kui-content-item--pill` — stay public for the rare element that must carry the
|
|
108
|
+
geometry itself (for example a `<ul>` list or a `Text` paragraph in an
|
|
109
|
+
application-owned adapter). Prefer `ContentItem` everywhere else so the framing
|
|
110
|
+
choice is typed. `npm run check:guidance` rejects a plain
|
|
111
|
+
`<div class="kui-content-item">` in the package's examples, browser fixtures,
|
|
112
|
+
and UX catalog, since that div is exactly what `ContentItem` renders.
|
|
113
|
+
|
|
75
114
|
## Public roles and tokens
|
|
76
115
|
|
|
77
|
-
| Need | Class
|
|
78
|
-
| ---------------------------------------- |
|
|
79
|
-
| Unpadded header/content/footer structure | `Pane`, `.kui-pane`
|
|
80
|
-
| Scrolling pane content | `.kui-pane__content`
|
|
81
|
-
| Optional logical-edge separators | `Pane.separators`
|
|
82
|
-
| Safe-area sides a pane may pad | `Pane.safeAreaEdges`
|
|
83
|
-
| Major vertical rhythm | `.kui-content`
|
|
84
|
-
| Self-contained child geometry |
|
|
85
|
-
| Pill child |
|
|
86
|
-
|
|
|
87
|
-
|
|
|
88
|
-
|
|
|
116
|
+
| Need | Class | Token / default |
|
|
117
|
+
| ---------------------------------------- | ---------------------------- | ------------------------------------------------------------------ |
|
|
118
|
+
| Unpadded header/content/footer structure | `Pane`, `.kui-pane` | — |
|
|
119
|
+
| Scrolling pane content | `.kui-pane__content` | — |
|
|
120
|
+
| Optional logical-edge separators | `Pane.separators` | `--kui-pane-separator-width: 1px` |
|
|
121
|
+
| Safe-area sides a pane may pad | `Pane.safeAreaEdges` | `--kui-safe-area-*: env(safe-area-inset-*)`, routed by each layout |
|
|
122
|
+
| Major vertical rhythm | `.kui-content` | `--kui-layout-content-gap: 24px` |
|
|
123
|
+
| Self-contained child geometry | `ContentItem` | 8px margin + 1px border + 8px padding |
|
|
124
|
+
| Pill child | `ContentItem shape="pill"` | `--kui-layout-pill-radius: 22px` |
|
|
125
|
+
| Visibly framed child | `ContentItem frame="framed"` | neutral 1px border, same geometry |
|
|
126
|
+
| Related controls | `.kui-control-cluster` | `--kui-layout-control-gap: 8px` |
|
|
127
|
+
| Inline metadata | `.kui-inline-metadata` | `--kui-layout-metadata-gap: 4px` |
|
|
128
|
+
| Explicit scroll owner outside a pane | `.kui-scroll-owner` | `overflow: auto` |
|
|
89
129
|
|
|
90
130
|
The component layer applies the same contract to `Toolbar`, `ListHeader`,
|
|
91
131
|
`ListItem`, `Toolbar`, `StateBanner`, `ValueTable`,
|
|
@@ -307,8 +347,8 @@ selected sides; the control wrapper applies its 8px outer margin only on
|
|
|
307
347
|
selected sides. Every direct child of `ListInsetControl` grows to fill the row
|
|
308
348
|
(a `Select`, a `wa-input`, or a `wa-button` spans the full inset width), and
|
|
309
349
|
several children share the row with an 8px gap; stack controls vertically with
|
|
310
|
-
a `List` using `controlInsets` instead. `
|
|
311
|
-
|
|
350
|
+
a `List` using `controlInsets` instead. Pass `sides="rl"` for tight text that
|
|
351
|
+
keeps the horizontal inset without adding vertical box space.
|
|
312
352
|
|
|
313
353
|
`--kui-space-s` (12px) and `--kui-space-xl` (32px) exist but are **off the
|
|
314
354
|
canonical rhythm** — reach for them only as a deliberate exception, never as a
|
package/docs/nav-stack.md
CHANGED
|
@@ -49,11 +49,55 @@ views.value = [
|
|
|
49
49
|
`NavStack` renders every entry stacked, the last one active and the rest kept
|
|
50
50
|
mounted (so their DOM state survives) but hidden. Each entry carries a
|
|
51
51
|
`key` (stable identity), `content`, an optional `title`, optional per-view
|
|
52
|
-
`toolbar`
|
|
52
|
+
`leading`, `center`, and trailing `toolbar` groups for the top toolbar, and an
|
|
53
|
+
optional per-view `bottomToolbar`. The component-level
|
|
53
54
|
`bottomToolbar` remains a persistent fallback for views that do not provide one.
|
|
54
55
|
The back control appears automatically once the stack has more than one entry;
|
|
55
56
|
`wireNavStack`'s `onBack` is where the app pops its own signal.
|
|
56
57
|
|
|
58
|
+
## The top toolbar
|
|
59
|
+
|
|
60
|
+
The top chrome is a real `Toolbar`, so it follows the same zone,
|
|
61
|
+
group, and responsive rules as every other toolbar. Its leading zone holds the
|
|
62
|
+
back control (a borderless `ToolbarControlGroup`, shown once the stack has
|
|
63
|
+
depth), then the active view's `leading` groups, then the view's `title` as a
|
|
64
|
+
`ToolbarText`. The view's `center` fills the center zone and its `toolbar`
|
|
65
|
+
fills the trailing zone. Give each zone `ToolbarControlGroup`s or `ToolbarText`,
|
|
66
|
+
as in any toolbar.
|
|
67
|
+
|
|
68
|
+
Configure the toolbar with `toolbarConfig` instead of styling it:
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
<NavStack
|
|
72
|
+
id="mail"
|
|
73
|
+
label="Mail"
|
|
74
|
+
views={views.value}
|
|
75
|
+
backText={previousTitle}
|
|
76
|
+
toolbarConfig={{
|
|
77
|
+
headingLevel: 1,
|
|
78
|
+
titleSize: "xlarge",
|
|
79
|
+
dividerSides: "b",
|
|
80
|
+
responsive: "wrap",
|
|
81
|
+
}}
|
|
82
|
+
/>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- `toolbarConfig` forwards the `Toolbar` configuration (`dividerSides`,
|
|
86
|
+
`centerAlign`, `responsive`, `responsiveAt`, `safeAreaEdges`) and adds
|
|
87
|
+
`label` (the toolbar's accessible name), `titleSize` (the title's
|
|
88
|
+
`ToolbarText` size, default `large`), and `headingLevel` (expose the title as
|
|
89
|
+
a heading; default a plain span). The defaults keep the stack's own chrome:
|
|
90
|
+
no divider, one 44px control band, and the top and side safe-area edges
|
|
91
|
+
claimed.
|
|
92
|
+
- `backIcon` replaces the default chevron-left icon. `backText` adds visible
|
|
93
|
+
text beside it (for example, the previous view's title); visible text names
|
|
94
|
+
the control, so `backLabel` applies only to the icon-only control.
|
|
95
|
+
|
|
96
|
+
The catalog's **Configured toolbar** example shows these together: a level-2
|
|
97
|
+
heading title over a bottom divider, leading and center groups on the root
|
|
98
|
+
view, a trailing group on the pushed view, and `backText` set to the previous
|
|
99
|
+
view's title.
|
|
100
|
+
|
|
57
101
|
Focus follows the controlled stack automatically. On push, `wireNavStack`
|
|
58
102
|
remembers the focused descendant of the departing view and moves focus into the
|
|
59
103
|
new top view. On pop it restores that exact descendant when it still exists. A
|
package/docs/recipes.md
CHANGED
|
@@ -57,8 +57,8 @@ component variables.
|
|
|
57
57
|
[Open the recipe](../ux-demo/?component=recipe-navigation-sidebar) · [TSX source](../ux-demo/recipes/navigation-sidebar.tsx)
|
|
58
58
|
|
|
59
59
|
One unpadded `.kui-pane` owns toolbar/content/footer structure. Its
|
|
60
|
-
`.kui-content` uses 24px major gaps; `ListHeader`, `ListItem`, and
|
|
61
|
-
|
|
60
|
+
`.kui-content` uses 24px major gaps; `ListHeader`, `ListItem`, and
|
|
61
|
+
`ContentItem` children own their 8px margin, 1px border, and 8px padding.
|
|
62
62
|
Rows and footer toolbar groups remain 44px tall. The app owns routes,
|
|
63
63
|
permissions, labels, selection, valid section counts and their localized
|
|
64
64
|
`countLabel` phrases, non-count badge content, disclosure state, and revealed
|
|
@@ -205,7 +205,8 @@ Chromium, Firefox, and WebKit by `tests/browser/collapsible-sidebar-recipe.spec.
|
|
|
205
205
|
`@kerfjs/ui/webawesome.css`.
|
|
206
206
|
- Compose, don't style. A recipe ships no stylesheet, sets no inline style, and
|
|
207
207
|
names no class outside the published layout vocabulary (`.kui-content`,
|
|
208
|
-
`.kui-
|
|
208
|
+
`.kui-control-cluster`, …) and themed Web Awesome classes — a content item is
|
|
209
|
+
a `ContentItem`, not a hand-written `.kui-content-item`; it configures
|
|
209
210
|
components through props, `rootAttributes`, and tokens. When a recipe needs a
|
|
210
211
|
capability no component offers, record it as a component gap rather than
|
|
211
212
|
papering over it with CSS. `npm run check:recipes` enforces these rules on
|
package/docs/split-view.md
CHANGED
|
@@ -53,11 +53,55 @@ const selected = signal<string | null>(null);
|
|
|
53
53
|
app's selection). This is the portrait-tablet / handset presentation; as a
|
|
54
54
|
dialog the compact form is a full-screen or large partial-cover modal.
|
|
55
55
|
|
|
56
|
+
## Configuring the list region and the compact stack
|
|
57
|
+
|
|
58
|
+
`resizable` forwards the list's `ResizableRegion` configuration alongside
|
|
59
|
+
`size`, `min`, and `max`: `separator` (`"hidden"` keeps the resize hit target
|
|
60
|
+
but paints no line), `handleIcon`, `contentOverflow`, and collapse —
|
|
61
|
+
`collapsed`, `transitioning`, `collapseMotion`, `restoreControl`, and
|
|
62
|
+
`restorePosition`. A collapsed list snaps to zero width, renders `inert` and
|
|
63
|
+
`aria-hidden`, and the detail fills the split; the app owns the `collapsed`
|
|
64
|
+
flag and renders the restore control (usually a `FloatingToolbar`). Omitted
|
|
65
|
+
options keep the region's defaults.
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
resizable={{
|
|
69
|
+
size: listWidth.value,
|
|
70
|
+
min: 220,
|
|
71
|
+
max: 480,
|
|
72
|
+
collapsed: listCollapsed.value,
|
|
73
|
+
restoreControl: <ShowThreadsToolbar />,
|
|
74
|
+
}}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`compactStack` configures the compact `NavStack`: `toolbarConfig`, `backIcon`,
|
|
78
|
+
`backText`, `hideToolbar`, and the persistent `bottomToolbar` forward to the
|
|
79
|
+
stack, and `list` / `detail` give each view its own top-toolbar groups
|
|
80
|
+
(`leading`, `center`, trailing `toolbar`) and `bottomToolbar`:
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
compactStack={{
|
|
84
|
+
backText: "Threads",
|
|
85
|
+
toolbarConfig: { headingLevel: 1 },
|
|
86
|
+
list: { toolbar: <ComposeGroup /> },
|
|
87
|
+
detail: { toolbar: <ReplyGroup />, bottomToolbar: <MessageActions /> },
|
|
88
|
+
}}
|
|
89
|
+
```
|
|
90
|
+
|
|
56
91
|
The catalog's **Interactive compact drill-down** example exercises this exact
|
|
57
92
|
controlled flow: a list action sets the selected message, `detailActive` pushes
|
|
58
93
|
its detail, and the wired Back action clears the selection to reveal the
|
|
59
|
-
preserved list.
|
|
60
|
-
|
|
94
|
+
preserved list. It also forwards `compactStack`: a level-2 heading title over
|
|
95
|
+
a bottom divider, a Compose group on the list view, and a Reply group plus a
|
|
96
|
+
bottom toolbar on the detail. Use the same structure in application demos so
|
|
97
|
+
compact examples show the interaction rather than rendering a disconnected
|
|
98
|
+
detail state.
|
|
99
|
+
|
|
100
|
+
The catalog's **Resizable, collapsible list** example forwards `resizable`: a
|
|
101
|
+
hidden separator that still resizes the list (its committed width comes back
|
|
102
|
+
through `wireResizableRegions`' `onCommit` into the app's size signal), a Hide
|
|
103
|
+
control in the list's own toolbar, and a `FloatingToolbar` restore control in
|
|
104
|
+
the split's bottom-start corner.
|
|
61
105
|
|
|
62
106
|
Compose the interactive wiring from the existing helpers — `SplitView` adds no
|
|
63
107
|
wire of its own.
|
package/docs/tab-scaffold.md
CHANGED
|
@@ -44,7 +44,8 @@ const dispose = wireTabScaffold(root, {
|
|
|
44
44
|
});
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
Each `TabScaffoldTab` has an `id`, `label`, optional `icon`,
|
|
47
|
+
Each `TabScaffoldTab` has an `id`, `label`, optional `icon`, optional `badge`
|
|
48
|
+
and `badgeLabel` (see [Tab badges](#tab-badges)), and `content`. The
|
|
48
49
|
bottom bar paints through the home-indicator safe area and pads for it and for
|
|
49
50
|
the side insets, while each scene pads for the top and side insets (a scene
|
|
50
51
|
whose only child is a `NavStack` or `Pane` lets that child own them; see
|
|
@@ -52,3 +53,51 @@ whose only child is a `NavStack` or `Pane` lets that child own them; see
|
|
|
52
53
|
truncate horizontally with an ellipsis when a destination name exceeds its
|
|
53
54
|
share of the bar. On larger device classes, promote the tab set to a
|
|
54
55
|
`Workbench` rail or a persistent sidebar instead of a bottom bar.
|
|
56
|
+
|
|
57
|
+
## Tab badges
|
|
58
|
+
|
|
59
|
+
Give a tab a `badge` (a count or short string such as `3`, `"99+"`, or
|
|
60
|
+
`"New"`) to show the iOS tab-bar badge: a compact, solid `danger` `Badge` at the
|
|
61
|
+
top-trailing corner of the tab's icon, growing outward as the text lengthens
|
|
62
|
+
(without an icon it sits above the label). The badge is decorative
|
|
63
|
+
(`aria-hidden`); its meaning reaches assistive technology through `badgeLabel`,
|
|
64
|
+
which the tab folds into its accessible name as `"<label>, <badgeLabel>"`:
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
{
|
|
68
|
+
id: "inbox",
|
|
69
|
+
label: "Inbox",
|
|
70
|
+
icon: <LucideIcon icon={Inbox} name="inbox" />,
|
|
71
|
+
badge: unread.value,
|
|
72
|
+
badgeLabel: `${unread.value} unread`,
|
|
73
|
+
content: <InboxStack />,
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`badgeLabel` defaults to the badge text itself, so supply a localized phrase
|
|
78
|
+
whenever the bare text would be ambiguous. Omitting `badge` (or passing an
|
|
79
|
+
empty string or a non-finite number) renders no badge and leaves the tab's name
|
|
80
|
+
as its label; `0` renders, so pass `undefined` when a count should disappear.
|
|
81
|
+
Keep the text short — clamp large counts (`"99+"`) in the app. The tone follows
|
|
82
|
+
the platform convention and is fixed; do not restyle the badge.
|
|
83
|
+
|
|
84
|
+
### Dot badges
|
|
85
|
+
|
|
86
|
+
For new content without a count, pass `badge: true`. The tab shows the iOS
|
|
87
|
+
tab-bar dot — an 8px solid `danger` `Badge` (`size="dot"`) centered on the
|
|
88
|
+
icon's top-trailing corner (above the label without an icon). A dot has no
|
|
89
|
+
text to fall back on, so `badgeLabel` is required by the types:
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
{
|
|
93
|
+
id: "feed",
|
|
94
|
+
label: "Feed",
|
|
95
|
+
icon: <LucideIcon icon={Rss} name="rss" />,
|
|
96
|
+
badge: hasNewPosts.value ? true : undefined,
|
|
97
|
+
badgeLabel: "New activity",
|
|
98
|
+
content: <FeedStack />,
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
The tab's accessible name becomes `"Feed, New activity"`. Pass `undefined` to
|
|
103
|
+
clear the dot; `false` is not a badge value.
|
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 `CssForegroundColor` (foreground tokens via `uiColor()` or `foregroundColorVar()`; fill
|
|
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 tokens such as `uiColor('success-fill-quiet')` 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`:
|
|
@@ -123,7 +123,7 @@ move errors into casts without making the integration safer.
|
|
|
123
123
|
keyword; replace raw Skeleton dimensions with `px`/`rem`/`em`/`pct` builders;
|
|
124
124
|
and replace raw choice colors with a foreground token such as
|
|
125
125
|
`uiColor('success-on-quiet')` or an app-owned `foregroundColorVar()`.
|
|
126
|
-
`SelectChoice.color` rejects fill
|
|
126
|
+
`SelectChoice.color` rejects fill tokens (`uiColor('success-fill-quiet')`) and
|
|
127
127
|
unqualified `colorVar()` values because a fill paints a nearly invisible
|
|
128
128
|
icon.
|
|
129
129
|
- Remove `style` from `ListItem` and `ListActionRow`; use `className`, public
|
package/docs/ux-demo.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# UX catalog contract
|
|
2
2
|
|
|
3
|
-
Run `npm run dev` from `ui/`. The catalog is a development and review surface, not a second implementation. The development server allows repo-owned assets used by the catalog, and its production bundle uses relative asset URLs so the complete catalog remains intact below preview and proxy paths.
|
|
3
|
+
Run `npm run dev` from `ui/`. The catalog is a development and review surface, not a second implementation. The development server reloads component source edits without a restart: component entries still load through their `dist/browser` wrappers, so each component's reachable CSS is exercised as consumers receive it, but the JavaScript those wrappers re-export (and every other `@kerfjs/ui` subpath) resolves to `src/`, and CSS resolves to `src/` as well. A component that gains a new CSS dependency needs a restart, because the wrapper listing its stylesheets is regenerated only by the build. Production demo builds, previews, and the browser tests use `dist/`. The development server allows repo-owned assets used by the catalog, and its production bundle uses relative asset URLs so the complete catalog remains intact below preview and proxy paths.
|
|
4
4
|
|
|
5
5
|
Every Playwright entry point builds current source before the preview server
|
|
6
6
|
starts. `npm run test:e2e -- tests/browser/row.spec.ts` and a direct focused
|
|
@@ -51,6 +51,6 @@ deterministic state, and semantic layout owners from the [recipe guide](./recipe
|
|
|
51
51
|
- The footer action log is an `aria-live` region, making interactions visible to both people and browser tests.
|
|
52
52
|
- 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.
|
|
53
53
|
- Browser coverage walks every Kerf, composition, and Web Awesome route, checks every listed Web Awesome custom element is registered in its focused specimen, exercises the ecosystem disclosure and both relationship directions, validates offline source/guidance hrefs and accessible wide/narrow/200%-zoom wrapping, and covers tab selection/reordering/overflow, semantic palettes and scoped overrides, light/dark rendering, toolbar popup and responsive find behavior, single/multiline search alignment, menu alignment, banner urgency, keyboard resizing, live custom-element values, and representative wide/narrow captures.
|
|
54
|
-
- The production build keeps the catalog shell and Kerf routes in the entry chunk, then dynamically imports the complete Web Awesome specimen and registration surface when an ecosystem route or the ToolbarControlGroup popup specimen is selected. Directly addressed routes pass through the same loader.
|
|
54
|
+
- The production build keeps the catalog shell and Kerf routes in the entry chunk and moves the third-party code loaded at startup (the Web Awesome select and popup-menu registrations with their Lit and Floating UI runtime) into an eagerly preloaded `vendor` chunk, so neither nears the largest-chunk limit in `demo-bundle-budget.json`; only modules statically reachable from the entry qualify, so lazy-only dependencies stay in their lazy chunks. It then dynamically imports the complete Web Awesome specimen and registration surface when an ecosystem route or the ToolbarControlGroup popup specimen is selected. Directly addressed routes pass through the same loader.
|
|
55
55
|
|
|
56
56
|
Before handoff, inspect the actual captures for readability, context, alignment, clipping, spacing, responsiveness, focus, and obvious defects. Fix and recapture rather than treating the screenshot as proof by itself.
|
package/docs/webawesome-theme.md
CHANGED
|
@@ -176,8 +176,7 @@ their open state uses the independent `rotate` property.
|
|
|
176
176
|
|
|
177
177
|
That scale applies to each Web Awesome component's intrinsic glyph and is
|
|
178
178
|
independent of Kerf `DisclosureArrow`, whose default box is 18px relative to
|
|
179
|
-
the root font size and whose consumer override is
|
|
180
|
-
`--kui-disclosure-arrow-size`.
|
|
179
|
+
the root font size and whose consumer override is its typed `size` prop.
|
|
181
180
|
|
|
182
181
|
Tooltip and Popover use arrowless floating surfaces by default, matching Hot
|
|
183
182
|
Sheet 2. The theme sets Web Awesome's public `--wa-tooltip-arrow-size` token to
|
package/docs/workbench.md
CHANGED
|
@@ -107,7 +107,13 @@ an optional `label`. Common shell behavior is configured rather than restyled:
|
|
|
107
107
|
defaults to two less than the overlay z-index (39), so they sit beneath
|
|
108
108
|
every overlay: an open overlay covers another panel's restore control as
|
|
109
109
|
it covers the rest of the work area, and a collapsed overlay, which drops
|
|
110
|
-
its pointer events, leaves the control beneath it usable
|
|
110
|
+
its pointer events, leaves the control beneath it usable. While a rail
|
|
111
|
+
overlay is open (static, or a responsive one whose breakpoint applies), the
|
|
112
|
+
work area's floating controls — restore corners and any `FloatingToolbar`
|
|
113
|
+
in `main` — are also hidden outright (out of the tab order and the
|
|
114
|
+
accessibility tree), so they can never paint over the rail whatever
|
|
115
|
+
stacking context the app gives the work area; they return as it closes.
|
|
116
|
+
The rail's own floating controls stay, and a drawer overlay hides nothing;
|
|
111
117
|
- `restoreControl` places an application-owned restore affordance in a
|
|
112
118
|
corner of the Workbench itself while the panel is collapsed. Prefer a
|
|
113
119
|
`toolbar.toggle`, which the Workbench relocates for you; keep
|
|
@@ -130,8 +136,8 @@ an optional `label`. Common shell behavior is configured rather than restyled:
|
|
|
130
136
|
carrying `collapsiblePanelToggleIcon(side, true)` — rather than a bare
|
|
131
137
|
button. To give it `FloatingToolbar`'s toolbar role and floating look, wrap
|
|
132
138
|
that group in a `FloatingToolbar` whose `position` matches the corner: the
|
|
133
|
-
corner owns the inset (it
|
|
134
|
-
toolbar floats from the corner instead of doubling it.
|
|
139
|
+
corner owns the inset (it zeroes the toolbar's default inset), so omit
|
|
140
|
+
`inset` there and the toolbar floats from the corner instead of doubling it.
|
|
135
141
|
|
|
136
142
|
- `resizable: true | { min, max }` opts the panel in to drag and keyboard
|
|
137
143
|
resizing, driven by `wireWorkbench` (off by default).
|
|
@@ -154,10 +160,12 @@ and close. A panel's `toolbar` has four parts:
|
|
|
154
160
|
- `constant` — groups that stay available either way. They trail the panel's
|
|
155
161
|
toolbar while it is open and move to the work area's toolbar while it is
|
|
156
162
|
closed.
|
|
157
|
-
- `toggle: { action, name }` — the standard collapse
|
|
158
|
-
Workbench renders: the per-side panel glyph,
|
|
159
|
-
panel, `aria-expanded`, a "Show …"/"Hide …"
|
|
163
|
+
- `toggle: { action, name, showLabel?, hideLabel? }` — the standard collapse
|
|
164
|
+
toggle, which the Workbench renders: the per-side panel glyph,
|
|
165
|
+
`aria-controls` naming the panel, `aria-expanded`, a "Show …"/"Hide …"
|
|
166
|
+
label (or your localized `showLabel` / `hideLabel`), and the `data-action`
|
|
160
167
|
the app handles. It is always the last group.
|
|
168
|
+
- `center` — optional panel-only center content.
|
|
161
169
|
|
|
162
170
|
While a panel is closed, its `constant` groups and then its toggle go to:
|
|
163
171
|
|
|
@@ -198,9 +206,37 @@ The work area's `Pane` can carry more fixed chrome: `mainHeader` renders under
|
|
|
198
206
|
line or a resource toolbar), each divided from the scrolling `main`.
|
|
199
207
|
`mainHeaderPlacement` and `mainFooterPlacement` (`"fixed"` by default, or
|
|
200
208
|
`"scroll"`) let that header or footer chrome scroll away with `main` instead —
|
|
201
|
-
useful where large text would leave pinned chrome little room. `
|
|
202
|
-
|
|
203
|
-
|
|
209
|
+
useful where large text would leave pinned chrome little room. `"auto"` keeps
|
|
210
|
+
it pinned while the work area is tall enough and lets it scroll with `main`
|
|
211
|
+
when the work area is short (the Pane's `chromePlacement="auto"`; it applies to
|
|
212
|
+
the pinned header and footer together).
|
|
213
|
+
|
|
214
|
+
Every toolbar the Workbench composes — `mainToolbar`, `mainBottomToolbar`, and
|
|
215
|
+
each panel's `toolbar` — takes the `Toolbar`'s configuration (`ToolbarConfig`):
|
|
216
|
+
`dividerSides`, `centerAlign`, `responsive`, `responsiveAt`, and
|
|
217
|
+
`safeAreaEdges`. Configure the toolbar through these props rather than styling
|
|
218
|
+
it. By default a panel toolbar keeps its bottom divider, and the work area draws
|
|
219
|
+
one divider under its header chrome and one over its footer chrome, wherever
|
|
220
|
+
that chrome ends; set `dividerSides: ""` to drop a toolbar's divider, for
|
|
221
|
+
example. `responsive: "wrap"` keeps a long title whole and wraps its actions
|
|
222
|
+
below it. `mainBottomToolbar` also takes a `center`. A panel's
|
|
223
|
+
`restorePosition` also places its floating restore controls.
|
|
224
|
+
|
|
225
|
+
The `Pane`s and `List`s the Workbench composes around your content are
|
|
226
|
+
configurable the same way:
|
|
227
|
+
|
|
228
|
+
- `mainPane` (`PaneConfig`: `contentElement`, `contentLabel`, `separators`,
|
|
229
|
+
`safeAreaEdges`) configures the work area's `Pane`, which exists whenever the
|
|
230
|
+
work area has a toolbar, `mainHeader`, or `mainFooter`;
|
|
231
|
+
- a panel's `pane` configures the `Pane` a `toolbar` panel's `content` renders
|
|
232
|
+
in — for example `{ contentElement: "nav", contentLabel: "Files" }` for a
|
|
233
|
+
navigator rail;
|
|
234
|
+
- `mainHeaderList` / `mainFooterList` (`ListConfig`: `gap`, `hAlign`,
|
|
235
|
+
`vAlign`, `dividerSides`, `textInsets`, `controlInsets`) configure the
|
|
236
|
+
`List`s holding `mainHeader` / `mainFooter`.
|
|
237
|
+
|
|
238
|
+
An omitted or `undefined` field keeps today's default, including the header
|
|
239
|
+
and footer dividers described above.
|
|
204
240
|
|
|
205
241
|
Size a rail so its title and groups fit at its narrowest (a resizable rail's
|
|
206
242
|
`min`); a toolbar that cannot hold them drops the title rather than
|
package/llms.txt
CHANGED
|
@@ -102,11 +102,16 @@ the folder modules, and CSS only imports their owner stylesheets.
|
|
|
102
102
|
without an application customization layer. Before adding `padding`, `margin`,
|
|
103
103
|
`width`, `height`, `border`, `background`, a wrapper card, or a decoration,
|
|
104
104
|
check whether the component, pane, or content-item already owns it. Prefer a
|
|
105
|
-
component prop
|
|
105
|
+
component prop — `FloatingToolbar inset`, `DisclosureArrow size`, `ListHeader
|
|
106
|
+
headingLevel`, `TokenSearchField clearIcon`, `ContentItem frame="framed"` for a
|
|
107
|
+
visibly bounded content item — over overriding its `--kui-*` token. CSS for genuinely new structure
|
|
106
108
|
belongs to the application-owned component that renders it and must not select
|
|
107
109
|
nested Kerf or Web Awesome components.
|
|
108
110
|
- **Never double-inset.** A `.kui-pane` has no padding; its `.kui-content` children
|
|
109
|
-
own the geometry (8px inline margin + 1px border + 8px padding).
|
|
111
|
+
own the geometry (8px inline margin + 1px border + 8px padding). Render an
|
|
112
|
+
ordinary surface-like child as `ContentItem` (`@kerfjs/ui/content-item`) with
|
|
113
|
+
typed `frame` (`none`/`framed`) and `shape` (`rounded`/`pill`) props instead
|
|
114
|
+
of hand-writing `<div class="kui-content-item">`. Do not add a
|
|
110
115
|
container padding on top of a content-item's own margin — pick one owner. Use
|
|
111
116
|
`.kui-content` for 24px major vertical rhythm.
|
|
112
117
|
- **Opt into document globals explicitly.** Import `@kerfjs/ui/document.css`
|
|
@@ -129,7 +134,7 @@ the folder modules, and CSS only imports their owner stylesheets.
|
|
|
129
134
|
`@kerfjs/ui/css-values` builders; raw CSS strings are rejected. Use `flex()`
|
|
130
135
|
for List flex, typed lengths for Skeleton geometry, and
|
|
131
136
|
foreground colors for choice icons: `uiColor()` with an `*-on-*`/text token
|
|
132
|
-
or `foregroundColorVar()`; fill
|
|
137
|
+
or `foregroundColorVar()`; fill tokens such as `uiColor('success-fill-quiet')` do not
|
|
133
138
|
type-check. These brands are intentionally
|
|
134
139
|
not interchangeable; rows use classes/tokens/props rather than raw `style`.
|
|
135
140
|
- **Use `Grid` for a fixed positive count of equal-width columns.** It uses
|
|
@@ -170,7 +175,21 @@ the folder modules, and CSS only imports their owner stylesheets.
|
|
|
170
175
|
label uses the same uppercase xs/650 treatment and its label and hint share
|
|
171
176
|
that 9px alignment.
|
|
172
177
|
- `Select` requires a visible `label` or an `ariaLabel` for a visually hidden
|
|
173
|
-
accessible name.
|
|
178
|
+
accessible name. Set `multiple` with an array `value` for any number of
|
|
179
|
+
choices: the popup stays open while choices toggle and closes on an outside
|
|
180
|
+
press or Escape, and the closed control summarizes the chosen labels. A
|
|
181
|
+
toolbar filter menu adds `selectedPresentation="icon-only"` and a fixed
|
|
182
|
+
`triggerIcon`: the trigger shows that icon plus a count badge while any
|
|
183
|
+
choice is chosen, and its accessible name ends with the chosen labels.
|
|
184
|
+
Icon-only Selects (single or multiple) and icon-only `PopupMenu`s show an
|
|
185
|
+
`aria-hidden` Web Awesome help tag repeating that name (and a Select's
|
|
186
|
+
choice) on hover and keyboard focus, hidden while the popup is open; the
|
|
187
|
+
register import installs it, so do not add a `title` or tooltip of your own.
|
|
188
|
+
The same installer tags an icon-only `<button>` or link inside a
|
|
189
|
+
`ToolbarControlGroup` named by `aria-label` (no visible text or `title`);
|
|
190
|
+
import `@kerfjs/ui/help-tags/register` once when a toolbar has such buttons
|
|
191
|
+
but no registered Select or PopupMenu.
|
|
192
|
+
The package names the internal combobox, including custom
|
|
174
193
|
selected content; consumers do not need shadow-DOM naming workarounds.
|
|
175
194
|
Import `select/register` once for the canonical animation lifecycle: stale
|
|
176
195
|
close/show completions cannot override a later request. Consumers must not
|
|
@@ -227,6 +246,11 @@ the folder modules, and CSS only imports their owner stylesheets.
|
|
|
227
246
|
scrolling `.kui-pane__content`, optional `.kui-pane__footer`). A visible pane owns
|
|
228
247
|
its collapse control; a hidden pane's restore moves to the adjacent main
|
|
229
248
|
toolbar's matching edge — no icon-only rail. Keep one scroll owner per region.
|
|
249
|
+
While a side overlay is open (a Workbench rail overlay, a `wireSidebar` compact
|
|
250
|
+
overlay, an overlay `CollapsiblePanel` or horizontal `ResizableRegion`), the
|
|
251
|
+
layout hides the covered work area's `FloatingToolbar`s and restore corners
|
|
252
|
+
itself (unfocusable, out of the accessibility tree) until it closes — do not
|
|
253
|
+
hide them from overlay state yourself.
|
|
230
254
|
- **State and behavior live in the app.** Components take semantic `data-action`
|
|
231
255
|
strings and controlled values; wire them once with `delegate()`/`delegateActions()`
|
|
232
256
|
or the disposer-returning `wire…` helpers, and own domain copy, transport, and
|
|
@@ -290,6 +314,10 @@ the folder modules, and CSS only imports their owner stylesheets.
|
|
|
290
314
|
- **Use `Badge` for compact non-interactive metadata.** Configure its semantic
|
|
291
315
|
tone, appearance, shape, and size instead of creating badge CSS in an app or
|
|
292
316
|
consuming component. Use a real button or link for interactive content.
|
|
317
|
+
For new content without a count, use the text-free `size="dot"` form: it
|
|
318
|
+
takes no children, and needs a `label` (announced as an image) or
|
|
319
|
+
`ariaHidden` when its owner announces it. A `TabScaffold` tab shows the dot
|
|
320
|
+
with `badge: true` plus its required `badgeLabel`.
|
|
293
321
|
|
|
294
322
|
## Public exports
|
|
295
323
|
|