@kerfjs/ui 5.0.0-beta.17 → 5.0.0-beta.21
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 +221 -81
- package/ai/application-ui-diagnostic-ids-v1.json +92 -0
- package/ai/application-ui-profile-sync.cjs +529 -0
- package/ai/application-ui-profile.d.mts +1 -0
- package/ai/application-ui-profile.d.ts +102 -0
- package/ai/application-ui-profile.defaults.json +41 -0
- package/ai/application-ui-profile.mjs +626 -0
- package/ai/application-ui-profile.schema.json +130 -0
- package/ai/catalog-authoring.json +25 -0
- package/ai/catalog-authoring.schema.json +61 -0
- package/ai/compile-time-contracts-v1.json +101 -0
- package/ai/compile-time-contracts-v1.schema.json +49 -0
- package/ai/component-catalog-extension-v2.d.ts +7 -0
- package/ai/component-catalog-extension-v2.schema.json +7 -0
- package/ai/component-catalog-extension.schema.json +79 -0
- package/ai/component-catalog-v2-overrides.json +326 -0
- package/ai/component-catalog-v2.d.ts +67 -0
- package/ai/component-catalog-v2.json +4441 -0
- package/ai/component-catalog-v2.schema.json +246 -0
- package/ai/component-catalog.json +649 -6
- package/ai/component-catalog.schema.json +15 -0
- package/ai/public-api-signatures-v1.md +357 -91
- package/ai/skill.md +95 -50
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/analyzer/cli.mjs +46 -0
- package/analyzer/index.d.mts +45 -0
- package/analyzer/index.mjs +743 -0
- package/analyzer/report.schema.json +66 -0
- package/dist/app-tab.d.ts +1 -1
- package/dist/app-tab.js +1 -1
- package/dist/browser/pane.js +3 -0
- package/dist/browser/sunken-panel.js +3 -0
- package/dist/catalog-resources.d.ts +34 -0
- package/dist/catalog-resources.js +22 -0
- package/dist/catalog-resources.js.map +1 -0
- package/dist/catalog.d.ts +29 -4
- package/dist/catalog.js +302 -84
- package/dist/catalog.js.map +1 -1
- package/dist/chunk-5VTB2BKP.js +35 -0
- package/dist/chunk-5VTB2BKP.js.map +1 -0
- package/dist/chunk-6WTETUZ6.js +21 -0
- package/dist/chunk-6WTETUZ6.js.map +1 -0
- package/dist/chunk-7KEUJIIC.js +218 -0
- package/dist/chunk-7KEUJIIC.js.map +1 -0
- package/dist/chunk-7L6EHUMV.js +31 -0
- package/dist/chunk-7L6EHUMV.js.map +1 -0
- package/dist/{chunk-XXMOARTH.js → chunk-AASLYRGE.js} +57 -16
- package/dist/chunk-AASLYRGE.js.map +1 -0
- package/dist/chunk-BBRXX6PF.js +108 -0
- package/dist/chunk-BBRXX6PF.js.map +1 -0
- package/dist/{chunk-6NLRBSVX.js → chunk-CN2XNTAM.js} +129 -72
- package/dist/chunk-CN2XNTAM.js.map +1 -0
- package/dist/chunk-DPDBVKNA.js +113 -0
- package/dist/chunk-DPDBVKNA.js.map +1 -0
- package/dist/chunk-DSNIYOZ3.js +114 -0
- package/dist/chunk-DSNIYOZ3.js.map +1 -0
- package/dist/chunk-ELSJX4W7.js +68 -0
- package/dist/chunk-ELSJX4W7.js.map +1 -0
- package/dist/{chunk-AHQI52QO.js → chunk-FEY65TBV.js} +6 -2
- package/dist/chunk-FEY65TBV.js.map +1 -0
- package/dist/chunk-JRKSK2HX.js +79 -0
- package/dist/chunk-JRKSK2HX.js.map +1 -0
- package/dist/chunk-K57KRAOV.js +117 -0
- package/dist/chunk-K57KRAOV.js.map +1 -0
- package/dist/chunk-LPOMRC4C.js +25 -0
- package/dist/chunk-LPOMRC4C.js.map +1 -0
- package/dist/chunk-M7JBER5U.js +41 -0
- package/dist/chunk-M7JBER5U.js.map +1 -0
- package/dist/chunk-NENBUYX5.js +79 -0
- package/dist/chunk-NENBUYX5.js.map +1 -0
- package/dist/chunk-OHU6CI22.js +83 -0
- package/dist/chunk-OHU6CI22.js.map +1 -0
- package/dist/{chunk-YGN7OMLT.js → chunk-OZWU5ZPZ.js} +2 -2
- package/dist/chunk-OZWU5ZPZ.js.map +1 -0
- package/dist/chunk-PIDTEQ3U.js +105 -0
- package/dist/chunk-PIDTEQ3U.js.map +1 -0
- package/dist/chunk-PX3YSS5C.js +32 -0
- package/dist/chunk-PX3YSS5C.js.map +1 -0
- package/dist/chunk-PZQVSDLH.js +61 -0
- package/dist/chunk-PZQVSDLH.js.map +1 -0
- package/dist/chunk-QO55FN2Y.js +20 -0
- package/dist/chunk-QO55FN2Y.js.map +1 -0
- package/dist/chunk-QQFJMRIB.js +45 -0
- package/dist/chunk-QQFJMRIB.js.map +1 -0
- package/dist/chunk-RYRIFZCT.js +58 -0
- package/dist/chunk-RYRIFZCT.js.map +1 -0
- package/dist/{chunk-7BR3DO2A.js → chunk-SRSJO5QE.js} +13 -4
- package/dist/chunk-SRSJO5QE.js.map +1 -0
- package/dist/chunk-VLYV65LK.js +38 -0
- package/dist/chunk-VLYV65LK.js.map +1 -0
- package/dist/chunk-W4CXQYSG.js +23 -0
- package/dist/chunk-W4CXQYSG.js.map +1 -0
- package/dist/{chunk-WXMGNX2Y.js → chunk-W7YD6E4N.js} +2 -2
- package/dist/chunk-W7YD6E4N.js.map +1 -0
- package/dist/{chunk-56RJXPHG.js → chunk-Y6LYKFXY.js} +1 -1
- package/dist/{chunk-56RJXPHG.js.map → chunk-Y6LYKFXY.js.map} +1 -1
- package/dist/collapsible-panel.d.ts +2 -2
- package/dist/collapsible-panel.js +47 -6
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/device-class.js +33 -5
- package/dist/device-class.js.map +1 -1
- package/dist/disclosure-arrow.js +1 -1
- package/dist/empty-state.d.ts +1 -1
- package/dist/empty-state.js +1 -1
- package/dist/floating-toolbar.d.ts +1 -1
- package/dist/floating-toolbar.js +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.js +27 -25
- package/dist/list-action-row.d.ts +1 -1
- package/dist/list-action-row.js +1 -1
- package/dist/list-header.d.ts +30 -9
- package/dist/list-header.js +1 -1
- package/dist/list-inset-control.d.ts +1 -1
- package/dist/list-inset-control.js +1 -1
- package/dist/list-inset-text.d.ts +1 -1
- package/dist/list-inset-text.js +1 -1
- package/dist/list-item.d.ts +1 -1
- package/dist/list-item.js +1 -1
- package/dist/loading-spinner.js +1 -1
- package/dist/nav-stack.d.ts +1 -1
- package/dist/nav-stack.js +1 -1
- package/dist/pane.d.ts +49 -0
- package/dist/pane.js +4 -0
- package/dist/pane.js.map +1 -0
- package/dist/panel-header.d.ts +10 -4
- package/dist/panel-header.js +1 -1
- package/dist/resizable-region.d.ts +1 -1
- package/dist/resizable-region.js +1 -1
- package/dist/segmented-control.d.ts +6 -6
- package/dist/segmented-control.js +1 -1
- package/dist/select.d.ts +11 -5
- package/dist/select.js +1 -1
- package/dist/skeleton.d.ts +1 -1
- package/dist/skeleton.js +1 -1
- package/dist/split-view.d.ts +1 -1
- package/dist/split-view.js +70 -10
- package/dist/split-view.js.map +1 -1
- package/dist/state-banner.d.ts +4 -3
- package/dist/state-banner.js +1 -1
- package/dist/styles/catalog.css +32 -6
- package/dist/styles/layout.css +2 -20
- package/dist/styles/pane.css +62 -0
- package/dist/styles/segmented-control.css +3 -7
- package/dist/styles/sunken-panel.css +18 -0
- package/dist/sunken-panel.d.ts +16 -0
- package/dist/sunken-panel.js +3 -0
- package/dist/sunken-panel.js.map +1 -0
- package/dist/tab-bar.d.ts +4 -3
- package/dist/tab-bar.js +1 -1
- package/dist/tab-scaffold.d.ts +6 -6
- package/dist/tab-scaffold.js +43 -8
- package/dist/tab-scaffold.js.map +1 -1
- package/dist/token-search-field.d.ts +25 -9
- package/dist/token-search-field.js +1 -1
- package/dist/toolbar-control-group.d.ts +10 -6
- package/dist/toolbar-control-group.js +1 -1
- package/dist/toolbar-text.d.ts +10 -11
- package/dist/toolbar-text.js +1 -1
- package/dist/toolbar.d.ts +1 -1
- package/dist/toolbar.js +1 -1
- package/dist/value-table.d.ts +2 -2
- package/dist/value-table.js +1 -1
- package/dist/wire-catalog.d.ts +31 -2
- package/dist/wire-catalog.js +203 -8
- package/dist/wire-catalog.js.map +1 -1
- package/dist/wire-nav-stack.js +22 -7
- package/dist/wire-nav-stack.js.map +1 -1
- package/dist/wire-resizable-regions.d.ts +1 -1
- package/dist/wire-resizable-regions.js +1 -1
- package/dist/wire-sidebar.js +52 -41
- package/dist/wire-sidebar.js.map +1 -1
- package/dist/wire-tab-bars.d.ts +5 -2
- package/dist/wire-tab-bars.js +1 -1
- package/dist/wire-tab-scaffold.js +9 -4
- package/dist/wire-tab-scaffold.js.map +1 -1
- package/dist/wire-token-search-fields.d.ts +12 -7
- package/dist/wire-token-search-fields.js +1 -1
- package/dist/workbench.d.ts +1 -1
- package/dist/workbench.js +56 -9
- package/dist/workbench.js.map +1 -1
- package/docs/app-layouts.md +7 -7
- package/docs/catalog.md +249 -46
- package/docs/collapsible-panel.md +38 -11
- package/docs/component-contract.md +132 -7
- package/docs/component-selection.md +79 -67
- package/docs/design/templates.md +1 -1
- package/docs/design-philosophy.md +7 -9
- package/docs/device-class.md +8 -8
- package/docs/examples/application-ui-profile.json +60 -0
- package/docs/examples/command-palette-adapter.tsx +67 -17
- package/docs/examples/component-catalog-extension-v2.json +81 -0
- package/docs/examples/component-catalog-extension.json +45 -0
- package/docs/layout.md +51 -32
- package/docs/nav-stack.md +15 -6
- package/docs/recipes.md +4 -4
- package/docs/split-view.md +3 -3
- package/docs/sunken-panel.md +43 -0
- package/docs/tab-scaffold.md +16 -7
- package/docs/type-contracts.md +99 -0
- package/docs/ui-analyzer.md +81 -0
- package/docs/ui-doctor.md +77 -0
- package/docs/ui-evaluator.md +122 -0
- package/docs/webawesome-theme.md +8 -8
- package/docs/workbench.md +18 -5
- package/doctor/cli.mjs +115 -0
- package/doctor/config.schema.json +68 -0
- package/doctor/index.d.mts +116 -0
- package/doctor/index.mjs +1256 -0
- package/doctor/report.schema.json +118 -0
- package/evaluator/cli.mjs +89 -0
- package/evaluator/index.d.mts +90 -0
- package/evaluator/index.mjs +1138 -0
- package/evaluator/report.schema.json +152 -0
- package/llms.txt +58 -15
- package/package.json +70 -10
- package/ux-demo/recipes/app-shell.tsx +206 -10
- package/ux-demo/recipes/collapsible-sidebar.tsx +167 -44
- package/ux-demo/recipes/compact-toolbar.tsx +114 -12
- package/ux-demo/recipes/composer-form.tsx +106 -18
- package/ux-demo/recipes/list-detail-dialog.tsx +144 -8
- package/ux-demo/recipes/list-workspace-states.tsx +165 -8
- package/ux-demo/recipes/loaders.ts +5 -2
- package/ux-demo/recipes/loading-inspector.tsx +124 -41
- package/ux-demo/recipes/mount-recipe.ts +27 -6
- package/ux-demo/recipes/navigation-sidebar.tsx +120 -9
- package/ux-demo/recipes/navigation-stack.tsx +61 -19
- package/ux-demo/recipes/types.ts +3 -1
- package/ux-demo/recipes/workspace-header.tsx +57 -2
- package/dist/chunk-2Z5TWHKQ.js +0 -34
- package/dist/chunk-2Z5TWHKQ.js.map +0 -1
- package/dist/chunk-37T3VNIZ.js +0 -19
- package/dist/chunk-37T3VNIZ.js.map +0 -1
- package/dist/chunk-55DATV3A.js +0 -10
- package/dist/chunk-55DATV3A.js.map +0 -1
- package/dist/chunk-5ATCDSQS.js +0 -42
- package/dist/chunk-5ATCDSQS.js.map +0 -1
- package/dist/chunk-5E2HVJ33.js +0 -10
- package/dist/chunk-5E2HVJ33.js.map +0 -1
- package/dist/chunk-6NLRBSVX.js.map +0 -1
- package/dist/chunk-7BR3DO2A.js.map +0 -1
- package/dist/chunk-7JB7VPRI.js +0 -34
- package/dist/chunk-7JB7VPRI.js.map +0 -1
- package/dist/chunk-7LDCTU7D.js +0 -134
- package/dist/chunk-7LDCTU7D.js.map +0 -1
- package/dist/chunk-AHQI52QO.js.map +0 -1
- package/dist/chunk-AQNKJRFH.js +0 -79
- package/dist/chunk-AQNKJRFH.js.map +0 -1
- package/dist/chunk-AVZHJN6C.js +0 -14
- package/dist/chunk-AVZHJN6C.js.map +0 -1
- package/dist/chunk-B24C4A6T.js +0 -22
- package/dist/chunk-B24C4A6T.js.map +0 -1
- package/dist/chunk-CH4SQ6H5.js +0 -39
- package/dist/chunk-CH4SQ6H5.js.map +0 -1
- package/dist/chunk-DAFFDO33.js +0 -14
- package/dist/chunk-DAFFDO33.js.map +0 -1
- package/dist/chunk-I7INRJO4.js +0 -17
- package/dist/chunk-I7INRJO4.js.map +0 -1
- package/dist/chunk-L4OKFDJY.js +0 -24
- package/dist/chunk-L4OKFDJY.js.map +0 -1
- package/dist/chunk-M5JRI6MN.js +0 -27
- package/dist/chunk-M5JRI6MN.js.map +0 -1
- package/dist/chunk-RNPGFQ33.js +0 -10
- package/dist/chunk-RNPGFQ33.js.map +0 -1
- package/dist/chunk-VPCTCUED.js +0 -10
- package/dist/chunk-VPCTCUED.js.map +0 -1
- package/dist/chunk-WRTAQ7BZ.js +0 -23
- package/dist/chunk-WRTAQ7BZ.js.map +0 -1
- package/dist/chunk-WVPYVDXY.js +0 -15
- package/dist/chunk-WVPYVDXY.js.map +0 -1
- package/dist/chunk-WXMGNX2Y.js.map +0 -1
- package/dist/chunk-XXMOARTH.js.map +0 -1
- package/dist/chunk-YGN7OMLT.js.map +0 -1
- package/dist/chunk-ZQQ6P4SV.js +0 -20
- package/dist/chunk-ZQQ6P4SV.js.map +0 -1
|
@@ -26,17 +26,57 @@ export function mountCommandPaletteAdapter(
|
|
|
26
26
|
const query = signal('');
|
|
27
27
|
const render = () => {
|
|
28
28
|
const needle = query.value.trim().toLocaleLowerCase();
|
|
29
|
-
const matches = commands.filter(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
29
|
+
const matches = commands.filter(
|
|
30
|
+
(command) =>
|
|
31
|
+
!needle ||
|
|
32
|
+
[command.label, ...(command.keywords ?? [])].some((value) =>
|
|
33
|
+
value.toLocaleLowerCase().includes(needle),
|
|
34
|
+
),
|
|
35
|
+
);
|
|
36
|
+
return (
|
|
37
|
+
<section
|
|
38
|
+
class="app-command-palette kui-content"
|
|
39
|
+
aria-label="Command palette"
|
|
40
|
+
>
|
|
41
|
+
<div class="kui-content-item">
|
|
42
|
+
<label for="app-command-query">Search commands</label>
|
|
43
|
+
<input
|
|
44
|
+
id="app-command-query"
|
|
45
|
+
type="search"
|
|
46
|
+
value={query.value}
|
|
47
|
+
autocomplete="off"
|
|
48
|
+
data-command-query
|
|
49
|
+
/>
|
|
50
|
+
</div>
|
|
51
|
+
<p class="kui-content-item" aria-live="polite">
|
|
52
|
+
{matches.length} matching commands
|
|
53
|
+
</p>
|
|
54
|
+
<ul class="kui-content-item" aria-label="Matching commands">
|
|
55
|
+
{matches.map((command) => (
|
|
56
|
+
<li>
|
|
57
|
+
<button
|
|
58
|
+
type="button"
|
|
59
|
+
data-action="run-command"
|
|
60
|
+
data-command-id={command.id}
|
|
61
|
+
>
|
|
62
|
+
{command.label}
|
|
63
|
+
</button>
|
|
64
|
+
</li>
|
|
65
|
+
))}
|
|
66
|
+
</ul>
|
|
67
|
+
<footer
|
|
68
|
+
class="kui-control-cluster kui-content-item"
|
|
69
|
+
aria-label="Command palette actions"
|
|
70
|
+
>
|
|
71
|
+
<button type="button" data-action="clear-query">
|
|
72
|
+
Clear search
|
|
73
|
+
</button>
|
|
74
|
+
<button type="button" data-action="close-palette">
|
|
75
|
+
Close
|
|
76
|
+
</button>
|
|
77
|
+
</footer>
|
|
78
|
+
</section>
|
|
79
|
+
);
|
|
40
80
|
};
|
|
41
81
|
|
|
42
82
|
const stopMount = mount(root, render);
|
|
@@ -52,12 +92,22 @@ export function mountCommandPaletteAdapter(
|
|
|
52
92
|
},
|
|
53
93
|
'close-palette': onClose,
|
|
54
94
|
});
|
|
55
|
-
const stopInput = delegate<HTMLInputElement>(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
95
|
+
const stopInput = delegate<HTMLInputElement>(
|
|
96
|
+
root,
|
|
97
|
+
'input',
|
|
98
|
+
'[data-command-query]',
|
|
99
|
+
(_event, input) => {
|
|
100
|
+
query.value = input.value;
|
|
101
|
+
},
|
|
102
|
+
);
|
|
103
|
+
const stopEscape = delegate(
|
|
104
|
+
root,
|
|
105
|
+
'keydown',
|
|
106
|
+
'[data-command-query]',
|
|
107
|
+
(event) => {
|
|
108
|
+
if ((event as KeyboardEvent).key === 'Escape') onClose();
|
|
109
|
+
},
|
|
110
|
+
);
|
|
61
111
|
let disposed = false;
|
|
62
112
|
return () => {
|
|
63
113
|
if (disposed) return;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../ai/component-catalog-extension-v2.schema.json",
|
|
3
|
+
"schemaVersion": 2,
|
|
4
|
+
"package": "@acme/ui",
|
|
5
|
+
"compatibility": {
|
|
6
|
+
"v1Catalog": "./component-catalog-extension.json",
|
|
7
|
+
"identity": "package:id"
|
|
8
|
+
},
|
|
9
|
+
"entries": [
|
|
10
|
+
{
|
|
11
|
+
"key": "@acme/ui:inspector",
|
|
12
|
+
"package": "@acme/ui",
|
|
13
|
+
"id": "inspector",
|
|
14
|
+
"name": "Inspector",
|
|
15
|
+
"kind": "composition",
|
|
16
|
+
"source": "application",
|
|
17
|
+
"parents": { "mode": "listed", "entries": ["@kerfjs/ui:layout"] },
|
|
18
|
+
"contexts": ["record-detail"],
|
|
19
|
+
"zones": [
|
|
20
|
+
{
|
|
21
|
+
"id": "header",
|
|
22
|
+
"accepts": ["@kerfjs/ui:panel-header"],
|
|
23
|
+
"cardinality": { "min": 1, "max": 1 },
|
|
24
|
+
"exclusiveWith": []
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "facts",
|
|
28
|
+
"accepts": ["@kerfjs/ui:value-table"],
|
|
29
|
+
"cardinality": { "min": 1, "max": 1 },
|
|
30
|
+
"exclusiveWith": []
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"children": {
|
|
34
|
+
"mode": "listed",
|
|
35
|
+
"concepts": ["@kerfjs/ui:panel-header", "@kerfjs/ui:value-table"],
|
|
36
|
+
"requiredConcepts": [
|
|
37
|
+
"@kerfjs/ui:panel-header",
|
|
38
|
+
"@kerfjs/ui:value-table"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"state": [
|
|
42
|
+
{ "id": "selected-record", "owner": "application", "required": true }
|
|
43
|
+
],
|
|
44
|
+
"wiring": { "required": false, "helpers": [], "obligations": [] },
|
|
45
|
+
"responsive": {
|
|
46
|
+
"owner": "application",
|
|
47
|
+
"behaviors": [
|
|
48
|
+
"May move between inline-end pane and dialog at the application breakpoint."
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"layout": {
|
|
52
|
+
"roles": ["inspector"],
|
|
53
|
+
"geometry": {
|
|
54
|
+
"margin": "parent",
|
|
55
|
+
"border": "child",
|
|
56
|
+
"padding": "child"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"accessibility": {
|
|
60
|
+
"obligations": ["The header names the inspector region."]
|
|
61
|
+
},
|
|
62
|
+
"boundaries": {
|
|
63
|
+
"rootClass": "acme-inspector",
|
|
64
|
+
"publicClasses": ["acme-inspector"],
|
|
65
|
+
"publicTokens": []
|
|
66
|
+
},
|
|
67
|
+
"diagnostics": [
|
|
68
|
+
{
|
|
69
|
+
"id": "KUI-C901",
|
|
70
|
+
"severity": "error",
|
|
71
|
+
"when": "the header or facts zone is absent",
|
|
72
|
+
"message": "Inspector requires exactly one header and one facts region."
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
"provenance": {
|
|
76
|
+
"selection": "docs/inspector.md",
|
|
77
|
+
"composition": "docs/inspector.md#composition-contract"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../ai/component-catalog-extension.schema.json",
|
|
3
|
+
"schemaVersion": 1,
|
|
4
|
+
"package": "@acme/ui",
|
|
5
|
+
"description": "Application-owned components composed with Kerf UI.",
|
|
6
|
+
"entries": [
|
|
7
|
+
{
|
|
8
|
+
"id": "acme-filter-chip",
|
|
9
|
+
"name": "FilterChip",
|
|
10
|
+
"kind": "component",
|
|
11
|
+
"purpose": "A removable application filter displayed inside a token-search workflow.",
|
|
12
|
+
"useWhen": [
|
|
13
|
+
"A saved application filter needs a compact visible label and remove action."
|
|
14
|
+
],
|
|
15
|
+
"avoidWhen": [
|
|
16
|
+
"The value belongs to TokenSearchField's own controlled token collection."
|
|
17
|
+
],
|
|
18
|
+
"publicClasses": ["acme-filter-chip"],
|
|
19
|
+
"publicTokens": ["--acme-filter-chip-accent"],
|
|
20
|
+
"geometry": {
|
|
21
|
+
"margin": "none",
|
|
22
|
+
"border": "self",
|
|
23
|
+
"padding": "self"
|
|
24
|
+
},
|
|
25
|
+
"documentation": "docs/filter-chip.md"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "acme-inspector",
|
|
29
|
+
"name": "Inspector",
|
|
30
|
+
"kind": "composition",
|
|
31
|
+
"purpose": "An application inspector composed from Kerf panel, content, and value primitives.",
|
|
32
|
+
"useWhen": ["A selected record needs a titled fact-and-action region."],
|
|
33
|
+
"avoidWhen": ["A ValueTable alone expresses the complete interaction."],
|
|
34
|
+
"geometry": {
|
|
35
|
+
"margin": "parent",
|
|
36
|
+
"border": "child",
|
|
37
|
+
"padding": "child",
|
|
38
|
+
"notes": [
|
|
39
|
+
"The embedding pane positions the inspector; PanelHeader, ValueTable, and action groups retain their own geometry."
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"documentation": "docs/inspector.md"
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
package/docs/layout.md
CHANGED
|
@@ -1,26 +1,39 @@
|
|
|
1
1
|
# Pane and content layout
|
|
2
2
|
|
|
3
|
-
Import `@kerfjs/ui/
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Import `Pane` from `@kerfjs/ui/pane`. Browser-aware bundlers receive its CSS
|
|
4
|
+
automatically; other consumers can import `@kerfjs/ui/pane.css`. Import
|
|
5
|
+
`@kerfjs/ui/layout.css` as well when using the related content-item and control
|
|
6
|
+
layout classes. The vocabulary deliberately describes structure rather than
|
|
7
|
+
location: the same pane can be placed anywhere.
|
|
6
8
|
|
|
7
9
|
## Anatomy
|
|
8
10
|
|
|
9
11
|
```tsx
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
<Pane
|
|
13
|
+
element="aside"
|
|
14
|
+
label="Workspace"
|
|
15
|
+
contentElement="nav"
|
|
16
|
+
contentLabel="Workspace pages"
|
|
17
|
+
separators={["inline-end"]}
|
|
18
|
+
header={<Toolbar label="Workspace" ... />}
|
|
19
|
+
footer={<Toolbar label="Actions" ... />}
|
|
20
|
+
>
|
|
13
21
|
<section>...</section>
|
|
14
22
|
<section>...</section>
|
|
15
|
-
|
|
16
|
-
<footer class="kui-pane__footer"><Toolbar label="Actions" ... /></footer>
|
|
17
|
-
</aside>
|
|
23
|
+
</Pane>
|
|
18
24
|
```
|
|
19
25
|
|
|
20
|
-
|
|
21
|
-
scrolling content area, and an optional footer. A
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
`Pane` has no padding. It reserves rows for an optional vertical header, one
|
|
27
|
+
scrolling vertical content area, and an optional footer. A header may contain a
|
|
28
|
+
top toolbar followed by secondary toolbar or status rows. A main area or dialog
|
|
29
|
+
often omits the footer; a navigation pane commonly uses all three. Fixed chrome
|
|
30
|
+
stays outside `.kui-pane__content`, which is the pane's only scroll owner.
|
|
31
|
+
|
|
32
|
+
Pass any combination of logical sides to `separators`: `block-start`,
|
|
33
|
+
`block-end`, `inline-start`, and `inline-end`. Every line is off by default and
|
|
34
|
+
each enabled side uses `--kui-pane-separator-width` (1px) and
|
|
35
|
+
`--kui-pane-separator-color` (`--kui-color-border`). Logical sides keep pane
|
|
36
|
+
boundaries correct in both left-to-right and right-to-left layouts.
|
|
24
37
|
|
|
25
38
|
`.kui-content` is a vertical stack with a 24px gap between major children.
|
|
26
39
|
Sections may contain adjacent `ListItem` rows without adding another major gap.
|
|
@@ -37,6 +50,11 @@ Use `.kui-content-item--pill` for the 22px pill radius expressed as
|
|
|
37
50
|
changing its geometry by setting `--kui-content-item-border` and
|
|
38
51
|
`--kui-content-item-background`.
|
|
39
52
|
|
|
53
|
+
Nested rounded edges stay concentric by subtracting their full inset from the
|
|
54
|
+
outer radius. For example, `SegmentedControl` places each item behind a 1px
|
|
55
|
+
control border and 1px control padding, so its default rounded-rectangle radius
|
|
56
|
+
is 10px inside the control's 12px radius.
|
|
57
|
+
|
|
40
58
|
A visible parent surface does not make every child another visible card. The
|
|
41
59
|
composer recipe keeps its form as the single surface, uses `PanelHeader` for
|
|
42
60
|
its task hierarchy, and places field and action control edges on the shared 8px
|
|
@@ -46,16 +64,17 @@ semantic status.
|
|
|
46
64
|
|
|
47
65
|
## Public roles and tokens
|
|
48
66
|
|
|
49
|
-
| Need
|
|
50
|
-
|
|
|
51
|
-
| Unpadded
|
|
52
|
-
| Scrolling pane content
|
|
53
|
-
|
|
|
54
|
-
|
|
|
55
|
-
|
|
|
56
|
-
|
|
|
57
|
-
|
|
|
58
|
-
|
|
|
67
|
+
| Need | Class | Token / default |
|
|
68
|
+
| ---------------------------------------- | ------------------------- | ------------------------------------- |
|
|
69
|
+
| Unpadded header/content/footer structure | `Pane`, `.kui-pane` | — |
|
|
70
|
+
| Scrolling pane content | `.kui-pane__content` | — |
|
|
71
|
+
| Optional logical-edge separators | `Pane.separators` | `--kui-pane-separator-width: 1px` |
|
|
72
|
+
| Major vertical rhythm | `.kui-content` | `--kui-layout-content-gap: 24px` |
|
|
73
|
+
| Self-contained child geometry | `.kui-content-item` | 8px margin + 1px border + 8px padding |
|
|
74
|
+
| Pill child | `.kui-content-item--pill` | `--kui-layout-pill-radius: 22px` |
|
|
75
|
+
| Related controls | `.kui-control-cluster` | `--kui-layout-control-gap: 8px` |
|
|
76
|
+
| Inline metadata | `.kui-inline-metadata` | `--kui-layout-metadata-gap: 4px` |
|
|
77
|
+
| Explicit scroll owner outside a pane | `.kui-scroll-owner` | `overflow: auto` |
|
|
59
78
|
|
|
60
79
|
The component layer applies the same contract to `Toolbar`, `ListHeader`,
|
|
61
80
|
`ListItem`, `PanelHeader`, `StateBanner`, `ValueTable`,
|
|
@@ -81,16 +100,16 @@ expressing exactly one relationship — pick the step by **how connected two
|
|
|
81
100
|
elements are**, not by eye. Every scalable value is `remify`-authored against the
|
|
82
101
|
fixed 16px baseline, so it delivers as `rem`.
|
|
83
102
|
|
|
84
|
-
| Value | Token
|
|
85
|
-
|
|
|
86
|
-
| 0px
|
|
87
|
-
| 4px
|
|
88
|
-
| 8px
|
|
89
|
-
| 16px
|
|
90
|
-
| 24px
|
|
103
|
+
| Value | Token | Relationship — when to use |
|
|
104
|
+
| ----- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
105
|
+
| 0px | `--kui-space-none` | No separation. The elements read as a single unit (a control and its own affordance, adjacent `ListItem` rows). |
|
|
106
|
+
| 4px | `--kui-space-2xs` | Very minor. Still one connected cluster, but readability or aesthetics demand a hair of air (inline metadata, an icon beside its label). |
|
|
107
|
+
| 8px | `--kui-space-xs` | Standard. Between elements **within a group** — the content-item padding/gutter, gaps between toolbar controls in a group. |
|
|
108
|
+
| 16px | `--kui-space-m` | Minor. Between **homogeneous groups** — two lists, two sibling sections of the same kind. |
|
|
109
|
+
| 24px | `--kui-space-l` | Major. Between **heterogeneous groups** — the `.kui-content` rhythm between major, differing regions. |
|
|
91
110
|
|
|
92
|
-
The two relationships that get confused most are 8px vs 24px: 8px is
|
|
93
|
-
group, 24px is
|
|
111
|
+
The two relationships that get confused most are 8px vs 24px: 8px is _inside_ a
|
|
112
|
+
group, 24px is _between_ major, differing regions. 16px sits between them for
|
|
94
113
|
same-kind groups.
|
|
95
114
|
|
|
96
115
|
`--kui-space-s` (12px) and `--kui-space-xl` (32px) exist but are **off the
|
package/docs/nav-stack.md
CHANGED
|
@@ -8,9 +8,9 @@ a `NavStack` with one entry**. It is one of the opt-in app layouts (see
|
|
|
8
8
|
Import the component and its companion stylesheet:
|
|
9
9
|
|
|
10
10
|
```ts
|
|
11
|
-
import { NavStack, type NavStackView } from
|
|
12
|
-
import { wireNavStack } from
|
|
13
|
-
import
|
|
11
|
+
import { NavStack, type NavStackView } from "@kerfjs/ui/nav-stack";
|
|
12
|
+
import { wireNavStack } from "@kerfjs/ui/wire-nav-stack";
|
|
13
|
+
import "@kerfjs/ui/nav-stack.css";
|
|
14
14
|
```
|
|
15
15
|
|
|
16
16
|
## State lives in the app
|
|
@@ -20,16 +20,25 @@ stack as a `signal<NavStackView[]>`, `NavStack({ views })` renders it, and
|
|
|
20
20
|
`wireNavStack` animates the transitions.
|
|
21
21
|
|
|
22
22
|
```tsx
|
|
23
|
-
const views = signal<NavStackView[]>([
|
|
23
|
+
const views = signal<NavStackView[]>([
|
|
24
|
+
{ key: "inbox", title: "Inbox", content: <InboxView /> },
|
|
25
|
+
]);
|
|
24
26
|
|
|
25
27
|
// render inside mount():
|
|
26
28
|
<NavStack id="mail" label="Mail" views={views.value} />;
|
|
27
29
|
|
|
28
30
|
// once, after first render:
|
|
29
|
-
const dispose = wireNavStack(root, {
|
|
31
|
+
const dispose = wireNavStack(root, {
|
|
32
|
+
onBack: () => {
|
|
33
|
+
views.value = views.value.slice(0, -1);
|
|
34
|
+
},
|
|
35
|
+
});
|
|
30
36
|
|
|
31
37
|
// push / pop by editing the signal:
|
|
32
|
-
views.value = [
|
|
38
|
+
views.value = [
|
|
39
|
+
...views.value,
|
|
40
|
+
{ key: id, title: "Message", content: <MessageView id={id} /> },
|
|
41
|
+
];
|
|
33
42
|
```
|
|
34
43
|
|
|
35
44
|
`NavStack` renders every entry stacked, the last one active and the rest kept
|
package/docs/recipes.md
CHANGED
|
@@ -14,12 +14,12 @@ the public `onCommit` callback, retains every disposer, and returns one
|
|
|
14
14
|
idempotent disposer:
|
|
15
15
|
|
|
16
16
|
```ts
|
|
17
|
-
import { createRecipe } from
|
|
18
|
-
import { mountRecipe } from
|
|
17
|
+
import { createRecipe } from "./navigation-sidebar.js";
|
|
18
|
+
import { mountRecipe } from "./mount-recipe.js";
|
|
19
19
|
|
|
20
|
-
const root = document.querySelector<HTMLElement>(
|
|
20
|
+
const root = document.querySelector<HTMLElement>("#navigation")!;
|
|
21
21
|
const stopRecipe = mountRecipe(root, createRecipe(announce));
|
|
22
|
-
window.addEventListener(
|
|
22
|
+
window.addEventListener("pagehide", stopRecipe, { once: true });
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
The adapter is delivered as reference source, not a new package runtime export.
|
package/docs/split-view.md
CHANGED
|
@@ -6,9 +6,9 @@ on compact ones. One of the opt-in app layouts (see
|
|
|
6
6
|
[`../../docs/23-app-layouts.md`](../../docs/23-app-layouts.md)).
|
|
7
7
|
|
|
8
8
|
```ts
|
|
9
|
-
import { SplitView } from
|
|
10
|
-
import { deviceClass } from
|
|
11
|
-
import
|
|
9
|
+
import { SplitView } from "@kerfjs/ui/split-view";
|
|
10
|
+
import { deviceClass } from "@kerfjs/ui/device-class";
|
|
11
|
+
import "@kerfjs/ui/split-view.css";
|
|
12
12
|
// plus nav-stack.css when the compact path is reachable, and
|
|
13
13
|
// wireResizableRegions / wireNavStack for the interactive behavior.
|
|
14
14
|
```
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# SunkenPanel
|
|
2
|
+
|
|
3
|
+
`SunkenPanel` is a visually lowered application surface with one compact inset
|
|
4
|
+
and a vertical content stack. Use it for a main work area or nested panel whose
|
|
5
|
+
background should sit behind ordinary content, such as the primary stage in an
|
|
6
|
+
issue tracker or component catalog.
|
|
7
|
+
|
|
8
|
+
```tsx
|
|
9
|
+
import { SunkenPanel } from '@kerfjs/ui/sunken-panel';
|
|
10
|
+
|
|
11
|
+
<SunkenPanel ariaLabel="Release workspace">
|
|
12
|
+
<ReleaseSummary />
|
|
13
|
+
<ReleaseChecks />
|
|
14
|
+
</SunkenPanel>;
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Ownership
|
|
18
|
+
|
|
19
|
+
The root owns its lowered background, 8px padding, and 8px vertical gap.
|
|
20
|
+
Children own their borders and internal geometry. The application owns child
|
|
21
|
+
order, responsive placement, and scrolling; `SunkenPanel` deliberately does not
|
|
22
|
+
create another scroll container.
|
|
23
|
+
|
|
24
|
+
Use `ariaLabel` only when the surface is a distinct region people need to find
|
|
25
|
+
by name. With a label, the root receives `role="region"`; without one it remains
|
|
26
|
+
a non-landmark grouping.
|
|
27
|
+
|
|
28
|
+
Do not use `SunkenPanel` merely to add padding, as a substitute for pane
|
|
29
|
+
header/content/footer anatomy, or around a child that already owns the same
|
|
30
|
+
outer surface.
|
|
31
|
+
|
|
32
|
+
## Public styling boundary
|
|
33
|
+
|
|
34
|
+
Override the public properties at the composition boundary:
|
|
35
|
+
|
|
36
|
+
- `--kui-sunken-panel-background`
|
|
37
|
+
- `--kui-sunken-panel-foreground`
|
|
38
|
+
- `--kui-sunken-panel-padding`
|
|
39
|
+
- `--kui-sunken-panel-gap`
|
|
40
|
+
- `--kui-sunken-panel-radius`
|
|
41
|
+
|
|
42
|
+
The public root class is `.kui-sunken-panel`. Prefer the properties above over
|
|
43
|
+
styling descendants.
|
package/docs/tab-scaffold.md
CHANGED
|
@@ -7,9 +7,9 @@ opt-in app layouts (see [`../../docs/23-app-layouts.md`](../../docs/23-app-layou
|
|
|
7
7
|
It is distinct from `TabBar` (document-oriented, reorderable strips).
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
|
-
import { TabScaffold } from
|
|
11
|
-
import { wireTabScaffold } from
|
|
12
|
-
import
|
|
10
|
+
import { TabScaffold } from "@kerfjs/ui/tab-scaffold";
|
|
11
|
+
import { wireTabScaffold } from "@kerfjs/ui/wire-tab-scaffold";
|
|
12
|
+
import "@kerfjs/ui/tab-scaffold.css";
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Controlled selection
|
|
@@ -19,20 +19,29 @@ The app owns the active tab (a signal); `TabScaffold` renders every tab's scene
|
|
|
19
19
|
clicks.
|
|
20
20
|
|
|
21
21
|
```tsx
|
|
22
|
-
const active = signal(
|
|
22
|
+
const active = signal("home");
|
|
23
23
|
|
|
24
24
|
<TabScaffold
|
|
25
25
|
id="app"
|
|
26
26
|
label="Sections"
|
|
27
27
|
active={active.value}
|
|
28
28
|
tabs={[
|
|
29
|
-
{ id:
|
|
30
|
-
{
|
|
29
|
+
{ id: "home", label: "Home", icon: <HomeIcon />, content: <HomeStack /> },
|
|
30
|
+
{
|
|
31
|
+
id: "search",
|
|
32
|
+
label: "Search",
|
|
33
|
+
icon: <SearchIcon />,
|
|
34
|
+
content: <SearchStack />,
|
|
35
|
+
},
|
|
31
36
|
]}
|
|
32
37
|
/>;
|
|
33
38
|
|
|
34
39
|
// once, after first render:
|
|
35
|
-
const dispose = wireTabScaffold(root, {
|
|
40
|
+
const dispose = wireTabScaffold(root, {
|
|
41
|
+
onSelect: (id) => {
|
|
42
|
+
active.value = id;
|
|
43
|
+
},
|
|
44
|
+
});
|
|
36
45
|
```
|
|
37
46
|
|
|
38
47
|
Each `TabScaffoldTab` has an `id`, `label`, optional `icon`, and `content`. The
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Compile-time contracts
|
|
2
|
+
|
|
3
|
+
Kerf UI rejects invalid integrations at compile time only when TypeScript can
|
|
4
|
+
prove the relationship from one call. The versioned
|
|
5
|
+
[`compile-time-contracts-v1.json`](../ai/compile-time-contracts-v1.json)
|
|
6
|
+
artifact names those guarantees with stable `KUI-T###` ids. Its source fixture
|
|
7
|
+
is compiled twice: against `src/` and against declarations extracted from the
|
|
8
|
+
actual `npm pack` tarball. `npm run check:catalog` also verifies that every
|
|
9
|
+
contract still points to a real catalog entry/import and a symbol in the emitted
|
|
10
|
+
public-signature artifact.
|
|
11
|
+
|
|
12
|
+
## Strengthened contracts
|
|
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` | `PanelHeader.summaryId` cannot exist without rendered `summary` content. |
|
|
23
|
+
| `KUI-T008` | `ToolbarText.maxLines` requires `wrap: true`; it is never silently ignored in typed code. |
|
|
24
|
+
| `KUI-T009` | A literal `TabScaffold.active` id belongs to its literal `tabs`. |
|
|
25
|
+
| `KUI-T010` | Adjacent-token keyboard removal requires `onRemoveToken`; disabling removal rejects the now-meaningless callback. |
|
|
26
|
+
| `KUI-T011` | Finite public variants have named exported union types, including tab activation, banner urgency, and all ToolbarControlGroup presentation axes. |
|
|
27
|
+
|
|
28
|
+
Literal identity inference is intentionally additive for dynamic applications.
|
|
29
|
+
When choices or ids arrive at runtime and the state signal is correctly typed as
|
|
30
|
+
`string`, widen the component explicitly:
|
|
31
|
+
|
|
32
|
+
```tsx
|
|
33
|
+
<Select<string> value={loadedValue.value} choices={loadedChoices.value} ... />
|
|
34
|
+
<SegmentedControl<string> value={mode.value} choices={loadedModes.value} ... />
|
|
35
|
+
<TabScaffold<string> active={active.value} tabs={loadedTabs.value} ... />
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The widening is an honest statement that TypeScript cannot know the runtime
|
|
39
|
+
dataset. Do not cast a known literal typo merely to bypass the relationship.
|
|
40
|
+
|
|
41
|
+
## Complete public-surface audit
|
|
42
|
+
|
|
43
|
+
The following existing contracts were already exact and remain covered by the
|
|
44
|
+
ordinary source/type gates:
|
|
45
|
+
|
|
46
|
+
- required identity or accessible-name inputs on `AppTab`, `FloatingToolbar`,
|
|
47
|
+
`NavStack`, `SplitView`, `Workbench`, `TabBar`, `ResizableRegion`,
|
|
48
|
+
`SegmentedControl`, `TokenSearchField`, `PanelHeader`, and `ValueTable`;
|
|
49
|
+
- finite variants exported or represented as literal props on `DisclosureArrow`,
|
|
50
|
+
`FloatingToolbar`, `Pane`, `ResizableRegion`, `SegmentedControl`, `StateBanner`,
|
|
51
|
+
`ToolbarText`, `CollapsiblePanel`, `Catalog`, and the wire helpers;
|
|
52
|
+
- required controlled-state callbacks on `wireResizableRegions`, `wireTabBars`,
|
|
53
|
+
and `wireTabScaffold`;
|
|
54
|
+
- mutually exclusive count/badge metadata on `ListHeader`; and
|
|
55
|
+
- protected application metadata boundaries on `AppTab`, `ListItem`,
|
|
56
|
+
`ListActionRow`, `ListHeader`, `Pane`, `CatalogExample`, and
|
|
57
|
+
`CatalogExampleStack`.
|
|
58
|
+
|
|
59
|
+
The remaining components (`LucideIcon`, `DisclosureArrow`, `Toolbar`,
|
|
60
|
+
`ToolbarControlGroup`, `ListInsetControl`, `ListInsetText`, `LoadingSpinner`,
|
|
61
|
+
`Skeleton`, `SunkenPanel`, `EmptyState`, `StateBanner`, `ValueTableRow`, and the
|
|
62
|
+
pure helpers) have independent props with no further conditional invalid state
|
|
63
|
+
that TypeScript can truthfully remove. Optional labels on decorative icons and
|
|
64
|
+
unnamed non-landmark surfaces are intentional variants, not missing contracts.
|
|
65
|
+
|
|
66
|
+
## Boundaries TypeScript cannot prove
|
|
67
|
+
|
|
68
|
+
Types do not claim to validate:
|
|
69
|
+
|
|
70
|
+
- the contents of `SafeHtml` slots (for example, “only AppTab children” or “no
|
|
71
|
+
interactive descendants”);
|
|
72
|
+
- nonempty arrays, unique ids, numeric min/max ordering, or a controlled value
|
|
73
|
+
loaded from dynamic data;
|
|
74
|
+
- equality between ids rendered in separate calls, elements discovered later in
|
|
75
|
+
the DOM, or an ARIA relationship's live target;
|
|
76
|
+
- that a caller retained and invoked a wiring disposer; or
|
|
77
|
+
- CSS class/token use inside arbitrary strings.
|
|
78
|
+
|
|
79
|
+
Those remain catalog `KUI-C###` diagnostics, runtime filtering/guards, lint or
|
|
80
|
+
browser assertions. Encoding them as permissive-looking TypeScript brands would
|
|
81
|
+
move errors into casts without making the integration safer.
|
|
82
|
+
|
|
83
|
+
## Migration from the earlier declarations
|
|
84
|
+
|
|
85
|
+
- Add `actionLabel` and `actionIcon` to a non-toggle `ListHeader` action. For a
|
|
86
|
+
disclosure, set literal `toggle: true`, provide `action` and controlled
|
|
87
|
+
`expanded`, and remove trailing-action-only props.
|
|
88
|
+
- Give every `Select` either `label` or `ariaLabel`. Use an explicit `<string>`
|
|
89
|
+
generic only for genuinely dynamic choice data.
|
|
90
|
+
- Put `expanded`/expand-action props behind `collapsible: true`.
|
|
91
|
+
- Replace `wireTokenSearchFields({ keyboard: true })` with either
|
|
92
|
+
`{ keyboard: { onRemoveToken } }` or
|
|
93
|
+
`{ keyboard: { removeAdjacentToken: false } }` when only caret navigation is
|
|
94
|
+
wanted.
|
|
95
|
+
- Remove orphaned `summaryId`, or render the matching `summary`; add
|
|
96
|
+
`wrap: true` anywhere `ToolbarText.maxLines` is used.
|
|
97
|
+
|
|
98
|
+
JavaScript runtime behavior remains defensive for previously emitted calls, but
|
|
99
|
+
new TypeScript builds report these invalid or ignored combinations.
|