@kerfjs/ui 5.0.0-beta.78 → 5.0.0-beta.79
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 +8 -6
- package/ai/application-ui-diagnostic-ids-v1.json +1 -0
- package/ai/compile-time-contracts-v1.json +3 -3
- package/ai/component-catalog.json +31 -22
- package/ai/component-composition-rules.json +6 -14
- package/ai/component-composition.json +21 -23
- package/ai/components/README.md +1 -1
- package/ai/components/document-baseline.md +1 -1
- package/ai/components/nav-stack.md +3 -3
- package/ai/components/pane.md +3 -1
- package/ai/components/{tab-scaffold.md → tab-navigator.md} +14 -14
- package/ai/components/token-search-field.md +1 -0
- package/ai/components/toolbar.md +4 -8
- package/ai/public-api-signatures-v1.md +20 -20
- package/ai/skill.md +7 -6
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/dist/browser/tab-navigator.js +4 -0
- package/dist/{chunk-QYXKMLHO.js → chunk-3CXRQAYT.js} +2 -2
- package/dist/chunk-3CXRQAYT.js.map +1 -0
- package/dist/{chunk-G4VKQP7B.js → chunk-3SXWV2IR.js} +5 -1
- package/dist/chunk-3SXWV2IR.js.map +1 -0
- package/dist/{chunk-VLPE6OPN.js → chunk-62VMNBV2.js} +6 -2
- package/dist/chunk-62VMNBV2.js.map +1 -0
- package/dist/index.js +3 -3
- package/dist/styles/components/actions/toolbar/toolbar.css +7 -14
- package/dist/styles/components/actions/toolbar-control-group/toolbar-control-group.css +3 -0
- package/dist/styles/components/actions/toolbar-text/toolbar-text.css +1 -0
- package/dist/styles/components/forms/token-search-field/token-search-field.css +12 -1
- package/dist/styles/components/layout/pane/pane.css +13 -3
- package/dist/styles/components/navigation/tab-scaffold/tab-scaffold.css +1 -1
- package/dist/styles/pane.css +13 -3
- package/dist/styles/{tab-scaffold.css → tab-navigator.css} +1 -1
- package/dist/styles/token-search-field.css +12 -1
- package/dist/styles/toolbar-control-group.css +3 -0
- package/dist/styles/toolbar-text.css +1 -0
- package/dist/styles/toolbar.css +7 -14
- package/dist/{tab-scaffold.d.ts → tab-navigator.d.ts} +10 -10
- package/dist/{tab-scaffold.js → tab-navigator.js} +3 -3
- package/dist/tab-navigator.js.map +1 -0
- package/dist/token-search-field.js +1 -1
- package/dist/wire-catalog.js +1 -1
- package/dist/wire-scroll-dividers.d.ts +3 -3
- package/dist/wire-scroll-dividers.js +1 -1
- package/dist/wire-tab-navigator.d.ts +11 -0
- package/dist/{wire-tab-scaffold.js → wire-tab-navigator.js} +3 -3
- package/dist/wire-tab-navigator.js.map +1 -0
- package/dist/wire-token-search-fields.js +1 -1
- package/docs/app-layouts.md +44 -11
- package/docs/component-contract.md +1 -1
- package/docs/component-selection.md +16 -14
- package/docs/design/templates/token-search-field/empty-dark.svg +1 -1
- package/docs/design/templates/token-search-field/empty.svg +1 -1
- package/docs/design/templates/token-search-field-dark.svg +1 -1
- package/docs/design/templates/token-search-field.svg +1 -1
- package/docs/design/templates.md +1 -1
- package/docs/examples/application-ui-profile.json +4 -4
- package/docs/layout.md +11 -8
- package/docs/recipes.md +1 -1
- package/docs/{tab-scaffold.md → tab-navigator.md} +32 -17
- package/docs/type-contracts.md +3 -3
- package/docs/ui-analyzer.md +5 -0
- package/docs/ui-doctor.md +18 -8
- package/doctor/component-style-checks.mjs +253 -20
- package/doctor/index.mjs +1 -0
- package/llms.txt +10 -8
- package/package.json +10 -10
- package/dist/browser/tab-scaffold.js +0 -4
- package/dist/chunk-G4VKQP7B.js.map +0 -1
- package/dist/chunk-QYXKMLHO.js.map +0 -1
- package/dist/chunk-VLPE6OPN.js.map +0 -1
- package/dist/tab-scaffold.js.map +0 -1
- package/dist/wire-tab-scaffold.d.ts +0 -11
- package/dist/wire-tab-scaffold.js.map +0 -1
package/README.md
CHANGED
|
@@ -38,8 +38,10 @@ Browser verification always builds current source: both `npm run test:e2e`
|
|
|
38
38
|
and direct focused Playwright commands run the catalog/conformance preflights
|
|
39
39
|
and production build before preview. See the [UX catalog contract](./docs/ux-demo.md).
|
|
40
40
|
Failed Playwright tests retain traces and screenshots alongside an HTML report.
|
|
41
|
-
|
|
42
|
-
the
|
|
41
|
+
CI runs the complete suite in concurrent Chromium, Firefox, and WebKit jobs,
|
|
42
|
+
while the `ui` job checks the package. A failing browser job uploads its report
|
|
43
|
+
and per-test evidence for 14 days as
|
|
44
|
+
`ui-browser-failure-<browser>-<run>-<attempt>`.
|
|
43
45
|
|
|
44
46
|
When authoring a component gallery, follow the single
|
|
45
47
|
[Catalog demo authoring contract](./docs/catalog.md#catalog-demo-authoring-contract)
|
|
@@ -233,8 +235,8 @@ interchangeable. `ListItem` and `ListActionRow` deliberately expose no raw
|
|
|
233
235
|
| `NavStack` | `@kerfjs/ui/nav-stack` | `@kerfjs/ui/nav-stack.css` |
|
|
234
236
|
| `wireNavStack` | `@kerfjs/ui/wire-nav-stack` | — |
|
|
235
237
|
| `SplitView` | `@kerfjs/ui/split-view` | `@kerfjs/ui/split-view.css` |
|
|
236
|
-
| `
|
|
237
|
-
| `
|
|
238
|
+
| `TabNavigator` | `@kerfjs/ui/tab-navigator` | `@kerfjs/ui/tab-navigator.css` |
|
|
239
|
+
| `wireTabNavigator` | `@kerfjs/ui/wire-tab-navigator` | — |
|
|
238
240
|
| `Workbench` | `@kerfjs/ui/workbench` | `@kerfjs/ui/workbench.css` |
|
|
239
241
|
| `wireWorkbench` | `@kerfjs/ui/wire-workbench` | — |
|
|
240
242
|
| `CollapsiblePanel`, `CollapsiblePanelToggle` | `@kerfjs/ui/collapsible-panel` | `@kerfjs/ui/collapsible-panel.css` |
|
|
@@ -263,11 +265,11 @@ Application layouts are separate component subpaths. Browser-condition imports
|
|
|
263
265
|
include their reachable CSS; use the matching manual CSS export when your
|
|
264
266
|
bundler does not select the browser condition. Add a wire subpath when the
|
|
265
267
|
layout has interactive behavior. The catalog
|
|
266
|
-
entries for `nav-stack`, `split-view`, `tab-
|
|
268
|
+
entries for `nav-stack`, `split-view`, `tab-navigator`, `workbench`, and
|
|
267
269
|
`collapsible-panel` document their selection rules, ownership boundaries,
|
|
268
270
|
public classes, tokens, and focused demos. See
|
|
269
271
|
[`docs/app-layouts.md`](./docs/app-layouts.md) for the layout decision matrix.
|
|
270
|
-
`NavStack` and `
|
|
272
|
+
`NavStack` and `TabNavigator` expose `chromeDividers="scroll" | "always" |
|
|
271
273
|
"none"` for their chrome lines; `SplitView` forwards the setting to its
|
|
272
274
|
compact stack. A sole `Pane` in a view or scene fills it, keeping the Pane's
|
|
273
275
|
header in place while its own content scrolls.
|
|
@@ -107,6 +107,7 @@
|
|
|
107
107
|
"KUI-T011"
|
|
108
108
|
],
|
|
109
109
|
"retired": {
|
|
110
|
+
"KUI-C101": "Toolbar zones accept KerfUiContent directly; grouping is a recommended presentation choice, not a composition requirement. Kept in ids so existing profile exceptions still load.",
|
|
110
111
|
"KUI-L005": "Folded into KUI-L019: any application rule whose subject is a cataloged component, forced dimensions included. Kept in ids so existing profile exceptions that name it still load."
|
|
111
112
|
}
|
|
112
113
|
}
|
|
@@ -62,10 +62,10 @@
|
|
|
62
62
|
},
|
|
63
63
|
{
|
|
64
64
|
"id": "KUI-T008",
|
|
65
|
-
"publicImport": "@kerfjs/ui/tab-
|
|
66
|
-
"symbols": ["
|
|
65
|
+
"publicImport": "@kerfjs/ui/tab-navigator",
|
|
66
|
+
"symbols": ["TabNavigatorTab", "TabNavigatorProps"],
|
|
67
67
|
"kind": "literal-identity",
|
|
68
|
-
"summary": "Literal
|
|
68
|
+
"summary": "Literal TabNavigator active ids are constrained to the declared tab ids; dynamic integrations may widen the generic to string."
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
71
|
"id": "KUI-T009",
|
|
@@ -478,7 +478,7 @@
|
|
|
478
478
|
"publicExports": [],
|
|
479
479
|
"useWhen": [
|
|
480
480
|
"An application wants Kerf UI to own document-level box sizing, body typography, native table-cell and form-control font metrics, surface, and link color.",
|
|
481
|
-
"A full-height shell (Workbench, SplitView, NavStack, or
|
|
481
|
+
"A full-height shell (Workbench, SplitView, NavStack, or TabNavigator) mounts into one direct container: put .kui-app-root on that container."
|
|
482
482
|
],
|
|
483
483
|
"avoidWhen": [
|
|
484
484
|
"Do not put .kui-app-root on several sibling containers; each requests the full available document height.",
|
|
@@ -624,7 +624,8 @@
|
|
|
624
624
|
"An application column needs shared header, content, and optional footer organization with exactly one scrolling content owner.",
|
|
625
625
|
"A pane boundary needs an opt-in separator on any combination of logical sides.",
|
|
626
626
|
"Pinned chrome needs a divider from the scrolling content only while content is scrolled beneath it (wireScrollDividers).",
|
|
627
|
-
"A lowered background must cover the scrolling work viewport and blank space after short content without a second scroll container (appearance: sunken)."
|
|
627
|
+
"A lowered background must cover the scrolling work viewport and blank space after short content without a second scroll container (appearance: sunken).",
|
|
628
|
+
"A child table or other component needs edge-to-edge decoration with text aligned to other pane content."
|
|
628
629
|
],
|
|
629
630
|
"avoidWhen": [
|
|
630
631
|
"Do not use Pane as a padded card or add a competing scroll owner around its content slot.",
|
|
@@ -667,8 +668,9 @@
|
|
|
667
668
|
"border": "conditional",
|
|
668
669
|
"padding": "child",
|
|
669
670
|
"notes": [
|
|
670
|
-
|
|
671
|
-
"Safe areas: the root and separators paint through unsafe areas while header, content, and footer pad the sides the pane still reaches (routed by --kui-edge-inset-*); content block insets are scroll padding."
|
|
671
|
+
"The pane is unpadded; separators are independently opt-in on logical edges and default off.",
|
|
672
|
+
"Safe areas: the root and separators paint through unsafe areas while header, content, and footer pad the sides the pane still reaches (routed by --kui-edge-inset-*); content block insets are scroll padding.",
|
|
673
|
+
"The scrolling content exposes its resolved logical inline padding to descendants as --kui-pane-content-inset-inline-start/end, including safe areas and deepInset."
|
|
672
674
|
]
|
|
673
675
|
},
|
|
674
676
|
"delivery": {
|
|
@@ -712,6 +714,8 @@
|
|
|
712
714
|
"--kui-pane-separator-color",
|
|
713
715
|
"--kui-pane-separator-width",
|
|
714
716
|
"--kui-pane-chrome-background",
|
|
717
|
+
"--kui-pane-content-inset-inline-start",
|
|
718
|
+
"--kui-pane-content-inset-inline-end",
|
|
715
719
|
"--kui-sunken-panel-background"
|
|
716
720
|
],
|
|
717
721
|
"links": {
|
|
@@ -745,7 +749,7 @@
|
|
|
745
749
|
],
|
|
746
750
|
"avoidWhen": [
|
|
747
751
|
"Do not use NavStack when a list and detail should remain visible together; use SplitView.",
|
|
748
|
-
"Do not use it for co-equal top-level destinations on compact devices; wrap one stack per destination in
|
|
752
|
+
"Do not use it for co-equal top-level destinations on compact devices; wrap one stack per destination in TabNavigator."
|
|
749
753
|
],
|
|
750
754
|
"alternatives": [
|
|
751
755
|
{
|
|
@@ -754,9 +758,9 @@
|
|
|
754
758
|
"when": "Promote a list-to-detail stack to SplitView once both regions fit together."
|
|
755
759
|
},
|
|
756
760
|
{
|
|
757
|
-
"id": "tab-
|
|
761
|
+
"id": "tab-navigator",
|
|
758
762
|
"relationship": "composes-with",
|
|
759
|
-
"when": "Use one NavStack as each
|
|
763
|
+
"when": "Use one NavStack as each TabNavigator tab's persistent content."
|
|
760
764
|
}
|
|
761
765
|
],
|
|
762
766
|
"appOwns": [
|
|
@@ -1011,27 +1015,27 @@
|
|
|
1011
1015
|
}
|
|
1012
1016
|
},
|
|
1013
1017
|
{
|
|
1014
|
-
"id": "tab-
|
|
1015
|
-
"name": "
|
|
1018
|
+
"id": "tab-navigator",
|
|
1019
|
+
"name": "TabNavigator",
|
|
1016
1020
|
"category": "Structure",
|
|
1017
1021
|
"kind": "component",
|
|
1018
1022
|
"source": "kerf",
|
|
1019
|
-
"description": "A controlled compact-device bottom tab
|
|
1023
|
+
"description": "A controlled compact-device bottom tab navigator that keeps every destination scene mounted so its navigation and scroll state survive selection changes.",
|
|
1020
1024
|
"uses": [
|
|
1021
1025
|
"badge"
|
|
1022
1026
|
],
|
|
1023
1027
|
"purpose": "Switch among two to five co-equal top-level destinations on compact devices while preserving each destination's independent content state.",
|
|
1024
1028
|
"publicExports": [
|
|
1025
|
-
"
|
|
1026
|
-
"
|
|
1027
|
-
"
|
|
1029
|
+
"TabNavigatorTab",
|
|
1030
|
+
"TabNavigatorProps",
|
|
1031
|
+
"TabNavigator"
|
|
1028
1032
|
],
|
|
1029
1033
|
"useWhen": [
|
|
1030
1034
|
"A handset or portrait-tablet app has two to five co-equal top-level destinations.",
|
|
1031
1035
|
"Each destination must stay mounted so its NavStack and scroll position survive tab switches."
|
|
1032
1036
|
],
|
|
1033
1037
|
"avoidWhen": [
|
|
1034
|
-
"Do not use
|
|
1038
|
+
"Do not use TabNavigator for document tabs or reorderable work items; use TabBar.",
|
|
1035
1039
|
"Do not retain the bottom bar on desktop when the same destinations should be promoted to a Workbench rail or sidebar."
|
|
1036
1040
|
],
|
|
1037
1041
|
"alternatives": [
|
|
@@ -1072,22 +1076,22 @@
|
|
|
1072
1076
|
"border": "conditional",
|
|
1073
1077
|
"padding": "self",
|
|
1074
1078
|
"notes": [
|
|
1075
|
-
"The
|
|
1079
|
+
"The navigator owns the full-height scene region and safe-area-aware bottom bar; scene content owns its internal geometry.",
|
|
1076
1080
|
"The bar's top line is scroll state (wireScrollDividers): it shows only while the active scene's content continues below the bar, by coloring the bar's always-present 1px top border."
|
|
1077
1081
|
]
|
|
1078
1082
|
},
|
|
1079
1083
|
"delivery": {
|
|
1080
|
-
"moduleImport": "@kerfjs/ui/tab-
|
|
1081
|
-
"browserImport": "@kerfjs/ui/tab-
|
|
1082
|
-
"manualCssImport": "@kerfjs/ui/tab-
|
|
1084
|
+
"moduleImport": "@kerfjs/ui/tab-navigator",
|
|
1085
|
+
"browserImport": "@kerfjs/ui/tab-navigator",
|
|
1086
|
+
"manualCssImport": "@kerfjs/ui/tab-navigator.css",
|
|
1083
1087
|
"sideEffects": [
|
|
1084
1088
|
"browser-condition-css"
|
|
1085
1089
|
]
|
|
1086
1090
|
},
|
|
1087
1091
|
"wiring": [
|
|
1088
1092
|
{
|
|
1089
|
-
"export": "
|
|
1090
|
-
"import": "@kerfjs/ui/wire-tab-
|
|
1093
|
+
"export": "wireTabNavigator",
|
|
1094
|
+
"import": "@kerfjs/ui/wire-tab-navigator",
|
|
1091
1095
|
"required": true
|
|
1092
1096
|
},
|
|
1093
1097
|
{
|
|
@@ -1120,8 +1124,8 @@
|
|
|
1120
1124
|
],
|
|
1121
1125
|
"publicTokens": [],
|
|
1122
1126
|
"links": {
|
|
1123
|
-
"catalogRoute": "?component=tab-
|
|
1124
|
-
"documentation": "docs/tab-
|
|
1127
|
+
"catalogRoute": "?component=tab-navigator",
|
|
1128
|
+
"documentation": "docs/tab-navigator.md",
|
|
1125
1129
|
"recipe": "docs/app-layouts.md#decision-matrix"
|
|
1126
1130
|
}
|
|
1127
1131
|
},
|
|
@@ -4299,6 +4303,11 @@
|
|
|
4299
4303
|
"name": "data-empty",
|
|
4300
4304
|
"on": "the text span inside kui-token-search__editor",
|
|
4301
4305
|
"meaning": "\"true\" on that span while it holds no text."
|
|
4306
|
+
},
|
|
4307
|
+
{
|
|
4308
|
+
"name": "data-placeholder-visible",
|
|
4309
|
+
"on": "the kui-token-search root",
|
|
4310
|
+
"meaning": "Tracks whether the DOM-owned editor is empty so its placeholder stays outside the editable area."
|
|
4302
4311
|
}
|
|
4303
4312
|
]
|
|
4304
4313
|
}
|
|
@@ -11,38 +11,30 @@
|
|
|
11
11
|
{
|
|
12
12
|
"id": "leading",
|
|
13
13
|
"jsx": { "prop": "leading" },
|
|
14
|
-
"accepts": ["
|
|
14
|
+
"accepts": ["KerfUiContent"],
|
|
15
15
|
"cardinality": { "min": 0, "max": "unbounded" },
|
|
16
16
|
"exclusiveWith": []
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"id": "center",
|
|
20
20
|
"jsx": { "prop": "center" },
|
|
21
|
-
"accepts": ["
|
|
21
|
+
"accepts": ["KerfUiContent"],
|
|
22
22
|
"cardinality": { "min": 0, "max": "unbounded" },
|
|
23
23
|
"exclusiveWith": []
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
"id": "trailing",
|
|
27
27
|
"jsx": { "prop": "trailing" },
|
|
28
|
-
"accepts": ["
|
|
28
|
+
"accepts": ["KerfUiContent"],
|
|
29
29
|
"cardinality": { "min": 0, "max": "unbounded" },
|
|
30
30
|
"exclusiveWith": []
|
|
31
31
|
}
|
|
32
32
|
],
|
|
33
33
|
"children": {
|
|
34
|
-
"mode": "
|
|
35
|
-
"concepts": [
|
|
34
|
+
"mode": "any",
|
|
35
|
+
"concepts": [],
|
|
36
36
|
"requiredConcepts": []
|
|
37
|
-
}
|
|
38
|
-
"diagnostics": [
|
|
39
|
-
{
|
|
40
|
-
"id": "KUI-C101",
|
|
41
|
-
"severity": "error",
|
|
42
|
-
"when": "a direct zone child is neither ToolbarText nor ToolbarControlGroup nor a standalone wa-button in trailing",
|
|
43
|
-
"message": "Wrap toolbar controls in ToolbarControlGroup; only ToolbarText and ToolbarControlGroup, plus one standalone primary wa-button in trailing, are direct zone children."
|
|
44
|
-
}
|
|
45
|
-
]
|
|
37
|
+
}
|
|
46
38
|
},
|
|
47
39
|
"@kerfjs/ui:pane": {
|
|
48
40
|
"_source": "docs/layout.md#anatomy",
|
|
@@ -642,7 +642,8 @@
|
|
|
642
642
|
"padding": "child",
|
|
643
643
|
"notes": [
|
|
644
644
|
"The pane is unpadded; separators are independently opt-in on logical edges and default off.",
|
|
645
|
-
"Safe areas: the root and separators paint through unsafe areas while header, content, and footer pad the sides the pane still reaches (routed by --kui-edge-inset-*); content block insets are scroll padding."
|
|
645
|
+
"Safe areas: the root and separators paint through unsafe areas while header, content, and footer pad the sides the pane still reaches (routed by --kui-edge-inset-*); content block insets are scroll padding.",
|
|
646
|
+
"The scrolling content exposes its resolved logical inline padding to descendants as --kui-pane-content-inset-inline-start/end, including safe areas and deepInset."
|
|
646
647
|
]
|
|
647
648
|
}
|
|
648
649
|
},
|
|
@@ -670,6 +671,8 @@
|
|
|
670
671
|
"--kui-pane-separator-color",
|
|
671
672
|
"--kui-pane-separator-width",
|
|
672
673
|
"--kui-pane-chrome-background",
|
|
674
|
+
"--kui-pane-content-inset-inline-start",
|
|
675
|
+
"--kui-pane-content-inset-inline-end",
|
|
673
676
|
"--kui-sunken-panel-background"
|
|
674
677
|
]
|
|
675
678
|
},
|
|
@@ -963,10 +966,10 @@
|
|
|
963
966
|
}
|
|
964
967
|
},
|
|
965
968
|
{
|
|
966
|
-
"key": "@kerfjs/ui:tab-
|
|
969
|
+
"key": "@kerfjs/ui:tab-navigator",
|
|
967
970
|
"package": "@kerfjs/ui",
|
|
968
|
-
"id": "tab-
|
|
969
|
-
"name": "
|
|
971
|
+
"id": "tab-navigator",
|
|
972
|
+
"name": "TabNavigator",
|
|
970
973
|
"kind": "component",
|
|
971
974
|
"source": "kerf",
|
|
972
975
|
"parents": { "mode": "any", "entries": [] },
|
|
@@ -1007,8 +1010,8 @@
|
|
|
1007
1010
|
],
|
|
1008
1011
|
"wiring": {
|
|
1009
1012
|
"required": true,
|
|
1010
|
-
"helpers": ["
|
|
1011
|
-
"obligations": ["Use
|
|
1013
|
+
"helpers": ["wireTabNavigator", "wireScrollDividers"],
|
|
1014
|
+
"obligations": ["Use wireTabNavigator as documented."],
|
|
1012
1015
|
"stateAttributes": [
|
|
1013
1016
|
{
|
|
1014
1017
|
"name": "data-scroll-overflow",
|
|
@@ -1032,7 +1035,7 @@
|
|
|
1032
1035
|
"border": "conditional",
|
|
1033
1036
|
"padding": "self",
|
|
1034
1037
|
"notes": [
|
|
1035
|
-
"The
|
|
1038
|
+
"The navigator owns the full-height scene region and safe-area-aware bottom bar; scene content owns its internal geometry.",
|
|
1036
1039
|
"The bar's top line is scroll state (wireScrollDividers): it shows only while the active scene's content continues below the bar, by coloring the bar's always-present 1px top border."
|
|
1037
1040
|
]
|
|
1038
1041
|
}
|
|
@@ -1427,30 +1430,26 @@
|
|
|
1427
1430
|
{
|
|
1428
1431
|
"id": "leading",
|
|
1429
1432
|
"jsx": { "prop": "leading" },
|
|
1430
|
-
"accepts": ["
|
|
1433
|
+
"accepts": ["KerfUiContent"],
|
|
1431
1434
|
"cardinality": { "min": 0, "max": "unbounded" },
|
|
1432
1435
|
"exclusiveWith": []
|
|
1433
1436
|
},
|
|
1434
1437
|
{
|
|
1435
1438
|
"id": "center",
|
|
1436
1439
|
"jsx": { "prop": "center" },
|
|
1437
|
-
"accepts": ["
|
|
1440
|
+
"accepts": ["KerfUiContent"],
|
|
1438
1441
|
"cardinality": { "min": 0, "max": "unbounded" },
|
|
1439
1442
|
"exclusiveWith": []
|
|
1440
1443
|
},
|
|
1441
1444
|
{
|
|
1442
1445
|
"id": "trailing",
|
|
1443
1446
|
"jsx": { "prop": "trailing" },
|
|
1444
|
-
"accepts": ["
|
|
1447
|
+
"accepts": ["KerfUiContent"],
|
|
1445
1448
|
"cardinality": { "min": 0, "max": "unbounded" },
|
|
1446
1449
|
"exclusiveWith": []
|
|
1447
1450
|
}
|
|
1448
1451
|
],
|
|
1449
|
-
"children": {
|
|
1450
|
-
"mode": "listed",
|
|
1451
|
-
"concepts": ["toolbar-text", "toolbar-control-group", "wa-button"],
|
|
1452
|
-
"requiredConcepts": []
|
|
1453
|
-
},
|
|
1452
|
+
"children": { "mode": "any", "concepts": [], "requiredConcepts": [] },
|
|
1454
1453
|
"state": [
|
|
1455
1454
|
{ "id": "actions", "owner": "application", "required": false },
|
|
1456
1455
|
{
|
|
@@ -1554,14 +1553,7 @@
|
|
|
1554
1553
|
"--kui-toolbar-zone-padding-inline"
|
|
1555
1554
|
]
|
|
1556
1555
|
},
|
|
1557
|
-
"diagnostics": [
|
|
1558
|
-
{
|
|
1559
|
-
"id": "KUI-C101",
|
|
1560
|
-
"severity": "error",
|
|
1561
|
-
"when": "a direct zone child is neither ToolbarText nor ToolbarControlGroup nor a standalone wa-button in trailing",
|
|
1562
|
-
"message": "Wrap toolbar controls in ToolbarControlGroup; only ToolbarText and ToolbarControlGroup, plus one standalone primary wa-button in trailing, are direct zone children."
|
|
1563
|
-
}
|
|
1564
|
-
],
|
|
1556
|
+
"diagnostics": [],
|
|
1565
1557
|
"provenance": {
|
|
1566
1558
|
"selection": "ai/component-catalog.json",
|
|
1567
1559
|
"composition": "docs/component-selection.md#toolbar-composition"
|
|
@@ -3499,6 +3491,12 @@
|
|
|
3499
3491
|
"on": "the text span inside kui-token-search__editor",
|
|
3500
3492
|
"helper": "wireTokenSearchFields",
|
|
3501
3493
|
"meaning": "\"true\" on that span while it holds no text."
|
|
3494
|
+
},
|
|
3495
|
+
{
|
|
3496
|
+
"name": "data-placeholder-visible",
|
|
3497
|
+
"on": "the kui-token-search root",
|
|
3498
|
+
"helper": "wireTokenSearchFields",
|
|
3499
|
+
"meaning": "Tracks whether the DOM-owned editor is empty so its placeholder stays outside the editable area."
|
|
3502
3500
|
}
|
|
3503
3501
|
]
|
|
3504
3502
|
},
|
package/ai/components/README.md
CHANGED
|
@@ -21,7 +21,7 @@ Exact prop and callback types live in [`public-api-signatures-v1.md`](../public-
|
|
|
21
21
|
- [Pane](./pane.md) — Organize a sidebar, main area, inspector, or dialog column into fixed vertical header/footer chrome around one scrolling content owner.
|
|
22
22
|
- [NavStack](./nav-stack.md) — Present a single linear or drill-down flow while preserving each prior view's state, scroll position, and place in the stack.
|
|
23
23
|
- [SplitView](./split-view.md) — Present a selectable list and its detail together when space permits, with a one-pane drill-down replacement on compact devices.
|
|
24
|
-
- [
|
|
24
|
+
- [TabNavigator](./tab-navigator.md) — Switch among two to five co-equal top-level destinations on compact devices while preserving each destination's independent content state.
|
|
25
25
|
- [Workbench](./workbench.md) — Arrange a complex tool or editor as a stable central work area with optional peripheral rails and a bottom drawer.
|
|
26
26
|
- [CollapsiblePanel](./collapsible-panel.md) — Add one independently collapsible peripheral panel without adopting the complete multi-panel Workbench shell.
|
|
27
27
|
- [SunkenPanel](./sunken-panel.md) — Group a vertical list of application content on a visually lowered surface with one owned 8px inset and an explicit rounded or square-corner shape.
|
|
@@ -11,7 +11,7 @@ Opt-in document-level defaults: border-box sizing, body margin/font/surface, nat
|
|
|
11
11
|
Let an application opt into Kerf UI-owned document defaults and a definite full-height chain for a percentage-height application shell.
|
|
12
12
|
|
|
13
13
|
- An application wants Kerf UI to own document-level box sizing, body typography, native table-cell and form-control font metrics, surface, and link color.
|
|
14
|
-
- A full-height shell (Workbench, SplitView, NavStack, or
|
|
14
|
+
- A full-height shell (Workbench, SplitView, NavStack, or TabNavigator) mounts into one direct container: put .kui-app-root on that container.
|
|
15
15
|
|
|
16
16
|
**Not when:**
|
|
17
17
|
|
|
@@ -16,12 +16,12 @@ Present a single linear or drill-down flow while preserving each prior view's st
|
|
|
16
16
|
**Not when:**
|
|
17
17
|
|
|
18
18
|
- Do not use NavStack when a list and detail should remain visible together; use SplitView.
|
|
19
|
-
- Do not use it for co-equal top-level destinations on compact devices; wrap one stack per destination in
|
|
19
|
+
- Do not use it for co-equal top-level destinations on compact devices; wrap one stack per destination in TabNavigator.
|
|
20
20
|
|
|
21
21
|
**Alternatives:**
|
|
22
22
|
|
|
23
23
|
- [SplitView](./split-view.md) (roomy-alternative) — Promote a list-to-detail stack to SplitView once both regions fit together.
|
|
24
|
-
- [
|
|
24
|
+
- [TabNavigator](./tab-navigator.md) (composes-with) — Use one NavStack as each TabNavigator tab's persistent content.
|
|
25
25
|
|
|
26
26
|
## Imports
|
|
27
27
|
|
|
@@ -100,6 +100,6 @@ Everything else is internal: `kerf-ui-analyze` reports private or unknown `.kui-
|
|
|
100
100
|
|
|
101
101
|
## Related
|
|
102
102
|
|
|
103
|
-
- Components: [Toolbar](./toolbar.md), [ToolbarControlGroup](./toolbar-control-group.md), [ToolbarText](./toolbar-text.md), [SplitView](./split-view.md), [
|
|
103
|
+
- Components: [Toolbar](./toolbar.md), [ToolbarControlGroup](./toolbar-control-group.md), [ToolbarText](./toolbar-text.md), [SplitView](./split-view.md), [TabNavigator](./tab-navigator.md).
|
|
104
104
|
- Docs: [`docs/nav-stack.md`](../../docs/nav-stack.md), [`docs/app-layouts.md#decision-matrix`](../../docs/app-layouts.md#decision-matrix).
|
|
105
105
|
- UX catalog route: `?component=nav-stack`.
|
package/ai/components/pane.md
CHANGED
|
@@ -14,6 +14,7 @@ Organize a sidebar, main area, inspector, or dialog column into fixed vertical h
|
|
|
14
14
|
- A pane boundary needs an opt-in separator on any combination of logical sides.
|
|
15
15
|
- Pinned chrome needs a divider from the scrolling content only while content is scrolled beneath it (wireScrollDividers).
|
|
16
16
|
- A lowered background must cover the scrolling work viewport and blank space after short content without a second scroll container (appearance: sunken).
|
|
17
|
+
- A child table or other component needs edge-to-edge decoration with text aligned to other pane content.
|
|
17
18
|
|
|
18
19
|
**Not when:**
|
|
19
20
|
|
|
@@ -76,6 +77,7 @@ Margin: child · border: conditional · padding: child (layout role: structure).
|
|
|
76
77
|
|
|
77
78
|
- The pane is unpadded; separators are independently opt-in on logical edges and default off.
|
|
78
79
|
- Safe areas: the root and separators paint through unsafe areas while header, content, and footer pad the sides the pane still reaches (routed by --kui-edge-inset-\*); content block insets are scroll padding.
|
|
80
|
+
- The scrolling content exposes its resolved logical inline padding to descendants as --kui-pane-content-inset-inline-start/end, including safe areas and deepInset.
|
|
79
81
|
|
|
80
82
|
## Accessibility
|
|
81
83
|
|
|
@@ -90,7 +92,7 @@ Public class hooks (select for layout placement only, never to change the compon
|
|
|
90
92
|
|
|
91
93
|
Never put `kui-pane`, `kui-pane__content`, `kui-pane__footer`, `kui-pane__header`, `kui-pane__toolbar` on an element you write; render `Pane` instead (`KUI-L103`).
|
|
92
94
|
|
|
93
|
-
Public tokens it reads: `--kui-edge-inset-block-end`, `--kui-edge-inset-block-start`, `--kui-edge-inset-inline-end`, `--kui-edge-inset-inline-start`, `--kui-pane-separator-color`, `--kui-pane-separator-width`, `--kui-pane-chrome-background`, `--kui-sunken-panel-background`. Set a token only where its public contract allows; prefer a prop.
|
|
95
|
+
Public tokens it reads: `--kui-edge-inset-block-end`, `--kui-edge-inset-block-start`, `--kui-edge-inset-inline-end`, `--kui-edge-inset-inline-start`, `--kui-pane-separator-color`, `--kui-pane-separator-width`, `--kui-pane-chrome-background`, `--kui-pane-content-inset-inline-start`, `--kui-pane-content-inset-inline-end`, `--kui-sunken-panel-background`. Set a token only where its public contract allows; prefer a prop.
|
|
94
96
|
|
|
95
97
|
Everything else is internal: `kerf-ui-analyze` reports private or unknown `.kui-*` selectors (`KUI-L001`, `KUI-L010`), unknown or private tokens (`KUI-L002`, `KUI-L012`), and any application rule that restyles the component, forced dimensions included (`KUI-L019`).
|
|
96
98
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# TabNavigator
|
|
2
2
|
|
|
3
3
|
<!-- Generated by scripts/sync-component-docs.mjs from ai/component-catalog.json and ai/component-composition.json. Do not edit; run `npm run catalog:sync`. -->
|
|
4
4
|
|
|
5
|
-
`@kerfjs/ui:tab-
|
|
5
|
+
`@kerfjs/ui:tab-navigator` · Kerf UI · component · Structure
|
|
6
6
|
|
|
7
|
-
A controlled compact-device bottom tab
|
|
7
|
+
A controlled compact-device bottom tab navigator that keeps every destination scene mounted so its navigation and scroll state survive selection changes.
|
|
8
8
|
|
|
9
9
|
## When to use
|
|
10
10
|
|
|
@@ -15,7 +15,7 @@ Switch among two to five co-equal top-level destinations on compact devices whil
|
|
|
15
15
|
|
|
16
16
|
**Not when:**
|
|
17
17
|
|
|
18
|
-
- Do not use
|
|
18
|
+
- Do not use TabNavigator for document tabs or reorderable work items; use TabBar.
|
|
19
19
|
- Do not retain the bottom bar on desktop when the same destinations should be promoted to a Workbench rail or sidebar.
|
|
20
20
|
|
|
21
21
|
**Alternatives:**
|
|
@@ -25,15 +25,15 @@ Switch among two to five co-equal top-level destinations on compact devices whil
|
|
|
25
25
|
|
|
26
26
|
## Imports
|
|
27
27
|
|
|
28
|
-
- JavaScript: `@kerfjs/ui/tab-
|
|
29
|
-
- CSS: the browser build of `@kerfjs/ui/tab-
|
|
30
|
-
- Wiring: `
|
|
28
|
+
- JavaScript: `@kerfjs/ui/tab-navigator` — exports `TabNavigatorTab`, `TabNavigatorProps`, `TabNavigator`.
|
|
29
|
+
- CSS: the browser build of `@kerfjs/ui/tab-navigator` pulls its CSS automatically; import `@kerfjs/ui/tab-navigator.css` manually only without the `browser` export condition.
|
|
30
|
+
- Wiring: `wireTabNavigator` from `@kerfjs/ui/wire-tab-navigator` (required).
|
|
31
31
|
- Wiring: `wireScrollDividers` from `@kerfjs/ui/wire-scroll-dividers` (optional).
|
|
32
32
|
- Declared side effects: browser-condition-css.
|
|
33
33
|
|
|
34
34
|
## Props
|
|
35
35
|
|
|
36
|
-
Exact prop names and types: [`@kerfjs/ui/tab-
|
|
36
|
+
Exact prop names and types: [`@kerfjs/ui/tab-navigator`](../public-api-signatures-v1.md#kerfjsuitab-navigator), [`@kerfjs/ui/wire-tab-navigator`](../public-api-signatures-v1.md#kerfjsuiwire-tab-navigator), [`@kerfjs/ui/wire-scroll-dividers`](../public-api-signatures-v1.md#kerfjsuiwire-scroll-dividers) in `public-api-signatures-v1.md`. Do not infer props from examples.
|
|
37
37
|
|
|
38
38
|
**Variants (configure, do not restyle):**
|
|
39
39
|
|
|
@@ -55,9 +55,9 @@ Exact prop names and types: [`@kerfjs/ui/tab-scaffold`](../public-api-signatures
|
|
|
55
55
|
|
|
56
56
|
**The app owns:** controlled active tab id; tab labels, icons, and content; tab badge counts or dots and their localized badgeLabel phrases; routing and persistence; responsive replacement on larger device classes; whether the bar divider follows the scroll, always shows, or never shows (chromeDividers).
|
|
57
57
|
|
|
58
|
-
**Wiring:** `
|
|
58
|
+
**Wiring:** `wireTabNavigator`, `wireScrollDividers` is required.
|
|
59
59
|
|
|
60
|
-
- Use
|
|
60
|
+
- Use wireTabNavigator as documented.
|
|
61
61
|
|
|
62
62
|
**Wiring-owned state attributes** — never render, remove, or branch on these as app state:
|
|
63
63
|
|
|
@@ -68,7 +68,7 @@ Exact prop names and types: [`@kerfjs/ui/tab-scaffold`](../public-api-signatures
|
|
|
68
68
|
|
|
69
69
|
Margin: none · border: conditional · padding: self (layout role: structure). `self` means the component already owns it — do not add wrapper padding, margin, or borders around it.
|
|
70
70
|
|
|
71
|
-
- The
|
|
71
|
+
- The navigator owns the full-height scene region and safe-area-aware bottom bar; scene content owns its internal geometry.
|
|
72
72
|
- The bar's top line is scroll state (wireScrollDividers): it shows only while the active scene's content continues below the bar, by coloring the bar's always-present 1px top border.
|
|
73
73
|
|
|
74
74
|
## Accessibility
|
|
@@ -83,12 +83,12 @@ The component owns its own styles. Configure it through its props and variants;
|
|
|
83
83
|
|
|
84
84
|
Public class hooks (select for layout placement only, never to change the component's look): `kui-tab-scaffold`, `kui-tab-scaffold__scenes`, `kui-tab-scaffold__scene`, `kui-tab-scaffold__bar`, `kui-tab-scaffold__tab`, `kui-tab-scaffold__tab-icon`, `kui-tab-scaffold__tab-badge`, `kui-tab-scaffold__tab-label`.
|
|
85
85
|
|
|
86
|
-
Never put `kui-tab-scaffold`, `kui-tab-scaffold__scenes`, `kui-tab-scaffold__scene`, `kui-tab-scaffold__bar`, `kui-tab-scaffold__tab`, `kui-tab-scaffold__tab-icon`, `kui-tab-scaffold__tab-badge`, `kui-tab-scaffold__tab-label` on an element you write; render `
|
|
86
|
+
Never put `kui-tab-scaffold`, `kui-tab-scaffold__scenes`, `kui-tab-scaffold__scene`, `kui-tab-scaffold__bar`, `kui-tab-scaffold__tab`, `kui-tab-scaffold__tab-icon`, `kui-tab-scaffold__tab-badge`, `kui-tab-scaffold__tab-label` on an element you write; render `TabNavigator` instead (`KUI-L103`).
|
|
87
87
|
|
|
88
88
|
Everything else is internal: `kerf-ui-analyze` reports private or unknown `.kui-*` selectors (`KUI-L001`, `KUI-L010`), unknown or private tokens (`KUI-L002`, `KUI-L012`), and any application rule that restyles the component, forced dimensions included (`KUI-L019`).
|
|
89
89
|
|
|
90
90
|
## Related
|
|
91
91
|
|
|
92
92
|
- Components: [Badge](./badge.md), [AppTab](./tabs.md), [Workbench](./workbench.md).
|
|
93
|
-
- Docs: [`docs/tab-
|
|
94
|
-
- UX catalog route: `?component=tab-
|
|
93
|
+
- Docs: [`docs/tab-navigator.md`](../../docs/tab-navigator.md), [`docs/app-layouts.md#decision-matrix`](../../docs/app-layouts.md#decision-matrix).
|
|
94
|
+
- UX catalog route: `?component=tab-navigator`.
|
|
@@ -70,6 +70,7 @@ Zones (a zone is bound to JSX only through its listed prop; never assume the zon
|
|
|
70
70
|
|
|
71
71
|
- `data-token-search-text` on `the text span inside kui-token-search__editor` (`wireTokenSearchFields`): Marks the plain-text span the helper inserts when the editor is emptied.
|
|
72
72
|
- `data-empty` on `the text span inside kui-token-search__editor` (`wireTokenSearchFields`): "true" on that span while it holds no text.
|
|
73
|
+
- `data-placeholder-visible` on `the kui-token-search root` (`wireTokenSearchFields`): Tracks whether the DOM-owned editor is empty so its placeholder stays outside the editable area.
|
|
73
74
|
|
|
74
75
|
## Geometry
|
|
75
76
|
|
package/ai/components/toolbar.md
CHANGED
|
@@ -47,14 +47,14 @@ Exact prop names and types: [`@kerfjs/ui/toolbar`](../public-api-signatures-v1.m
|
|
|
47
47
|
|
|
48
48
|
- Parents: any.
|
|
49
49
|
- Contexts: `application-chrome`, `page-header`, `panel-header`, `dialog-header`.
|
|
50
|
-
- Children:
|
|
50
|
+
- Children: unrestricted.
|
|
51
51
|
- Built from: [ToolbarText](./toolbar-text.md), [ToolbarControlGroup](./toolbar-control-group.md), [Button](./wa-button.md), [PopupMenu](./popup-menu.md).
|
|
52
52
|
|
|
53
53
|
Zones (a zone is bound to JSX only through its listed prop; never assume the zone id is a prop):
|
|
54
54
|
|
|
55
|
-
- `leading` — JSX prop `leading`; accepts
|
|
56
|
-
- `center` — JSX prop `center`; accepts
|
|
57
|
-
- `trailing` — JSX prop `trailing`; accepts
|
|
55
|
+
- `leading` — JSX prop `leading`; accepts `KerfUiContent`; any number.
|
|
56
|
+
- `center` — JSX prop `center`; accepts `KerfUiContent`; any number.
|
|
57
|
+
- `trailing` — JSX prop `trailing`; accepts `KerfUiContent`; any number.
|
|
58
58
|
|
|
59
59
|
## State and wiring
|
|
60
60
|
|
|
@@ -94,10 +94,6 @@ Public tokens it reads: `--kui-color-neutral-border-normal`, `--kui-font-sans`,
|
|
|
94
94
|
|
|
95
95
|
Everything else is internal: `kerf-ui-analyze` reports private or unknown `.kui-*` selectors (`KUI-L001`, `KUI-L010`), unknown or private tokens (`KUI-L002`, `KUI-L012`), and any application rule that restyles the component, forced dimensions included (`KUI-L019`).
|
|
96
96
|
|
|
97
|
-
## Diagnostics
|
|
98
|
-
|
|
99
|
-
- `KUI-C101` (error) when a direct zone child is neither ToolbarText nor ToolbarControlGroup nor a standalone wa-button in trailing: Wrap toolbar controls in ToolbarControlGroup; only ToolbarText and ToolbarControlGroup, plus one standalone primary wa-button in trailing, are direct zone children.
|
|
100
|
-
|
|
101
97
|
## Related
|
|
102
98
|
|
|
103
99
|
- Components: [ToolbarText](./toolbar-text.md), [ToolbarControlGroup](./toolbar-control-group.md), [Button](./wa-button.md), [PopupMenu](./popup-menu.md).
|