@kerfjs/ui 4.4.1 → 5.0.0-beta.10
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 +240 -10
- package/ai/component-catalog.json +4766 -0
- package/ai/component-catalog.schema.json +79 -0
- package/ai/public-api-signatures-v1.md +1327 -0
- package/ai/skill.md +73 -11
- package/ai/webawesome-jsx-signatures-v1.md +106 -0
- package/dist/app-tab.d.ts +14 -2
- package/dist/app-tab.js +3 -1
- package/dist/browser/app-tab.js +3 -2
- package/dist/browser/disclosure-arrow.js +4 -0
- package/dist/browser/empty-state.js +3 -3
- package/dist/browser/list-action-row.js +4 -0
- package/dist/browser/list-header.js +6 -0
- package/dist/browser/list-item.js +4 -0
- package/dist/browser/loading-spinner.js +2 -2
- package/dist/browser/lucide-icon.js +2 -2
- package/dist/browser/panel-header.js +7 -0
- package/dist/browser/resizable-region.js +2 -2
- package/dist/browser/segmented-control.js +3 -2
- package/dist/browser/select.js +4 -3
- package/dist/browser/skeleton.js +3 -0
- package/dist/browser/state-banner.js +3 -2
- package/dist/browser/tab-bar.js +2 -2
- package/dist/browser/token-search-field.js +4 -0
- package/dist/browser/toolbar-control-group.js +2 -2
- package/dist/browser/toolbar-text.js +3 -2
- package/dist/browser/toolbar.js +2 -2
- package/dist/browser/value-table.js +3 -2
- package/dist/catalog.d.ts +119 -0
- package/dist/catalog.js +143 -0
- package/dist/catalog.js.map +1 -0
- package/dist/chunk-2Z5TWHKQ.js +34 -0
- package/dist/chunk-2Z5TWHKQ.js.map +1 -0
- package/dist/chunk-37T3VNIZ.js +19 -0
- package/dist/chunk-37T3VNIZ.js.map +1 -0
- package/dist/chunk-56RJXPHG.js +43 -0
- package/dist/chunk-56RJXPHG.js.map +1 -0
- package/dist/chunk-7BR3DO2A.js +31 -0
- package/dist/chunk-7BR3DO2A.js.map +1 -0
- package/dist/chunk-7JB7VPRI.js +34 -0
- package/dist/chunk-7JB7VPRI.js.map +1 -0
- package/dist/chunk-7LDCTU7D.js +134 -0
- package/dist/chunk-7LDCTU7D.js.map +1 -0
- package/dist/{chunk-4HHCYSGT.js → chunk-AQNKJRFH.js} +2 -2
- package/dist/{chunk-4HHCYSGT.js.map → chunk-AQNKJRFH.js.map} +1 -1
- package/dist/{chunk-MBR3TYNL.js → chunk-AVZHJN6C.js} +3 -3
- package/dist/chunk-AVZHJN6C.js.map +1 -0
- package/dist/chunk-B24C4A6T.js +22 -0
- package/dist/chunk-B24C4A6T.js.map +1 -0
- package/dist/chunk-BLK3UEEI.js +23 -0
- package/dist/chunk-BLK3UEEI.js.map +1 -0
- package/dist/chunk-CVZYNJJ5.js +265 -0
- package/dist/chunk-CVZYNJJ5.js.map +1 -0
- package/dist/chunk-I7INRJO4.js +17 -0
- package/dist/chunk-I7INRJO4.js.map +1 -0
- package/dist/chunk-L4OKFDJY.js +24 -0
- package/dist/chunk-L4OKFDJY.js.map +1 -0
- package/dist/chunk-LC3YSAZC.js +39 -0
- package/dist/chunk-LC3YSAZC.js.map +1 -0
- package/dist/{chunk-3O7ZEUW2.js → chunk-M5JRI6MN.js} +3 -3
- package/dist/chunk-M5JRI6MN.js.map +1 -0
- package/dist/chunk-RUNWEPR4.js +10 -0
- package/dist/chunk-RUNWEPR4.js.map +1 -0
- package/dist/chunk-W5EQ3HYQ.js +42 -0
- package/dist/chunk-W5EQ3HYQ.js.map +1 -0
- package/dist/{chunk-MQIZAD4A.js → chunk-XXMOARTH.js} +5 -3
- package/dist/chunk-XXMOARTH.js.map +1 -0
- package/dist/chunk-Y5MRDTLC.js +20 -0
- package/dist/chunk-Y5MRDTLC.js.map +1 -0
- package/dist/{chunk-TRNBHPNW.js → chunk-YGN7OMLT.js} +11 -8
- package/dist/chunk-YGN7OMLT.js.map +1 -0
- package/dist/collapsible-panel.d.ts +66 -0
- package/dist/collapsible-panel.js +22 -0
- package/dist/collapsible-panel.js.map +1 -0
- package/dist/device-class.d.ts +62 -0
- package/dist/device-class.js +75 -0
- package/dist/device-class.js.map +1 -0
- package/dist/disclosure-arrow.d.ts +14 -0
- package/dist/disclosure-arrow.js +4 -0
- package/dist/disclosure-arrow.js.map +1 -0
- package/dist/index.d.ts +10 -6
- package/dist/index.js +21 -16
- package/dist/list-action-row.d.ts +52 -0
- package/dist/list-action-row.js +5 -0
- package/dist/list-action-row.js.map +1 -0
- package/dist/list-header.d.ts +43 -0
- package/dist/list-header.js +7 -0
- package/dist/list-header.js.map +1 -0
- package/dist/list-item.d.ts +33 -0
- package/dist/list-item.js +5 -0
- package/dist/list-item.js.map +1 -0
- package/dist/nav-stack.d.ts +38 -0
- package/dist/nav-stack.js +5 -0
- package/dist/nav-stack.js.map +1 -0
- package/dist/panel-header.d.ts +36 -0
- package/dist/panel-header.js +7 -0
- package/dist/panel-header.js.map +1 -0
- package/dist/resizable-region.d.ts +3 -1
- package/dist/resizable-region.js +1 -1
- package/dist/segmented-control.d.ts +3 -1
- package/dist/segmented-control.js +2 -1
- package/dist/select-register.d.ts +5 -1
- package/dist/select-register.js +3 -0
- package/dist/select-register.js.map +1 -1
- package/dist/select.d.ts +5 -2
- package/dist/select.js +2 -1
- package/dist/skeleton.d.ts +24 -0
- package/dist/skeleton.js +3 -0
- package/dist/skeleton.js.map +1 -0
- package/dist/split-view.d.ts +42 -0
- package/dist/split-view.js +21 -0
- package/dist/split-view.js.map +1 -0
- package/dist/state-banner.d.ts +3 -1
- package/dist/state-banner.js +2 -1
- package/dist/styles/app-tab.css +152 -0
- package/dist/styles/catalog.css +498 -0
- package/dist/styles/collapsible-panel.css +146 -0
- package/dist/styles/disclosure-arrow.css +23 -0
- package/dist/styles/empty-state.css +47 -0
- package/dist/styles/foundation.css +347 -0
- package/dist/styles/layout.css +73 -0
- package/dist/styles/list-action-row.css +160 -0
- package/dist/styles/list-header.css +160 -0
- package/dist/styles/list-item.css +123 -0
- package/dist/styles/loading-spinner.css +21 -0
- package/dist/styles/lucide-icon.css +6 -0
- package/dist/styles/nav-stack.css +111 -0
- package/dist/styles/panel-header.css +64 -0
- package/dist/styles/resizable-region.css +111 -0
- package/{src → dist/styles}/segmented-control.css +62 -31
- package/dist/styles/select.css +138 -0
- package/dist/styles/skeleton.css +31 -0
- package/dist/styles/split-view.css +35 -0
- package/dist/styles/state-banner.css +173 -0
- package/dist/styles/styles.css +23 -0
- package/dist/styles/tab-bar.css +45 -0
- package/dist/styles/tab-scaffold.css +84 -0
- package/dist/styles/token-search-field.css +289 -0
- package/dist/styles/toolbar-control-group.css +211 -0
- package/dist/styles/toolbar-text.css +40 -0
- package/dist/styles/toolbar.css +61 -0
- package/dist/styles/value-table.css +75 -0
- package/{src → dist/styles}/webawesome.css +119 -29
- package/dist/styles/workbench.css +94 -0
- package/dist/tab-bar.d.ts +8 -1
- package/dist/tab-bar.js +1 -1
- package/dist/tab-scaffold.d.ts +30 -0
- package/dist/tab-scaffold.js +16 -0
- package/dist/tab-scaffold.js.map +1 -0
- package/dist/token-search-field.d.ts +43 -0
- package/dist/token-search-field.js +4 -0
- package/dist/token-search-field.js.map +1 -0
- package/dist/toolbar-text.d.ts +15 -3
- package/dist/toolbar-text.js +2 -1
- package/dist/value-table.d.ts +12 -2
- package/dist/value-table.js +2 -1
- package/dist/webawesome.d.ts +100 -0
- package/dist/webawesome.js +3 -0
- package/dist/webawesome.js.map +1 -0
- package/dist/wire-catalog.d.ts +26 -0
- package/dist/wire-catalog.js +48 -0
- package/dist/wire-catalog.js.map +1 -0
- package/dist/wire-nav-stack.d.ts +15 -0
- package/dist/wire-nav-stack.js +88 -0
- package/dist/wire-nav-stack.js.map +1 -0
- package/dist/wire-resizable-regions.js +1 -1
- package/dist/wire-sidebar.d.ts +43 -0
- package/dist/wire-sidebar.js +117 -0
- package/dist/wire-sidebar.js.map +1 -0
- package/dist/wire-tab-bars.d.ts +15 -2
- package/dist/wire-tab-bars.js +1 -1
- package/dist/wire-tab-scaffold.d.ts +11 -0
- package/dist/wire-tab-scaffold.js +16 -0
- package/dist/wire-tab-scaffold.js.map +1 -0
- package/dist/wire-token-search-fields.d.ts +97 -0
- package/dist/wire-token-search-fields.js +5 -0
- package/dist/wire-token-search-fields.js.map +1 -0
- package/dist/workbench.d.ts +33 -0
- package/dist/workbench.js +17 -0
- package/dist/workbench.js.map +1 -0
- package/docs/accessibility.md +101 -3
- package/docs/app-layouts.md +61 -0
- package/docs/catalog.md +155 -0
- package/docs/collapsible-panel.md +102 -0
- package/docs/component-contract.md +169 -4
- package/docs/component-selection.md +185 -0
- package/docs/design/templates/panel-header/icon-actions-dark.svg +1 -0
- package/docs/design/templates/panel-header/icon-actions.svg +1 -0
- package/docs/design/templates/panel-header/icon-summary-actions-dark.svg +1 -0
- package/docs/design/templates/panel-header/icon-summary-actions.svg +1 -0
- package/docs/design/templates/panel-header/no-icon-dark.svg +1 -0
- package/docs/design/templates/panel-header/no-icon.svg +1 -0
- package/docs/design/templates/panel-header/page-heading-dark.svg +1 -0
- package/docs/design/templates/panel-header/page-heading.svg +1 -0
- package/docs/design/templates/panel-header/title-only-dark.svg +1 -0
- package/docs/design/templates/panel-header/title-only.svg +1 -0
- package/docs/design/templates/panel-header-dark.svg +13 -0
- package/docs/design/templates/panel-header.svg +13 -0
- package/docs/design/templates/toolbar-control-group/borderless-single-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group/borderless-single.svg +1 -0
- package/docs/design/templates/toolbar-control-group/icon-buttons-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group/icon-buttons.svg +1 -0
- package/docs/design/templates/toolbar-control-group/push-buttons-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group/push-buttons.svg +1 -0
- package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group/with-text.svg +1 -0
- package/docs/design/templates/toolbar-control-group-dark.svg +11 -0
- package/docs/design/templates/toolbar-control-group.svg +11 -0
- package/docs/design/templates.md +83 -0
- package/docs/design-philosophy.md +61 -1
- package/docs/device-class.md +54 -0
- package/docs/examples/command-palette-adapter.tsx +70 -0
- package/docs/layout.md +131 -0
- package/docs/nav-stack.md +47 -0
- package/docs/recipes.md +167 -0
- package/docs/split-view.md +49 -0
- package/docs/tab-scaffold.md +41 -0
- package/docs/ux-demo.md +23 -9
- package/docs/webawesome-theme.md +15 -0
- package/docs/workbench.md +47 -0
- package/llms.txt +123 -14
- package/package.json +139 -44
- package/ux-demo/recipes/app-shell.tsx +32 -0
- package/ux-demo/recipes/collapsible-sidebar.tsx +100 -0
- package/ux-demo/recipes/compact-toolbar.tsx +43 -0
- package/ux-demo/recipes/composer-form.tsx +63 -0
- package/ux-demo/recipes/list-detail-dialog.tsx +45 -0
- package/ux-demo/recipes/list-workspace-states.tsx +26 -0
- package/ux-demo/recipes/loaders.ts +33 -0
- package/ux-demo/recipes/loading-inspector.tsx +81 -0
- package/ux-demo/recipes/mount-recipe.ts +43 -0
- package/ux-demo/recipes/navigation-sidebar.tsx +26 -0
- package/ux-demo/recipes/navigation-stack.tsx +76 -0
- package/ux-demo/recipes/recipes.css +448 -0
- package/ux-demo/recipes/types.ts +17 -0
- package/ux-demo/recipes/workspace-header.tsx +12 -0
- package/dist/browser/dialog-header.js +0 -3
- package/dist/browser/menu-header.js +0 -3
- package/dist/browser/menu-item.js +0 -3
- package/dist/browser/page-header.js +0 -3
- package/dist/chunk-2PES33HS.js +0 -13
- package/dist/chunk-2PES33HS.js.map +0 -1
- package/dist/chunk-3O7ZEUW2.js.map +0 -1
- package/dist/chunk-723YNJBH.js +0 -17
- package/dist/chunk-723YNJBH.js.map +0 -1
- package/dist/chunk-GY5WH7TO.js +0 -10
- package/dist/chunk-GY5WH7TO.js.map +0 -1
- package/dist/chunk-MBR3TYNL.js.map +0 -1
- package/dist/chunk-MQIZAD4A.js.map +0 -1
- package/dist/chunk-NHXX4JI5.js +0 -28
- package/dist/chunk-NHXX4JI5.js.map +0 -1
- package/dist/chunk-OPCJRCYO.js +0 -19
- package/dist/chunk-OPCJRCYO.js.map +0 -1
- package/dist/chunk-T5XNMVOI.js +0 -24
- package/dist/chunk-T5XNMVOI.js.map +0 -1
- package/dist/chunk-TRNBHPNW.js.map +0 -1
- package/dist/chunk-VHW5YNIB.js +0 -17
- package/dist/chunk-VHW5YNIB.js.map +0 -1
- package/dist/chunk-VKH2JLDZ.js +0 -10
- package/dist/chunk-VKH2JLDZ.js.map +0 -1
- package/dist/chunk-WY4CAEPG.js +0 -14
- package/dist/chunk-WY4CAEPG.js.map +0 -1
- package/dist/dialog-header.d.ts +0 -14
- package/dist/dialog-header.js +0 -3
- package/dist/dialog-header.js.map +0 -1
- package/dist/menu-header.d.ts +0 -15
- package/dist/menu-header.js +0 -3
- package/dist/menu-header.js.map +0 -1
- package/dist/menu-item.d.ts +0 -22
- package/dist/menu-item.js +0 -3
- package/dist/menu-item.js.map +0 -1
- package/dist/page-header.d.ts +0 -9
- package/dist/page-header.js +0 -3
- package/dist/page-header.js.map +0 -1
- package/src/app-tab.css +0 -20
- package/src/dialog-header.css +0 -9
- package/src/empty-state.css +0 -6
- package/src/foundation.css +0 -106
- package/src/loading-spinner.css +0 -4
- package/src/lucide-icon.css +0 -1
- package/src/menu-header.css +0 -13
- package/src/menu-item.css +0 -12
- package/src/page-header.css +0 -3
- package/src/resizable-region.css +0 -19
- package/src/select.css +0 -18
- package/src/state-banner.css +0 -31
- package/src/styles.css +0 -18
- package/src/tab-bar.css +0 -4
- package/src/toolbar-control-group.css +0 -25
- package/src/toolbar-text.css +0 -4
- package/src/toolbar.css +0 -9
- package/src/value-table.css +0 -5
|
@@ -0,0 +1,1327 @@
|
|
|
1
|
+
# Public API signatures for the UI authoring corpus
|
|
2
|
+
|
|
3
|
+
Generated from emitted declarations for `@kerfjs/ui@5.0.0-beta.10` and `kerfjs@5.0.0-beta.10`. This bounded reference covers only APIs used by the seven-task corpus. It is interface evidence, not an implementation or runtime guarantee.
|
|
4
|
+
|
|
5
|
+
## `@kerfjs/ui/disclosure-arrow`
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { SafeHtml } from 'kerfjs';
|
|
9
|
+
|
|
10
|
+
type DisclosureDirection = 'up' | 'down' | 'left' | 'right';
|
|
11
|
+
interface DisclosureArrowProps {
|
|
12
|
+
open: boolean;
|
|
13
|
+
openDirection?: DisclosureDirection;
|
|
14
|
+
closedDirection?: DisclosureDirection;
|
|
15
|
+
/** Replacement icons should use right as their unrotated orientation. */
|
|
16
|
+
icon?: SafeHtml;
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
19
|
+
declare function DisclosureArrow({ open, openDirection, closedDirection, icon, className, }: DisclosureArrowProps): SafeHtml;
|
|
20
|
+
|
|
21
|
+
export { DisclosureArrow, type DisclosureArrowProps, type DisclosureDirection };
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## `@kerfjs/ui/toolbar`
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { SafeHtml } from 'kerfjs';
|
|
28
|
+
|
|
29
|
+
interface ToolbarProps {
|
|
30
|
+
leading?: SafeHtml;
|
|
31
|
+
center?: SafeHtml;
|
|
32
|
+
trailing?: SafeHtml;
|
|
33
|
+
label?: string;
|
|
34
|
+
divider?: boolean;
|
|
35
|
+
className?: string;
|
|
36
|
+
}
|
|
37
|
+
declare function Toolbar({ leading, center, trailing, label, divider, className }: ToolbarProps): SafeHtml;
|
|
38
|
+
|
|
39
|
+
export { Toolbar, type ToolbarProps };
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## `@kerfjs/ui/toolbar-text`
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import * as kerfjs from 'kerfjs';
|
|
46
|
+
|
|
47
|
+
type ToolbarTextSize = 'xlarge' | 'large' | 'default' | 'small';
|
|
48
|
+
/** ARIA heading level for a title exposed as a heading landmark. */
|
|
49
|
+
type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
|
|
50
|
+
interface ToolbarTextProps {
|
|
51
|
+
text: string;
|
|
52
|
+
size?: ToolbarTextSize;
|
|
53
|
+
className?: string;
|
|
54
|
+
/** Optional id, e.g. so a dialog can reference the title via aria-labelledby. */
|
|
55
|
+
id?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Expose heading semantics (`role="heading"` + `aria-level`) so the text acts as
|
|
58
|
+
* a heading landmark — e.g. a page's primary title. Omit to keep the plain span
|
|
59
|
+
* (the default), which suits a dialog title referenced via `aria-labelledby`.
|
|
60
|
+
*/
|
|
61
|
+
headingLevel?: HeadingLevel;
|
|
62
|
+
/** Render the text as an unanimated loading skeleton instead of its value. */
|
|
63
|
+
placeholder?: boolean;
|
|
64
|
+
}
|
|
65
|
+
declare function ToolbarText({ text, size, className, id, headingLevel, placeholder }: ToolbarTextProps): kerfjs.SafeHtml;
|
|
66
|
+
|
|
67
|
+
export { type HeadingLevel, ToolbarText, type ToolbarTextProps, type ToolbarTextSize };
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## `@kerfjs/ui/toolbar-control-group`
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { SafeHtml } from 'kerfjs';
|
|
74
|
+
|
|
75
|
+
interface ToolbarControlGroupProps {
|
|
76
|
+
children: SafeHtml | SafeHtml[];
|
|
77
|
+
label?: string;
|
|
78
|
+
className?: string;
|
|
79
|
+
expanded?: boolean;
|
|
80
|
+
single?: boolean;
|
|
81
|
+
appearance?: 'contained' | 'borderless';
|
|
82
|
+
tone?: 'default' | 'dark';
|
|
83
|
+
buttonAppearance?: 'plain' | 'push';
|
|
84
|
+
}
|
|
85
|
+
declare function ToolbarControlGroup({ children, label, className, expanded, single, appearance, tone, buttonAppearance }: ToolbarControlGroupProps): SafeHtml;
|
|
86
|
+
|
|
87
|
+
export { ToolbarControlGroup, type ToolbarControlGroupProps };
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## `@kerfjs/ui/list-header`
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { SafeHtml } from 'kerfjs';
|
|
94
|
+
|
|
95
|
+
type ListHeaderRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
|
|
96
|
+
'data-component'?: never;
|
|
97
|
+
'data-action'?: never;
|
|
98
|
+
'data-has-badge'?: never;
|
|
99
|
+
'data-has-count'?: never;
|
|
100
|
+
'data-toggle'?: never;
|
|
101
|
+
}>;
|
|
102
|
+
type ListHeaderTriggerAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
|
|
103
|
+
'data-action'?: never;
|
|
104
|
+
popoverTarget?: string;
|
|
105
|
+
popoverTargetAction?: 'toggle' | 'show' | 'hide';
|
|
106
|
+
'aria-controls'?: string;
|
|
107
|
+
'aria-haspopup'?: 'dialog' | 'menu' | 'listbox' | 'tree' | 'grid' | 'true';
|
|
108
|
+
}>;
|
|
109
|
+
interface ListHeaderBaseProps {
|
|
110
|
+
label: string;
|
|
111
|
+
action?: string;
|
|
112
|
+
actionLabel?: string;
|
|
113
|
+
actionIcon?: SafeHtml;
|
|
114
|
+
actionDisabled?: boolean;
|
|
115
|
+
disabledReason?: string;
|
|
116
|
+
expanded?: boolean;
|
|
117
|
+
toggle?: boolean;
|
|
118
|
+
/** Render as an unanimated loading skeleton: keep the label and action affordance, disable interaction. */
|
|
119
|
+
placeholder?: boolean;
|
|
120
|
+
rootAttributes?: ListHeaderRootAttributes;
|
|
121
|
+
triggerAttributes?: ListHeaderTriggerAttributes;
|
|
122
|
+
}
|
|
123
|
+
type ListHeaderIndicatorProps = {
|
|
124
|
+
count: number;
|
|
125
|
+
countLabel: string;
|
|
126
|
+
badge?: never;
|
|
127
|
+
} | {
|
|
128
|
+
count?: never;
|
|
129
|
+
countLabel?: never;
|
|
130
|
+
badge?: SafeHtml;
|
|
131
|
+
};
|
|
132
|
+
type ListHeaderProps = ListHeaderBaseProps & ListHeaderIndicatorProps;
|
|
133
|
+
declare function ListHeader({ label, count, countLabel, badge, action, actionLabel, actionIcon, actionDisabled, disabledReason, expanded, toggle, placeholder, rootAttributes, triggerAttributes }: ListHeaderProps): SafeHtml;
|
|
134
|
+
|
|
135
|
+
export { ListHeader, type ListHeaderProps };
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## `@kerfjs/ui/list-action-row`
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
import { SafeHtml } from 'kerfjs';
|
|
142
|
+
|
|
143
|
+
type ListActionRowRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
|
|
144
|
+
'data-component'?: never;
|
|
145
|
+
'data-action'?: never;
|
|
146
|
+
'data-item-id'?: never;
|
|
147
|
+
'data-has-icon'?: never;
|
|
148
|
+
'data-multiline'?: never;
|
|
149
|
+
'data-state'?: never;
|
|
150
|
+
'data-selected'?: never;
|
|
151
|
+
'data-pressed'?: never;
|
|
152
|
+
}>;
|
|
153
|
+
type ListActionRowTrailingAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
|
|
154
|
+
'data-component'?: never;
|
|
155
|
+
'data-action'?: never;
|
|
156
|
+
'data-item-id'?: never;
|
|
157
|
+
popoverTarget?: string;
|
|
158
|
+
popoverTargetAction?: 'toggle' | 'show' | 'hide';
|
|
159
|
+
'aria-controls'?: string;
|
|
160
|
+
'aria-haspopup'?: 'dialog' | 'menu' | 'listbox' | 'tree' | 'grid' | 'true';
|
|
161
|
+
}>;
|
|
162
|
+
interface ListActionRowProps {
|
|
163
|
+
/** Visible dormant content for the primary button. Must not contain interactive descendants. */
|
|
164
|
+
label: string | SafeHtml;
|
|
165
|
+
/** Decorative dormant content for the primary button. Must not contain interactive descendants. */
|
|
166
|
+
icon?: SafeHtml;
|
|
167
|
+
action: string;
|
|
168
|
+
itemId?: string;
|
|
169
|
+
selected?: boolean;
|
|
170
|
+
pressed?: boolean;
|
|
171
|
+
accessibleLabel?: string;
|
|
172
|
+
title?: string;
|
|
173
|
+
multiline?: boolean;
|
|
174
|
+
state?: string;
|
|
175
|
+
disabled?: boolean;
|
|
176
|
+
tabIndex?: number;
|
|
177
|
+
/** Render as an unanimated loading skeleton, disabling both actions. */
|
|
178
|
+
placeholder?: boolean;
|
|
179
|
+
trailingAction: string;
|
|
180
|
+
trailingActionLabel: string;
|
|
181
|
+
/** Decorative dormant content for the trailing button. Must not contain interactive descendants. */
|
|
182
|
+
trailingActionIcon: SafeHtml;
|
|
183
|
+
trailingActionDisabled?: boolean;
|
|
184
|
+
trailingActionTitle?: string;
|
|
185
|
+
className?: string;
|
|
186
|
+
style?: string;
|
|
187
|
+
rootAttributes?: ListActionRowRootAttributes;
|
|
188
|
+
trailingActionAttributes?: ListActionRowTrailingAttributes;
|
|
189
|
+
}
|
|
190
|
+
declare function ListActionRow({ label, icon, action, itemId, selected, pressed, accessibleLabel, title, multiline, state, disabled, tabIndex, placeholder, trailingAction, trailingActionLabel, trailingActionIcon, trailingActionDisabled, trailingActionTitle, className, style, rootAttributes, trailingActionAttributes }: ListActionRowProps): SafeHtml;
|
|
191
|
+
|
|
192
|
+
export { ListActionRow, type ListActionRowProps };
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## `@kerfjs/ui/list-item`
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
import { SafeHtml } from 'kerfjs';
|
|
199
|
+
|
|
200
|
+
type ListItemRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
|
|
201
|
+
'data-component'?: never;
|
|
202
|
+
'data-action'?: never;
|
|
203
|
+
'data-item-id'?: never;
|
|
204
|
+
'data-has-icon'?: never;
|
|
205
|
+
'data-multiline'?: never;
|
|
206
|
+
'data-state'?: never;
|
|
207
|
+
}>;
|
|
208
|
+
interface ListItemProps {
|
|
209
|
+
label: string | SafeHtml;
|
|
210
|
+
icon?: SafeHtml;
|
|
211
|
+
trailing?: SafeHtml;
|
|
212
|
+
selected?: boolean;
|
|
213
|
+
action: string;
|
|
214
|
+
itemId?: string;
|
|
215
|
+
className?: string;
|
|
216
|
+
style?: string;
|
|
217
|
+
pressed?: boolean;
|
|
218
|
+
accessibleLabel?: string;
|
|
219
|
+
title?: string;
|
|
220
|
+
multiline?: boolean;
|
|
221
|
+
state?: string;
|
|
222
|
+
disabled?: boolean;
|
|
223
|
+
tabIndex?: number;
|
|
224
|
+
/** Render the row as an unanimated loading skeleton, disabling its action. */
|
|
225
|
+
placeholder?: boolean;
|
|
226
|
+
rootAttributes?: ListItemRootAttributes;
|
|
227
|
+
}
|
|
228
|
+
declare function ListItem({ label, icon, trailing, selected, action, itemId, className, style, pressed, accessibleLabel, title, multiline, state, disabled, tabIndex, placeholder, rootAttributes }: ListItemProps): SafeHtml;
|
|
229
|
+
|
|
230
|
+
export { ListItem, type ListItemProps };
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## `@kerfjs/ui/panel-header`
|
|
234
|
+
|
|
235
|
+
```ts
|
|
236
|
+
import { SafeHtml } from 'kerfjs';
|
|
237
|
+
import { HeadingLevel } from './toolbar-text.js';
|
|
238
|
+
|
|
239
|
+
interface PanelHeaderProps {
|
|
240
|
+
title: string;
|
|
241
|
+
titleId: string;
|
|
242
|
+
summary?: string;
|
|
243
|
+
summaryId?: string;
|
|
244
|
+
icon?: SafeHtml;
|
|
245
|
+
iconClassName?: string;
|
|
246
|
+
actions?: SafeHtml;
|
|
247
|
+
/**
|
|
248
|
+
* Expose the title as a heading landmark (`role="heading"` + `aria-level`). Set it
|
|
249
|
+
* for a PAGE or view heading so screen-reader heading navigation works and the view
|
|
250
|
+
* has a primary heading; omit it (the default) for a dialog title, which is instead
|
|
251
|
+
* referenced via `aria-labelledby={titleId}` and needs no heading landmark.
|
|
252
|
+
*/
|
|
253
|
+
headingLevel?: HeadingLevel;
|
|
254
|
+
/** Render the title and summary as unanimated loading skeletons, keeping the icon and actions. */
|
|
255
|
+
placeholder?: boolean;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* The heading of a panel, dialog, or page: a plain `Toolbar` whose leading zone
|
|
259
|
+
* holds an optional icon control group and the title as extra-large `ToolbarText`,
|
|
260
|
+
* whose trailing zone holds the app's action controls, and with an optional
|
|
261
|
+
* subtitle on its own row, left-aligned with the title.
|
|
262
|
+
*
|
|
263
|
+
* PanelHeader overrides no Toolbar styles — it is just a Toolbar with an xl title.
|
|
264
|
+
* The only styling it adds is the icon group's fill/border color and the subtitle.
|
|
265
|
+
* When no icon is provided, the icon group is omitted entirely. The `actions` slot
|
|
266
|
+
* is passed straight into the toolbar's trailing zone; the app supplies whatever
|
|
267
|
+
* trailing controls it needs (typically a `ToolbarControlGroup`).
|
|
268
|
+
*/
|
|
269
|
+
declare function PanelHeader({ title, titleId, summary, summaryId, icon, iconClassName, actions, headingLevel, placeholder }: PanelHeaderProps): SafeHtml;
|
|
270
|
+
|
|
271
|
+
export { PanelHeader, type PanelHeaderProps };
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## `@kerfjs/ui/value-table`
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
import { SafeHtml } from 'kerfjs';
|
|
278
|
+
|
|
279
|
+
interface ValueTableRowProps {
|
|
280
|
+
label: string | SafeHtml;
|
|
281
|
+
value: string | SafeHtml;
|
|
282
|
+
icon?: SafeHtml;
|
|
283
|
+
className?: string;
|
|
284
|
+
/** Render the value as an unanimated loading skeleton, keeping the field label. */
|
|
285
|
+
placeholder?: boolean;
|
|
286
|
+
}
|
|
287
|
+
declare function ValueTableRow({ label, value, icon, className, placeholder }: ValueTableRowProps): SafeHtml;
|
|
288
|
+
|
|
289
|
+
interface ValueTableProps {
|
|
290
|
+
label: string;
|
|
291
|
+
className?: string;
|
|
292
|
+
children: SafeHtml | readonly SafeHtml[];
|
|
293
|
+
}
|
|
294
|
+
declare function ValueTable({ label, className, children }: ValueTableProps): SafeHtml;
|
|
295
|
+
|
|
296
|
+
export { ValueTable, type ValueTableProps, ValueTableRow, type ValueTableRowProps };
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
## `@kerfjs/ui/app-tab`
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
import { SafeHtml } from 'kerfjs';
|
|
303
|
+
|
|
304
|
+
type AppTabRootAttributes = Readonly<Record<`data-${string}`, string | undefined> & {
|
|
305
|
+
'data-component'?: never;
|
|
306
|
+
'data-action'?: never;
|
|
307
|
+
'data-tab-id'?: never;
|
|
308
|
+
'data-selected'?: never;
|
|
309
|
+
'data-tab-dragging'?: never;
|
|
310
|
+
'data-tab-drop-position'?: never;
|
|
311
|
+
}>;
|
|
312
|
+
interface AppTabProps {
|
|
313
|
+
id: string;
|
|
314
|
+
name: string;
|
|
315
|
+
selected?: boolean;
|
|
316
|
+
closable?: boolean;
|
|
317
|
+
draggable?: boolean;
|
|
318
|
+
leading?: SafeHtml;
|
|
319
|
+
trailing?: SafeHtml;
|
|
320
|
+
/** Decorative dormant content for the close button. Must not contain interactive descendants. */
|
|
321
|
+
closeIcon?: SafeHtml;
|
|
322
|
+
selectAction?: string;
|
|
323
|
+
closeAction?: string;
|
|
324
|
+
className?: string;
|
|
325
|
+
/** Render as an unanimated loading skeleton, disabling select/close and dragging. */
|
|
326
|
+
placeholder?: boolean;
|
|
327
|
+
rootAttributes?: AppTabRootAttributes;
|
|
328
|
+
}
|
|
329
|
+
declare function AppTab({ id, name, selected, closable, draggable, leading, trailing, closeIcon, selectAction, closeAction, className, placeholder, rootAttributes }: AppTabProps): SafeHtml;
|
|
330
|
+
|
|
331
|
+
export { AppTab, type AppTabProps };
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## `@kerfjs/ui/tab-bar`
|
|
335
|
+
|
|
336
|
+
```ts
|
|
337
|
+
import { SafeHtml } from 'kerfjs';
|
|
338
|
+
|
|
339
|
+
interface TabBarProps {
|
|
340
|
+
id: string;
|
|
341
|
+
label: string;
|
|
342
|
+
children: SafeHtml | readonly SafeHtml[];
|
|
343
|
+
leading?: SafeHtml;
|
|
344
|
+
trailing?: SafeHtml;
|
|
345
|
+
className?: string;
|
|
346
|
+
/**
|
|
347
|
+
* Keyboard activation mode for this strip, emitted as `data-tab-activation` for
|
|
348
|
+
* `wireTabBars` to read (overrides its `activation` option). `'automatic'` (default)
|
|
349
|
+
* selects on arrow / Home / End; `'manual'` moves roving focus only and the user
|
|
350
|
+
* selects with Enter / Space / click — use it when selecting a tab is a heavy action.
|
|
351
|
+
*/
|
|
352
|
+
activation?: 'automatic' | 'manual';
|
|
353
|
+
}
|
|
354
|
+
/** Render a controlled tab strip. The application owns selection, order, and persistence. */
|
|
355
|
+
declare function TabBar({ id, label, children, leading, trailing, className, activation }: TabBarProps): SafeHtml;
|
|
356
|
+
|
|
357
|
+
export { TabBar, type TabBarProps };
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
## `@kerfjs/ui/wire-tab-bars`
|
|
361
|
+
|
|
362
|
+
```ts
|
|
363
|
+
type TabReorderSource = 'pointer' | 'keyboard';
|
|
364
|
+
type TabDropPosition = 'before' | 'after';
|
|
365
|
+
interface TabReorder {
|
|
366
|
+
barId: string;
|
|
367
|
+
sourceId: string;
|
|
368
|
+
targetId: string;
|
|
369
|
+
position: TabDropPosition;
|
|
370
|
+
source: TabReorderSource;
|
|
371
|
+
}
|
|
372
|
+
type TabActivation = 'automatic' | 'manual';
|
|
373
|
+
interface WireTabBarsOptions {
|
|
374
|
+
onReorder: (change: TabReorder) => void;
|
|
375
|
+
/**
|
|
376
|
+
* How arrow / Home / End keys activate tabs (default `'automatic'`):
|
|
377
|
+
* - `'automatic'` moves roving focus **and** selects the focused tab (clicks it).
|
|
378
|
+
* - `'manual'` moves roving focus only; the user selects with Enter / Space / click
|
|
379
|
+
* (the ARIA Tabs manual-activation pattern). Use this when activation is a heavy or
|
|
380
|
+
* side-effecting action (e.g. a tab that loads a project) so arrowing through the
|
|
381
|
+
* strip doesn't trigger it on every tab.
|
|
382
|
+
*
|
|
383
|
+
* A per-bar `data-tab-activation="manual" | "automatic"` attribute (see the `TabBar`
|
|
384
|
+
* `activation` prop) overrides this option for that strip.
|
|
385
|
+
*/
|
|
386
|
+
activation?: TabActivation;
|
|
387
|
+
}
|
|
388
|
+
declare function reorderTabs<T>(items: readonly T[], getId: (item: T) => string, sourceId: string, targetId: string, position: TabDropPosition): T[];
|
|
389
|
+
/** Wire reordering and keyboard navigation while leaving controlled state in the application. */
|
|
390
|
+
declare function wireTabBars(root: HTMLElement | Document, { onReorder, activation }: WireTabBarsOptions): () => void;
|
|
391
|
+
|
|
392
|
+
export { type TabActivation, type TabDropPosition, type TabReorder, type TabReorderSource, type WireTabBarsOptions, reorderTabs, wireTabBars };
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
## `@kerfjs/ui/nav-stack`
|
|
396
|
+
|
|
397
|
+
```ts
|
|
398
|
+
import { SafeHtml } from 'kerfjs';
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* One entry in a {@link NavStack}. The app owns the stack as an array (usually a
|
|
402
|
+
* signal); `NavStack` renders it and `wireNavStack` animates the transitions.
|
|
403
|
+
*/
|
|
404
|
+
interface NavStackView {
|
|
405
|
+
/** Stable identity for keyed reconcile and transition direction. */
|
|
406
|
+
key: string;
|
|
407
|
+
content: SafeHtml;
|
|
408
|
+
/** Title shown in the top toolbar for this view. */
|
|
409
|
+
title?: string;
|
|
410
|
+
/** Trailing actions for this view's top toolbar. */
|
|
411
|
+
toolbar?: SafeHtml;
|
|
412
|
+
}
|
|
413
|
+
interface NavStackProps {
|
|
414
|
+
id: string;
|
|
415
|
+
/** Accessible name for the stack region. */
|
|
416
|
+
label: string;
|
|
417
|
+
/** The stack, root first; the last entry is the active top view. */
|
|
418
|
+
views: NavStackView[];
|
|
419
|
+
/** Accessible label for the back control (default "Back"). */
|
|
420
|
+
backLabel?: string;
|
|
421
|
+
/** Hide the top toolbar entirely (rare — a fully custom-chrome view). */
|
|
422
|
+
hideToolbar?: boolean;
|
|
423
|
+
/** Optional persistent bottom toolbar. */
|
|
424
|
+
bottomToolbar?: SafeHtml;
|
|
425
|
+
className?: string;
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* A navigation stack (iOS-style push/pop). Renders every entry stacked, the last
|
|
429
|
+
* one active; `@kerfjs/ui/wire-nav-stack`'s `wireNavStack` slides the content and
|
|
430
|
+
* cross-fades the chrome across a change. A single-pane layout is a `NavStack`
|
|
431
|
+
* with one entry. See `docs/23-app-layouts.md` §3.1.
|
|
432
|
+
*/
|
|
433
|
+
declare function NavStack({ id, label, views, backLabel, hideToolbar, bottomToolbar, className }: NavStackProps): SafeHtml;
|
|
434
|
+
|
|
435
|
+
export { NavStack, type NavStackProps, type NavStackView };
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
## `@kerfjs/ui/wire-nav-stack`
|
|
439
|
+
|
|
440
|
+
```ts
|
|
441
|
+
interface WireNavStackOptions {
|
|
442
|
+
/** Invoked when the back control is activated. The app pops its own stack. */
|
|
443
|
+
onBack?: () => void;
|
|
444
|
+
/** Transition duration in ms (default 200). Set 0 to disable animation. */
|
|
445
|
+
duration?: number;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Animate a `NavStack`'s push/pop transitions and wire its back control. The app
|
|
449
|
+
* owns the stack (a signal of `NavStackView[]`) and re-renders `NavStack` when it
|
|
450
|
+
* changes; this helper slides the content and settles the chrome across each
|
|
451
|
+
* change, and calls `onBack` when the back control is used. Returns a disposer.
|
|
452
|
+
*/
|
|
453
|
+
declare function wireNavStack(root: Element, options?: WireNavStackOptions): () => void;
|
|
454
|
+
|
|
455
|
+
export { type WireNavStackOptions, wireNavStack };
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
## `@kerfjs/ui/split-view`
|
|
459
|
+
|
|
460
|
+
```ts
|
|
461
|
+
import { SafeHtml } from 'kerfjs';
|
|
462
|
+
|
|
463
|
+
interface SplitViewResizable {
|
|
464
|
+
size: number;
|
|
465
|
+
min: number;
|
|
466
|
+
max: number;
|
|
467
|
+
}
|
|
468
|
+
interface SplitViewProps {
|
|
469
|
+
id: string;
|
|
470
|
+
label: string;
|
|
471
|
+
/** The list (primary) pane. */
|
|
472
|
+
list: SafeHtml;
|
|
473
|
+
/** The detail (secondary) pane. */
|
|
474
|
+
detail: SafeHtml;
|
|
475
|
+
/**
|
|
476
|
+
* Compact ("one pane at a time") classes — a handset or portrait tablet.
|
|
477
|
+
* Derive from `deviceClass().value.compact`. When true the split collapses to
|
|
478
|
+
* a `NavStack`: the list is the root and the detail is pushed over it.
|
|
479
|
+
*/
|
|
480
|
+
compact?: boolean;
|
|
481
|
+
/** In compact mode, whether the detail is currently pushed over the list. */
|
|
482
|
+
detailActive?: boolean;
|
|
483
|
+
/** Title/label for the list (compact NavStack root + region label). */
|
|
484
|
+
listTitle?: string;
|
|
485
|
+
/** Title/label for the detail (compact NavStack pushed view + region label). */
|
|
486
|
+
detailTitle?: string;
|
|
487
|
+
/** Back label for the compact NavStack (default "Back"). */
|
|
488
|
+
backLabel?: string;
|
|
489
|
+
/** A resizable separator on roomy classes (min/max px). Omit for a fixed split. */
|
|
490
|
+
resizable?: SplitViewResizable;
|
|
491
|
+
className?: string;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* A list-detail split. On roomy classes it shows both panes side
|
|
495
|
+
* by side with an optional resizable separator; on compact classes it collapses
|
|
496
|
+
* to a `NavStack` (list → detail). See `docs/23-app-layouts.md` §3.2. Compose the
|
|
497
|
+
* resizable wiring with `wireResizableRegions` and the compact back with
|
|
498
|
+
* `wireNavStack`.
|
|
499
|
+
*/
|
|
500
|
+
declare function SplitView({ id, label, list, detail, compact, detailActive, listTitle, detailTitle, backLabel, resizable, className }: SplitViewProps): SafeHtml;
|
|
501
|
+
|
|
502
|
+
export { SplitView, type SplitViewProps, type SplitViewResizable };
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
## `@kerfjs/ui/workbench`
|
|
506
|
+
|
|
507
|
+
```ts
|
|
508
|
+
import { SafeHtml } from 'kerfjs';
|
|
509
|
+
|
|
510
|
+
/** A collapsible Workbench panel — a side rail or the bottom drawer. */
|
|
511
|
+
interface WorkbenchPanel {
|
|
512
|
+
content: SafeHtml;
|
|
513
|
+
/** Whether the panel is currently collapsed (the app owns this). */
|
|
514
|
+
collapsed?: boolean;
|
|
515
|
+
/** Rail width, or drawer height, in px. Overrides the CSS default. */
|
|
516
|
+
size?: number;
|
|
517
|
+
/** Accessible name for the panel region. */
|
|
518
|
+
label?: string;
|
|
519
|
+
}
|
|
520
|
+
interface WorkbenchProps {
|
|
521
|
+
id: string;
|
|
522
|
+
label: string;
|
|
523
|
+
/** The central work area. */
|
|
524
|
+
main: SafeHtml;
|
|
525
|
+
leftRail?: WorkbenchPanel;
|
|
526
|
+
rightRail?: WorkbenchPanel;
|
|
527
|
+
bottomDrawer?: WorkbenchPanel;
|
|
528
|
+
className?: string;
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* The Xcode-like multi-panel workspace: a collapsible left rail, right rail, and
|
|
532
|
+
* bottom drawer around a central work area (any absent). Collapsing snaps the
|
|
533
|
+
* panel's track to zero in one reflow while its fixed-size content slides out via
|
|
534
|
+
* a composited transform — the instant-width / sliding-content technique, so the
|
|
535
|
+
* work area relayouts once, not per frame. The app owns each `collapsed` flag;
|
|
536
|
+
* the collapse is pure CSS (no wire). See `docs/23-app-layouts.md` §3.3.
|
|
537
|
+
*/
|
|
538
|
+
declare function Workbench({ id, label, main, leftRail, rightRail, bottomDrawer, className }: WorkbenchProps): SafeHtml;
|
|
539
|
+
|
|
540
|
+
export { Workbench, type WorkbenchPanel, type WorkbenchProps };
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
## `@kerfjs/ui/collapsible-panel`
|
|
544
|
+
|
|
545
|
+
```ts
|
|
546
|
+
import { SafeHtml } from 'kerfjs';
|
|
547
|
+
import { LucideIcon } from './lucide-icon.js';
|
|
548
|
+
import 'lucide';
|
|
549
|
+
|
|
550
|
+
/** Which edge a {@link CollapsiblePanel} docks to. */
|
|
551
|
+
type CollapsiblePanelSide = 'left' | 'right' | 'bottom';
|
|
552
|
+
/**
|
|
553
|
+
* The standard collapse/expand icon for a panel `side` and `collapsed` state,
|
|
554
|
+
* so every app's sidebars and drawers use one recognizable convention:
|
|
555
|
+
* `PanelLeft*` for a left rail, `PanelRight*` for a right rail, `PanelBottom*`
|
|
556
|
+
* for a bottom drawer — the `Close` glyph while open, the `Open` glyph while
|
|
557
|
+
* collapsed. Exposed so an app can render its own toggle affordance.
|
|
558
|
+
*/
|
|
559
|
+
declare function collapsiblePanelToggleIcon(side: CollapsiblePanelSide, collapsed: boolean): {
|
|
560
|
+
icon: Parameters<typeof LucideIcon>[0]['icon'];
|
|
561
|
+
name: string;
|
|
562
|
+
};
|
|
563
|
+
interface CollapsiblePanelToggleProps {
|
|
564
|
+
/** The panel this toggle controls. */
|
|
565
|
+
side: CollapsiblePanelSide;
|
|
566
|
+
/** The panel's current collapsed state (drives the icon direction). */
|
|
567
|
+
collapsed: boolean;
|
|
568
|
+
/** `data-action` the button carries so `wireSidebar` can delegate its click. */
|
|
569
|
+
action: string;
|
|
570
|
+
/** The panel id the button targets (`data-tab-panel`-style: `data-collapsible-panel`). */
|
|
571
|
+
panelId?: string;
|
|
572
|
+
/** Accessible label; defaults to "Collapse"/"Expand". */
|
|
573
|
+
label?: string;
|
|
574
|
+
className?: string;
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* A standard collapse/expand toggle button for a {@link CollapsiblePanel}: the
|
|
578
|
+
* recognizable per-side icon (see {@link collapsiblePanelToggleIcon}) plus the
|
|
579
|
+
* `data-action` / `aria-expanded` `wireSidebar` reads. Placement is the app's —
|
|
580
|
+
* put it in the panel's own header (to collapse) and somewhere always-visible
|
|
581
|
+
* (to expand while collapsed).
|
|
582
|
+
*/
|
|
583
|
+
declare function CollapsiblePanelToggle({ side, collapsed, action, panelId, label, className }: CollapsiblePanelToggleProps): SafeHtml;
|
|
584
|
+
interface CollapsiblePanelProps {
|
|
585
|
+
/** A stable id for the panel — `wireSidebar` targets it and toggles reference it. */
|
|
586
|
+
id: string;
|
|
587
|
+
/** Which edge the panel docks to: a left/right rail or a bottom drawer. */
|
|
588
|
+
side: CollapsiblePanelSide;
|
|
589
|
+
/** Whether the panel is currently collapsed (the app owns this signal). */
|
|
590
|
+
collapsed?: boolean;
|
|
591
|
+
/** Rail width or drawer height in px. Overrides the CSS default. */
|
|
592
|
+
size?: number;
|
|
593
|
+
/** Accessible label for the panel region. */
|
|
594
|
+
label?: string;
|
|
595
|
+
/** Panel content. */
|
|
596
|
+
children?: SafeHtml | readonly SafeHtml[];
|
|
597
|
+
className?: string;
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* A standalone collapsible side rail or bottom drawer, outside the full
|
|
601
|
+
* {@link Workbench} shell. It owns only the presentation: a fixed-size content
|
|
602
|
+
* area that stays laid out while the panel's track snaps to zero and the content
|
|
603
|
+
* slides out via `transform` (one reflow, composited — the same technique
|
|
604
|
+
* `Workbench` and the catalog sidebar use). The app owns the `collapsed` signal;
|
|
605
|
+
* pair it with `wireSidebar` for the toggle, focus, compact-overlay, keyboard,
|
|
606
|
+
* and persistence semantics, and with `CollapsiblePanelToggle` for the standard
|
|
607
|
+
* affordance. See `docs/24-collapsible-panel.md`.
|
|
608
|
+
*/
|
|
609
|
+
declare function CollapsiblePanel({ id, side, collapsed, size, label, children, className }: CollapsiblePanelProps): SafeHtml;
|
|
610
|
+
|
|
611
|
+
export { CollapsiblePanel, type CollapsiblePanelProps, type CollapsiblePanelSide, CollapsiblePanelToggle, type CollapsiblePanelToggleProps, collapsiblePanelToggleIcon };
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
## `@kerfjs/ui/wire-sidebar`
|
|
615
|
+
|
|
616
|
+
```ts
|
|
617
|
+
import { Signal, ReadonlySignal } from 'kerfjs';
|
|
618
|
+
import { DeviceClass } from './device-class.js';
|
|
619
|
+
|
|
620
|
+
/** Minimal `localStorage`-shaped store, so the persistence hook is testable. */
|
|
621
|
+
interface SidebarStorage {
|
|
622
|
+
getItem(key: string): string | null;
|
|
623
|
+
setItem(key: string, value: string): void;
|
|
624
|
+
}
|
|
625
|
+
interface WireSidebarPanel {
|
|
626
|
+
/** The panel id — matches `CollapsiblePanel`'s `id` and a toggle's `panelId`. */
|
|
627
|
+
id: string;
|
|
628
|
+
/** The app-owned collapsed signal. `wireSidebar` reads it (focus, overlay) and
|
|
629
|
+
* writes it (toggle, Escape, backdrop, persistence). */
|
|
630
|
+
collapsed: Signal<boolean>;
|
|
631
|
+
/** `data-action` value the panel's toggle button(s) carry. */
|
|
632
|
+
toggleAction: string;
|
|
633
|
+
/** When set, the collapsed state is loaded from and saved to `storage` under
|
|
634
|
+
* this key (a persistence hook), so the panel remembers its state. */
|
|
635
|
+
storageKey?: string;
|
|
636
|
+
}
|
|
637
|
+
interface WireSidebarOptions {
|
|
638
|
+
panels: readonly WireSidebarPanel[];
|
|
639
|
+
/**
|
|
640
|
+
* When provided, the sidebar adopts a compact **overlay** presentation while
|
|
641
|
+
* `deviceClass.compact` is true: an open panel floats over the content with a
|
|
642
|
+
* dismissable backdrop, Escape and backdrop-click collapse it, and focus is
|
|
643
|
+
* trapped within the open panel (the ARIA dialog pattern). Without it the panel
|
|
644
|
+
* is always inline.
|
|
645
|
+
*/
|
|
646
|
+
deviceClass?: ReadonlySignal<DeviceClass>;
|
|
647
|
+
/** Persistence store (default `globalThis.localStorage`, if present). */
|
|
648
|
+
storage?: SidebarStorage;
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* The reusable sidebar-semantics layer for {@link CollapsiblePanel}s: toggle
|
|
652
|
+
* delegation with focus restore, focus-into on open, an optional compact overlay
|
|
653
|
+
* (backdrop + Escape + focus trap) driven by {@link deviceClass}, and an optional
|
|
654
|
+
* persistence hook. The app owns each `collapsed` signal and the layout; this wire
|
|
655
|
+
* owns the interaction. Returns a disposer. See `docs/24-collapsible-panel.md`.
|
|
656
|
+
*/
|
|
657
|
+
declare function wireSidebar(root: HTMLElement, { panels, deviceClass, storage }: WireSidebarOptions): () => void;
|
|
658
|
+
|
|
659
|
+
export { type SidebarStorage, type WireSidebarOptions, type WireSidebarPanel, wireSidebar };
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
## `@kerfjs/ui/tab-scaffold`
|
|
663
|
+
|
|
664
|
+
```ts
|
|
665
|
+
import { SafeHtml } from 'kerfjs';
|
|
666
|
+
|
|
667
|
+
interface TabScaffoldTab {
|
|
668
|
+
id: string;
|
|
669
|
+
label: string;
|
|
670
|
+
/** Decorative icon shown above the label in the bottom bar. */
|
|
671
|
+
icon?: SafeHtml;
|
|
672
|
+
/** The tab's content — typically a `NavStack` so each tab keeps its own stack. */
|
|
673
|
+
content: SafeHtml;
|
|
674
|
+
}
|
|
675
|
+
interface TabScaffoldProps {
|
|
676
|
+
id: string;
|
|
677
|
+
/** Accessible name for the tab bar. */
|
|
678
|
+
label: string;
|
|
679
|
+
tabs: TabScaffoldTab[];
|
|
680
|
+
/** The controlled active tab id (the app owns selection). */
|
|
681
|
+
active: string;
|
|
682
|
+
className?: string;
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* A mobile-first, iOS-like bottom tab scaffold: a bottom tab bar that switches
|
|
686
|
+
* between major sections, each tab keeping its own content (usually a `NavStack`)
|
|
687
|
+
* mounted so its stack and scroll survive a switch. Controlled — the app owns
|
|
688
|
+
* `active`; wire selection with `@kerfjs/ui/wire-tab-scaffold`'s `wireTabScaffold`.
|
|
689
|
+
* On larger classes, promote the tabs to a `Workbench` rail or sidebar instead of
|
|
690
|
+
* a bottom bar. See `docs/23-app-layouts.md` §3.4.
|
|
691
|
+
*/
|
|
692
|
+
declare function TabScaffold({ id, label, tabs, active, className }: TabScaffoldProps): SafeHtml;
|
|
693
|
+
|
|
694
|
+
export { TabScaffold, type TabScaffoldProps, type TabScaffoldTab };
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
## `@kerfjs/ui/wire-tab-scaffold`
|
|
698
|
+
|
|
699
|
+
```ts
|
|
700
|
+
interface WireTabScaffoldOptions {
|
|
701
|
+
/** Invoked with the selected tab id when a bottom-bar tab is activated. */
|
|
702
|
+
onSelect: (tabId: string) => void;
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Wire a `TabScaffold`'s bottom tab bar: clicking a tab calls `onSelect` with its
|
|
706
|
+
* id (the app then updates its controlled `active`). Returns a disposer.
|
|
707
|
+
*/
|
|
708
|
+
declare function wireTabScaffold(root: Element, options: WireTabScaffoldOptions): () => void;
|
|
709
|
+
|
|
710
|
+
export { type WireTabScaffoldOptions, wireTabScaffold };
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
## `@kerfjs/ui/resizable-region`
|
|
714
|
+
|
|
715
|
+
```ts
|
|
716
|
+
import { SafeHtml } from 'kerfjs';
|
|
717
|
+
|
|
718
|
+
type ResizableRegionAxis = 'horizontal' | 'vertical';
|
|
719
|
+
type ResizableRegionEdge = 'start' | 'end';
|
|
720
|
+
interface ResizableRegionProps {
|
|
721
|
+
id: string;
|
|
722
|
+
label: string;
|
|
723
|
+
size: number;
|
|
724
|
+
min: number;
|
|
725
|
+
max: number;
|
|
726
|
+
axis?: ResizableRegionAxis;
|
|
727
|
+
edge?: ResizableRegionEdge;
|
|
728
|
+
collapsed?: boolean;
|
|
729
|
+
transitioning?: boolean;
|
|
730
|
+
/** Decorative dormant content for the separator handle. Must not contain interactive descendants. */
|
|
731
|
+
handleIcon?: SafeHtml;
|
|
732
|
+
children: SafeHtml | SafeHtml[];
|
|
733
|
+
}
|
|
734
|
+
declare const clampRegionSize: (size: number, min: number, max: number) => number;
|
|
735
|
+
declare const resizeRegionFromPointer: (startSize: number, delta: number, edge: ResizableRegionEdge) => number;
|
|
736
|
+
declare function ResizableRegion({ id, label, size, min, max, axis, edge, collapsed, transitioning, handleIcon, children }: ResizableRegionProps): SafeHtml;
|
|
737
|
+
|
|
738
|
+
export { ResizableRegion, type ResizableRegionAxis, type ResizableRegionEdge, type ResizableRegionProps, clampRegionSize, resizeRegionFromPointer };
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
## `@kerfjs/ui/wire-resizable-regions`
|
|
742
|
+
|
|
743
|
+
```ts
|
|
744
|
+
interface ResizeCommit {
|
|
745
|
+
id: string;
|
|
746
|
+
size: number;
|
|
747
|
+
source: 'keyboard' | 'pointer';
|
|
748
|
+
}
|
|
749
|
+
interface WireResizableRegionsOptions {
|
|
750
|
+
step?: number;
|
|
751
|
+
largeStep?: number;
|
|
752
|
+
onPreview?: (change: ResizeCommit) => void;
|
|
753
|
+
onCommit: (change: ResizeCommit) => void;
|
|
754
|
+
}
|
|
755
|
+
/** Wire pointer and separator-keyboard behavior for every ResizableRegion below root. */
|
|
756
|
+
declare function wireResizableRegions(root: HTMLElement, { step, largeStep, onPreview, onCommit }: WireResizableRegionsOptions): () => void;
|
|
757
|
+
|
|
758
|
+
export { type ResizeCommit, type WireResizableRegionsOptions, wireResizableRegions };
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
## `@kerfjs/ui/device-class`
|
|
762
|
+
|
|
763
|
+
```ts
|
|
764
|
+
import { ReadonlySignal } from 'kerfjs';
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* Reactive device-class detection for `@kerfjs/ui` (see `docs/23-app-layouts.md`
|
|
768
|
+
* §2). `deviceClass()` returns a `ReadonlySignal<DeviceClass>` describing the
|
|
769
|
+
* current viewport as a size bucket × orientation × viewport-segment count, so a
|
|
770
|
+
* layout can pick its presentation reactively instead of hand-wiring `matchMedia`.
|
|
771
|
+
*
|
|
772
|
+
* One shared viewport source backs every reader; the pure `classifyViewport`
|
|
773
|
+
* core is DOM-free and directly unit-tested.
|
|
774
|
+
*/
|
|
775
|
+
type DeviceSize = 'xs-mobile' | 'mobile' | 'tablet' | 'desktop' | 'xl-desktop';
|
|
776
|
+
type DeviceOrientation = 'portrait' | 'landscape';
|
|
777
|
+
/** Minimum widths (px) at which each larger bucket begins. `xs-mobile` is 0. */
|
|
778
|
+
interface DeviceBreakpoints {
|
|
779
|
+
mobile: number;
|
|
780
|
+
tablet: number;
|
|
781
|
+
desktop: number;
|
|
782
|
+
'xl-desktop': number;
|
|
783
|
+
}
|
|
784
|
+
interface DeviceClass {
|
|
785
|
+
size: DeviceSize;
|
|
786
|
+
orientation: DeviceOrientation;
|
|
787
|
+
/** Horizontal viewport segments (foldables / dual-screen); 1 on ordinary devices. */
|
|
788
|
+
segments: number;
|
|
789
|
+
/** Vertical viewport segments; 1 on ordinary devices. */
|
|
790
|
+
verticalSegments: number;
|
|
791
|
+
/** Small phones — `xs-mobile` or `mobile`. */
|
|
792
|
+
handset: boolean;
|
|
793
|
+
/** "One pane at a time" — a handset or a portrait tablet. */
|
|
794
|
+
compact: boolean;
|
|
795
|
+
/** True when the current size is `size` or larger, e.g. `atLeast('tablet')`. */
|
|
796
|
+
atLeast(size: DeviceSize): boolean;
|
|
797
|
+
}
|
|
798
|
+
/** A raw viewport snapshot, before breakpoints are applied. */
|
|
799
|
+
interface Viewport {
|
|
800
|
+
width: number;
|
|
801
|
+
height: number;
|
|
802
|
+
segments: number;
|
|
803
|
+
verticalSegments: number;
|
|
804
|
+
}
|
|
805
|
+
interface DeviceClassOptions {
|
|
806
|
+
/** Override any of the default bucket thresholds. */
|
|
807
|
+
breakpoints?: Partial<DeviceBreakpoints>;
|
|
808
|
+
/** The viewport assumed when there is no DOM (SSR). Defaults to 1024×768, one segment. */
|
|
809
|
+
ssr?: Partial<Viewport>;
|
|
810
|
+
}
|
|
811
|
+
declare const DEFAULT_BREAKPOINTS: DeviceBreakpoints;
|
|
812
|
+
/**
|
|
813
|
+
* Classify a raw viewport into a {@link DeviceClass}. Pure and DOM-free — the
|
|
814
|
+
* single source of truth for the bucketing rules.
|
|
815
|
+
*/
|
|
816
|
+
declare function classifyViewport(width: number, orientation: DeviceOrientation, segments?: number, verticalSegments?: number, breakpoints?: DeviceBreakpoints): DeviceClass;
|
|
817
|
+
/**
|
|
818
|
+
* A reactive signal of the current {@link DeviceClass}. Reading it inside an
|
|
819
|
+
* `effect`/`computed` re-runs when the viewport crosses a breakpoint, rotates,
|
|
820
|
+
* or changes its segment count. Without a DOM it resolves to `options.ssr`
|
|
821
|
+
* (default 1024×768, landscape, one segment).
|
|
822
|
+
*/
|
|
823
|
+
declare function deviceClass(options?: DeviceClassOptions): ReadonlySignal<DeviceClass>;
|
|
824
|
+
|
|
825
|
+
export { DEFAULT_BREAKPOINTS, type DeviceBreakpoints, type DeviceClass, type DeviceClassOptions, type DeviceOrientation, type DeviceSize, type Viewport, classifyViewport, deviceClass };
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
## `@kerfjs/ui/catalog`
|
|
829
|
+
|
|
830
|
+
```ts
|
|
831
|
+
import { SafeHtml } from 'kerfjs';
|
|
832
|
+
|
|
833
|
+
/** A reference link shown in the detail footer for the active entry. */
|
|
834
|
+
interface CatalogResource {
|
|
835
|
+
label: string;
|
|
836
|
+
href: string;
|
|
837
|
+
/** Optional monospace detail (e.g. a file path) shown after the label. */
|
|
838
|
+
detail?: string;
|
|
839
|
+
}
|
|
840
|
+
/** A related entry offered in the detail footer's "Related entries" popup menu. */
|
|
841
|
+
interface CatalogRelated {
|
|
842
|
+
id: string;
|
|
843
|
+
name: string;
|
|
844
|
+
/** Group heading in the menu, e.g. "Uses" / "Used by". */
|
|
845
|
+
group: string;
|
|
846
|
+
}
|
|
847
|
+
interface CatalogEntry {
|
|
848
|
+
id: string;
|
|
849
|
+
name: string;
|
|
850
|
+
description?: string;
|
|
851
|
+
resources?: readonly CatalogResource[];
|
|
852
|
+
related?: readonly CatalogRelated[];
|
|
853
|
+
}
|
|
854
|
+
interface CatalogSection {
|
|
855
|
+
category: string;
|
|
856
|
+
entries: readonly CatalogEntry[];
|
|
857
|
+
}
|
|
858
|
+
/**
|
|
859
|
+
* A secondary group of sections shown below the primary sidebar sections with a
|
|
860
|
+
* quieter "ecosystem" treatment (e.g. third-party components). Optionally
|
|
861
|
+
* collapsible — the app owns `expanded` and toggles it from `wireCatalog`'s
|
|
862
|
+
* `onToggleSecondary`.
|
|
863
|
+
*/
|
|
864
|
+
interface CatalogSecondaryGroup {
|
|
865
|
+
label: string;
|
|
866
|
+
sections: readonly CatalogSection[];
|
|
867
|
+
/** When true, the group's label is a disclosure toggle controlling `expanded`. */
|
|
868
|
+
collapsible?: boolean;
|
|
869
|
+
/** Whether the group is expanded (controlled). Ignored unless `collapsible`. */
|
|
870
|
+
expanded?: boolean;
|
|
871
|
+
}
|
|
872
|
+
interface CatalogBrand {
|
|
873
|
+
title: string;
|
|
874
|
+
subtitle?: string;
|
|
875
|
+
/** Logo image URL (rendered decorative). Omit for a text-only brand. */
|
|
876
|
+
logoUrl?: string;
|
|
877
|
+
}
|
|
878
|
+
interface CatalogProps {
|
|
879
|
+
brand: CatalogBrand;
|
|
880
|
+
sections: readonly CatalogSection[];
|
|
881
|
+
/** The controlled active entry id — the app owns this signal. */
|
|
882
|
+
active: string;
|
|
883
|
+
/** The rendered preview for the active entry; the app computes it from `active`. */
|
|
884
|
+
content: SafeHtml;
|
|
885
|
+
/** Whether the sidebar is collapsed (controlled). */
|
|
886
|
+
collapsed?: boolean;
|
|
887
|
+
/** Current theme; when set, a theme toggle is shown that switches to the opposite. Omit to hide it. */
|
|
888
|
+
theme?: 'light' | 'dark';
|
|
889
|
+
/** Extra header controls placed before the theme toggle (each a `ToolbarControlGroup`). */
|
|
890
|
+
headerActions?: SafeHtml;
|
|
891
|
+
/** A secondary "ecosystem" group of sections below the primary category groups. */
|
|
892
|
+
secondarySections?: CatalogSecondaryGroup;
|
|
893
|
+
/** Extra sidebar content below the category groups (and the secondary group). */
|
|
894
|
+
sidebarFooter?: SafeHtml;
|
|
895
|
+
/** Status line content shown at the start of the detail footer. */
|
|
896
|
+
status?: SafeHtml;
|
|
897
|
+
selectAction?: string;
|
|
898
|
+
toggleSidebarAction?: string;
|
|
899
|
+
toggleThemeAction?: string;
|
|
900
|
+
/** Action fired by the secondary group's disclosure toggle (when collapsible). */
|
|
901
|
+
toggleSecondaryAction?: string;
|
|
902
|
+
className?: string;
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* A reusable component-catalog shell: a collapsible category sidebar, a titled
|
|
906
|
+
* detail stage that renders the active entry's preview, and a footer with
|
|
907
|
+
* reference links and a related-entry popup menu. Built entirely from public
|
|
908
|
+
* `@kerfjs/ui` primitives. Controlled and stateless — the app owns the `active`,
|
|
909
|
+
* `collapsed`, and `theme` signals and computes `content` from `active` in its own
|
|
910
|
+
* render; wire the sidebar/collapse/theme actions with `wireCatalog`.
|
|
911
|
+
*/
|
|
912
|
+
declare function Catalog({ brand, sections, active, content, collapsed, theme, headerActions, secondarySections, sidebarFooter, status, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, className, }: CatalogProps): SafeHtml;
|
|
913
|
+
/**
|
|
914
|
+
* How a {@link CatalogExample}'s content aligns its visible left edge with the
|
|
915
|
+
* example's `ListHeader` label (which sits 16px in — 8px title + 8px label):
|
|
916
|
+
* - `'glyph'` — a bare glyph/text specimen with no inline geometry insets the full 16px.
|
|
917
|
+
* - `'inline-control'` — a control that already carries ~8px of its own inline padding insets 8px so its content lands on the same line.
|
|
918
|
+
* - `'none'` — a content-item / composition that owns its geometry and already aligns; no inset (default).
|
|
919
|
+
*/
|
|
920
|
+
type CatalogExampleAlign = 'glyph' | 'inline-control' | 'none';
|
|
921
|
+
interface CatalogExampleProps {
|
|
922
|
+
/** The example's label, shown as a `ListHeader` above the specimen. Omit for a bare specimen. */
|
|
923
|
+
label?: string;
|
|
924
|
+
/** Optional explanatory note between the label and the specimen. */
|
|
925
|
+
note?: SafeHtml | string;
|
|
926
|
+
/** Alignment inset for the specimen — see {@link CatalogExampleAlign}. Default `'none'`. */
|
|
927
|
+
align?: CatalogExampleAlign;
|
|
928
|
+
className?: string;
|
|
929
|
+
children?: SafeHtml | readonly SafeHtml[];
|
|
930
|
+
}
|
|
931
|
+
/**
|
|
932
|
+
* One labeled example in a catalog preview: a `ListHeader` label, an optional
|
|
933
|
+
* note, and the specimen. `align` insets the specimen so its visible left edge
|
|
934
|
+
* lines up with the label text, encoding the catalog's alignment rules as a
|
|
935
|
+
* first-class prop instead of per-demo CSS. The inset is published as the
|
|
936
|
+
* `--kui-catalog-example-align` custom property so a debug overlay can exclude it
|
|
937
|
+
* from a specimen's measured margin.
|
|
938
|
+
*/
|
|
939
|
+
declare function CatalogExample({ label, note, align, className, children }: CatalogExampleProps): SafeHtml;
|
|
940
|
+
interface CatalogExampleStackProps {
|
|
941
|
+
/** Accessible label for the stack region. */
|
|
942
|
+
label?: string;
|
|
943
|
+
className?: string;
|
|
944
|
+
children?: SafeHtml | readonly SafeHtml[];
|
|
945
|
+
}
|
|
946
|
+
/** A vertically-stacked group of {@link CatalogExample}s with the catalog's example rhythm. */
|
|
947
|
+
declare function CatalogExampleStack({ label, className, children }: CatalogExampleStackProps): SafeHtml;
|
|
948
|
+
|
|
949
|
+
export { Catalog, type CatalogBrand, type CatalogEntry, CatalogExample, type CatalogExampleAlign, type CatalogExampleProps, CatalogExampleStack, type CatalogExampleStackProps, type CatalogProps, type CatalogRelated, type CatalogResource, type CatalogSecondaryGroup, type CatalogSection };
|
|
950
|
+
```
|
|
951
|
+
|
|
952
|
+
## `@kerfjs/ui/wire-catalog`
|
|
953
|
+
|
|
954
|
+
```ts
|
|
955
|
+
interface WireCatalogOptions {
|
|
956
|
+
/** Invoked with the entry id when a sidebar item or a related-entry option is chosen. */
|
|
957
|
+
onSelect: (id: string) => void;
|
|
958
|
+
/** Invoked when the sidebar collapse/expand control is activated. */
|
|
959
|
+
onToggleSidebar?: () => void;
|
|
960
|
+
/** Invoked when the theme toggle is activated. */
|
|
961
|
+
onToggleTheme?: () => void;
|
|
962
|
+
/** Invoked when the secondary (ecosystem) group's disclosure toggle is activated. */
|
|
963
|
+
onToggleSecondary?: () => void;
|
|
964
|
+
/** When set, `?<urlParam>=<id>` is written on select via `history.replaceState`. */
|
|
965
|
+
urlParam?: string;
|
|
966
|
+
selectAction?: string;
|
|
967
|
+
toggleSidebarAction?: string;
|
|
968
|
+
toggleThemeAction?: string;
|
|
969
|
+
toggleSecondaryAction?: string;
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* Wire a {@link Catalog}'s interactions with one delegated listener set: sidebar
|
|
973
|
+
* item selection (and the related-entry popup menu), the sidebar collapse toggle, and
|
|
974
|
+
* the theme toggle. The app owns the `active`/`collapsed`/`theme` signals and updates
|
|
975
|
+
* them in the callbacks; optionally mirror the active id into the URL via `urlParam`.
|
|
976
|
+
* Returns a disposer.
|
|
977
|
+
*/
|
|
978
|
+
declare function wireCatalog(root: HTMLElement, { onSelect, onToggleSidebar, onToggleTheme, onToggleSecondary, urlParam, selectAction, toggleSidebarAction, toggleThemeAction, toggleSecondaryAction, }: WireCatalogOptions): () => void;
|
|
979
|
+
|
|
980
|
+
export { type WireCatalogOptions, wireCatalog };
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
## `@kerfjs/ui/segmented-control`
|
|
984
|
+
|
|
985
|
+
```ts
|
|
986
|
+
import { SafeHtml } from 'kerfjs';
|
|
987
|
+
|
|
988
|
+
type SegmentedControlAppearance = 'filled' | 'outlined' | 'toolbar';
|
|
989
|
+
type SegmentedControlShape = 'rounded' | 'pill';
|
|
990
|
+
type SegmentedControlSize = 'small' | 'default';
|
|
991
|
+
type SegmentedControlLayout = 'content' | 'equal';
|
|
992
|
+
interface SegmentedControlChoice {
|
|
993
|
+
value: string;
|
|
994
|
+
label: string;
|
|
995
|
+
content?: SafeHtml;
|
|
996
|
+
title?: string;
|
|
997
|
+
disabled?: boolean;
|
|
998
|
+
}
|
|
999
|
+
interface SegmentedControlProps {
|
|
1000
|
+
id: string;
|
|
1001
|
+
label: string;
|
|
1002
|
+
value: string;
|
|
1003
|
+
choices: readonly SegmentedControlChoice[];
|
|
1004
|
+
action?: string;
|
|
1005
|
+
appearance?: SegmentedControlAppearance;
|
|
1006
|
+
shape?: SegmentedControlShape;
|
|
1007
|
+
size?: SegmentedControlSize;
|
|
1008
|
+
layout?: SegmentedControlLayout;
|
|
1009
|
+
className?: string;
|
|
1010
|
+
/** Render as an unanimated loading skeleton, disabling every segment. */
|
|
1011
|
+
placeholder?: boolean;
|
|
1012
|
+
}
|
|
1013
|
+
declare function SegmentedControl({ id, label, value, choices, action, appearance, shape, size, layout, className, placeholder, }: SegmentedControlProps): SafeHtml;
|
|
1014
|
+
|
|
1015
|
+
export { SegmentedControl, type SegmentedControlAppearance, type SegmentedControlChoice, type SegmentedControlLayout, type SegmentedControlProps, type SegmentedControlShape, type SegmentedControlSize };
|
|
1016
|
+
```
|
|
1017
|
+
|
|
1018
|
+
## `@kerfjs/ui/state-banner`
|
|
1019
|
+
|
|
1020
|
+
```ts
|
|
1021
|
+
import { SafeHtml } from 'kerfjs';
|
|
1022
|
+
|
|
1023
|
+
type StateBannerTone = 'neutral' | 'info' | 'success' | 'warning' | 'danger';
|
|
1024
|
+
interface StateBannerProps {
|
|
1025
|
+
title: string;
|
|
1026
|
+
detail?: string;
|
|
1027
|
+
icon?: SafeHtml;
|
|
1028
|
+
action?: SafeHtml;
|
|
1029
|
+
tone?: StateBannerTone;
|
|
1030
|
+
urgency?: 'status' | 'alert';
|
|
1031
|
+
className?: string;
|
|
1032
|
+
/** Render the title and detail as unanimated loading skeletons, keeping the icon and tone. */
|
|
1033
|
+
placeholder?: boolean;
|
|
1034
|
+
}
|
|
1035
|
+
declare function StateBanner({ title, detail, icon, action, tone, urgency, className, placeholder }: StateBannerProps): SafeHtml;
|
|
1036
|
+
|
|
1037
|
+
export { StateBanner, type StateBannerProps, type StateBannerTone };
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
## `@kerfjs/ui/empty-state`
|
|
1041
|
+
|
|
1042
|
+
```ts
|
|
1043
|
+
import { SafeHtml } from 'kerfjs';
|
|
1044
|
+
|
|
1045
|
+
interface EmptyStateProps {
|
|
1046
|
+
title: string;
|
|
1047
|
+
detail?: string;
|
|
1048
|
+
icon?: SafeHtml;
|
|
1049
|
+
action?: SafeHtml;
|
|
1050
|
+
busy?: boolean;
|
|
1051
|
+
className?: string;
|
|
1052
|
+
}
|
|
1053
|
+
declare function EmptyState({ title, detail, icon, action, busy, className }: EmptyStateProps): SafeHtml;
|
|
1054
|
+
|
|
1055
|
+
export { EmptyState, type EmptyStateProps };
|
|
1056
|
+
```
|
|
1057
|
+
|
|
1058
|
+
## `@kerfjs/ui/loading-spinner`
|
|
1059
|
+
|
|
1060
|
+
```ts
|
|
1061
|
+
import * as kerfjs from 'kerfjs';
|
|
1062
|
+
|
|
1063
|
+
interface LoadingSpinnerProps {
|
|
1064
|
+
className?: string;
|
|
1065
|
+
label?: string;
|
|
1066
|
+
}
|
|
1067
|
+
/** Stable viewBox-centered progress ring based on svg-spinners' MIT-licensed 180-ring. */
|
|
1068
|
+
declare function LoadingSpinner({ className, label }: LoadingSpinnerProps): kerfjs.SafeHtml;
|
|
1069
|
+
|
|
1070
|
+
export { LoadingSpinner, type LoadingSpinnerProps };
|
|
1071
|
+
```
|
|
1072
|
+
|
|
1073
|
+
## `@kerfjs/ui/skeleton`
|
|
1074
|
+
|
|
1075
|
+
```ts
|
|
1076
|
+
import * as kerfjs from 'kerfjs';
|
|
1077
|
+
|
|
1078
|
+
interface SkeletonProps {
|
|
1079
|
+
/** Width as any CSS length (e.g. `remify(120px)`, `60%`). Defaults to filling its slot. */
|
|
1080
|
+
width?: string;
|
|
1081
|
+
/** Height as any CSS length. Defaults to a single text line. */
|
|
1082
|
+
height?: string;
|
|
1083
|
+
/** Corner radius override (a CSS length). Defaults to the small radius token. */
|
|
1084
|
+
radius?: string;
|
|
1085
|
+
/** Render this many stacked lines (the last one shorter), for multi-line text. */
|
|
1086
|
+
lines?: number;
|
|
1087
|
+
/** Accessible label. Omit to keep the block decorative (`aria-hidden`). */
|
|
1088
|
+
label?: string;
|
|
1089
|
+
className?: string;
|
|
1090
|
+
}
|
|
1091
|
+
/**
|
|
1092
|
+
* A subtle, deliberately **unanimated** loading placeholder block. Use it for a
|
|
1093
|
+
* value slot whose content is not yet known, on its own or via a component's
|
|
1094
|
+
* `placeholder` prop. Decorative by default (`aria-hidden`); pass `label` to
|
|
1095
|
+
* announce it. Sizes to its slot unless `width`/`height` are given.
|
|
1096
|
+
*/
|
|
1097
|
+
declare function Skeleton({ width, height, radius, lines, label, className }: SkeletonProps): kerfjs.SafeHtml;
|
|
1098
|
+
|
|
1099
|
+
export { Skeleton, type SkeletonProps };
|
|
1100
|
+
```
|
|
1101
|
+
|
|
1102
|
+
## `@kerfjs/ui/token-search-field`
|
|
1103
|
+
|
|
1104
|
+
```ts
|
|
1105
|
+
import { SafeHtml } from 'kerfjs';
|
|
1106
|
+
|
|
1107
|
+
interface TokenSearchToken {
|
|
1108
|
+
value: string;
|
|
1109
|
+
label: string;
|
|
1110
|
+
offset?: number;
|
|
1111
|
+
accessibleLabel?: string;
|
|
1112
|
+
}
|
|
1113
|
+
interface TokenSearchFieldProps {
|
|
1114
|
+
id: string;
|
|
1115
|
+
label: string;
|
|
1116
|
+
query?: string;
|
|
1117
|
+
tokens?: readonly TokenSearchToken[];
|
|
1118
|
+
placeholder?: string;
|
|
1119
|
+
tokenPlaceholder?: string;
|
|
1120
|
+
disabled?: boolean;
|
|
1121
|
+
autofocus?: boolean;
|
|
1122
|
+
/** Allow an empty field to render as one iconic action. */
|
|
1123
|
+
collapsible?: boolean;
|
|
1124
|
+
/** Keep an empty collapsible field open while the application owns focus. */
|
|
1125
|
+
expanded?: boolean;
|
|
1126
|
+
expandAction?: string;
|
|
1127
|
+
expandLabel?: string;
|
|
1128
|
+
leading?: SafeHtml;
|
|
1129
|
+
trailing?: SafeHtml;
|
|
1130
|
+
editAction?: string;
|
|
1131
|
+
removeAction?: string;
|
|
1132
|
+
clearAction?: string;
|
|
1133
|
+
clearLabel?: string;
|
|
1134
|
+
className?: string;
|
|
1135
|
+
editorAttributes?: Readonly<Record<`data-${string}`, string>>;
|
|
1136
|
+
}
|
|
1137
|
+
interface TokenSearchFieldValue {
|
|
1138
|
+
query: string;
|
|
1139
|
+
tokens: TokenSearchToken[];
|
|
1140
|
+
}
|
|
1141
|
+
declare function TokenSearchField({ id, label, query, tokens, placeholder, tokenPlaceholder, disabled, autofocus, collapsible, expanded, expandAction, expandLabel, leading, trailing, editAction, removeAction, clearAction, clearLabel, className, editorAttributes, }: TokenSearchFieldProps): SafeHtml;
|
|
1142
|
+
/** Read editable text and ordered token offsets from a rendered TokenSearchField editor. */
|
|
1143
|
+
declare function readTokenSearchField(editor: HTMLElement, knownTokens?: readonly TokenSearchToken[]): TokenSearchFieldValue;
|
|
1144
|
+
/** Focus an editor and place its caret at a text offset, skipping atomic token chips. */
|
|
1145
|
+
declare function placeTokenSearchCaret(editor: HTMLElement, offset?: number): void;
|
|
1146
|
+
|
|
1147
|
+
export { TokenSearchField, type TokenSearchFieldProps, type TokenSearchFieldValue, type TokenSearchToken, placeTokenSearchCaret, readTokenSearchField };
|
|
1148
|
+
```
|
|
1149
|
+
|
|
1150
|
+
## `@kerfjs/ui/wire-token-search-fields`
|
|
1151
|
+
|
|
1152
|
+
```ts
|
|
1153
|
+
import { Signal } from 'kerfjs';
|
|
1154
|
+
|
|
1155
|
+
interface TokenSearchSubmit {
|
|
1156
|
+
id: string;
|
|
1157
|
+
editor: HTMLElement;
|
|
1158
|
+
}
|
|
1159
|
+
/** Reported when adjacent-token keyboard deletion asks the app to drop a chip. */
|
|
1160
|
+
interface TokenSearchTokenRemoval {
|
|
1161
|
+
id: string;
|
|
1162
|
+
/** The `data-token-value` of the token the app should remove from its state. */
|
|
1163
|
+
value: string;
|
|
1164
|
+
editor: HTMLElement;
|
|
1165
|
+
/** `'backward'` = the token before the caret (Backspace); `'forward'` = after (Delete). */
|
|
1166
|
+
direction: 'backward' | 'forward';
|
|
1167
|
+
}
|
|
1168
|
+
/**
|
|
1169
|
+
* Opt-in keyboard behavior for the atomic token chips. Off unless `keyboard` is
|
|
1170
|
+
* set; each piece defaults on once opted in. The helper never mutates app state:
|
|
1171
|
+
* a removal is reported through {@link TokenSearchKeyboardOptions.onRemoveToken}
|
|
1172
|
+
* for the caller to apply, while caret movement past a chip is a pure ephemeral
|
|
1173
|
+
* mechanic the helper performs itself.
|
|
1174
|
+
*/
|
|
1175
|
+
interface TokenSearchKeyboardOptions {
|
|
1176
|
+
/**
|
|
1177
|
+
* From a collapsed caret with no selection, Backspace removes the token
|
|
1178
|
+
* immediately before it and Delete the token immediately after — reported via
|
|
1179
|
+
* `onRemoveToken` — instead of deleting a character. Default: true.
|
|
1180
|
+
*/
|
|
1181
|
+
removeAdjacentToken?: boolean;
|
|
1182
|
+
/**
|
|
1183
|
+
* ArrowRight moves the caret past a trailing atomic token so text typed next
|
|
1184
|
+
* lands after the chip. Default: true.
|
|
1185
|
+
*/
|
|
1186
|
+
moveCaretPastToken?: boolean;
|
|
1187
|
+
/** Apply the reported removal to your controlled state, then re-render. */
|
|
1188
|
+
onRemoveToken?: (removal: TokenSearchTokenRemoval) => void;
|
|
1189
|
+
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Managed collapsible behavior for the iconic TokenSearchField. Every piece is on
|
|
1192
|
+
* by default; disable a specific one to own it in the app. Provide `signals` to
|
|
1193
|
+
* drive app-owned `expanded` signals per field id instead of helper-created ones.
|
|
1194
|
+
*/
|
|
1195
|
+
interface TokenSearchCollapsibleOptions {
|
|
1196
|
+
/** Expand the field and focus its editor when the iconic trigger is activated. Default: true. */
|
|
1197
|
+
expandOnActivate?: boolean;
|
|
1198
|
+
/** Collapse the field when focus leaves it while it is empty. Default: true. */
|
|
1199
|
+
collapseOnEmptyBlur?: boolean;
|
|
1200
|
+
/** Collapse an empty field on Escape and restore focus to its trigger. Default: true. */
|
|
1201
|
+
collapseOnEscape?: boolean;
|
|
1202
|
+
/** Focus the editor on expand and the trigger on Escape-collapse. Default: true. */
|
|
1203
|
+
manageFocus?: boolean;
|
|
1204
|
+
/**
|
|
1205
|
+
* Keep an empty field expanded when focus moves to a caller-owned surface
|
|
1206
|
+
* rendered outside the field — a suggestions dropdown, date picker, or help
|
|
1207
|
+
* popover shown beside it. Return true for any focus target that must NOT
|
|
1208
|
+
* trigger collapse-on-empty-blur. An element carrying `data-token-search-keep-open`
|
|
1209
|
+
* (or any node inside one) is always exempt, so this predicate is only needed
|
|
1210
|
+
* for surfaces you cannot mark declaratively.
|
|
1211
|
+
*/
|
|
1212
|
+
keepOpenOn?: (target: Node | null) => boolean;
|
|
1213
|
+
/** App-owned `expanded` signals keyed by field id; adopted instead of helper-created. */
|
|
1214
|
+
signals?: Readonly<Record<string, Signal<boolean>>>;
|
|
1215
|
+
}
|
|
1216
|
+
interface WireTokenSearchFieldsOptions {
|
|
1217
|
+
onSubmit?: (submission: TokenSearchSubmit) => void;
|
|
1218
|
+
/** Fired on every editor `input`, after the browser mutates it, so a caller can drop its own `input` listener. */
|
|
1219
|
+
onEdit?: (edit: TokenSearchSubmit) => void;
|
|
1220
|
+
/** Managed collapsible transient behavior. `true`/omitted = on with defaults; `false` = fully off. */
|
|
1221
|
+
collapsible?: boolean | TokenSearchCollapsibleOptions;
|
|
1222
|
+
/** Opt-in atomic-chip keyboard behavior (off by default). `true` = on with defaults. */
|
|
1223
|
+
keyboard?: boolean | TokenSearchKeyboardOptions;
|
|
1224
|
+
}
|
|
1225
|
+
/**
|
|
1226
|
+
* The value returned from {@link wireTokenSearchFields}: call it (or `dispose()`) to
|
|
1227
|
+
* tear down. When collapsible behavior is managed, it also exposes the transient
|
|
1228
|
+
* `expanded` state per field id so the app can read it in render, hand in its own
|
|
1229
|
+
* signal, or drive it imperatively.
|
|
1230
|
+
*/
|
|
1231
|
+
interface TokenSearchFieldsHandle {
|
|
1232
|
+
(): void;
|
|
1233
|
+
dispose(): void;
|
|
1234
|
+
/** The managed `expanded` signal for a field id (adopted or helper-created); undefined when unmanaged. */
|
|
1235
|
+
expanded(id: string): Signal<boolean> | undefined;
|
|
1236
|
+
/** Expand the field (and, when focus is managed, focus its editor). */
|
|
1237
|
+
open(id: string): void;
|
|
1238
|
+
/** Collapse the field (and, when focus is managed, restore focus to its trigger). */
|
|
1239
|
+
close(id: string): void;
|
|
1240
|
+
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Wire every TokenSearchField under `root`: submit on Enter, preserve the caret across
|
|
1243
|
+
* controlled token deletion, and (by default) manage the collapsible field's transient
|
|
1244
|
+
* expand/collapse/focus. Returns a {@link TokenSearchFieldsHandle} — a disposer that also
|
|
1245
|
+
* exposes the managed `expanded` state per field id.
|
|
1246
|
+
*/
|
|
1247
|
+
declare function wireTokenSearchFields(root: HTMLElement, { onSubmit, onEdit, collapsible, keyboard }?: WireTokenSearchFieldsOptions): TokenSearchFieldsHandle;
|
|
1248
|
+
|
|
1249
|
+
export { type TokenSearchCollapsibleOptions, type TokenSearchFieldsHandle, type TokenSearchKeyboardOptions, type TokenSearchSubmit, type TokenSearchTokenRemoval, type WireTokenSearchFieldsOptions, wireTokenSearchFields };
|
|
1250
|
+
```
|
|
1251
|
+
|
|
1252
|
+
## `kerfjs/actions`
|
|
1253
|
+
|
|
1254
|
+
```ts
|
|
1255
|
+
import { A as AttrSpec } from './attrSelector-Cmu2ZoGO.js';
|
|
1256
|
+
import { D as DelegateOptions } from './delegate-CL9VTZFb.js';
|
|
1257
|
+
|
|
1258
|
+
/**
|
|
1259
|
+
* `kerfjs/actions` — the delegated action-table helper.
|
|
1260
|
+
*
|
|
1261
|
+
* The most-reinvented idiom across real kerf apps: one table of `data-action`
|
|
1262
|
+
* attribute specs used as the single source of truth for BOTH the JSX attribute
|
|
1263
|
+
* and the delegate selector, plus a hand-rolled `switch (dataset.action)`
|
|
1264
|
+
* dispatcher. This subpath blesses it as two thin helpers over the existing
|
|
1265
|
+
* `attr()` + `delegate()` — it does NOT replace them.
|
|
1266
|
+
*
|
|
1267
|
+
* import { action, delegateActions } from 'kerfjs/actions';
|
|
1268
|
+
*
|
|
1269
|
+
* const A = {
|
|
1270
|
+
* select: action('select-file'),
|
|
1271
|
+
* remove: action('remove-file'),
|
|
1272
|
+
* };
|
|
1273
|
+
*
|
|
1274
|
+
* // JSX — spread the attr (rename-safe; no hardcoded attribute name):
|
|
1275
|
+
* // <button {...A.select.attrs} data-id={id}>…</button>
|
|
1276
|
+
*
|
|
1277
|
+
* // Wire the whole table with ONE delegated listener; returns a disposer:
|
|
1278
|
+
* const dispose = delegateActions(root, 'click', {
|
|
1279
|
+
* [A.select.value]: (_e, el) => selectFile(el.getAttribute('data-id')),
|
|
1280
|
+
* [A.remove.value]: (_e, el) => removeFile(el.getAttribute('data-id')),
|
|
1281
|
+
* });
|
|
1282
|
+
*
|
|
1283
|
+
* Contract: `delegateActions` returns a `() => void` disposer and holds no
|
|
1284
|
+
* per-instance state — the same shape as `delegate()`, which it builds on (so
|
|
1285
|
+
* it inherits the single-listener dispatch and the capture auto-promotion for
|
|
1286
|
+
* well-known non-bubbling event types). One event type per call, mirroring
|
|
1287
|
+
* `delegate()`; collect the disposers for a root that needs several.
|
|
1288
|
+
*/
|
|
1289
|
+
|
|
1290
|
+
/**
|
|
1291
|
+
* A handler in a {@link delegateActions} table. Receives the DOM event and the
|
|
1292
|
+
* matched element (walk-up `closest()` match by default) — the same shape as a
|
|
1293
|
+
* `delegate()` handler.
|
|
1294
|
+
*/
|
|
1295
|
+
type ActionHandler<E extends Element = Element> = (event: Event, el: E) => void;
|
|
1296
|
+
/**
|
|
1297
|
+
* `action(value)` — an {@link AttrSpec} on `data-action`. A thin specialization
|
|
1298
|
+
* of `attr('data-action', value)`: spread its `.attrs` in JSX and use its
|
|
1299
|
+
* `.value` as the handler-table key, so the action name lives in exactly one
|
|
1300
|
+
* place and can't drift between the markup and the dispatcher.
|
|
1301
|
+
*/
|
|
1302
|
+
declare function action<V extends string>(value: V): AttrSpec<'data-action', V>;
|
|
1303
|
+
/** Options for {@link delegateActions}. Extends {@link DelegateOptions}. */
|
|
1304
|
+
interface DelegateActionsOptions extends DelegateOptions {
|
|
1305
|
+
/**
|
|
1306
|
+
* The attribute the table keys on. Default `'data-action'`. Override it only
|
|
1307
|
+
* if you also author the specs with `attr(yourName, …)` instead of `action()`.
|
|
1308
|
+
*/
|
|
1309
|
+
attr?: string;
|
|
1310
|
+
}
|
|
1311
|
+
/**
|
|
1312
|
+
* Wire a whole table of action handlers with ONE delegated listener.
|
|
1313
|
+
*
|
|
1314
|
+
* On `eventType`, the nearest element carrying the action attribute (walk-up
|
|
1315
|
+
* `closest()` by default; pass `{ match: 'direct' }` for an exact-element match)
|
|
1316
|
+
* is looked up in `table` by its attribute value, and the matching handler
|
|
1317
|
+
* runs. An element whose action is absent from the table is ignored — the same
|
|
1318
|
+
* behavior as a `switch (dataset.action)` with no matching `case`.
|
|
1319
|
+
*
|
|
1320
|
+
* Returns a `() => void` disposer. One event type per call (the smallest
|
|
1321
|
+
* surface, mirroring `delegate()`); collect the disposers when a root needs
|
|
1322
|
+
* several event types.
|
|
1323
|
+
*/
|
|
1324
|
+
declare function delegateActions<E extends Element = Element>(root: HTMLElement, eventType: string, table: Readonly<Record<string, ActionHandler<E>>>, options?: DelegateActionsOptions): () => void;
|
|
1325
|
+
|
|
1326
|
+
export { type ActionHandler, type DelegateActionsOptions, action, delegateActions };
|
|
1327
|
+
```
|