@kerfjs/ui 5.0.0-beta.54 → 5.0.0-beta.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -11
- package/ai/compile-time-contracts-v1.json +2 -2
- package/ai/component-catalog-v2.json +206 -39
- package/ai/component-catalog.json +306 -58
- package/ai/public-api-signatures-v1.md +671 -92
- package/ai/skill.md +43 -38
- package/ai/webawesome-jsx-signatures-v1.md +8 -2
- package/dist/app-tab.js +1 -1
- package/dist/badge.d.ts +35 -7
- package/dist/badge.js +1 -1
- package/dist/browser/content-item.js +3 -0
- package/dist/browser/popup-menu.js +3 -0
- package/dist/browser/select.js +1 -0
- package/dist/catalog-resources.d.ts +12 -1
- package/dist/catalog.d.ts +21 -4
- package/dist/catalog.js +260 -308
- package/dist/catalog.js.map +1 -1
- package/dist/{chunk-7IUSV4XG.js → chunk-24PHKUR3.js} +2 -2
- package/dist/chunk-24PHKUR3.js.map +1 -0
- package/dist/{chunk-WZ2GLEY4.js → chunk-2G2ZJQYK.js} +2 -14
- package/dist/chunk-2G2ZJQYK.js.map +1 -0
- package/dist/{chunk-D7GWXIAS.js → chunk-5I7QGQVT.js} +1 -1
- package/dist/chunk-5I7QGQVT.js.map +1 -0
- package/dist/{chunk-HJKRCKDR.js → chunk-63ZWBGE3.js} +6 -3
- package/dist/chunk-63ZWBGE3.js.map +1 -0
- package/dist/{chunk-44IG7PFV.js → chunk-6CINWX2E.js} +3 -3
- package/dist/{chunk-44IG7PFV.js.map → chunk-6CINWX2E.js.map} +1 -1
- package/dist/{chunk-C2FAYFDE.js → chunk-AGXQQFKZ.js} +2 -2
- package/dist/{chunk-C2FAYFDE.js.map → chunk-AGXQQFKZ.js.map} +1 -1
- package/dist/{chunk-ATHXW6RP.js → chunk-AHEG27M7.js} +2 -2
- package/dist/{chunk-ATHXW6RP.js.map → chunk-AHEG27M7.js.map} +1 -1
- package/dist/{chunk-7GUQYHKA.js → chunk-AK67F6QN.js} +4 -1
- package/dist/chunk-AK67F6QN.js.map +1 -0
- package/dist/chunk-BFPBS5Y4.js +250 -0
- package/dist/chunk-BFPBS5Y4.js.map +1 -0
- package/dist/chunk-DG6G5EPF.js +35 -0
- package/dist/chunk-DG6G5EPF.js.map +1 -0
- package/dist/{chunk-MTM43SJO.js → chunk-G33XC2NB.js} +1 -1
- package/dist/chunk-G33XC2NB.js.map +1 -0
- package/dist/{chunk-TZ5IHWB2.js → chunk-K6UNVKDK.js} +3 -3
- package/dist/{chunk-TZ5IHWB2.js.map → chunk-K6UNVKDK.js.map} +1 -1
- package/dist/chunk-KH6VUGHU.js +399 -0
- package/dist/chunk-KH6VUGHU.js.map +1 -0
- package/dist/{chunk-HMQ2ZDGG.js → chunk-KROD7KZK.js} +3 -2
- package/dist/chunk-KROD7KZK.js.map +1 -0
- package/dist/{chunk-5NDQABWK.js → chunk-M7QV3IHH.js} +3 -1
- package/dist/chunk-M7QV3IHH.js.map +1 -0
- package/dist/{chunk-RNZAKSME.js → chunk-MA6Z6EIM.js} +3 -3
- package/dist/{chunk-RNZAKSME.js.map → chunk-MA6Z6EIM.js.map} +1 -1
- package/dist/chunk-MA73TA6D.js +42 -0
- package/dist/chunk-MA73TA6D.js.map +1 -0
- package/dist/{chunk-ZMBU522F.js → chunk-MEY33VWB.js} +2 -2
- package/dist/{chunk-ZMBU522F.js.map → chunk-MEY33VWB.js.map} +1 -1
- package/dist/{chunk-T22EM4ET.js → chunk-MOBRFZH3.js} +81 -31
- package/dist/chunk-MOBRFZH3.js.map +1 -0
- package/dist/chunk-MP2GDBQZ.js +50 -0
- package/dist/chunk-MP2GDBQZ.js.map +1 -0
- package/dist/{chunk-3NBL3OUQ.js → chunk-NAPE7WUS.js} +2 -2
- package/dist/chunk-NAPE7WUS.js.map +1 -0
- package/dist/{chunk-CMUIXJZM.js → chunk-NBYTIVHS.js} +2 -2
- package/dist/{chunk-CMUIXJZM.js.map → chunk-NBYTIVHS.js.map} +1 -1
- package/dist/chunk-O3EXIBEZ.js +114 -0
- package/dist/chunk-O3EXIBEZ.js.map +1 -0
- package/dist/{chunk-KPNTVB7A.js → chunk-PK4N5QTO.js} +8 -7
- package/dist/chunk-PK4N5QTO.js.map +1 -0
- package/dist/chunk-QQOTQTDD.js +415 -0
- package/dist/chunk-QQOTQTDD.js.map +1 -0
- package/dist/{chunk-BJJKFVWW.js → chunk-T4UZTNZ4.js} +5 -5
- package/dist/chunk-T4UZTNZ4.js.map +1 -0
- package/dist/chunk-V65EOWNF.js +83 -0
- package/dist/chunk-V65EOWNF.js.map +1 -0
- package/dist/{chunk-GUIHMIT2.js → chunk-VNPQDCQZ.js} +3 -3
- package/dist/{chunk-GUIHMIT2.js.map → chunk-VNPQDCQZ.js.map} +1 -1
- package/dist/{chunk-5I22LMCV.js → chunk-VZOFZPSO.js} +2 -2
- package/dist/chunk-VZOFZPSO.js.map +1 -0
- package/dist/chunk-WLG6SSNT.js +94 -0
- package/dist/chunk-WLG6SSNT.js.map +1 -0
- package/dist/{chunk-NE5JAOQS.js → chunk-WOUF7YXM.js} +3 -3
- package/dist/{chunk-NE5JAOQS.js.map → chunk-WOUF7YXM.js.map} +1 -1
- package/dist/collapsible-panel.d.ts +51 -13
- package/dist/collapsible-panel.js +38 -10
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/content-item.d.ts +46 -0
- package/dist/content-item.js +4 -0
- package/dist/content-item.js.map +1 -0
- package/dist/css-values.d.ts +5 -11
- package/dist/css-values.js +1 -1
- package/dist/disclosure-arrow.d.ts +4 -1
- package/dist/disclosure-arrow.js +1 -1
- package/dist/floating-toolbar.d.ts +17 -6
- package/dist/floating-toolbar.js +1 -1
- package/dist/grid.js +1 -1
- package/dist/help-tags-register.d.ts +13 -0
- package/dist/help-tags-register.js +9 -0
- package/dist/help-tags-register.js.map +1 -0
- package/dist/index.d.ts +7 -5
- package/dist/index.js +31 -29
- package/dist/list-action-row.js +1 -1
- package/dist/list-header.d.ts +14 -1
- package/dist/list-header.js +1 -1
- package/dist/list-inset-control.d.ts +1 -1
- package/dist/list-inset-control.js +1 -1
- package/dist/list-inset-text.d.ts +9 -10
- package/dist/list-inset-text.js +2 -1
- package/dist/list-item.js +1 -1
- package/dist/list.d.ts +10 -3
- package/dist/list.js +1 -1
- package/dist/nav-stack.d.ts +38 -5
- package/dist/nav-stack.js +4 -1
- package/dist/pane.d.ts +20 -2
- package/dist/pane.js +1 -1
- package/dist/panel-toolbar-C8sF-YZC.d.ts +63 -0
- package/dist/popup-menu-register.d.ts +9 -0
- package/dist/popup-menu-register.js +31 -0
- package/dist/popup-menu-register.js.map +1 -0
- package/dist/popup-menu.d.ts +71 -0
- package/dist/popup-menu.js +3 -0
- package/dist/popup-menu.js.map +1 -0
- package/dist/row.d.ts +1 -1
- package/dist/row.js +1 -1
- package/dist/select-register.js +70 -3
- package/dist/select-register.js.map +1 -1
- package/dist/select.d.ts +46 -8
- package/dist/select.js +2 -1
- package/dist/{divider-sides-BzB6rphT.d.ts → sides-BPSWde0A.d.ts} +1 -3
- package/dist/skeleton.js +1 -1
- package/dist/spacer.js +1 -1
- package/dist/split-view.d.ts +31 -3
- package/dist/split-view.js +33 -5
- package/dist/split-view.js.map +1 -1
- package/dist/state-banner.js +1 -1
- package/dist/styles/badge.css +13 -0
- package/dist/styles/catalog/components/catalog-example.css +1 -17
- package/dist/styles/catalog/components/catalog-stage.css +9 -14
- package/dist/styles/catalog/components/catalog.css +8 -18
- package/dist/styles/catalog.css +0 -5
- package/dist/styles/collapsible-panel.css +192 -39
- package/dist/styles/content-item.css +30 -0
- package/dist/styles/floating-toolbar.css +5 -0
- package/dist/styles/foundation.css +28 -19
- package/dist/styles/layout.css +1 -21
- package/dist/styles/list-action-row.css +13 -1
- package/dist/styles/list-inset-text.css +1 -2
- package/dist/styles/list-item.css +14 -1
- package/dist/styles/list.css +1 -1
- package/dist/styles/nav-stack.css +29 -64
- package/dist/styles/pane.css +33 -1
- package/dist/styles/popup-menu.css +90 -0
- package/dist/styles/resizable-region.css +53 -10
- package/dist/styles/select.css +39 -12
- package/dist/styles/split-view.css +21 -25
- package/dist/styles/state-banner.css +13 -4
- package/dist/styles/styles.css +1 -0
- package/dist/styles/tab-bar.css +31 -3
- package/dist/styles/tab-scaffold.css +36 -14
- package/dist/styles/text.css +1 -1
- package/dist/styles/token-search-field.css +4 -4
- package/dist/styles/toolbar-control-group.css +44 -12
- package/dist/styles/toolbar.css +57 -7
- package/dist/styles/value-table.css +19 -2
- package/dist/styles/webawesome.css +3 -1
- package/dist/styles/workbench.css +165 -31
- package/dist/tab-scaffold.d.ts +35 -1
- package/dist/tab-scaffold.js +50 -16
- package/dist/tab-scaffold.js.map +1 -1
- package/dist/text.js +1 -1
- package/dist/token-search-field.d.ts +13 -2
- package/dist/token-search-field.js +1 -1
- package/dist/toolbar-text.js +1 -1
- package/dist/toolbar.d.ts +12 -4
- package/dist/toolbar.js +1 -1
- package/dist/{types-CEsieBZi.d.ts → types-DXAGogOS.d.ts} +48 -0
- package/dist/value-table.js +1 -1
- package/dist/webawesome.d.ts +7 -1
- package/dist/wire-catalog.d.ts +24 -1
- package/dist/wire-catalog.js +26 -3
- package/dist/wire-catalog.js.map +1 -1
- package/dist/wire-sidebar.js +6 -3
- package/dist/wire-sidebar.js.map +1 -1
- package/dist/wire-token-search-fields.js +1 -1
- package/dist/wire-workbench.js +1 -350
- package/dist/wire-workbench.js.map +1 -1
- package/dist/workbench.d.ts +144 -6
- package/dist/workbench.js +11 -208
- package/dist/workbench.js.map +1 -1
- package/docs/accessibility.md +126 -6
- package/docs/app-layouts.md +9 -7
- package/docs/catalog.md +41 -9
- package/docs/collapsible-panel.md +79 -5
- package/docs/component-contract.md +38 -12
- package/docs/component-selection.md +64 -55
- package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
- package/docs/design/templates/empty-state/with-action.svg +1 -1
- package/docs/design/templates/empty-state-dark.svg +1 -1
- package/docs/design/templates/empty-state.svg +1 -1
- package/docs/design/templates/list/compact-dark.svg +1 -1
- package/docs/design/templates/list/compact.svg +1 -1
- package/docs/design/templates/list/stack-dark.svg +1 -1
- package/docs/design/templates/list/stack.svg +1 -1
- package/docs/design/templates/list-action-row/default-dark.svg +1 -1
- package/docs/design/templates/list-action-row/default.svg +1 -1
- package/docs/design/templates/list-action-row/selected-dark.svg +1 -1
- package/docs/design/templates/list-action-row/selected.svg +1 -1
- package/docs/design/templates/list-action-row-dark.svg +1 -1
- package/docs/design/templates/list-action-row.svg +1 -1
- package/docs/design/templates/list-dark.svg +1 -1
- package/docs/design/templates/list-item/default-dark.svg +1 -1
- package/docs/design/templates/list-item/default.svg +1 -1
- package/docs/design/templates/list-item/selected-dark.svg +1 -1
- package/docs/design/templates/list-item/selected.svg +1 -1
- package/docs/design/templates/list-item/trailing-dark.svg +1 -1
- package/docs/design/templates/list-item/trailing.svg +1 -1
- package/docs/design/templates/list-item-dark.svg +1 -1
- package/docs/design/templates/list-item.svg +1 -1
- package/docs/design/templates/list.svg +1 -1
- package/docs/design/templates/state-banner/danger-dark.svg +1 -1
- package/docs/design/templates/state-banner/danger.svg +1 -1
- package/docs/design/templates/state-banner/info-dark.svg +1 -1
- package/docs/design/templates/state-banner/info.svg +1 -1
- package/docs/design/templates/state-banner/success-dark.svg +1 -1
- package/docs/design/templates/state-banner/success.svg +1 -1
- package/docs/design/templates/state-banner/warning-dark.svg +1 -1
- package/docs/design/templates/state-banner/warning.svg +1 -1
- package/docs/design/templates/state-banner-dark.svg +1 -1
- package/docs/design/templates/state-banner.svg +1 -1
- package/docs/design/templates/value-table/details-dark.svg +1 -1
- package/docs/design/templates/value-table/details.svg +1 -1
- package/docs/design/templates/value-table-dark.svg +1 -1
- package/docs/design/templates/value-table.svg +1 -1
- package/docs/design-philosophy.md +1 -1
- package/docs/examples/command-palette-adapter.tsx +3 -2
- package/docs/layout.md +74 -29
- package/docs/nav-stack.md +45 -1
- package/docs/recipes.md +48 -40
- package/docs/split-view.md +46 -2
- package/docs/surface-scaffold.md +1 -1
- package/docs/tab-scaffold.md +50 -1
- package/docs/type-contracts.md +17 -17
- package/docs/ux-demo.md +8 -4
- package/docs/webawesome-theme.md +1 -2
- package/docs/workbench.md +131 -10
- package/llms.txt +38 -9
- package/package.json +24 -2
- package/ux-demo/recipes/app-shell.tsx +141 -223
- package/ux-demo/recipes/collapsible-sidebar.tsx +47 -77
- package/ux-demo/recipes/list-detail-dialog.tsx +150 -54
- package/ux-demo/recipes/mount-recipe.ts +0 -5
- package/ux-demo/recipes/navigation-sidebar.tsx +3 -2
- package/ux-demo/recipes/navigation-stack.tsx +3 -2
- package/ux-demo/recipes/types.ts +0 -1
- package/dist/chunk-3NBL3OUQ.js.map +0 -1
- package/dist/chunk-5I22LMCV.js.map +0 -1
- package/dist/chunk-5NDQABWK.js.map +0 -1
- package/dist/chunk-7GUQYHKA.js.map +0 -1
- package/dist/chunk-7IUSV4XG.js.map +0 -1
- package/dist/chunk-BJJKFVWW.js.map +0 -1
- package/dist/chunk-D7GWXIAS.js.map +0 -1
- package/dist/chunk-DQA5FMOX.js +0 -85
- package/dist/chunk-DQA5FMOX.js.map +0 -1
- package/dist/chunk-HJKRCKDR.js.map +0 -1
- package/dist/chunk-HMQ2ZDGG.js.map +0 -1
- package/dist/chunk-KPNTVB7A.js.map +0 -1
- package/dist/chunk-MTM43SJO.js.map +0 -1
- package/dist/chunk-T22EM4ET.js.map +0 -1
- package/dist/chunk-WZ2GLEY4.js.map +0 -1
- package/dist/chunk-XD7DWYXG.js +0 -34
- package/dist/chunk-XD7DWYXG.js.map +0 -1
- package/dist/chunk-ZK5EGVFP.js +0 -27
- package/dist/chunk-ZK5EGVFP.js.map +0 -1
- package/dist/styles/catalog/components/catalog-detail.css +0 -35
- package/dist/styles/catalog/components/catalog-resource-footer.css +0 -37
- package/dist/styles/catalog/components/catalog-secondary-sections.css +0 -38
- package/dist/styles/catalog/components/catalog-section-list.css +0 -22
- package/dist/styles/catalog/components/catalog-sidebar.css +0 -82
package/dist/workbench.d.ts
CHANGED
|
@@ -1,13 +1,77 @@
|
|
|
1
1
|
import { SafeHtml } from 'kerfjs';
|
|
2
|
+
import { ListConfig } from './list.js';
|
|
3
|
+
import { PaneConfig } from './pane.js';
|
|
2
4
|
import { ResizableRegionSeparator, ResizableRegionCollapseMotion, ResizableRegionContentOverflow, ResizableRegionPresentation, ResizableRegionRestorePosition } from './resizable-region.js';
|
|
3
5
|
import { K as KerfUiContent } from './semantic-content-BbzjvSu9.js';
|
|
6
|
+
import { a as PanelToolbar, b as PanelToggle } from './panel-toolbar-C8sF-YZC.js';
|
|
7
|
+
import { ToolbarConfig } from './toolbar.js';
|
|
8
|
+
import './css-values.js';
|
|
9
|
+
import './flex-alignment-4ms8ZbV8.js';
|
|
10
|
+
import './sides-BPSWde0A.js';
|
|
11
|
+
import './lucide-icon.js';
|
|
12
|
+
import 'lucide';
|
|
13
|
+
|
|
14
|
+
/** The standard toggle a Workbench renders for a panel (see {@link PanelToggle}). */
|
|
15
|
+
type WorkbenchPanelToggle = PanelToggle;
|
|
16
|
+
/**
|
|
17
|
+
* A Workbench panel's top toolbar, composed by the Workbench so its groups can
|
|
18
|
+
* follow the panel's open state (see {@link PanelToolbar} for the roles).
|
|
19
|
+
* A collapsed rail's `constant` groups and toggle go to the leading edge of
|
|
20
|
+
* `mainToolbar` (left rail) or its trailing edge (right rail); a collapsed
|
|
21
|
+
* drawer's go to the trailing edge of `mainBottomToolbar`, else to a
|
|
22
|
+
* `FloatingToolbar` in the work area's bottom-end corner.
|
|
23
|
+
*/
|
|
24
|
+
type WorkbenchPanelToolbar = PanelToolbar;
|
|
25
|
+
/**
|
|
26
|
+
* The work area's top toolbar; collapsed rails add their groups to it. Its
|
|
27
|
+
* configuration forwards to its `Toolbar`. By default it draws the divider
|
|
28
|
+
* under the work area's header chrome: its own bottom edge, or none when a
|
|
29
|
+
* `mainHeader` follows (which then carries the divider).
|
|
30
|
+
*/
|
|
31
|
+
interface WorkbenchMainToolbar extends ToolbarConfig {
|
|
32
|
+
label: string;
|
|
33
|
+
/** The work area's title, usually an extra-large `ToolbarText`. */
|
|
34
|
+
title?: KerfUiContent;
|
|
35
|
+
/** Groups after the title. */
|
|
36
|
+
leading?: KerfUiContent;
|
|
37
|
+
center?: KerfUiContent;
|
|
38
|
+
/** Groups at the trailing edge, before a collapsed right rail's groups. */
|
|
39
|
+
trailing?: KerfUiContent;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The work area's bottom toolbar; a collapsed drawer adds its groups to it.
|
|
43
|
+
* Its configuration forwards to its `Toolbar`. By default it draws the divider
|
|
44
|
+
* over the work area's footer chrome: its own top edge, or none when a
|
|
45
|
+
* `mainFooter` precedes it.
|
|
46
|
+
*/
|
|
47
|
+
interface WorkbenchMainBottomToolbar extends ToolbarConfig {
|
|
48
|
+
label: string;
|
|
49
|
+
leading?: KerfUiContent;
|
|
50
|
+
center?: KerfUiContent;
|
|
51
|
+
trailing?: KerfUiContent;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Whether the work area's header or footer chrome stays pinned (`fixed`),
|
|
55
|
+
* scrolls away with the content (`scroll`), or stays pinned while the work
|
|
56
|
+
* area is tall enough and scrolls with the content when it is short (`auto`,
|
|
57
|
+
* the Pane's `chromePlacement="auto"`; it applies to the pinned header and
|
|
58
|
+
* footer together).
|
|
59
|
+
*/
|
|
60
|
+
type WorkbenchChromePlacement = 'fixed' | 'scroll' | 'auto';
|
|
4
61
|
|
|
5
62
|
/**
|
|
6
63
|
* The Workbench container breakpoint below which a panel presents as an
|
|
7
64
|
* overlay: `narrow` (704px or less) or `compact` (448px or less) — the same
|
|
8
|
-
* breakpoints as `ResizableRegion`'s `responsiveFillAt
|
|
65
|
+
* breakpoints as `ResizableRegion`'s `responsiveFillAt` — or `never` to keep
|
|
66
|
+
* it inline at every width.
|
|
67
|
+
*/
|
|
68
|
+
type WorkbenchResponsiveOverlayAt = 'compact' | 'narrow' | 'never';
|
|
69
|
+
/**
|
|
70
|
+
* How wide a rail's overlay is in a compact (448px or less) Workbench: `inset`
|
|
71
|
+
* fills the Workbench less a dismiss margin on the side away from the rail's
|
|
72
|
+
* edge, so a press beside it closes it; `full` fills the Workbench.
|
|
9
73
|
*/
|
|
10
|
-
type
|
|
74
|
+
type WorkbenchCompactOverlay = 'inset' | 'full';
|
|
11
75
|
/** Drag-resize limits for a resizable Workbench panel, in px. */
|
|
12
76
|
interface WorkbenchPanelResizable {
|
|
13
77
|
/** Smallest size (default 180 for a rail, 120 for the drawer). */
|
|
@@ -18,6 +82,22 @@ interface WorkbenchPanelResizable {
|
|
|
18
82
|
/** A collapsible Workbench panel — a side rail or the bottom drawer. */
|
|
19
83
|
interface WorkbenchPanel {
|
|
20
84
|
content: KerfUiContent;
|
|
85
|
+
/**
|
|
86
|
+
* The panel's top toolbar, composed by the Workbench: its `constant` groups
|
|
87
|
+
* and standard `toggle` move to the work area's toolbar while the panel is
|
|
88
|
+
* collapsed. With it, `content` renders in a `Pane` below the toolbar.
|
|
89
|
+
*/
|
|
90
|
+
toolbar?: WorkbenchPanelToolbar;
|
|
91
|
+
/** Optional bottom toolbar under a `toolbar` panel's content. */
|
|
92
|
+
footer?: KerfUiContent;
|
|
93
|
+
/**
|
|
94
|
+
* Configuration for a `toolbar` panel's `Pane` (`contentElement`,
|
|
95
|
+
* `contentLabel`, `separators`, `safeAreaEdges`) — for example
|
|
96
|
+
* `{ contentElement: 'nav', contentLabel: 'Sections' }` for a navigation
|
|
97
|
+
* rail. Omitted or `undefined` fields keep the `Pane` defaults. Ignored
|
|
98
|
+
* without a `toolbar`, where `content` renders as given.
|
|
99
|
+
*/
|
|
100
|
+
pane?: PaneConfig;
|
|
21
101
|
/** Whether the panel is currently collapsed (the app owns this). */
|
|
22
102
|
collapsed?: boolean;
|
|
23
103
|
/**
|
|
@@ -43,13 +123,22 @@ interface WorkbenchPanel {
|
|
|
43
123
|
* Present the panel as an overlay, without a separator, below a Workbench
|
|
44
124
|
* container breakpoint, and inline above it — the CSS decides, so the app
|
|
45
125
|
* needs no device-class check. A rail overlays from its side at full
|
|
46
|
-
* height
|
|
126
|
+
* height, over the work area and an open drawer; the bottom drawer
|
|
127
|
+
* overlays the bottom of the work-area column. Rails default to `narrow`
|
|
128
|
+
* (pass `never` to keep one inline); the drawer defaults to inline.
|
|
47
129
|
*/
|
|
48
130
|
responsiveOverlayAt?: WorkbenchResponsiveOverlayAt;
|
|
131
|
+
/**
|
|
132
|
+
* A rail's overlay width in a compact Workbench (default `inset`: the
|
|
133
|
+
* Workbench less `--kui-workbench-overlay-dismiss-margin`, 44px). Ignored
|
|
134
|
+
* by the drawer.
|
|
135
|
+
*/
|
|
136
|
+
compactOverlay?: WorkbenchCompactOverlay;
|
|
49
137
|
/**
|
|
50
138
|
* Control shown while collapsed, in a safe-area-aware corner of the
|
|
51
139
|
* Workbench (not the viewport); the bottom drawer's sits in the work-area
|
|
52
|
-
* column.
|
|
140
|
+
* column. Prefer `toolbar.toggle`, which the Workbench relocates into the
|
|
141
|
+
* work area's toolbar (or this corner when that toolbar is absent).
|
|
53
142
|
*/
|
|
54
143
|
restoreControl?: SafeHtml;
|
|
55
144
|
restorePosition?: ResizableRegionRestorePosition;
|
|
@@ -64,6 +153,55 @@ interface WorkbenchProps {
|
|
|
64
153
|
label: string;
|
|
65
154
|
/** The central work area. */
|
|
66
155
|
main: KerfUiContent;
|
|
156
|
+
/**
|
|
157
|
+
* The work area's top toolbar. A collapsed left rail's `constant` groups
|
|
158
|
+
* and toggle lead it; a collapsed right rail's trail it. With it, `main`
|
|
159
|
+
* renders in a `Pane` below the toolbar.
|
|
160
|
+
*/
|
|
161
|
+
mainToolbar?: WorkbenchMainToolbar;
|
|
162
|
+
/**
|
|
163
|
+
* Fixed content under `mainToolbar` — supporting copy such as a
|
|
164
|
+
* description — divided from the scrolling `main` below it.
|
|
165
|
+
*/
|
|
166
|
+
mainHeader?: KerfUiContent;
|
|
167
|
+
/**
|
|
168
|
+
* Fixed content over `mainBottomToolbar` — a status line or a resource
|
|
169
|
+
* toolbar — divided from the scrolling `main` above it.
|
|
170
|
+
*/
|
|
171
|
+
mainFooter?: KerfUiContent;
|
|
172
|
+
/**
|
|
173
|
+
* The work area's bottom toolbar. A collapsed drawer's `constant` groups and
|
|
174
|
+
* toggle trail it; without it they float in the work area's corner.
|
|
175
|
+
*/
|
|
176
|
+
mainBottomToolbar?: WorkbenchMainBottomToolbar;
|
|
177
|
+
/**
|
|
178
|
+
* Whether `mainToolbar` and `mainHeader` stay pinned (`fixed`, default),
|
|
179
|
+
* scroll away with `main` (`scroll`) — useful where large text would leave
|
|
180
|
+
* pinned chrome little room — or stay pinned while the work area is tall
|
|
181
|
+
* enough and scroll with `main` when it is short (`auto`).
|
|
182
|
+
*/
|
|
183
|
+
mainHeaderPlacement?: WorkbenchChromePlacement;
|
|
184
|
+
/** The same for `mainFooter` and `mainBottomToolbar` (default `fixed`). */
|
|
185
|
+
mainFooterPlacement?: WorkbenchChromePlacement;
|
|
186
|
+
/**
|
|
187
|
+
* Configuration for the work area's `Pane` (`contentElement`,
|
|
188
|
+
* `contentLabel`, `separators`, `safeAreaEdges`), which it has whenever it
|
|
189
|
+
* has a toolbar, `mainHeader`, or `mainFooter`; without that chrome, `main`
|
|
190
|
+
* renders as given and this is ignored. Omitted or `undefined` fields keep
|
|
191
|
+
* the `Pane` defaults.
|
|
192
|
+
*/
|
|
193
|
+
mainPane?: PaneConfig;
|
|
194
|
+
/**
|
|
195
|
+
* Configuration for the `List` that holds `mainHeader` (`gap`, `hAlign`,
|
|
196
|
+
* `vAlign`, `dividerSides`, `textInsets`, `controlInsets`). Omitted or
|
|
197
|
+
* `undefined` fields keep the defaults, including its bottom divider.
|
|
198
|
+
*/
|
|
199
|
+
mainHeaderList?: ListConfig;
|
|
200
|
+
/**
|
|
201
|
+
* The same for the `List` that holds `mainFooter`; by default it draws a
|
|
202
|
+
* top divider, or none when a `mainBottomToolbar` follows it.
|
|
203
|
+
*/
|
|
204
|
+
mainFooterList?: ListConfig;
|
|
67
205
|
leftRail?: WorkbenchPanel;
|
|
68
206
|
rightRail?: WorkbenchPanel;
|
|
69
207
|
bottomDrawer?: WorkbenchPanel;
|
|
@@ -100,6 +238,6 @@ interface WorkbenchProps {
|
|
|
100
238
|
* lives outside it and stays reachable). A panel may opt in to drag and keyboard resizing with
|
|
101
239
|
* `resizable`, which `wireWorkbench` drives. See `docs/23-app-layouts.md` §3.3.
|
|
102
240
|
*/
|
|
103
|
-
declare function Workbench({ id, label, main, leftRail, rightRail, bottomDrawer, mainMinSize, mainMinHeight, className, slot, }: WorkbenchProps): SafeHtml;
|
|
241
|
+
declare function Workbench({ id, label, main, leftRail, rightRail, bottomDrawer, mainToolbar, mainHeader, mainFooter, mainBottomToolbar, mainHeaderPlacement, mainFooterPlacement, mainPane, mainHeaderList, mainFooterList, mainMinSize, mainMinHeight, className, slot, }: WorkbenchProps): SafeHtml;
|
|
104
242
|
|
|
105
|
-
export { Workbench, type WorkbenchPanel, type WorkbenchPanelResizable, type WorkbenchProps, type WorkbenchResponsiveOverlayAt };
|
|
243
|
+
export { Workbench, type WorkbenchChromePlacement, type WorkbenchCompactOverlay, type WorkbenchMainBottomToolbar, type WorkbenchMainToolbar, type WorkbenchPanel, type WorkbenchPanelResizable, type WorkbenchPanelToggle, type WorkbenchPanelToolbar, type WorkbenchProps, type WorkbenchResponsiveOverlayAt };
|
package/dist/workbench.js
CHANGED
|
@@ -1,212 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export { Workbench } from './chunk-QQOTQTDD.js';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
4
12
|
|
|
5
|
-
var EDGES = {
|
|
6
|
-
leftRail: "end",
|
|
7
|
-
rightRail: "start",
|
|
8
|
-
bottomDrawer: "start"
|
|
9
|
-
};
|
|
10
|
-
var DEFAULT_LABELS = {
|
|
11
|
-
leftRail: "left rail",
|
|
12
|
-
rightRail: "right rail",
|
|
13
|
-
bottomDrawer: "bottom drawer"
|
|
14
|
-
};
|
|
15
|
-
function resolveResize(id, key, panel) {
|
|
16
|
-
if (!panel.resizable) return void 0;
|
|
17
|
-
const defaults = WORKBENCH_RESIZE_DEFAULTS[key];
|
|
18
|
-
const limits = panel.resizable === true ? {} : panel.resizable;
|
|
19
|
-
const min = limits.min ?? defaults.min;
|
|
20
|
-
const max = Math.max(min, limits.max ?? defaults.max);
|
|
21
|
-
return {
|
|
22
|
-
regionId: workbenchRegionId(id, key),
|
|
23
|
-
axis: key === "bottomDrawer" ? "vertical" : "horizontal",
|
|
24
|
-
edge: EDGES[key],
|
|
25
|
-
size: clampRegionSize(panel.size ?? defaults.size, min, max),
|
|
26
|
-
min,
|
|
27
|
-
max
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
var resizeAttributes = (resize) => resize ? {
|
|
31
|
-
"data-resizable": "true",
|
|
32
|
-
"data-region-id": resize.regionId,
|
|
33
|
-
"data-axis": resize.axis,
|
|
34
|
-
"data-edge": resize.edge
|
|
35
|
-
} : {};
|
|
36
|
-
function panelStyle(panel, resize, sizeProperty) {
|
|
37
|
-
if (resize) return `--kui-resizable-region-size:${resize.size}px`;
|
|
38
|
-
return panel.size ? `${sizeProperty}: ${panel.size}px` : void 0;
|
|
39
|
-
}
|
|
40
|
-
function PanelHandle({
|
|
41
|
-
panel,
|
|
42
|
-
resize,
|
|
43
|
-
label
|
|
44
|
-
}) {
|
|
45
|
-
const inert = Boolean(panel.collapsed) || (panel.presentation ?? "inline") !== "inline";
|
|
46
|
-
return /* @__PURE__ */ jsx(
|
|
47
|
-
"div",
|
|
48
|
-
{
|
|
49
|
-
class: "kui-workbench__handle",
|
|
50
|
-
role: "separator",
|
|
51
|
-
tabindex: inert ? "-1" : "0",
|
|
52
|
-
"aria-label": `Resize ${label}`,
|
|
53
|
-
"aria-orientation": resize.axis === "horizontal" ? "vertical" : "horizontal",
|
|
54
|
-
"aria-valuemin": resize.min,
|
|
55
|
-
"aria-valuemax": resize.max,
|
|
56
|
-
"aria-valuenow": resize.size,
|
|
57
|
-
"aria-hidden": inert ? "true" : void 0,
|
|
58
|
-
"data-kui-resize-handle": true,
|
|
59
|
-
"data-region-id": resize.regionId,
|
|
60
|
-
children: /* @__PURE__ */ jsx("span", { class: "kui-workbench__handle-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx(ResizeGrip, { axis: resize.axis }) })
|
|
61
|
-
}
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
function hiddenFromAccessibility(panel) {
|
|
65
|
-
return panel.collapsed || panel.presentation === "hidden" ? "true" : void 0;
|
|
66
|
-
}
|
|
67
|
-
function Rail({
|
|
68
|
-
id,
|
|
69
|
-
side,
|
|
70
|
-
panel
|
|
71
|
-
}) {
|
|
72
|
-
const key = side === "left" ? "leftRail" : "rightRail";
|
|
73
|
-
const resize = resolveResize(id, key, panel);
|
|
74
|
-
return /* @__PURE__ */ jsxs(
|
|
75
|
-
"aside",
|
|
76
|
-
{
|
|
77
|
-
id: workbenchRegionId(id, key),
|
|
78
|
-
class: `kui-workbench__rail kui-workbench__rail--${side}`,
|
|
79
|
-
"data-workbench-rail": side,
|
|
80
|
-
"data-collapsed": String(panel.collapsed ?? false),
|
|
81
|
-
"data-separator": panel.separator ?? "auto",
|
|
82
|
-
"data-collapse-motion": panel.collapseMotion ?? "slide",
|
|
83
|
-
"data-content-overflow": panel.contentOverflow ?? "clip",
|
|
84
|
-
"data-presentation": panel.presentation ?? "inline",
|
|
85
|
-
"data-responsive-overlay-at": panel.responsiveOverlayAt,
|
|
86
|
-
...resizeAttributes(resize),
|
|
87
|
-
"aria-label": panel.label || void 0,
|
|
88
|
-
"aria-hidden": hiddenFromAccessibility(panel),
|
|
89
|
-
inert: Boolean(panel.collapsed),
|
|
90
|
-
style: panelStyle(panel, resize, "--kui-workbench-rail-width"),
|
|
91
|
-
children: [
|
|
92
|
-
/* @__PURE__ */ jsx(
|
|
93
|
-
"div",
|
|
94
|
-
{
|
|
95
|
-
class: "kui-workbench__panel-content",
|
|
96
|
-
inert: Boolean(panel.collapsed),
|
|
97
|
-
children: panel.content
|
|
98
|
-
}
|
|
99
|
-
),
|
|
100
|
-
resize && /* @__PURE__ */ jsx(
|
|
101
|
-
PanelHandle,
|
|
102
|
-
{
|
|
103
|
-
panel,
|
|
104
|
-
resize,
|
|
105
|
-
label: panel.label || DEFAULT_LABELS[key]
|
|
106
|
-
}
|
|
107
|
-
)
|
|
108
|
-
]
|
|
109
|
-
}
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
function Drawer({ id, panel }) {
|
|
113
|
-
const resize = resolveResize(id, "bottomDrawer", panel);
|
|
114
|
-
return /* @__PURE__ */ jsxs(
|
|
115
|
-
"section",
|
|
116
|
-
{
|
|
117
|
-
id: workbenchRegionId(id, "bottomDrawer"),
|
|
118
|
-
class: "kui-workbench__drawer",
|
|
119
|
-
"data-workbench-drawer": true,
|
|
120
|
-
"data-collapsed": String(panel.collapsed ?? false),
|
|
121
|
-
"data-separator": panel.separator ?? "auto",
|
|
122
|
-
"data-collapse-motion": panel.collapseMotion ?? "slide",
|
|
123
|
-
"data-content-overflow": panel.contentOverflow ?? "clip",
|
|
124
|
-
"data-presentation": panel.presentation ?? "inline",
|
|
125
|
-
"data-responsive-overlay-at": panel.responsiveOverlayAt,
|
|
126
|
-
...resizeAttributes(resize),
|
|
127
|
-
"aria-label": panel.label || void 0,
|
|
128
|
-
"aria-hidden": hiddenFromAccessibility(panel),
|
|
129
|
-
inert: Boolean(panel.collapsed),
|
|
130
|
-
style: panelStyle(panel, resize, "--kui-workbench-drawer-height"),
|
|
131
|
-
children: [
|
|
132
|
-
/* @__PURE__ */ jsx(
|
|
133
|
-
"div",
|
|
134
|
-
{
|
|
135
|
-
class: "kui-workbench__panel-content",
|
|
136
|
-
inert: Boolean(panel.collapsed),
|
|
137
|
-
children: panel.content
|
|
138
|
-
}
|
|
139
|
-
),
|
|
140
|
-
resize && /* @__PURE__ */ jsx(
|
|
141
|
-
PanelHandle,
|
|
142
|
-
{
|
|
143
|
-
panel,
|
|
144
|
-
resize,
|
|
145
|
-
label: panel.label || DEFAULT_LABELS.bottomDrawer
|
|
146
|
-
}
|
|
147
|
-
)
|
|
148
|
-
]
|
|
149
|
-
}
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
function restore(panel, side, position) {
|
|
153
|
-
if (!panel?.collapsed || !panel.restoreControl || panel.presentation === "hidden")
|
|
154
|
-
return "";
|
|
155
|
-
return /* @__PURE__ */ jsx(
|
|
156
|
-
"div",
|
|
157
|
-
{
|
|
158
|
-
class: "kui-workbench__restore",
|
|
159
|
-
"data-panel": side,
|
|
160
|
-
"data-position": panel.restorePosition ?? position,
|
|
161
|
-
children: panel.restoreControl
|
|
162
|
-
}
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
function Workbench({
|
|
166
|
-
id,
|
|
167
|
-
label,
|
|
168
|
-
main,
|
|
169
|
-
leftRail,
|
|
170
|
-
rightRail,
|
|
171
|
-
bottomDrawer,
|
|
172
|
-
mainMinSize = WORKBENCH_MAIN_MIN_SIZE,
|
|
173
|
-
mainMinHeight = WORKBENCH_MAIN_MIN_HEIGHT,
|
|
174
|
-
className = "",
|
|
175
|
-
slot
|
|
176
|
-
}) {
|
|
177
|
-
const px = (value) => Math.max(0, Math.round(value));
|
|
178
|
-
const mainMin = leftRail || rightRail ? px(mainMinSize) : void 0;
|
|
179
|
-
const mainMinBlock = bottomDrawer ? px(mainMinHeight) : void 0;
|
|
180
|
-
const style = [
|
|
181
|
-
mainMin === void 0 ? "" : `--_kui-workbench-main-min-width:${mainMin}px`,
|
|
182
|
-
mainMinBlock === void 0 ? "" : `--_kui-workbench-main-min-height:${mainMinBlock}px`
|
|
183
|
-
].filter(Boolean).join(";");
|
|
184
|
-
return /* @__PURE__ */ jsxs(
|
|
185
|
-
"section",
|
|
186
|
-
{
|
|
187
|
-
class: `kui-workbench ${className}`.trim(),
|
|
188
|
-
id,
|
|
189
|
-
"data-component": "workbench",
|
|
190
|
-
"data-main-min-size": mainMin === void 0 ? void 0 : String(mainMin),
|
|
191
|
-
"data-main-min-height": mainMinBlock === void 0 ? void 0 : String(mainMinBlock),
|
|
192
|
-
style: style || void 0,
|
|
193
|
-
"aria-label": label,
|
|
194
|
-
slot,
|
|
195
|
-
children: [
|
|
196
|
-
leftRail && /* @__PURE__ */ jsx(Rail, { id, side: "left", panel: leftRail }),
|
|
197
|
-
restore(leftRail, "left", "bottom-start"),
|
|
198
|
-
/* @__PURE__ */ jsxs("div", { class: "kui-workbench__center", children: [
|
|
199
|
-
/* @__PURE__ */ jsx("div", { class: "kui-workbench__main", "data-workbench-main": true, children: main }),
|
|
200
|
-
bottomDrawer && /* @__PURE__ */ jsx(Drawer, { id, panel: bottomDrawer }),
|
|
201
|
-
restore(bottomDrawer, "bottom", "bottom-end")
|
|
202
|
-
] }),
|
|
203
|
-
rightRail && /* @__PURE__ */ jsx(Rail, { id, side: "right", panel: rightRail }),
|
|
204
|
-
restore(rightRail, "right", "bottom-end")
|
|
205
|
-
]
|
|
206
|
-
}
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
13
|
|
|
210
|
-
export { Workbench };
|
|
211
14
|
|
|
212
15
|
//# sourceMappingURL=workbench.js.map
|
package/dist/workbench.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/workbench.tsx"],"names":[],"mappings":";;;;AA6HA,IAAM,KAAA,GAAwD;AAAA,EAC5D,QAAA,EAAU,KAAA;AAAA,EACV,SAAA,EAAW,OAAA;AAAA,EACX,YAAA,EAAc;AAChB,CAAA;AAEA,IAAM,cAAA,GAAoD;AAAA,EACxD,QAAA,EAAU,WAAA;AAAA,EACV,SAAA,EAAW,YAAA;AAAA,EACX,YAAA,EAAc;AAChB,CAAA;AAEA,SAAS,aAAA,CACP,EAAA,EACA,GAAA,EACA,KAAA,EAC4B;AAC5B,EAAA,IAAI,CAAC,KAAA,CAAM,SAAA,EAAW,OAAO,MAAA;AAC7B,EAAA,MAAM,QAAA,GAAW,0BAA0B,GAAG,CAAA;AAC9C,EAAA,MAAM,SAAS,KAAA,CAAM,SAAA,KAAc,IAAA,GAAO,KAAK,KAAA,CAAM,SAAA;AACrD,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,GAAA,IAAO,QAAA,CAAS,GAAA;AACnC,EAAA,MAAM,MAAM,IAAA,CAAK,GAAA,CAAI,KAAK,MAAA,CAAO,GAAA,IAAO,SAAS,GAAG,CAAA;AACpD,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,iBAAA,CAAkB,EAAA,EAAI,GAAG,CAAA;AAAA,IACnC,IAAA,EAAM,GAAA,KAAQ,cAAA,GAAiB,UAAA,GAAa,YAAA;AAAA,IAC5C,IAAA,EAAM,MAAM,GAAG,CAAA;AAAA,IACf,MAAM,eAAA,CAAgB,KAAA,CAAM,QAAQ,QAAA,CAAS,IAAA,EAAM,KAAK,GAAG,CAAA;AAAA,IAC3D,GAAA;AAAA,IACA;AAAA,GACF;AACF;AAGA,IAAM,gBAAA,GAAmB,CAAC,MAAA,KACxB,MAAA,GACI;AAAA,EACE,gBAAA,EAAkB,MAAA;AAAA,EAClB,kBAAkB,MAAA,CAAO,QAAA;AAAA,EACzB,aAAa,MAAA,CAAO,IAAA;AAAA,EACpB,aAAa,MAAA,CAAO;AACtB,CAAA,GACA,EAAC;AAOP,SAAS,UAAA,CACP,KAAA,EACA,MAAA,EACA,YAAA,EACA;AACA,EAAA,IAAI,MAAA,EAAQ,OAAO,CAAA,4BAAA,EAA+B,MAAA,CAAO,IAAI,CAAA,EAAA,CAAA;AAC7D,EAAA,OAAO,MAAM,IAAA,GAAO,CAAA,EAAG,YAAY,CAAA,EAAA,EAAK,KAAA,CAAM,IAAI,CAAA,EAAA,CAAA,GAAO,MAAA;AAC3D;AAOA,SAAS,WAAA,CAAY;AAAA,EACnB,KAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA,EAIG;AACD,EAAA,MAAM,QACJ,OAAA,CAAQ,KAAA,CAAM,SAAS,CAAA,IAAA,CAAM,KAAA,CAAM,gBAAgB,QAAA,MAAc,QAAA;AACnE,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAM,uBAAA;AAAA,MACN,IAAA,EAAK,WAAA;AAAA,MACL,QAAA,EAAU,QAAQ,IAAA,GAAO,GAAA;AAAA,MACzB,YAAA,EAAY,UAAU,KAAK,CAAA,CAAA;AAAA,MAC3B,kBAAA,EACE,MAAA,CAAO,IAAA,KAAS,YAAA,GAAe,UAAA,GAAa,YAAA;AAAA,MAE9C,iBAAe,MAAA,CAAO,GAAA;AAAA,MACtB,iBAAe,MAAA,CAAO,GAAA;AAAA,MACtB,iBAAe,MAAA,CAAO,IAAA;AAAA,MACtB,aAAA,EAAa,QAAQ,MAAA,GAAS,MAAA;AAAA,MAC9B,wBAAA,EAAsB,IAAA;AAAA,MACtB,kBAAgB,MAAA,CAAO,QAAA;AAAA,MAEvB,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAM,4BAAA,EAA6B,aAAA,EAAY,MAAA,EACnD,QAAA,kBAAA,GAAA,CAAC,UAAA,EAAA,EAAW,IAAA,EAAM,MAAA,CAAO,IAAA,EAAM,CAAA,EACjC;AAAA;AAAA,GACF;AAEJ;AASA,SAAS,wBAAwB,KAAA,EAAuB;AACtD,EAAA,OAAO,KAAA,CAAM,SAAA,IAAa,KAAA,CAAM,YAAA,KAAiB,WAC5C,MAAA,GACD,MAAA;AACN;AAEA,SAAS,IAAA,CAAK;AAAA,EACZ,EAAA;AAAA,EACA,IAAA;AAAA,EACA;AACF,CAAA,EAIG;AACD,EAAA,MAAM,GAAA,GAAyB,IAAA,KAAS,MAAA,GAAS,UAAA,GAAa,WAAA;AAC9D,EAAA,MAAM,MAAA,GAAS,aAAA,CAAc,EAAA,EAAI,GAAA,EAAK,KAAK,CAAA;AAC3C,EAAA,uBACE,IAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,EAAA,EAAI,iBAAA,CAAkB,EAAA,EAAI,GAAG,CAAA;AAAA,MAC7B,KAAA,EAAO,4CAA4C,IAAI,CAAA,CAAA;AAAA,MACvD,qBAAA,EAAqB,IAAA;AAAA,MACrB,gBAAA,EAAgB,MAAA,CAAO,KAAA,CAAM,SAAA,IAAa,KAAK,CAAA;AAAA,MAC/C,gBAAA,EAAgB,MAAM,SAAA,IAAa,MAAA;AAAA,MACnC,sBAAA,EAAsB,MAAM,cAAA,IAAkB,OAAA;AAAA,MAC9C,uBAAA,EAAuB,MAAM,eAAA,IAAmB,MAAA;AAAA,MAChD,mBAAA,EAAmB,MAAM,YAAA,IAAgB,QAAA;AAAA,MACzC,8BAA4B,KAAA,CAAM,mBAAA;AAAA,MACjC,GAAG,iBAAiB,MAAM,CAAA;AAAA,MAC3B,YAAA,EAAY,MAAM,KAAA,IAAS,MAAA;AAAA,MAC3B,aAAA,EAAa,wBAAwB,KAAK,CAAA;AAAA,MAC1C,KAAA,EAAO,OAAA,CAAQ,KAAA,CAAM,SAAS,CAAA;AAAA,MAC9B,KAAA,EAAO,UAAA,CAAW,KAAA,EAAO,MAAA,EAAQ,4BAA4B,CAAA;AAAA,MAE7D,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAM,8BAAA;AAAA,YACN,KAAA,EAAO,OAAA,CAAQ,KAAA,CAAM,SAAS,CAAA;AAAA,YAE7B,QAAA,EAAA,KAAA,CAAM;AAAA;AAAA,SACT;AAAA,QACC,MAAA,oBACC,GAAA;AAAA,UAAC,WAAA;AAAA,UAAA;AAAA,YACC,KAAA;AAAA,YACA,MAAA;AAAA,YACA,KAAA,EAAO,KAAA,CAAM,KAAA,IAAS,cAAA,CAAe,GAAG;AAAA;AAAA;AAC1C;AAAA;AAAA,GAEJ;AAEJ;AAEA,SAAS,MAAA,CAAO,EAAE,EAAA,EAAI,KAAA,EAAM,EAA0C;AACpE,EAAA,MAAM,MAAA,GAAS,aAAA,CAAc,EAAA,EAAI,cAAA,EAAgB,KAAK,CAAA;AACtD,EAAA,uBACE,IAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,EAAA,EAAI,iBAAA,CAAkB,EAAA,EAAI,cAAc,CAAA;AAAA,MACxC,KAAA,EAAM,uBAAA;AAAA,MACN,uBAAA,EAAqB,IAAA;AAAA,MACrB,gBAAA,EAAgB,MAAA,CAAO,KAAA,CAAM,SAAA,IAAa,KAAK,CAAA;AAAA,MAC/C,gBAAA,EAAgB,MAAM,SAAA,IAAa,MAAA;AAAA,MACnC,sBAAA,EAAsB,MAAM,cAAA,IAAkB,OAAA;AAAA,MAC9C,uBAAA,EAAuB,MAAM,eAAA,IAAmB,MAAA;AAAA,MAChD,mBAAA,EAAmB,MAAM,YAAA,IAAgB,QAAA;AAAA,MACzC,8BAA4B,KAAA,CAAM,mBAAA;AAAA,MACjC,GAAG,iBAAiB,MAAM,CAAA;AAAA,MAC3B,YAAA,EAAY,MAAM,KAAA,IAAS,MAAA;AAAA,MAC3B,aAAA,EAAa,wBAAwB,KAAK,CAAA;AAAA,MAC1C,KAAA,EAAO,OAAA,CAAQ,KAAA,CAAM,SAAS,CAAA;AAAA,MAC9B,KAAA,EAAO,UAAA,CAAW,KAAA,EAAO,MAAA,EAAQ,+BAA+B,CAAA;AAAA,MAEhE,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAM,8BAAA;AAAA,YACN,KAAA,EAAO,OAAA,CAAQ,KAAA,CAAM,SAAS,CAAA;AAAA,YAE7B,QAAA,EAAA,KAAA,CAAM;AAAA;AAAA,SACT;AAAA,QACC,MAAA,oBACC,GAAA;AAAA,UAAC,WAAA;AAAA,UAAA;AAAA,YACC,KAAA;AAAA,YACA,MAAA;AAAA,YACA,KAAA,EAAO,KAAA,CAAM,KAAA,IAAS,cAAA,CAAe;AAAA;AAAA;AACvC;AAAA;AAAA,GAEJ;AAEJ;AAGA,SAAS,OAAA,CACP,KAAA,EACA,IAAA,EACA,QAAA,EACA;AACA,EAAA,IACE,CAAC,KAAA,EAAO,SAAA,IACR,CAAC,KAAA,CAAM,cAAA,IACP,MAAM,YAAA,KAAiB,QAAA;AAEvB,IAAA,OAAO,EAAA;AACT,EAAA,uBACE,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAM,wBAAA;AAAA,MACN,YAAA,EAAY,IAAA;AAAA,MACZ,eAAA,EAAe,MAAM,eAAA,IAAmB,QAAA;AAAA,MAEvC,QAAA,EAAA,KAAA,CAAM;AAAA;AAAA,GACT;AAEJ;AAeO,SAAS,SAAA,CAAU;AAAA,EACxB,EAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA;AAAA,EACA,WAAA,GAAc,uBAAA;AAAA,EACd,aAAA,GAAgB,yBAAA;AAAA,EAChB,SAAA,GAAY,EAAA;AAAA,EACZ;AACF,CAAA,EAAmB;AAGjB,EAAA,MAAM,EAAA,GAAK,CAAC,KAAA,KAAkB,IAAA,CAAK,IAAI,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,KAAK,CAAC,CAAA;AAC3D,EAAA,MAAM,OAAA,GAAU,QAAA,IAAY,SAAA,GAAY,EAAA,CAAG,WAAW,CAAA,GAAI,MAAA;AAC1D,EAAA,MAAM,YAAA,GAAe,YAAA,GAAe,EAAA,CAAG,aAAa,CAAA,GAAI,MAAA;AACxD,EAAA,MAAM,KAAA,GAAQ;AAAA,IACZ,OAAA,KAAY,MAAA,GAAY,EAAA,GAAK,CAAA,gCAAA,EAAmC,OAAO,CAAA,EAAA,CAAA;AAAA,IACvE,YAAA,KAAiB,MAAA,GACb,EAAA,GACA,CAAA,iCAAA,EAAoC,YAAY,CAAA,EAAA;AAAA,GACtD,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AACX,EAAA,uBACE,IAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,CAAA,cAAA,EAAiB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK;AAAA,MACzC,EAAA;AAAA,MACA,gBAAA,EAAe,WAAA;AAAA,MACf,oBAAA,EAAoB,OAAA,KAAY,MAAA,GAAY,MAAA,GAAY,OAAO,OAAO,CAAA;AAAA,MACtE,sBAAA,EACE,YAAA,KAAiB,MAAA,GAAY,MAAA,GAAY,OAAO,YAAY,CAAA;AAAA,MAE9D,OAAO,KAAA,IAAS,MAAA;AAAA,MAChB,YAAA,EAAY,KAAA;AAAA,MACZ,IAAA;AAAA,MAEC,QAAA,EAAA;AAAA,QAAA,QAAA,wBAAa,IAAA,EAAA,EAAK,EAAA,EAAQ,IAAA,EAAK,MAAA,EAAO,OAAO,QAAA,EAAU,CAAA;AAAA,QACvD,OAAA,CAAQ,QAAA,EAAU,MAAA,EAAQ,cAAc,CAAA;AAAA,wBACzC,IAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,uBAAA,EACT,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAM,qBAAA,EAAsB,qBAAA,EAAmB,MACjD,QAAA,EAAA,IAAA,EACH,CAAA;AAAA,UACC,YAAA,oBAAgB,GAAA,CAAC,MAAA,EAAA,EAAO,EAAA,EAAQ,OAAO,YAAA,EAAc,CAAA;AAAA,UACrD,OAAA,CAAQ,YAAA,EAAc,QAAA,EAAU,YAAY;AAAA,SAAA,EAC/C,CAAA;AAAA,QACC,6BAAa,GAAA,CAAC,IAAA,EAAA,EAAK,IAAQ,IAAA,EAAK,OAAA,EAAQ,OAAO,SAAA,EAAW,CAAA;AAAA,QAC1D,OAAA,CAAQ,SAAA,EAAW,OAAA,EAAS,YAAY;AAAA;AAAA;AAAA,GAC3C;AAEJ","file":"workbench.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport {\n clampRegionSize,\n type ResizableRegionAxis,\n type ResizableRegionCollapseMotion,\n type ResizableRegionContentOverflow,\n type ResizableRegionEdge,\n type ResizableRegionPresentation,\n type ResizableRegionRestorePosition,\n type ResizableRegionSeparator,\n} from './resizable-region.js';\nimport { ResizeGrip } from './resize-grip.js';\nimport type { KerfUiContent } from './semantic-content.js';\nimport {\n WORKBENCH_MAIN_MIN_HEIGHT,\n WORKBENCH_MAIN_MIN_SIZE,\n WORKBENCH_RESIZE_DEFAULTS,\n type WorkbenchPanelKey,\n workbenchRegionId,\n} from './workbench-resize.js';\n\n/**\n * The Workbench container breakpoint below which a panel presents as an\n * overlay: `narrow` (704px or less) or `compact` (448px or less) — the same\n * breakpoints as `ResizableRegion`'s `responsiveFillAt`.\n */\nexport type WorkbenchResponsiveOverlayAt = 'compact' | 'narrow';\n\n/** Drag-resize limits for a resizable Workbench panel, in px. */\nexport interface WorkbenchPanelResizable {\n /** Smallest size (default 180 for a rail, 120 for the drawer). */\n min?: number;\n /** Largest size (default 480). */\n max?: number;\n}\n\n/** A collapsible Workbench panel — a side rail or the bottom drawer. */\nexport interface WorkbenchPanel {\n content: KerfUiContent;\n /** Whether the panel is currently collapsed (the app owns this). */\n collapsed?: boolean;\n /**\n * Rail width, or drawer height, in px. Overrides the CSS default. For a\n * resizable panel it is the current size (default 280 for a rail, 220 for\n * the drawer), clamped to the limits; the app owns it and `wireWorkbench`\n * reports each resize.\n */\n size?: number;\n /**\n * Opt in to drag and keyboard resizing on the panel's inner separator:\n * `true` for the default limits, or `{ min, max }`. Off by default. Pair it\n * with `wireWorkbench` from `@kerfjs/ui/wire-workbench`.\n */\n resizable?: boolean | WorkbenchPanelResizable;\n /** Accessible name for the panel region. */\n label?: string;\n separator?: ResizableRegionSeparator;\n collapseMotion?: ResizableRegionCollapseMotion;\n contentOverflow?: ResizableRegionContentOverflow;\n presentation?: ResizableRegionPresentation;\n /**\n * Present the panel as an overlay, without a separator, below a Workbench\n * container breakpoint, and inline above it — the CSS decides, so the app\n * needs no device-class check. A rail overlays from its side at full\n * height; the bottom drawer overlays the bottom of the work-area column.\n */\n responsiveOverlayAt?: WorkbenchResponsiveOverlayAt;\n /**\n * Control shown while collapsed, in a safe-area-aware corner of the\n * Workbench (not the viewport); the bottom drawer's sits in the work-area\n * column.\n */\n restoreControl?: SafeHtml;\n restorePosition?: ResizableRegionRestorePosition;\n}\n\nexport interface WorkbenchProps {\n /**\n * The Workbench's `id`. Each panel's `id` derives from it —\n * `<id>-left-rail`, `<id>-right-rail`, `<id>-bottom-drawer` — so a toggle\n * can name the panel it shows and hides with `aria-controls`.\n */\n id: string;\n label: string;\n /** The central work area. */\n main: KerfUiContent;\n leftRail?: WorkbenchPanel;\n rightRail?: WorkbenchPanel;\n bottomDrawer?: WorkbenchPanel;\n /**\n * Minimum width, in px, the work area keeps beside the inline rails, fixed\n * or `resizable` (default 320; `0` turns it off). Resizing a rail stops\n * where the work area would drop below it, and inline rails shrink\n * proportionally when the Workbench gets narrower. Workbenches without a\n * rail ignore it.\n */\n mainMinSize?: number;\n /**\n * Minimum height, in px, the work area keeps above an inline bottom drawer,\n * fixed or `resizable` (default 120; `0` turns it off) — the drawer's\n * counterpart of `mainMinSize`. Resizing the drawer stops where the work\n * area would drop below it, and the drawer shrinks when the Workbench gets\n * shorter. Workbenches without a drawer ignore it.\n */\n mainMinHeight?: number;\n className?: string;\n /** Native named-slot assignment when composed inside a web component. */\n slot?: string;\n}\n\ninterface ResolvedResize {\n regionId: string;\n axis: ResizableRegionAxis;\n edge: ResizableRegionEdge;\n size: number;\n min: number;\n max: number;\n}\n\n/**\n * Each panel's separator is its inner edge. Growing the left rail moves that\n * edge toward the inline end; growing the right rail or the drawer moves it\n * toward the start — the same edge vocabulary `ResizableRegion` uses.\n */\nconst EDGES: Record<WorkbenchPanelKey, ResizableRegionEdge> = {\n leftRail: 'end',\n rightRail: 'start',\n bottomDrawer: 'start',\n};\n\nconst DEFAULT_LABELS: Record<WorkbenchPanelKey, string> = {\n leftRail: 'left rail',\n rightRail: 'right rail',\n bottomDrawer: 'bottom drawer',\n};\n\nfunction resolveResize(\n id: string,\n key: WorkbenchPanelKey,\n panel: WorkbenchPanel,\n): ResolvedResize | undefined {\n if (!panel.resizable) return undefined;\n const defaults = WORKBENCH_RESIZE_DEFAULTS[key];\n const limits = panel.resizable === true ? {} : panel.resizable;\n const min = limits.min ?? defaults.min;\n const max = Math.max(min, limits.max ?? defaults.max);\n return {\n regionId: workbenchRegionId(id, key),\n axis: key === 'bottomDrawer' ? 'vertical' : 'horizontal',\n edge: EDGES[key],\n size: clampRegionSize(panel.size ?? defaults.size, min, max),\n min,\n max,\n };\n}\n\n/** The attributes a resizable panel adds for the resize wiring to read. */\nconst resizeAttributes = (resize: ResolvedResize | undefined) =>\n resize\n ? {\n 'data-resizable': 'true',\n 'data-region-id': resize.regionId,\n 'data-axis': resize.axis,\n 'data-edge': resize.edge,\n }\n : {};\n\n/**\n * A resizable panel's size lives in the resize wiring's track property, so a\n * drag or key press resizes the panel before the app re-renders; the CSS maps\n * it onto the rail width or drawer height.\n */\nfunction panelStyle(\n panel: WorkbenchPanel,\n resize: ResolvedResize | undefined,\n sizeProperty: string,\n) {\n if (resize) return `--kui-resizable-region-size:${resize.size}px`;\n return panel.size ? `${sizeProperty}: ${panel.size}px` : undefined;\n}\n\n/**\n * The separator a resizable panel owns: the same focusable `role=\"separator\"`\n * contract a `ResizableRegion` handle carries, so one resize wiring drives\n * both. It leaves the tab order while the panel is collapsed or not inline.\n */\nfunction PanelHandle({\n panel,\n resize,\n label,\n}: {\n panel: WorkbenchPanel;\n resize: ResolvedResize;\n label: string;\n}) {\n const inert =\n Boolean(panel.collapsed) || (panel.presentation ?? 'inline') !== 'inline';\n return (\n <div\n class=\"kui-workbench__handle\"\n role=\"separator\"\n tabindex={inert ? '-1' : '0'}\n aria-label={`Resize ${label}`}\n aria-orientation={\n resize.axis === 'horizontal' ? 'vertical' : 'horizontal'\n }\n aria-valuemin={resize.min}\n aria-valuemax={resize.max}\n aria-valuenow={resize.size}\n aria-hidden={inert ? 'true' : undefined}\n data-kui-resize-handle\n data-region-id={resize.regionId}\n >\n <span class=\"kui-workbench__handle-icon\" aria-hidden=\"true\">\n <ResizeGrip axis={resize.axis} />\n </span>\n </div>\n );\n}\n\n/**\n * A collapsed panel leaves the accessibility tree as a whole, like a collapsed\n * `CollapsiblePanel`: its content and separator are already inert or hidden,\n * so the labeled landmark would otherwise stay behind, empty, for a screen\n * reader to land on. Its restore control renders outside it and stays\n * reachable.\n */\nfunction hiddenFromAccessibility(panel: WorkbenchPanel) {\n return panel.collapsed || panel.presentation === 'hidden'\n ? ('true' as const)\n : undefined;\n}\n\nfunction Rail({\n id,\n side,\n panel,\n}: {\n id: string;\n side: 'left' | 'right';\n panel: WorkbenchPanel;\n}) {\n const key: WorkbenchPanelKey = side === 'left' ? 'leftRail' : 'rightRail';\n const resize = resolveResize(id, key, panel);\n return (\n <aside\n id={workbenchRegionId(id, key)}\n class={`kui-workbench__rail kui-workbench__rail--${side}`}\n data-workbench-rail={side}\n data-collapsed={String(panel.collapsed ?? false)}\n data-separator={panel.separator ?? 'auto'}\n data-collapse-motion={panel.collapseMotion ?? 'slide'}\n data-content-overflow={panel.contentOverflow ?? 'clip'}\n data-presentation={panel.presentation ?? 'inline'}\n data-responsive-overlay-at={panel.responsiveOverlayAt}\n {...resizeAttributes(resize)}\n aria-label={panel.label || undefined}\n aria-hidden={hiddenFromAccessibility(panel)}\n inert={Boolean(panel.collapsed)}\n style={panelStyle(panel, resize, '--kui-workbench-rail-width')}\n >\n <div\n class=\"kui-workbench__panel-content\"\n inert={Boolean(panel.collapsed)}\n >\n {panel.content}\n </div>\n {resize && (\n <PanelHandle\n panel={panel}\n resize={resize}\n label={panel.label || DEFAULT_LABELS[key]}\n />\n )}\n </aside>\n );\n}\n\nfunction Drawer({ id, panel }: { id: string; panel: WorkbenchPanel }) {\n const resize = resolveResize(id, 'bottomDrawer', panel);\n return (\n <section\n id={workbenchRegionId(id, 'bottomDrawer')}\n class=\"kui-workbench__drawer\"\n data-workbench-drawer\n data-collapsed={String(panel.collapsed ?? false)}\n data-separator={panel.separator ?? 'auto'}\n data-collapse-motion={panel.collapseMotion ?? 'slide'}\n data-content-overflow={panel.contentOverflow ?? 'clip'}\n data-presentation={panel.presentation ?? 'inline'}\n data-responsive-overlay-at={panel.responsiveOverlayAt}\n {...resizeAttributes(resize)}\n aria-label={panel.label || undefined}\n aria-hidden={hiddenFromAccessibility(panel)}\n inert={Boolean(panel.collapsed)}\n style={panelStyle(panel, resize, '--kui-workbench-drawer-height')}\n >\n <div\n class=\"kui-workbench__panel-content\"\n inert={Boolean(panel.collapsed)}\n >\n {panel.content}\n </div>\n {resize && (\n <PanelHandle\n panel={panel}\n resize={resize}\n label={panel.label || DEFAULT_LABELS.bottomDrawer}\n />\n )}\n </section>\n );\n}\n\n/** A collapsed panel's restore control, outside the clipped panel. */\nfunction restore(\n panel: WorkbenchPanel | undefined,\n side: 'left' | 'right' | 'bottom',\n position: ResizableRegionRestorePosition,\n) {\n if (\n !panel?.collapsed ||\n !panel.restoreControl ||\n panel.presentation === 'hidden'\n )\n return '';\n return (\n <div\n class=\"kui-workbench__restore\"\n data-panel={side}\n data-position={panel.restorePosition ?? position}\n >\n {panel.restoreControl}\n </div>\n );\n}\n\n/**\n * The Xcode-like multi-panel workspace: a collapsible left rail, right rail, and\n * bottom drawer around a central work area (any absent). Collapsing snaps the\n * panel's track to zero in one reflow while its fixed-size content slides out via\n * a composited transform — the instant-width / sliding-content technique, so the\n * work area relayouts once, not per frame. Bottom-drawer content stays anchored\n * to the shell's stable bottom edge throughout that transition. The app owns\n * each `collapsed` flag; the collapse is pure CSS. A collapsed panel renders\n * `inert` and `aria-hidden`, so neither Tab nor assistive technology reaches\n * controls that have slid out of view or an empty landmark (its restore control\n * lives outside it and stays reachable). A panel may opt in to drag and keyboard resizing with\n * `resizable`, which `wireWorkbench` drives. See `docs/23-app-layouts.md` §3.3.\n */\nexport function Workbench({\n id,\n label,\n main,\n leftRail,\n rightRail,\n bottomDrawer,\n mainMinSize = WORKBENCH_MAIN_MIN_SIZE,\n mainMinHeight = WORKBENCH_MAIN_MIN_HEIGHT,\n className = '',\n slot,\n}: WorkbenchProps) {\n // Each work-area minimum applies only on an axis a panel shares with it:\n // the width beside a rail, the height above the drawer.\n const px = (value: number) => Math.max(0, Math.round(value));\n const mainMin = leftRail || rightRail ? px(mainMinSize) : undefined;\n const mainMinBlock = bottomDrawer ? px(mainMinHeight) : undefined;\n const style = [\n mainMin === undefined ? '' : `--_kui-workbench-main-min-width:${mainMin}px`,\n mainMinBlock === undefined\n ? ''\n : `--_kui-workbench-main-min-height:${mainMinBlock}px`,\n ]\n .filter(Boolean)\n .join(';');\n return (\n <section\n class={`kui-workbench ${className}`.trim()}\n id={id}\n data-component=\"workbench\"\n data-main-min-size={mainMin === undefined ? undefined : String(mainMin)}\n data-main-min-height={\n mainMinBlock === undefined ? undefined : String(mainMinBlock)\n }\n style={style || undefined}\n aria-label={label}\n slot={slot}\n >\n {leftRail && <Rail id={id} side=\"left\" panel={leftRail} />}\n {restore(leftRail, 'left', 'bottom-start')}\n <div class=\"kui-workbench__center\">\n <div class=\"kui-workbench__main\" data-workbench-main>\n {main}\n </div>\n {bottomDrawer && <Drawer id={id} panel={bottomDrawer} />}\n {restore(bottomDrawer, 'bottom', 'bottom-end')}\n </div>\n {rightRail && <Rail id={id} side=\"right\" panel={rightRail} />}\n {restore(rightRail, 'right', 'bottom-end')}\n </section>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"workbench.js"}
|
package/docs/accessibility.md
CHANGED
|
@@ -16,7 +16,7 @@ These are normative contracts for package components and consuming applications.
|
|
|
16
16
|
- `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.
|
|
17
17
|
- `EmptyState` reports busy state through `aria-busy` and never relies on an illustration as its label.
|
|
18
18
|
- `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.
|
|
19
|
-
- `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
|
|
19
|
+
- `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.
|
|
20
20
|
- `List` is layout-only and adds no `list` role. Children own their native or ARIA semantics. Give a scrollable List a bounded block size, avoid nested scroll owners, and keep focused children visible while scrolling.
|
|
21
21
|
|
|
22
22
|
## Select
|
|
@@ -30,18 +30,44 @@ adding height or spacing. This also applies to `renderSelected`: selected conten
|
|
|
30
30
|
stays separate from the control's stable accessible name. Applications do not
|
|
31
31
|
need shadow-DOM patches or extra label styling.
|
|
32
32
|
|
|
33
|
+
Set `multiple` (with an array `value`) to let the person choose any number
|
|
34
|
+
of choices. The popup stays open while they toggle choices with the pointer,
|
|
35
|
+
Enter, or Space, and closes on an outside press, Escape, or focus leaving,
|
|
36
|
+
returning focus to the combobox. The listbox is `aria-multiselectable`, each
|
|
37
|
+
chosen option shows its check, and the closed control reads the chosen labels
|
|
38
|
+
in choice order as one short localized list (the `placeholderText` when none
|
|
39
|
+
are chosen) instead of a removable tag per choice. `change` and `input` report
|
|
40
|
+
the value array; in a form, every chosen value is submitted under `name`.
|
|
41
|
+
|
|
42
|
+
A toolbar filter menu (a "Filter by label" funnel) is a multiple Select with
|
|
43
|
+
`selectedPresentation="icon-only"` and a fixed `triggerIcon`; the types accept
|
|
44
|
+
`triggerIcon` only there, and require it there, because no single chosen
|
|
45
|
+
choice has an icon to show. The trigger keeps the icon-only pill geometry
|
|
46
|
+
below: the fixed icon, then, while any choice is chosen, a compact brand
|
|
47
|
+
`Badge` with the count 4px after it, then the caret. The badge is hidden from
|
|
48
|
+
assistive technology; instead the combobox's accessible name ends with the
|
|
49
|
+
chosen labels in choice order ("Filter by label: Bug, Docs", just "Filter by
|
|
50
|
+
label" when none are chosen), and its hidden value text stays empty so screen
|
|
51
|
+
readers do not announce the list twice. With a visible `label` the same summary
|
|
52
|
+
reads in the label, standing in for the hidden value.
|
|
53
|
+
|
|
33
54
|
Use `presentation="toolbar-borderless"` inside a `ToolbarControlGroup`, with
|
|
34
55
|
`size="compact"` in a compact group; set `focusRingOwner="group"` when that
|
|
35
56
|
parent paints the composed focus ring. `selectedPresentation="icon-only"` hides
|
|
36
57
|
only the visible selected label—the required `label` or `ariaLabel` still names
|
|
37
58
|
the combobox. An icon-only trigger keeps its disclosure caret: the selected icon
|
|
38
|
-
and caret form one pill with the same geometry as a
|
|
59
|
+
and caret form one pill with the same geometry as a `PopupMenu`
|
|
39
60
|
trigger (8px inline padding on both sides, 12px from the icon to the caret, a
|
|
40
61
|
40px default or 32px compact control height), so the caret still signals a
|
|
41
62
|
choice list. Inside a group the trigger is inset evenly on every side (2px in a
|
|
42
63
|
default group, 1px in a compact one) with a concentric radius; the group grows
|
|
43
64
|
to the trigger's width, so a single group is wider than it is tall and its
|
|
44
|
-
focus ring follows the pill while focused
|
|
65
|
+
focus ring follows the pill while focused. While the listbox is open the
|
|
66
|
+
trigger drops its ring, as a `PopupMenu` trigger does: the open popup and its
|
|
67
|
+
current option show where focus is, and the ring returns when the listbox
|
|
68
|
+
closes with focus still on the control. A group that owns the ring
|
|
69
|
+
(`focusRing="outline"` or `"halo"`) drops it the same way while a Select
|
|
70
|
+
listbox or `PopupMenu` inside the group is open.
|
|
45
71
|
Beside other controls in one group, the icon-only trigger is one more segment:
|
|
46
72
|
it keeps the group's gap and its siblings' block inset, height, item radius,
|
|
47
73
|
and hover pill. In a group with per-control rings (`focusRing="control"`, the
|
|
@@ -81,6 +107,95 @@ repeated and out-of-order completions, cancellation, instance isolation, and
|
|
|
81
107
|
removal. `tests/browser/select-lifecycle.spec.ts` repeats animation/resize/reopen
|
|
82
108
|
sequences at wide and narrow widths in Chromium, Firefox, and WebKit.
|
|
83
109
|
|
|
110
|
+
### Help tags on icon-only triggers
|
|
111
|
+
|
|
112
|
+
An icon-only control has no visible title, so sighted pointer and keyboard users
|
|
113
|
+
would otherwise see only its icon (and a filter's count). Following the Apple
|
|
114
|
+
HIG convention for toolbar items, three kinds of icon-only control show a help
|
|
115
|
+
tag: a Web Awesome `wa-tooltip` in the theme's tooltip palette, below the
|
|
116
|
+
control.
|
|
117
|
+
|
|
118
|
+
- an icon-only `Select` (`selectedPresentation="icon-only"`, single or
|
|
119
|
+
`multiple`);
|
|
120
|
+
- an icon-only `PopupMenu` (named by `label` rather than visible `text`);
|
|
121
|
+
- an icon-only `<button>` or link (`<a href>`) inside a `ToolbarControlGroup`,
|
|
122
|
+
named by a non-empty `aria-label`, with no visible text, no native `title`,
|
|
123
|
+
and no Web Awesome tooltip `for` it.
|
|
124
|
+
|
|
125
|
+
Tags are on by default and take no props. One document-level installer covers
|
|
126
|
+
all three kinds, and any of `@kerfjs/ui/select/register`,
|
|
127
|
+
`@kerfjs/ui/popup-menu/register`, or `@kerfjs/ui/help-tags/register` installs
|
|
128
|
+
it (once per document, however many are imported). An application whose
|
|
129
|
+
toolbars have icon-only buttons but no registered `Select` or `PopupMenu`
|
|
130
|
+
imports `@kerfjs/ui/help-tags/register`, which registers only the tooltip
|
|
131
|
+
element. Pure `SafeHtml` rendering stays zero-JS: without an installer, nothing
|
|
132
|
+
shows a tag.
|
|
133
|
+
|
|
134
|
+
- **Text.** The tag says what the accessible name says: a filter's name and
|
|
135
|
+
chosen labels ("Filter by label: Bug, Docs", or "Filter by label" when none
|
|
136
|
+
are chosen), a single Select's name and current choice ("Rendering balance:
|
|
137
|
+
Balanced"), a menu's `label` ("Sort tickets"), or a toolbar button's
|
|
138
|
+
`aria-label` ("Pin view"). It updates with the selection.
|
|
139
|
+
- **Showing.** It appears after the pointer rests on the control for 500ms, at
|
|
140
|
+
once when a neighboring tag closed moments ago (so scanning along a toolbar
|
|
141
|
+
stays quick, across buttons, Selects, and menus alike), and immediately on
|
|
142
|
+
keyboard focus (`:focus-visible`). A pointer press that focuses the control
|
|
143
|
+
and touch input never show it.
|
|
144
|
+
- **Hiding.** It hides when the pointer and keyboard focus have both left the
|
|
145
|
+
control, on a press, on Escape, and whenever a popup opens. It does not come
|
|
146
|
+
back when the popup closes and focus returns to the trigger, or while the
|
|
147
|
+
pointer stays on a pressed button; it returns after the pointer moves onto
|
|
148
|
+
something else or focus leaves and comes back.
|
|
149
|
+
- **Assistive technology.** The tag is `aria-hidden` and never joins the
|
|
150
|
+
control's `aria-labelledby` or `aria-describedby` (kerf anchors it directly
|
|
151
|
+
rather than through `for`), so the accessible name is unchanged and announced
|
|
152
|
+
once; the accessibility tree is identical with the tag open or closed.
|
|
153
|
+
- **Isolation.** A Select's or PopupMenu's tag lives in the control's own
|
|
154
|
+
shadow root, so the morph never touches it and light-DOM `:has([open])`
|
|
155
|
+
selectors do not see it. A plain button cannot host a shadow root, so its tag
|
|
156
|
+
lives in one `aria-hidden`, `data-morph-skip` layer at the end of `<body>`
|
|
157
|
+
(fixed and zero-sized, so it never joins a grid or flex body's flow, and
|
|
158
|
+
re-attached if a body re-render drops it) and leaves that layer once hidden.
|
|
159
|
+
It copies the button's `color-scheme`, so it matches a subtree theme, and its
|
|
160
|
+
popup renders in the browser's top layer, so it shows above a modal dialog
|
|
161
|
+
that holds the button. Tags' `wa-show` / `wa-hide` lifecycle events stop at
|
|
162
|
+
the tag, so a listener on the control (or a delegated one above it) hears only
|
|
163
|
+
the popup; a document capture-phase listener still observes them. A long tag
|
|
164
|
+
wraps at the tooltip's maximum width and keeps 8px clear of the viewport
|
|
165
|
+
edge.
|
|
166
|
+
|
|
167
|
+
A labeled Select, a `PopupMenu` with visible `text`, and a toolbar button with
|
|
168
|
+
visible text get no tag: their visible text already names them. A button that
|
|
169
|
+
carries a native `title`, or that the application has already given a
|
|
170
|
+
`wa-tooltip` `for` its `id`, keeps that and gets no second tag, so nothing is
|
|
171
|
+
shown twice. Zero-JS components that name an icon control with a native `title`
|
|
172
|
+
(the `ListHeader` action, the `AppTab` close button, the `TokenSearchField`
|
|
173
|
+
reveal and clear buttons, and `SegmentedControl` choice titles) keep the
|
|
174
|
+
browser's own tooltip, which needs no script; the installer deliberately skips
|
|
175
|
+
them rather than stacking a second tag on the first. Icon-only buttons outside
|
|
176
|
+
a `ToolbarControlGroup` are application markup and keep whatever naming the
|
|
177
|
+
application gives them.
|
|
178
|
+
`tests/unit/help-tag.test.ts` walks the hover, focus, press, Escape, popup, and
|
|
179
|
+
warm-window transitions for every kind; `tests/browser/select-help-tag.spec.ts`
|
|
180
|
+
and `tests/browser/toolbar-help-tag.spec.ts` check the real elements in
|
|
181
|
+
Chromium.
|
|
182
|
+
|
|
183
|
+
## PopupMenu
|
|
184
|
+
|
|
185
|
+
`PopupMenu` renders a Web Awesome dropdown, so the menu roles, arrow-key and
|
|
186
|
+
typeahead navigation, Escape, and focus return to the trigger come from
|
|
187
|
+
`wa-dropdown`. Kerf's part is the trigger's name. A Web Awesome button takes its
|
|
188
|
+
name from its content and ignores an `aria-label` on the host, so an icon-only
|
|
189
|
+
trigger requires `label`, which renders as visually hidden text inside the
|
|
190
|
+
button; a trigger with visible `text` is named by that text. An icon-only
|
|
191
|
+
trigger also shows its `label` as an `aria-hidden` help tag on hover and
|
|
192
|
+
keyboard focus (see [Help tags on icon-only triggers](#help-tags-on-icon-only-triggers)). Group headings
|
|
193
|
+
render as the same uppercase group titles a grouped `Select` shows, and dividers
|
|
194
|
+
are presentational. A keyboard-focused item is the menu's current row, painted
|
|
195
|
+
with the Select's current-option fill rather than a second focus ring inside the
|
|
196
|
+
open popup. A disabled item stays in the menu but cannot be
|
|
197
|
+
chosen; disable the whole trigger only when every command is unavailable.
|
|
198
|
+
|
|
84
199
|
## ListActionRow
|
|
85
200
|
|
|
86
201
|
`ListActionRow` renders a noninteractive visual root containing primary and
|
|
@@ -172,10 +287,15 @@ forced to a dark color scheme, but it is **not** in the top layer, so it never
|
|
|
172
287
|
covers dialogs, popovers, or other overlays. Its children are the app's controls
|
|
173
288
|
(normally `ToolbarControlGroup`s), which keep their own names, focus, and
|
|
174
289
|
keyboard behavior; the application owns their actions, the toolbar's visibility,
|
|
175
|
-
and — via `position` and
|
|
176
|
-
or an ancestor — where it sits. Inside a `Workbench`, `CollapsiblePanel`, or
|
|
290
|
+
and — via `position` and the typed `inset` prop — where it sits. Inside a `Workbench`, `CollapsiblePanel`, or
|
|
177
291
|
`ResizableRegion` `restoreControl` the restore corner owns the inset, so the
|
|
178
|
-
toolbar floats from that corner.
|
|
292
|
+
toolbar floats from that corner. While one of those layouts has a side overlay
|
|
293
|
+
open over the toolbar's region (a Workbench rail overlay, a `wireSidebar`
|
|
294
|
+
compact overlay, an overlay `CollapsiblePanel` or horizontal
|
|
295
|
+
`ResizableRegion`), the toolbar is hidden (`visibility: hidden`), so it is
|
|
296
|
+
unfocusable and out of the accessibility tree rather than a control stranded
|
|
297
|
+
behind the overlay's focus trap; it returns when the overlay closes. The
|
|
298
|
+
overlay's own floating toolbars stay.
|
|
179
299
|
|
|
180
300
|
## Tabs
|
|
181
301
|
|