@kerfjs/ui 5.0.0-beta.61 → 5.0.0-beta.63
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 +4 -0
- package/ai/component-catalog-extension.schema.json +13 -0
- package/ai/component-catalog.json +20 -7
- package/ai/component-composition.json +17 -3
- package/ai/components/list-item.md +1 -1
- package/ai/components/pane.md +3 -2
- package/ai/components/select.md +1 -0
- package/ai/components/toolbar-text.md +2 -1
- package/ai/components/workbench.md +3 -2
- package/ai/public-api-signatures-v1.md +162 -48
- package/ai/skill.md +11 -5
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/analyzer/index.mjs +3 -2
- package/catalog-projection-cli.mjs +96 -0
- package/catalog-projection.d.mts +55 -0
- package/catalog-projection.mjs +62 -0
- package/dist/browser/catalog.js +1 -1
- package/dist/browser/collapsible-panel.js +2 -0
- package/dist/browser/nav-stack.js +1 -0
- package/dist/browser/split-view.js +1 -0
- package/dist/browser/toolbar-control-group.js +1 -0
- package/dist/browser/workbench.js +1 -0
- package/dist/catalog-resources.d.ts +1 -1
- package/dist/catalog.d.ts +1 -1
- package/dist/catalog.js +11 -10
- package/dist/catalog.js.map +1 -1
- package/dist/chip.d.ts +9 -3
- package/dist/chip.js +1 -1
- package/dist/{chunk-EZVNC4J6.js → chunk-3BYFWTP3.js} +7 -3
- package/dist/chunk-3BYFWTP3.js.map +1 -0
- package/dist/{chunk-5Q3N6EV7.js → chunk-5IJ6UGNZ.js} +3 -3
- package/dist/{chunk-5Q3N6EV7.js.map → chunk-5IJ6UGNZ.js.map} +1 -1
- package/dist/chunk-7AKGPBCC.js +76 -0
- package/dist/chunk-7AKGPBCC.js.map +1 -0
- package/dist/{chunk-KROD7KZK.js → chunk-AUVG54KC.js} +2 -2
- package/dist/{chunk-KROD7KZK.js.map → chunk-AUVG54KC.js.map} +1 -1
- package/dist/{chunk-AUKT3KMG.js → chunk-CQHN45XR.js} +17 -2
- package/dist/chunk-CQHN45XR.js.map +1 -0
- package/dist/{chunk-SWVW56CV.js → chunk-EN4LDR5Y.js} +2 -2
- package/dist/{chunk-SWVW56CV.js.map → chunk-EN4LDR5Y.js.map} +1 -1
- package/dist/{chunk-TEYARRAK.js → chunk-F7OCOBTG.js} +5 -2
- package/dist/chunk-F7OCOBTG.js.map +1 -0
- package/dist/{chunk-5PESG2VP.js → chunk-HXCMWANP.js} +6 -5
- package/dist/chunk-HXCMWANP.js.map +1 -0
- package/dist/{chunk-NYL63PSD.js → chunk-IA4D5XNT.js} +61 -10
- package/dist/chunk-IA4D5XNT.js.map +1 -0
- package/dist/{chunk-F4QMLOXJ.js → chunk-IAOAZUOO.js} +2 -2
- package/dist/{chunk-F4QMLOXJ.js.map → chunk-IAOAZUOO.js.map} +1 -1
- package/dist/{chunk-Y74NWGQW.js → chunk-KFYANKJI.js} +66 -22
- package/dist/chunk-KFYANKJI.js.map +1 -0
- package/dist/chunk-MOSIE4Z2.js +51 -0
- package/dist/chunk-MOSIE4Z2.js.map +1 -0
- package/dist/{chunk-7JUBXOIV.js → chunk-NXWE5S57.js} +25 -6
- package/dist/chunk-NXWE5S57.js.map +1 -0
- package/dist/{chunk-NNMLEDMD.js → chunk-OBAFAH5B.js} +36 -8
- package/dist/chunk-OBAFAH5B.js.map +1 -0
- package/dist/{chunk-A3CKOW2R.js → chunk-R75GGNWY.js} +123 -20
- package/dist/chunk-R75GGNWY.js.map +1 -0
- package/dist/chunk-RGS4WX2M.js +44 -0
- package/dist/chunk-RGS4WX2M.js.map +1 -0
- package/dist/{chunk-N3GKMPDW.js → chunk-RKTTF3L4.js} +3 -1
- package/dist/chunk-RKTTF3L4.js.map +1 -0
- package/dist/{chunk-RRB26JRJ.js → chunk-RTJNJTG3.js} +2 -2
- package/dist/{chunk-RRB26JRJ.js.map → chunk-RTJNJTG3.js.map} +1 -1
- package/dist/{chunk-EAC4CDY7.js → chunk-SMZGAPCU.js} +15 -2
- package/dist/chunk-SMZGAPCU.js.map +1 -0
- package/dist/{chunk-C4OYOKWX.js → chunk-UA6JW52D.js} +36 -2
- package/dist/chunk-UA6JW52D.js.map +1 -0
- package/dist/{chunk-3SXMEK3B.js → chunk-V3DX3K65.js} +1 -1
- package/dist/chunk-V3DX3K65.js.map +1 -0
- package/dist/{chunk-6ZXOQEAN.js → chunk-WF75U3V4.js} +7 -1
- package/dist/chunk-WF75U3V4.js.map +1 -0
- package/dist/{chunk-VCBTX62E.js → chunk-ZRWXFDDS.js} +2 -2
- package/dist/chunk-ZRWXFDDS.js.map +1 -0
- package/dist/collapsible-panel.d.ts +18 -7
- package/dist/collapsible-panel.js +19 -3
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/content-item.d.ts +36 -5
- package/dist/content-item.js +1 -1
- package/dist/disclosure-arrow.js +2 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +22 -22
- package/dist/list-action-row.js +1 -1
- package/dist/list-header.js +1 -1
- package/dist/list-item.js +1 -1
- package/dist/lucide-icon.d.ts +5 -2
- package/dist/lucide-icon.js +2 -1
- package/dist/nav-stack.d.ts +3 -1
- package/dist/nav-stack.js +2 -1
- package/dist/pane.d.ts +10 -4
- package/dist/pane.js +1 -1
- package/dist/{panel-toolbar-DqwtBxQL.d.ts → panel-toolbar-DDKh4uKd.d.ts} +11 -2
- package/dist/popup-menu-register.js +38 -1
- package/dist/popup-menu-register.js.map +1 -1
- package/dist/popup-menu.d.ts +2 -2
- package/dist/popup-menu.js +1 -1
- package/dist/select.d.ts +2 -0
- package/dist/select.js +1 -1
- package/dist/split-view.d.ts +1 -1
- package/dist/split-view.js +2 -1
- package/dist/split-view.js.map +1 -1
- package/dist/styles/app-tab.css +84 -0
- package/dist/styles/chip.css +14 -0
- package/dist/styles/content-item.css +36 -0
- package/dist/styles/list-action-row.css +4 -3
- package/dist/styles/list-header.css +4 -3
- package/dist/styles/list-item.css +21 -11
- package/dist/styles/lucide-icon.css +5 -0
- package/dist/styles/nav-stack.css +13 -0
- package/dist/styles/pane.css +36 -2
- package/dist/styles/popup-menu.css +15 -10
- package/dist/styles/resizable-region.css +9 -0
- package/dist/styles/select.css +26 -0
- package/dist/styles/split-view.css +6 -0
- package/dist/styles/sunken-panel.css +7 -0
- package/dist/styles/tab-bar.css +3 -0
- package/dist/styles/tab-scaffold.css +13 -0
- package/dist/styles/text.css +29 -0
- package/dist/styles/token-search-field.css +29 -6
- package/dist/styles/toolbar-control-group.css +35 -0
- package/dist/styles/toolbar-text.css +15 -6
- package/dist/styles/toolbar.css +7 -0
- package/dist/styles/workbench.css +260 -90
- package/dist/sunken-panel.d.ts +6 -1
- package/dist/sunken-panel.js +1 -1
- package/dist/tab-bar.d.ts +6 -2
- package/dist/tab-bar.js +1 -1
- package/dist/tab-scaffold.d.ts +3 -0
- package/dist/tab-scaffold.js +1 -0
- package/dist/tab-scaffold.js.map +1 -1
- package/dist/text.d.ts +14 -3
- package/dist/text.js +1 -1
- package/dist/token-search-field.js +2 -1
- package/dist/toolbar-control-group.d.ts +5 -1
- package/dist/toolbar-control-group.js +2 -1
- package/dist/toolbar-text.d.ts +1 -1
- package/dist/toolbar-text.js +1 -1
- package/dist/toolbar.d.ts +7 -4
- package/dist/toolbar.js +1 -1
- package/dist/wire-catalog.js +1 -1
- package/dist/wire-content-items.d.ts +9 -0
- package/dist/wire-content-items.js +62 -0
- package/dist/wire-content-items.js.map +1 -0
- package/dist/wire-tab-bars.js +1 -1
- package/dist/wire-token-search-fields.js +2 -1
- package/dist/wire-workbench.d.ts +7 -0
- package/dist/wire-workbench.js +1 -1
- package/dist/workbench.d.ts +24 -8
- package/dist/workbench.js +2 -1
- package/docs/accessibility.md +21 -5
- package/docs/catalog.md +36 -0
- package/docs/collapsible-panel.md +12 -4
- package/docs/component-contract.md +10 -4
- package/docs/component-selection.md +65 -15
- package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -1
- package/docs/design/templates/toolbar/title-and-actions.svg +1 -1
- package/docs/design/templates/toolbar-dark.svg +1 -1
- package/docs/design/templates/toolbar.svg +1 -1
- package/docs/examples/component-catalog-extension.json +6 -0
- package/docs/layout.md +61 -3
- package/docs/nav-stack.md +5 -0
- package/docs/split-view.md +5 -0
- package/docs/sunken-panel.md +30 -1
- package/docs/tab-scaffold.md +5 -0
- package/docs/ui-analyzer.md +4 -0
- package/docs/webawesome-theme.md +36 -6
- package/docs/workbench.md +60 -14
- package/llms.txt +12 -4
- package/package.json +16 -2
- package/scripts/component-catalog-extension-validation.mjs +28 -0
- package/dist/chunk-3SXMEK3B.js.map +0 -1
- package/dist/chunk-4R777DUZ.js +0 -34
- package/dist/chunk-4R777DUZ.js.map +0 -1
- package/dist/chunk-5PESG2VP.js.map +0 -1
- package/dist/chunk-6ZXOQEAN.js.map +0 -1
- package/dist/chunk-7JUBXOIV.js.map +0 -1
- package/dist/chunk-A3CKOW2R.js.map +0 -1
- package/dist/chunk-AUKT3KMG.js.map +0 -1
- package/dist/chunk-C4OYOKWX.js.map +0 -1
- package/dist/chunk-EAC4CDY7.js.map +0 -1
- package/dist/chunk-EZVNC4J6.js.map +0 -1
- package/dist/chunk-MA73TA6D.js +0 -42
- package/dist/chunk-MA73TA6D.js.map +0 -1
- package/dist/chunk-MERWRTBG.js +0 -45
- package/dist/chunk-MERWRTBG.js.map +0 -1
- package/dist/chunk-N3GKMPDW.js.map +0 -1
- package/dist/chunk-NNMLEDMD.js.map +0 -1
- package/dist/chunk-NYL63PSD.js.map +0 -1
- package/dist/chunk-TEYARRAK.js.map +0 -1
- package/dist/chunk-VCBTX62E.js.map +0 -1
- package/dist/chunk-Y74NWGQW.js.map +0 -1
|
@@ -60,6 +60,10 @@ interface ToolbarControlGroupProps {
|
|
|
60
60
|
relocateOnCollapse?: boolean;
|
|
61
61
|
/** Add contrast behind photo-backed avatar content. */
|
|
62
62
|
scrim?: boolean;
|
|
63
|
+
/** Block the group's controls and show a spinner without changing its dimensions. */
|
|
64
|
+
busy?: boolean;
|
|
65
|
+
/** Announced status while busy; defaults to “Working”. */
|
|
66
|
+
busyLabel?: string;
|
|
63
67
|
/**
|
|
64
68
|
* Avatar image URL. A single-control group paints it on the group; a
|
|
65
69
|
* multi-control group paints it only on the pressed selection highlight.
|
|
@@ -68,6 +72,6 @@ interface ToolbarControlGroupProps {
|
|
|
68
72
|
/** Native named-slot assignment when composed inside a web component. */
|
|
69
73
|
slot?: string;
|
|
70
74
|
}
|
|
71
|
-
declare function ToolbarControlGroup({ children, label, className, expanded, single, appearance, tone, buttonAppearance, shape, size, density, content, focusRing, selectedChrome, selectedTone, nestedDropdown, menuInset, overflow, visibility, relocateOnCollapse, scrim, avatarImage, slot, }: ToolbarControlGroupProps): kerfjs.SafeHtml;
|
|
75
|
+
declare function ToolbarControlGroup({ children, label, className, expanded, single, appearance, tone, buttonAppearance, shape, size, density, content, focusRing, selectedChrome, selectedTone, nestedDropdown, menuInset, overflow, visibility, relocateOnCollapse, scrim, busy, busyLabel, avatarImage, slot, }: ToolbarControlGroupProps): kerfjs.SafeHtml;
|
|
72
76
|
|
|
73
77
|
export { ToolbarActionLink, type ToolbarActionLinkProps, ToolbarControlGroup, type ToolbarControlGroupAppearance, type ToolbarControlGroupButtonAppearance, type ToolbarControlGroupContent, type ToolbarControlGroupDensity, type ToolbarControlGroupFocusRing, type ToolbarControlGroupMenuInset, type ToolbarControlGroupOverflow, type ToolbarControlGroupProps, type ToolbarControlGroupSelectedChrome, type ToolbarControlGroupSelectedTone, type ToolbarControlGroupShape, type ToolbarControlGroupSize, type ToolbarControlGroupTone, type ToolbarControlGroupVisibility };
|
package/dist/toolbar-text.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as kerfjs from 'kerfjs';
|
|
2
2
|
|
|
3
|
-
type ToolbarTextSize = 'xlarge' | 'large' | 'default' | 'small' | 'xsmall';
|
|
3
|
+
type ToolbarTextSize = 'xlarge' | 'xlarge-fixed' | 'large' | 'default' | 'small' | 'xsmall';
|
|
4
4
|
/** ARIA heading level for a title exposed as a heading landmark. */
|
|
5
5
|
type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
|
6
6
|
interface ToolbarTextBaseProps {
|
package/dist/toolbar-text.js
CHANGED
package/dist/toolbar.d.ts
CHANGED
|
@@ -3,11 +3,14 @@ import { PaneSeparatorSide } from './pane.js';
|
|
|
3
3
|
import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
|
|
4
4
|
import { S as Sides } from './sides-BPSWde0A.js';
|
|
5
5
|
|
|
6
|
+
type ToolbarPosition = 'header' | 'footer';
|
|
6
7
|
interface ToolbarProps {
|
|
7
8
|
leading?: KerfUiContent;
|
|
8
9
|
center?: KerfUiContent;
|
|
9
10
|
trailing?: KerfUiContent;
|
|
10
11
|
label?: string;
|
|
12
|
+
/** Use footer semantics for a bottom toolbar; defaults to header. */
|
|
13
|
+
position?: ToolbarPosition;
|
|
11
14
|
/**
|
|
12
15
|
* Physical divider edges in canonical top/right/bottom/left order, drawn
|
|
13
16
|
* always. Defaults to none: a toolbar pinned over or under scrolling content
|
|
@@ -17,8 +20,8 @@ interface ToolbarProps {
|
|
|
17
20
|
* then draws its facing side the same way.
|
|
18
21
|
*/
|
|
19
22
|
dividerSides?: Sides;
|
|
20
|
-
/**
|
|
21
|
-
centerAlign?: 'center' | 'stretch';
|
|
23
|
+
/** `balanced` gives both side zones equal tracks, centering the middle zone on the toolbar even if only one side has controls. */
|
|
24
|
+
centerAlign?: 'center' | 'stretch' | 'balanced';
|
|
22
25
|
/**
|
|
23
26
|
* Component-owned responsive layout; applications choose the policy rather
|
|
24
27
|
* than restyling toolbar internals. Under every policy the trailing zone
|
|
@@ -57,6 +60,6 @@ interface ToolbarProps {
|
|
|
57
60
|
* toolbar) forwards, so the app configures that toolbar instead of styling it.
|
|
58
61
|
*/
|
|
59
62
|
type ToolbarConfig = Pick<ToolbarProps, 'dividerSides' | 'centerAlign' | 'responsive' | 'responsiveAt' | 'safeAreaEdges'>;
|
|
60
|
-
declare function Toolbar({ leading, center, trailing, label, dividerSides, centerAlign, responsive, responsiveAt, safeAreaEdges, className, slot, }: ToolbarProps): kerfjs.SafeHtml;
|
|
63
|
+
declare function Toolbar({ leading, center, trailing, label, position, dividerSides, centerAlign, responsive, responsiveAt, safeAreaEdges, className, slot, }: ToolbarProps): kerfjs.SafeHtml;
|
|
61
64
|
|
|
62
|
-
export { Sides, Toolbar, type ToolbarConfig, type ToolbarProps };
|
|
65
|
+
export { Sides, Toolbar, type ToolbarConfig, type ToolbarPosition, type ToolbarProps };
|
package/dist/toolbar.js
CHANGED
package/dist/wire-catalog.js
CHANGED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Give interactive ContentItems native-like Enter/Space activation with one
|
|
3
|
+
* delegated listener pair. Space activates on release and is cancelled if
|
|
4
|
+
* focus moves; the item's own `data-action` still goes through the app's
|
|
5
|
+
* ordinary delegated click handler. Returns a disposer.
|
|
6
|
+
*/
|
|
7
|
+
declare function wireContentItems(root: HTMLElement): () => void;
|
|
8
|
+
|
|
9
|
+
export { wireContentItems };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// src/wire-content-items.ts
|
|
2
|
+
var ITEM_SELECTOR = '[data-component="content-item"][data-interactive="true"]';
|
|
3
|
+
var NESTED_CONTROL_SELECTOR = 'button, a[href], input, select, textarea, [contenteditable="true"], [role="button"]';
|
|
4
|
+
function actionItem(root, target) {
|
|
5
|
+
if (!(target instanceof Element)) return null;
|
|
6
|
+
const item = target.closest(ITEM_SELECTOR);
|
|
7
|
+
if (!item || !root.contains(item) || item.dataset.disabled === "true")
|
|
8
|
+
return null;
|
|
9
|
+
const nested = target.closest(NESTED_CONTROL_SELECTOR);
|
|
10
|
+
if (nested && nested !== item && item.contains(nested)) return null;
|
|
11
|
+
return item;
|
|
12
|
+
}
|
|
13
|
+
function wireContentItems(root) {
|
|
14
|
+
let pendingSpace = null;
|
|
15
|
+
const clearSpace = () => {
|
|
16
|
+
pendingSpace?.removeAttribute("data-kui-pressed");
|
|
17
|
+
pendingSpace = null;
|
|
18
|
+
};
|
|
19
|
+
const keydown = (event) => {
|
|
20
|
+
if (event.defaultPrevented || event.altKey || event.ctrlKey || event.metaKey)
|
|
21
|
+
return;
|
|
22
|
+
const item = actionItem(root, event.target);
|
|
23
|
+
if (!item) return;
|
|
24
|
+
if (event.key === "Enter") {
|
|
25
|
+
event.preventDefault();
|
|
26
|
+
item.click();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (event.key === " " || event.key === "Spacebar") {
|
|
30
|
+
event.preventDefault();
|
|
31
|
+
if (event.repeat) return;
|
|
32
|
+
clearSpace();
|
|
33
|
+
pendingSpace = item;
|
|
34
|
+
item.setAttribute("data-kui-pressed", "true");
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
const keyup = (event) => {
|
|
38
|
+
if (event.key !== " " && event.key !== "Spacebar") return;
|
|
39
|
+
const item = pendingSpace;
|
|
40
|
+
if (!item) return;
|
|
41
|
+
event.preventDefault();
|
|
42
|
+
clearSpace();
|
|
43
|
+
if (item === actionItem(root, event.target) && item.ownerDocument.activeElement === item)
|
|
44
|
+
item.click();
|
|
45
|
+
};
|
|
46
|
+
const focusout = (event) => {
|
|
47
|
+
if (event.target === pendingSpace) clearSpace();
|
|
48
|
+
};
|
|
49
|
+
root.addEventListener("keydown", keydown);
|
|
50
|
+
root.addEventListener("keyup", keyup);
|
|
51
|
+
root.addEventListener("focusout", focusout);
|
|
52
|
+
return () => {
|
|
53
|
+
clearSpace();
|
|
54
|
+
root.removeEventListener("keydown", keydown);
|
|
55
|
+
root.removeEventListener("keyup", keyup);
|
|
56
|
+
root.removeEventListener("focusout", focusout);
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { wireContentItems };
|
|
61
|
+
|
|
62
|
+
//# sourceMappingURL=wire-content-items.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/wire-content-items.ts"],"names":[],"mappings":"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","file":"wire-content-items.js","sourcesContent":["const ITEM_SELECTOR =\n '[data-component=\"content-item\"][data-interactive=\"true\"]';\nconst NESTED_CONTROL_SELECTOR =\n 'button, a[href], input, select, textarea, [contenteditable=\"true\"], [role=\"button\"]';\n\nfunction actionItem(root: HTMLElement, target: EventTarget | null) {\n if (!(target instanceof Element)) return null;\n const item = target.closest<HTMLElement>(ITEM_SELECTOR);\n if (!item || !root.contains(item) || item.dataset.disabled === 'true')\n return null;\n const nested = target.closest(NESTED_CONTROL_SELECTOR);\n if (nested && nested !== item && item.contains(nested)) return null;\n return item;\n}\n\n/**\n * Give interactive ContentItems native-like Enter/Space activation with one\n * delegated listener pair. Space activates on release and is cancelled if\n * focus moves; the item's own `data-action` still goes through the app's\n * ordinary delegated click handler. Returns a disposer.\n */\nexport function wireContentItems(root: HTMLElement): () => void {\n let pendingSpace: HTMLElement | null = null;\n\n const clearSpace = () => {\n pendingSpace?.removeAttribute('data-kui-pressed');\n pendingSpace = null;\n };\n\n const keydown = (event: KeyboardEvent) => {\n if (\n event.defaultPrevented ||\n event.altKey ||\n event.ctrlKey ||\n event.metaKey\n )\n return;\n const item = actionItem(root, event.target);\n if (!item) return;\n if (event.key === 'Enter') {\n event.preventDefault();\n item.click();\n return;\n }\n if (event.key === ' ' || event.key === 'Spacebar') {\n event.preventDefault();\n if (event.repeat) return;\n clearSpace();\n pendingSpace = item;\n item.setAttribute('data-kui-pressed', 'true');\n }\n };\n\n const keyup = (event: KeyboardEvent) => {\n if (event.key !== ' ' && event.key !== 'Spacebar') return;\n const item = pendingSpace;\n if (!item) return;\n event.preventDefault();\n clearSpace();\n if (\n item === actionItem(root, event.target) &&\n item.ownerDocument.activeElement === item\n )\n item.click();\n };\n\n const focusout = (event: FocusEvent) => {\n if (event.target === pendingSpace) clearSpace();\n };\n\n root.addEventListener('keydown', keydown);\n root.addEventListener('keyup', keyup);\n root.addEventListener('focusout', focusout);\n return () => {\n clearSpace();\n root.removeEventListener('keydown', keydown);\n root.removeEventListener('keyup', keyup);\n root.removeEventListener('focusout', focusout);\n };\n}\n"]}
|
package/dist/wire-tab-bars.js
CHANGED
package/dist/wire-workbench.d.ts
CHANGED
|
@@ -32,6 +32,13 @@ interface WireWorkbenchPanel {
|
|
|
32
32
|
* keeps Tab inside it, and it closes on Escape or a press outside it.
|
|
33
33
|
*/
|
|
34
34
|
collapsed?: Signal<boolean>;
|
|
35
|
+
/**
|
|
36
|
+
* Treat presses in a portal surface launched by this panel (for example a
|
|
37
|
+
* body-level menu or dialog) as inside it. The predicate receives each Node
|
|
38
|
+
* in the press's composed path; return true for the portal root. Ordinary
|
|
39
|
+
* presses outside the panel and its allowed surfaces still dismiss it.
|
|
40
|
+
*/
|
|
41
|
+
keepOpenOn?: (target: Node) => boolean;
|
|
35
42
|
}
|
|
36
43
|
/** A resize the user made, after `wireWorkbench` wrote it to the size signal. */
|
|
37
44
|
interface WorkbenchResize {
|
package/dist/wire-workbench.js
CHANGED
package/dist/workbench.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { ListConfig } from './list.js';
|
|
|
3
3
|
import { PaneConfig } from './pane.js';
|
|
4
4
|
import { ResizableRegionSeparator, ResizableRegionCollapseMotion, ResizableRegionContentOverflow, ResizableRegionPresentation, ResizableRegionRestorePosition } from './resizable-region.js';
|
|
5
5
|
import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
|
|
6
|
-
import { a as PanelToolbar, b as PanelToggle } from './panel-toolbar-
|
|
6
|
+
import { a as PanelToolbar, b as PanelChromePlacement, c as PanelBottomToolbar, d as PanelToggle } from './panel-toolbar-DDKh4uKd.js';
|
|
7
7
|
import { ToolbarConfig } from './toolbar.js';
|
|
8
8
|
import './css-values.js';
|
|
9
9
|
import './flex-alignment-4ms8ZbV8.js';
|
|
@@ -22,6 +22,7 @@ type WorkbenchPanelToggle = PanelToggle;
|
|
|
22
22
|
* `FloatingToolbar` in the work area's bottom-end corner.
|
|
23
23
|
*/
|
|
24
24
|
type WorkbenchPanelToolbar = PanelToolbar;
|
|
25
|
+
type WorkbenchPanelBottomToolbar = PanelBottomToolbar;
|
|
25
26
|
/**
|
|
26
27
|
* The work area's top toolbar; collapsed rails add their groups to it. Its
|
|
27
28
|
* configuration forwards to its `Toolbar`. It draws no divider of its own by
|
|
@@ -57,7 +58,7 @@ interface WorkbenchMainBottomToolbar extends ToolbarConfig {
|
|
|
57
58
|
* the Pane's `chromePlacement="auto"`; it applies to the pinned header and
|
|
58
59
|
* footer together).
|
|
59
60
|
*/
|
|
60
|
-
type WorkbenchChromePlacement =
|
|
61
|
+
type WorkbenchChromePlacement = PanelChromePlacement;
|
|
61
62
|
|
|
62
63
|
/**
|
|
63
64
|
* The Workbench container breakpoint below which a panel presents as an
|
|
@@ -65,7 +66,7 @@ type WorkbenchChromePlacement = 'fixed' | 'scroll' | 'auto';
|
|
|
65
66
|
* breakpoints as `ResizableRegion`'s `responsiveFillAt` — or `never` to keep
|
|
66
67
|
* it inline at every width.
|
|
67
68
|
*/
|
|
68
|
-
type WorkbenchResponsiveOverlayAt = 'compact' | 'narrow' | 'never';
|
|
69
|
+
type WorkbenchResponsiveOverlayAt = 'compact' | 'narrow' | 'never' | number;
|
|
69
70
|
/**
|
|
70
71
|
* How wide a rail's overlay is in a compact (448px or less) Workbench: `inset`
|
|
71
72
|
* fills the Workbench less a dismiss margin on the side away from the rail's
|
|
@@ -88,8 +89,20 @@ interface WorkbenchPanel {
|
|
|
88
89
|
* collapsed. With it, `content` renders in a `Pane` below the toolbar.
|
|
89
90
|
*/
|
|
90
91
|
toolbar?: WorkbenchPanelToolbar;
|
|
91
|
-
/**
|
|
92
|
+
/** Fixed content below a toolbar panel's top toolbar, above its scroll region. */
|
|
93
|
+
header?: KerfUiContent;
|
|
94
|
+
/** List layout for `header`; omitted fields keep List defaults. */
|
|
95
|
+
headerList?: ListConfig;
|
|
96
|
+
/** Placement of the top toolbar and header together; default `fixed`. */
|
|
97
|
+
headerPlacement?: WorkbenchChromePlacement;
|
|
98
|
+
/** Fixed content above a toolbar panel's bottom toolbar. */
|
|
92
99
|
footer?: KerfUiContent;
|
|
100
|
+
/** List layout for `footer`; omitted fields keep List defaults. */
|
|
101
|
+
footerList?: ListConfig;
|
|
102
|
+
/** Fixed toolbar below `footer`, using footer semantics. */
|
|
103
|
+
bottomToolbar?: WorkbenchPanelBottomToolbar;
|
|
104
|
+
/** Placement of the footer and bottom toolbar together; default `fixed`. */
|
|
105
|
+
footerPlacement?: WorkbenchChromePlacement;
|
|
93
106
|
/**
|
|
94
107
|
* Configuration for a `toolbar` panel's `Pane` (`contentElement`,
|
|
95
108
|
* `contentLabel`, `separators`, `safeAreaEdges`, `chromeDividers`) — for example
|
|
@@ -121,8 +134,9 @@ interface WorkbenchPanel {
|
|
|
121
134
|
presentation?: ResizableRegionPresentation;
|
|
122
135
|
/**
|
|
123
136
|
* Present the panel as an overlay, without a separator, below a Workbench
|
|
124
|
-
* container breakpoint, and inline above it
|
|
125
|
-
*
|
|
137
|
+
* container breakpoint, and inline above it. `compact` and `narrow` use
|
|
138
|
+
* CSS container queries; a positive number is a pixel threshold measured
|
|
139
|
+
* by `wireWorkbench` and requires a `collapsed` signal. A rail overlays from its side at full
|
|
126
140
|
* height, over the work area and an open drawer; the bottom drawer
|
|
127
141
|
* overlays the bottom of the work-area column. Rails default to `narrow`
|
|
128
142
|
* (pass `never` to keep one inline); the drawer defaults to inline.
|
|
@@ -222,6 +236,8 @@ interface WorkbenchProps {
|
|
|
222
236
|
* shorter. Workbenches without a drawer ignore it.
|
|
223
237
|
*/
|
|
224
238
|
mainMinHeight?: number;
|
|
239
|
+
/** Dim the work area below any open overlay and absorb outside presses; off by default. */
|
|
240
|
+
overlayBackdrop?: boolean;
|
|
225
241
|
className?: string;
|
|
226
242
|
/** Native named-slot assignment when composed inside a web component. */
|
|
227
243
|
slot?: string;
|
|
@@ -239,6 +255,6 @@ interface WorkbenchProps {
|
|
|
239
255
|
* lives outside it and stays reachable). A panel may opt in to drag and keyboard resizing with
|
|
240
256
|
* `resizable`, which `wireWorkbench` drives. See `docs/23-app-layouts.md` §3.3.
|
|
241
257
|
*/
|
|
242
|
-
declare function Workbench({ id, label, main, leftRail, rightRail, bottomDrawer, mainToolbar, mainHeader, mainFooter, mainBottomToolbar, mainHeaderPlacement, mainFooterPlacement, mainPane, mainHeaderList, mainFooterList, mainMinSize, mainMinHeight, className, slot, }: WorkbenchProps): SafeHtml;
|
|
258
|
+
declare function Workbench({ id, label, main, leftRail, rightRail, bottomDrawer, mainToolbar, mainHeader, mainFooter, mainBottomToolbar, mainHeaderPlacement, mainFooterPlacement, mainPane, mainHeaderList, mainFooterList, mainMinSize, mainMinHeight, overlayBackdrop, className, slot, }: WorkbenchProps): SafeHtml;
|
|
243
259
|
|
|
244
|
-
export { Workbench, type WorkbenchChromePlacement, type WorkbenchCompactOverlay, type WorkbenchMainBottomToolbar, type WorkbenchMainToolbar, type WorkbenchPanel, type WorkbenchPanelResizable, type WorkbenchPanelToggle, type WorkbenchPanelToolbar, type WorkbenchProps, type WorkbenchResponsiveOverlayAt };
|
|
260
|
+
export { Workbench, type WorkbenchChromePlacement, type WorkbenchCompactOverlay, type WorkbenchMainBottomToolbar, type WorkbenchMainToolbar, type WorkbenchPanel, type WorkbenchPanelBottomToolbar, type WorkbenchPanelResizable, type WorkbenchPanelToggle, type WorkbenchPanelToolbar, type WorkbenchProps, type WorkbenchResponsiveOverlayAt };
|
package/dist/workbench.js
CHANGED
package/docs/accessibility.md
CHANGED
|
@@ -5,7 +5,7 @@ These are normative contracts for package components and consuming applications.
|
|
|
5
5
|
## Shared rules
|
|
6
6
|
|
|
7
7
|
- All controls have accessible names and visible `:focus-visible` treatment.
|
|
8
|
-
- Decorative `LucideIcon` output is `aria-hidden`; pass `label` only when the SVG itself conveys meaning.
|
|
8
|
+
- Decorative `LucideIcon` output is `aria-hidden`; pass `label` only when the SVG itself conveys meaning. `size="xs|s|m|l|xl"` selects the 12/16/20/24/32px root-scaled icon steps, and a positive numeric `size` converts pixels to rem; omitting `size` keeps 1em. Size changes the visual only, never the owning control's hit target or accessible name.
|
|
9
9
|
- `ListItem` uses native button Enter/Space behavior. `selected` maps to `aria-current="page"`; `pressed` maps to `aria-pressed`. Selected rows keep the normal foreground over their brand-tinted fill so text retains WCAG AA contrast in light and dark themes. Its leading icon visual is 18px while the row retains its 44px minimum target; multiline icons align to the first text line. Its `trailing` content is dormant and must not contain controls. Its `rootAttributes` slot accepts only application `data-*` metadata and deliberately cannot emit `role="menuitem"` in isolation—a true ARIA menu must own arrow, Home/End, Escape, and focus behavior as one widget.
|
|
10
10
|
- `ListItemLink` shares that row content and geometry but uses native anchor Enter behavior and requires `href`. It has no `action` or `pressed` state. `external` opens a new tab with `rel="noopener noreferrer"`; the default accessible name announces the new tab for a string label, so an explicit `accessibleLabel` should do the same. Disabled and loading links omit `href`, expose `aria-disabled`, and leave the tab order. Its trailing content remains dormant.
|
|
11
11
|
- `ListHeader` owns action naming, disabled state, and disclosure `aria-expanded`. Toggle mode supplies one decorative 18px `DisclosureArrow` when `actionIcon` is omitted; it mirrors `expanded` while the native button's accessible name stays stable. The application must update that controlled state and reveal or hide real content. A valid `count` is visually rendered in an `aria-hidden` neutral pill while the required localized `countLabel` becomes part of the owning heading or disclosure button's accessible name; zero remains a real count. Its narrow `triggerAttributes` slot may describe a native popover or controlled-content relationship with `popoverTarget`, `popoverTargetAction`, `aria-controls`, and `aria-haspopup`; the application owns the target surface and its focus/dismissal behavior.
|
|
@@ -13,9 +13,12 @@ These are normative contracts for package components and consuming applications.
|
|
|
13
13
|
- `wireNavStack` moves focus into every newly active top view and remembers the last focused descendant of each mounted view for pop restoration. Mark a preferred initial heading or control with `data-nav-focus` (and `tabindex="-1"` when it is not normally tabbable); otherwise the helper uses the first enabled focusable descendant, then a programmatically focusable view-container fallback.
|
|
14
14
|
- In any `.kui-pane`, menu rows, `ListHeader` actions, and toolbar groups keep a minimum 44px target in both dimensions. A `ListHeader` fills the available inline width and keeps that action at the logical end, including in RTL. Its action visual defaults to 18px through `--kui-list-header-action-icon-size` inside a fitted 36px hover square; a transparent hit layer extends the pointer target to at least 44 × 44 around that square without moving layout or enlarging the painted surface. Compact headers are 36px tall like the rest of the compact List family, so their action target is 44px wide and clamped to the 36px header height instead of reaching into a neighboring row. Do not reduce the target to the visible icon, and do not force the button itself to 44px.
|
|
15
15
|
- `LoadingSpinner` is either labeled (`role="img"`) or hidden. Its rotation stops for reduced motion.
|
|
16
|
+
- A busy `ToolbarControlGroup` makes its controls inert and exposes `aria-busy`; its `busyLabel` is announced by an adjacent status node outside the inert group. Clear `busy` when the operation finishes so the controls rejoin the focus order.
|
|
17
|
+
- A bottom `Toolbar` uses `position="footer"` for footer semantics; top toolbars keep the default `header`. Workbench's main bottom toolbar sets this automatically.
|
|
18
|
+
- Interactive `ContentItem` cards have a keyboard reachable button or option role. Set `selectionMode="toggle"` for `aria-pressed`, or `selectionMode="single"` inside a listbox for `aria-selected`; wire `wireContentItems` once so Enter and Space activate their delegated action. Disabled cards expose `aria-disabled` and leave the Tab order.
|
|
16
19
|
- An unlabeled `Skeleton` (including the value slots a component's `placeholder` prop renders) is decorative loading chrome: it is `aria-hidden`, conveys no information a user needs to act on, and is deliberately exempt from the WCAG 3:1 non-text-contrast target. Inside a solid `Badge` it stays subtle (about 2.1–4.4:1 in light, 2.4–2.8:1 in dark, depending on tone); `tests/browser/tone-contrast.spec.ts` holds those values as a regression floor rather than an accessibility threshold. Announce loading through a labeled `Skeleton`, `LoadingSpinner`, or `aria-busy` on the owning region, never through the skeleton's visibility.
|
|
17
20
|
- `StateBanner` defaults to polite `role="status"`; use `urgency="alert"` only for an attention-requiring failure. Its optional `badge` is persistent inline status/count content beside the title and is announced as part of the banner; keep it terse and do not rely on color alone for its meaning.
|
|
18
|
-
- A removable `Chip` has a native button with a specific `removeLabel`, such as "Remove Urgent tag". The button is absent for a plain chip and disabled for a disabled chip. Tag text remains visible because tone does not convey meaning alone.
|
|
21
|
+
- A removable `Chip` has a native button with a specific `removeLabel`, such as "Remove Urgent tag". The button is absent for a plain chip and disabled for a disabled chip. Its leading `icon` is decorative; the visible label names the tag. `truncate` retains the full plain-text label as a native tooltip. Tag text remains visible because tone does not convey meaning alone.
|
|
19
22
|
- `EmptyState` reports busy state through `aria-busy` and never relies on an illustration as its label.
|
|
20
23
|
- `Select` follows the Web Awesome host's standard `input`/`change` events. Application tests verify the live `value`, focus, and events—not attributes alone. Its decorative option icons and value-dependent selected content remain present after controlled rerenders, so the visible choice does not silently lose its non-text cue.
|
|
21
24
|
- `DisclosureArrow` is an 18px root-scaled decorative visual by default, not an interaction target. Its owning native control supplies a stable accessible name, pointer and keyboard interaction, and `aria-expanded`; multiple arrows keep independently controlled state. Consumers may resize it with the typed `size` prop without changing that ownership. Configured directions animate over the shortest path; a 180-degree closed-to-open tie uses counterclockwise rotation.
|
|
@@ -205,7 +208,9 @@ open popup. A disabled item stays in the menu but cannot be
|
|
|
205
208
|
chosen; disable the whole trigger only when every command is unavailable.
|
|
206
209
|
Nested items use Web Awesome's submenu pointer and Left/Right arrow routing;
|
|
207
210
|
headings and dividers can separate nested groups without becoming keyboard
|
|
208
|
-
choices.
|
|
211
|
+
choices. A rapid ArrowDown or ArrowUp after opening a submenu keeps the chosen
|
|
212
|
+
item focused when its show animation finishes. Set `checked` to `true` or `false` for checkbox menu semantics; omit it
|
|
213
|
+
for a plain command. `details` supplies optional
|
|
209
214
|
trailing visual content without changing a command's accessible label. A
|
|
210
215
|
`context` menu's invisible anchor is outside the accessibility tree and normal
|
|
211
216
|
Tab order; opening the menu moves focus into its commands and Escape dismisses
|
|
@@ -443,10 +448,21 @@ remove actions, and suggestions are managed. Arrow Down moves from the editor
|
|
|
443
448
|
to suggestions, arrow keys move between suggestions, Enter selects one, and
|
|
444
449
|
Escape returns focus to the editor. The application still announces results
|
|
445
450
|
when needed and can supply an `evaluate` callback to compute them. Omitting the
|
|
446
|
-
model leaves the manual behavior above intact.
|
|
451
|
+
model leaves the manual behavior above intact. After a chip commit, suggestion
|
|
452
|
+
choice, chip edit, or Backspace/Delete chip removal, focus restoration runs at
|
|
453
|
+
the controlled render checkpoint and keeps the query-relative caret offset;
|
|
454
|
+
it leaves focus on a different control if the user moved there in the meantime.
|
|
455
|
+
Suggestions use Floating UI positioning, following the same viewport-aware
|
|
456
|
+
popup behavior as the Web Awesome controls behind Select and PopupMenu. They
|
|
457
|
+
follow the field while scrolling, flip above it at the bottom edge, and shift
|
|
458
|
+
within narrow viewports without growing its toolbar row. One
|
|
459
|
+
suggestion keeps a pill outline; lists with multiple choices use the standard
|
|
460
|
+
rounded surface and scroll once they reach 240px. The clear button's hover and focus
|
|
461
|
+
highlight follows the field's pill shape or its toolbar group's rounded shape.
|
|
447
462
|
|
|
448
463
|
Managed clear captures the action before application handlers run, keeps the adopted
|
|
449
|
-
expanded signal open
|
|
464
|
+
expanded signal open for a collapsible field, and restores the editor focus for
|
|
465
|
+
both collapsible and plain model fields at the actual
|
|
450
466
|
mutation checkpoint before the next input task. It also returns keyboard activation
|
|
451
467
|
from the clear button to a surviving editor immediately. No animation frame owns
|
|
452
468
|
clear focus, so fast typing cannot escape to page shortcuts or lose its first letter. The app still owns clearing query/tokens and emptying
|
package/docs/catalog.md
CHANGED
|
@@ -215,6 +215,42 @@ border, and padding. Catalogs for downstream components should conform to the
|
|
|
215
215
|
contract and can start from the checked
|
|
216
216
|
[`component-catalog-extension.json`](./examples/component-catalog-extension.json)
|
|
217
217
|
example; provide those entries beside Kerf's shipped catalog to AI tools.
|
|
218
|
+
An extension entry may declare `uses` with direct Kerf or extension entry ids,
|
|
219
|
+
plus repository-relative `source` and `demoSource` paths. Keep the ids unique
|
|
220
|
+
and resolvable across both catalogs; paths use `/` separators and cannot
|
|
221
|
+
traverse outside the repository. These fields let consumer demos derive source
|
|
222
|
+
links and composition relationships from the catalog.
|
|
223
|
+
|
|
224
|
+
For a consumer UX demo, `@kerfjs/ui/catalog-projection` exports
|
|
225
|
+
`projectConsumerCatalog(extension, kerfCatalog, options)` and
|
|
226
|
+
`projectCatalogEntries(entries, options)`. The projection maps `purpose` to
|
|
227
|
+
`description`, `uses` to related-entry ids, `source` to `componentSource`, and
|
|
228
|
+
`demoSource` to the demo source link. It defaults the source identity to
|
|
229
|
+
`consumer` and category to `Application`. Explicit paths in an extension entry
|
|
230
|
+
take precedence over templates. Template placeholders are `{id}`, `{name}`,
|
|
231
|
+
`{kind}`, and `{package}`. Design templates are omitted unless configured.
|
|
232
|
+
|
|
233
|
+
The package also ships `kerf-catalog-demo` for a committed TypeScript module:
|
|
234
|
+
|
|
235
|
+
```sh
|
|
236
|
+
kerf-catalog-demo --extension ai/component-catalog-extension.json \
|
|
237
|
+
--out ux-demo/catalog.generated.ts \
|
|
238
|
+
--repo-base https://github.com/acme/app/blob/main/ \
|
|
239
|
+
--source-template 'src/{id}.tsx' \
|
|
240
|
+
--demo-template 'ux-demo/demos/{id}.tsx' --write
|
|
241
|
+
kerf-catalog-demo --extension ai/component-catalog-extension.json \
|
|
242
|
+
--out ux-demo/catalog.generated.ts \
|
|
243
|
+
--repo-base https://github.com/acme/app/blob/main/ \
|
|
244
|
+
--source-template 'src/{id}.tsx' \
|
|
245
|
+
--demo-template 'ux-demo/demos/{id}.tsx' --check
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
The command uses the Kerf catalog shipped with the package to resolve `uses`;
|
|
249
|
+
`--kerf-catalog` selects another catalog file. `--category`,
|
|
250
|
+
`--documentation-template`, and `--design-template` configure optional row
|
|
251
|
+
fields. `--check` fails if the generated file is missing or stale. The output
|
|
252
|
+
exports `generatedConsumerCatalog` and `catalogRepositoryBlobUrl`; the latter
|
|
253
|
+
is normalized to a trailing slash for source and documentation links.
|
|
218
254
|
|
|
219
255
|
### Automated conformance and reviewed exceptions
|
|
220
256
|
|
|
@@ -80,9 +80,10 @@ and that of the components it renders (`Pane`, `Toolbar`, `ToolbarControlGroup`,
|
|
|
80
80
|
corners, with typed `restoreInset` for the corner distance. Set
|
|
81
81
|
`restorePlacement="inline"` when the container should place the control in
|
|
82
82
|
normal flow. An inline region's surface uses
|
|
83
|
-
`--kui-resizable-region-background`;
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
`--kui-resizable-region-background`; an open descendant `PopupMenu` or Web
|
|
84
|
+
Awesome dropdown releases clipping and raises the popup layer for its
|
|
85
|
+
lifecycle. Set `contentOverflow="visible"` for other anchored content that
|
|
86
|
+
must escape the region's content box.
|
|
86
87
|
Overlay presentation also clamps fixed-size animated content to the configured
|
|
87
88
|
responsive overlay maximum, so a remembered desktop size cannot escape a narrow
|
|
88
89
|
viewport.
|
|
@@ -133,7 +134,7 @@ and that of the components it renders (`Pane`, `Toolbar`, `ToolbarControlGroup`,
|
|
|
133
134
|
|
|
134
135
|
Give a panel a `toolbar` (the same roles as a
|
|
135
136
|
[Workbench panel toolbar](workbench.md#panel-toolbars)) and it composes its own
|
|
136
|
-
top toolbar over a `Pane
|
|
137
|
+
top toolbar over a `Pane`:
|
|
137
138
|
|
|
138
139
|
- `title` precedes the `leading` zone; `leading`, `center`, and `trailing`
|
|
139
140
|
place groups wherever the open panel needs them;
|
|
@@ -141,6 +142,13 @@ top toolbar over a `Pane`, with an optional `footer` below its content:
|
|
|
141
142
|
work area when the panel closes; the standard `toggle: { action, name,
|
|
142
143
|
showLabel?, hideLabel? }` is always the final group.
|
|
143
144
|
|
|
145
|
+
The panel can also take `header` under its toolbar, `footer` below its content,
|
|
146
|
+
`bottomToolbar` below that, `headerList` / `footerList` for those fixed content
|
|
147
|
+
stacks, and `headerPlacement` / `footerPlacement` (`fixed`, `scroll`, or `auto`).
|
|
148
|
+
These slots share the panel's one `Pane` scroll owner; the bottom toolbar uses
|
|
149
|
+
footer semantics. With no `toolbar`, the panel renders its children directly
|
|
150
|
+
and ignores the chrome slots.
|
|
151
|
+
|
|
144
152
|
The toolbar also takes the `Toolbar`'s configuration (`dividerSides`,
|
|
145
153
|
`centerAlign`, `responsive`, `responsiveAt`, `safeAreaEdges`); it draws no
|
|
146
154
|
divider of its own unless `dividerSides` says so. The `Pane` under it draws
|
|
@@ -243,6 +243,9 @@ example. Keep app and Kerf entries as package-qualified inputs, then let people
|
|
|
243
243
|
or AI tools search their combined entries and compare `geometry` before adding
|
|
244
244
|
wrappers or insets. Do not add app-owned entries to Kerf's canonical catalog or
|
|
245
245
|
claim Kerf delivery paths for them.
|
|
246
|
+
Extension entries may add `uses` for direct composition dependencies and
|
|
247
|
+
repository-relative `source` and `demoSource` files. Resolve each dependency
|
|
248
|
+
against the combined Kerf and consumer catalogs; do not duplicate a Kerf id.
|
|
246
249
|
|
|
247
250
|
- Components own semantic markup, stable anatomy, documented variants, ARIA projection, and package CSS hooks.
|
|
248
251
|
- Applications own signals/stores, product copy, domain-state mapping, persistence, routing, permissions, and transport.
|
|
@@ -504,9 +507,10 @@ without application `::part(menu)` CSS; the default `standard` keeps each menu's
|
|
|
504
507
|
own inset (8px for a raw `wa-dropdown`, the Select listbox's 4px for a
|
|
505
508
|
`PopupMenu`), while `compact` and `list-zero` apply to every nested menu. A
|
|
506
509
|
`PopupMenu` and a `Select` draw one popup: the same caret that turns to face the
|
|
507
|
-
open popup, fade-in surface, surface inset, row height and padding,
|
|
508
|
-
|
|
509
|
-
|
|
510
|
+
open popup, fade-in surface, surface inset, row height and padding, current-row
|
|
511
|
+
fill, and group titles, all read from one private popup-choice contract in
|
|
512
|
+
`foundation.css`. Checkbox items reserve a check column; plain commands start
|
|
513
|
+
at the checkmark's leading edge. Compact mixed controls retain the standard
|
|
510
514
|
item padding, omit an internal separator, and let the raised selected item paint
|
|
511
515
|
over the outer border instead of shrinking to an inset highlight. The Web
|
|
512
516
|
Awesome trigger's shadow base owns max-content sizing, so icons, localized text,
|
|
@@ -578,7 +582,9 @@ by default it also owns the collapsible field's transient expand/collapse/focus
|
|
|
578
582
|
state in a signal it exposes on the returned handle. An app reads that signal in
|
|
579
583
|
render, hands in its own via `collapsible.signals`, drives it through
|
|
580
584
|
`handle.open`/`handle.close`, or disables any individual behavior — so transient
|
|
581
|
-
UI is consistent by default without every app reinventing it.
|
|
585
|
+
UI is consistent by default without every app reinventing it. A collapsed
|
|
586
|
+
field may reveal its editor after the current microtask; the helper keeps a
|
|
587
|
+
bounded render-frame focus handoff for that reveal and cancels it on disposal.
|
|
582
588
|
|
|
583
589
|
A public subpath that exposes several visual components is a folder-backed
|
|
584
590
|
surface. Put each component in its own source file and give each visual
|