@kerfjs/ui 5.0.0-beta.50 → 5.0.0-beta.51
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 +29 -5
- package/ai/compile-time-contracts-v1.json +5 -2
- package/ai/component-catalog-v2.d.ts +19 -1
- package/ai/component-catalog-v2.json +842 -127
- package/ai/component-catalog-v2.schema.json +33 -1
- package/ai/component-catalog.json +603 -126
- package/ai/component-catalog.schema.json +21 -1
- package/ai/public-api-signatures-v1.md +201 -29
- package/ai/skill.md +12 -9
- package/ai/webawesome-jsx-signatures-v1.md +1 -1
- package/analyzer/index.mjs +105 -35
- package/dist/app-tab.js +1 -1
- package/dist/catalog-resources.d.ts +1 -1
- package/dist/catalog.d.ts +28 -5
- package/dist/catalog.js +66 -25
- package/dist/catalog.js.map +1 -1
- package/dist/{chunk-COUPLRZG.js → chunk-5FZZMIMD.js} +3 -3
- package/dist/{chunk-COUPLRZG.js.map → chunk-5FZZMIMD.js.map} +1 -1
- package/dist/{chunk-DARTMI5Z.js → chunk-5PMGQDG7.js} +2 -2
- package/dist/{chunk-DARTMI5Z.js.map → chunk-5PMGQDG7.js.map} +1 -1
- package/dist/{chunk-V6RZWDII.js → chunk-7GUQYHKA.js} +19 -2
- package/dist/chunk-7GUQYHKA.js.map +1 -0
- package/dist/{chunk-ZNZ2JDBW.js → chunk-7IUSV4XG.js} +1 -1
- package/dist/chunk-7IUSV4XG.js.map +1 -0
- package/dist/{chunk-ELRMBQEC.js → chunk-AEPXGCNF.js} +17 -2
- package/dist/chunk-AEPXGCNF.js.map +1 -0
- package/dist/{chunk-5CE64WGC.js → chunk-D547PH4L.js} +3 -3
- package/dist/{chunk-5CE64WGC.js.map → chunk-D547PH4L.js.map} +1 -1
- package/dist/{chunk-S6ZTTTV7.js → chunk-DVZCMMB3.js} +3 -3
- package/dist/{chunk-S6ZTTTV7.js.map → chunk-DVZCMMB3.js.map} +1 -1
- package/dist/chunk-EKYZCRCX.js +256 -0
- package/dist/chunk-EKYZCRCX.js.map +1 -0
- package/dist/{chunk-3V75EQIP.js → chunk-JM53SMVF.js} +3 -3
- package/dist/{chunk-3V75EQIP.js.map → chunk-JM53SMVF.js.map} +1 -1
- package/dist/{chunk-2WMSE4MK.js → chunk-JMGKM7RK.js} +2 -2
- package/dist/{chunk-2WMSE4MK.js.map → chunk-JMGKM7RK.js.map} +1 -1
- package/dist/{chunk-2YOUUEWR.js → chunk-KX7DP2GO.js} +4 -4
- package/dist/{chunk-2YOUUEWR.js.map → chunk-KX7DP2GO.js.map} +1 -1
- package/dist/{chunk-OL4TC3U2.js → chunk-MO56ZZLG.js} +6 -2
- package/dist/chunk-MO56ZZLG.js.map +1 -0
- package/dist/{chunk-OQI7RCRP.js → chunk-MTM43SJO.js} +7 -1
- package/dist/chunk-MTM43SJO.js.map +1 -0
- package/dist/{chunk-ZSYLBVWG.js → chunk-NMGTHYW3.js} +3 -3
- package/dist/{chunk-ZSYLBVWG.js.map → chunk-NMGTHYW3.js.map} +1 -1
- package/dist/{chunk-AQSKJ6U6.js → chunk-NZXWU4R5.js} +21 -2
- package/dist/chunk-NZXWU4R5.js.map +1 -0
- package/dist/{chunk-DJKWFYAA.js → chunk-O3RCCSQJ.js} +3 -3
- package/dist/{chunk-DJKWFYAA.js.map → chunk-O3RCCSQJ.js.map} +1 -1
- package/dist/{chunk-UMGY5JSP.js → chunk-S4QRSBFI.js} +22 -2
- package/dist/chunk-S4QRSBFI.js.map +1 -0
- package/dist/{chunk-KKNK3JUT.js → chunk-UBH743HV.js} +5 -5
- package/dist/chunk-UBH743HV.js.map +1 -0
- package/dist/{chunk-54HM36IQ.js → chunk-ULCDZTWL.js} +2 -2
- package/dist/{chunk-54HM36IQ.js.map → chunk-ULCDZTWL.js.map} +1 -1
- package/dist/{chunk-SIU2AC5W.js → chunk-UPZ6EEJN.js} +3 -3
- package/dist/{chunk-SIU2AC5W.js.map → chunk-UPZ6EEJN.js.map} +1 -1
- package/dist/collapsible-panel.d.ts +1 -1
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/css-values.d.ts +39 -3
- package/dist/css-values.js +1 -1
- package/dist/grid.d.ts +15 -1
- package/dist/grid.js +2 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +19 -19
- package/dist/list-action-row.js +1 -1
- package/dist/list-header.js +1 -1
- package/dist/list-item.js +1 -1
- package/dist/list.d.ts +21 -2
- package/dist/list.js +2 -1
- package/dist/nav-stack.js +1 -1
- package/dist/pane.d.ts +17 -2
- package/dist/pane.js +1 -1
- package/dist/row.d.ts +19 -1
- package/dist/row.js +2 -1
- package/dist/segmented-control.js +1 -1
- package/dist/select.d.ts +13 -3
- package/dist/select.js +1 -1
- package/dist/skeleton.js +1 -1
- package/dist/spacer.js +1 -1
- package/dist/split-view.js +1 -1
- package/dist/state-banner.js +1 -1
- package/dist/styles/catalog/components/catalog-example-stack.css +4 -1
- package/dist/styles/catalog/components/catalog-example.css +145 -0
- package/dist/styles/collapsible-panel.css +132 -4
- package/dist/styles/document.css +23 -0
- package/dist/styles/foundation.css +21 -7
- package/dist/styles/grid.css +10 -0
- package/dist/styles/list-header.css +45 -0
- package/dist/styles/list-inset-control.css +8 -1
- package/dist/styles/list-item.css +6 -0
- package/dist/styles/list.css +11 -0
- package/dist/styles/nav-stack.css +89 -2
- package/dist/styles/pane.css +86 -1
- package/dist/styles/resizable-region.css +93 -5
- package/dist/styles/row.css +10 -0
- package/dist/styles/select.css +39 -4
- package/dist/styles/split-view.css +107 -1
- package/dist/styles/tab-scaffold.css +64 -1
- package/dist/styles/text.css +6 -0
- package/dist/styles/toolbar-control-group.css +90 -11
- package/dist/styles/toolbar-text.css +4 -1
- package/dist/styles/toolbar.css +130 -38
- package/dist/styles/webawesome.css +48 -2
- package/dist/styles/workbench.css +136 -4
- package/dist/text.d.ts +4 -3
- package/dist/text.js +1 -1
- package/dist/toolbar-text.js +1 -1
- package/dist/toolbar.d.ts +24 -3
- package/dist/toolbar.js +1 -1
- package/dist/{types-CzgSrFXP.d.ts → types-CEsieBZi.d.ts} +6 -1
- package/dist/value-table.js +1 -1
- package/dist/wire-resizable-regions.js +1 -1
- package/dist/wire-sidebar.d.ts +18 -3
- package/dist/wire-sidebar.js +95 -14
- package/dist/wire-sidebar.js.map +1 -1
- package/docs/accessibility.md +45 -8
- package/docs/app-layouts.md +73 -0
- package/docs/catalog.md +23 -2
- package/docs/collapsible-panel.md +81 -8
- package/docs/component-contract.md +28 -9
- package/docs/component-integration.md +9 -4
- package/docs/component-selection.md +25 -6
- package/docs/design/templates/list/stack-dark.svg +1 -1
- package/docs/design/templates/list/stack.svg +1 -1
- package/docs/design/templates/list-dark.svg +1 -1
- package/docs/design/templates/list-header/action-dark.svg +1 -1
- package/docs/design/templates/list-header/action.svg +1 -1
- package/docs/design/templates/list-header/count-dark.svg +1 -1
- package/docs/design/templates/list-header/count.svg +1 -1
- package/docs/design/templates/list-header/inline-action-dark.svg +1 -1
- package/docs/design/templates/list-header/inline-action.svg +1 -1
- package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -1
- package/docs/design/templates/list-header/toggle-expanded.svg +1 -1
- package/docs/design/templates/list-header-dark.svg +1 -1
- package/docs/design/templates/list-header.svg +1 -1
- package/docs/design/templates/list.svg +1 -1
- package/docs/design/templates/state-banner/info-badge-dark.svg +1 -1
- package/docs/design/templates/state-banner/info-badge.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/toolbar/title-and-actions-dark.svg +1 -1
- package/docs/design/templates/toolbar/title-and-actions.svg +1 -1
- package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -1
- package/docs/design/templates/toolbar-control-group/with-text.svg +1 -1
- package/docs/design/templates/toolbar-control-group-dark.svg +1 -1
- package/docs/design/templates/toolbar-control-group.svg +1 -1
- package/docs/design/templates/toolbar-dark.svg +1 -1
- package/docs/design/templates/toolbar-text/default-dark.svg +1 -1
- package/docs/design/templates/toolbar-text/default.svg +1 -1
- package/docs/design/templates/toolbar-text/large-dark.svg +1 -1
- package/docs/design/templates/toolbar-text/large.svg +1 -1
- package/docs/design/templates/toolbar-text/small-dark.svg +1 -1
- package/docs/design/templates/toolbar-text/small.svg +1 -1
- package/docs/design/templates/toolbar-text-dark.svg +1 -1
- package/docs/design/templates/toolbar-text.svg +1 -1
- package/docs/design/templates/toolbar.svg +1 -1
- package/docs/document-baseline.md +31 -0
- package/docs/layout.md +86 -21
- package/docs/nav-stack.md +8 -0
- package/docs/recipes.md +78 -43
- package/docs/split-view.md +8 -0
- package/docs/tab-scaffold.md +4 -2
- package/docs/type-contracts.md +21 -17
- package/docs/ui-analyzer.md +19 -0
- package/docs/ui-evaluator.md +17 -0
- package/docs/ux-demo.md +4 -4
- package/docs/webawesome-theme.md +20 -2
- package/docs/workbench.md +20 -1
- package/evaluator/index.mjs +73 -8
- package/llms.txt +32 -14
- package/package.json +4 -2
- package/ux-demo/recipes/app-shell.tsx +209 -178
- package/ux-demo/recipes/collapsible-sidebar.tsx +188 -159
- package/ux-demo/recipes/compact-toolbar.tsx +48 -35
- package/ux-demo/recipes/composer-form.tsx +85 -79
- package/ux-demo/recipes/list-detail-dialog.tsx +124 -142
- package/ux-demo/recipes/list-workspace-states.tsx +83 -83
- package/ux-demo/recipes/loaders.ts +5 -2
- package/ux-demo/recipes/loading-inspector.tsx +157 -160
- package/ux-demo/recipes/navigation-sidebar.tsx +111 -109
- package/ux-demo/recipes/navigation-stack.tsx +50 -49
- package/ux-demo/recipes/types.ts +14 -0
- package/ux-demo/recipes/workspace-header.tsx +73 -56
- package/dist/chunk-AQSKJ6U6.js.map +0 -1
- package/dist/chunk-ELRMBQEC.js.map +0 -1
- package/dist/chunk-J3EE6XWD.js +0 -115
- package/dist/chunk-J3EE6XWD.js.map +0 -1
- package/dist/chunk-KKNK3JUT.js.map +0 -1
- package/dist/chunk-OL4TC3U2.js.map +0 -1
- package/dist/chunk-OQI7RCRP.js.map +0 -1
- package/dist/chunk-UMGY5JSP.js.map +0 -1
- package/dist/chunk-V6RZWDII.js.map +0 -1
- package/dist/chunk-ZNZ2JDBW.js.map +0 -1
- package/ux-demo/recipes/app-shell.css +0 -87
- package/ux-demo/recipes/collapsible-sidebar.css +0 -83
- package/ux-demo/recipes/compact-toolbar.css +0 -35
- package/ux-demo/recipes/composer-form.css +0 -19
- package/ux-demo/recipes/list-detail-dialog.css +0 -42
- package/ux-demo/recipes/list-workspace-states.css +0 -30
- package/ux-demo/recipes/loading-inspector.css +0 -7
- package/ux-demo/recipes/navigation-sidebar.css +0 -12
- package/ux-demo/recipes/navigation-stack.css +0 -12
- package/ux-demo/recipes/recipe-root.css +0 -67
- package/ux-demo/recipes/recipe-root.tsx +0 -87
- package/ux-demo/recipes/workspace-header.css +0 -7
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import '@kerfjs/ui/layout.css';
|
|
2
|
-
import './app-shell.css';
|
|
3
2
|
|
|
3
|
+
import { deviceClass } from '@kerfjs/ui/device-class';
|
|
4
|
+
import { Grid } from '@kerfjs/ui/grid';
|
|
5
|
+
import { List } from '@kerfjs/ui/list';
|
|
4
6
|
import { ListHeader } from '@kerfjs/ui/list-header';
|
|
5
7
|
import { ListItem } from '@kerfjs/ui/list-item';
|
|
6
8
|
import { LucideIcon } from '@kerfjs/ui/lucide-icon';
|
|
7
|
-
import { Pane } from '@kerfjs/ui/pane';
|
|
9
|
+
import { Pane, type PaneSeparatorSide } from '@kerfjs/ui/pane';
|
|
8
10
|
import { ResizableRegion } from '@kerfjs/ui/resizable-region';
|
|
11
|
+
import { Row } from '@kerfjs/ui/row';
|
|
9
12
|
import { Toolbar } from '@kerfjs/ui/toolbar';
|
|
10
13
|
import { ToolbarControlGroup } from '@kerfjs/ui/toolbar-control-group';
|
|
11
14
|
import { ToolbarText } from '@kerfjs/ui/toolbar-text';
|
|
@@ -13,70 +16,203 @@ import { ValueTable, ValueTableRow } from '@kerfjs/ui/value-table';
|
|
|
13
16
|
import { signal } from 'kerfjs';
|
|
14
17
|
import { Bell, Folder, Inbox, Settings } from 'lucide';
|
|
15
18
|
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
import type { RecipeFactory, RecipePresentation } from './types.js';
|
|
20
|
+
|
|
21
|
+
type ShellPane = 'content' | 'navigation' | 'inspector';
|
|
22
|
+
type ScreenEdges = readonly PaneSeparatorSide[];
|
|
23
|
+
|
|
24
|
+
// Safe areas: the app bar claims the top edge and both sides, so it clears the
|
|
25
|
+
// status area. Each pane below compensates only for the screen edges it
|
|
26
|
+
// actually reaches: the bottom, plus its outer side in the three-pane layout or
|
|
27
|
+
// both sides when it is the only pane shown.
|
|
28
|
+
const appBarEdges: ScreenEdges = ['block-start', 'inline-start', 'inline-end'];
|
|
29
|
+
const soleEdges: ScreenEdges = ['block-end', 'inline-start', 'inline-end'];
|
|
30
|
+
|
|
31
|
+
const tasks = [
|
|
32
|
+
['Release accessibility audit', 'Interface systems · due this week'],
|
|
33
|
+
['Prepare tablet navigation', 'Interface systems · due this week'],
|
|
34
|
+
['Review stale-data states', 'Platform · due next week'],
|
|
35
|
+
['Confirm package boundaries', 'Platform · due next week'],
|
|
36
|
+
] as const;
|
|
37
|
+
|
|
38
|
+
export const presentation: RecipePresentation = {
|
|
39
|
+
viewport: {
|
|
40
|
+
width: 'full',
|
|
41
|
+
height: 'app',
|
|
42
|
+
frame: 'solid',
|
|
43
|
+
surface: 'default',
|
|
44
|
+
overflow: 'hidden',
|
|
45
|
+
shadow: true,
|
|
46
|
+
},
|
|
47
|
+
note: 'The recipe owns pane geometry and one scroll owner per pane. The app owns routing, data, pane visibility, sizes, and persistence.',
|
|
48
|
+
};
|
|
22
49
|
|
|
23
50
|
export const createRecipe: RecipeFactory = (announce) => {
|
|
24
51
|
const selected = signal('inbox');
|
|
25
52
|
const navigationSize = signal(224);
|
|
26
53
|
const inspectorSize = signal(240);
|
|
27
|
-
const responsivePane = signal<'content'
|
|
28
|
-
|
|
54
|
+
const responsivePane = signal<ShellPane>('content');
|
|
55
|
+
// Desktop-class viewports show all three panes; smaller ones show one pane
|
|
56
|
+
// at a time and let the toolbar switch between them.
|
|
57
|
+
const device = deviceClass();
|
|
58
|
+
|
|
59
|
+
const paneButton = (
|
|
60
|
+
pane: ShellPane,
|
|
61
|
+
label: string,
|
|
62
|
+
icon: typeof Folder,
|
|
63
|
+
iconName: string,
|
|
64
|
+
) => (
|
|
65
|
+
<button
|
|
66
|
+
type="button"
|
|
67
|
+
aria-label={label}
|
|
68
|
+
aria-controls={`recipe-shell-${pane}`}
|
|
69
|
+
aria-pressed={String(responsivePane.value === pane)}
|
|
70
|
+
data-action="recipe-action"
|
|
71
|
+
data-recipe-command={`show-${pane}`}
|
|
72
|
+
>
|
|
73
|
+
<LucideIcon icon={icon} name={iconName} />
|
|
74
|
+
</button>
|
|
29
75
|
);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
76
|
+
|
|
77
|
+
const navigation = (edges: ScreenEdges) => (
|
|
78
|
+
<Pane
|
|
79
|
+
element="aside"
|
|
80
|
+
safeAreaEdges={edges}
|
|
81
|
+
id="recipe-shell-navigation"
|
|
82
|
+
contentElement="nav"
|
|
83
|
+
contentLabel="Workspace"
|
|
34
84
|
>
|
|
35
|
-
<
|
|
36
|
-
|
|
37
|
-
|
|
85
|
+
<section>
|
|
86
|
+
<ListHeader label="Workspace" />
|
|
87
|
+
<ListItem
|
|
88
|
+
action="recipe-action"
|
|
89
|
+
itemId="inbox"
|
|
90
|
+
label="Inbox"
|
|
91
|
+
icon={<LucideIcon icon={Inbox} name="inbox" />}
|
|
92
|
+
selected={selected.value === 'inbox'}
|
|
93
|
+
/>
|
|
94
|
+
<ListItem
|
|
95
|
+
action="recipe-action"
|
|
96
|
+
itemId="projects"
|
|
97
|
+
label="Projects with a deliberately wrapping title"
|
|
98
|
+
icon={<LucideIcon icon={Folder} name="folder" />}
|
|
99
|
+
selected={selected.value === 'projects'}
|
|
100
|
+
multiline
|
|
101
|
+
/>
|
|
102
|
+
</section>
|
|
103
|
+
</Pane>
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const content = (edges: ScreenEdges) => (
|
|
107
|
+
<Pane
|
|
108
|
+
element="main"
|
|
109
|
+
safeAreaEdges={edges}
|
|
110
|
+
id="recipe-shell-content"
|
|
111
|
+
header={
|
|
112
|
+
<Toolbar
|
|
113
|
+
label="Current workspace view"
|
|
114
|
+
dividerSides=""
|
|
115
|
+
leading={
|
|
116
|
+
<ToolbarText
|
|
117
|
+
text={
|
|
118
|
+
selected.value === 'inbox' ? 'Inbox triage' : 'Active projects'
|
|
119
|
+
}
|
|
120
|
+
size="xlarge"
|
|
121
|
+
id="recipe-shell-main-title"
|
|
122
|
+
/>
|
|
123
|
+
}
|
|
124
|
+
trailing={
|
|
125
|
+
<ToolbarControlGroup appearance="borderless" content="text" single>
|
|
126
|
+
<button
|
|
127
|
+
type="button"
|
|
128
|
+
data-action="recipe-action"
|
|
129
|
+
data-recipe-command="new"
|
|
130
|
+
>
|
|
131
|
+
New task
|
|
132
|
+
</button>
|
|
133
|
+
</ToolbarControlGroup>
|
|
134
|
+
}
|
|
135
|
+
/>
|
|
136
|
+
}
|
|
137
|
+
>
|
|
138
|
+
<section aria-label="Tasks">
|
|
139
|
+
{tasks.map(([title, detail]) => (
|
|
140
|
+
<ListItem
|
|
141
|
+
action="recipe-action"
|
|
142
|
+
label={title}
|
|
143
|
+
description={detail}
|
|
144
|
+
multiline
|
|
145
|
+
rootAttributes={{ 'data-recipe-command': 'open-task' }}
|
|
146
|
+
/>
|
|
147
|
+
))}
|
|
148
|
+
</section>
|
|
149
|
+
</Pane>
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const inspector = (edges: ScreenEdges) => (
|
|
153
|
+
<Pane
|
|
154
|
+
element="aside"
|
|
155
|
+
safeAreaEdges={edges}
|
|
156
|
+
id="recipe-shell-inspector"
|
|
157
|
+
header={
|
|
158
|
+
<Toolbar
|
|
159
|
+
label="Inspector"
|
|
160
|
+
dividerSides=""
|
|
161
|
+
leading={
|
|
162
|
+
<ToolbarText
|
|
163
|
+
text="Inspector"
|
|
164
|
+
size="xlarge"
|
|
165
|
+
id="recipe-shell-inspector-title"
|
|
166
|
+
/>
|
|
167
|
+
}
|
|
168
|
+
/>
|
|
169
|
+
}
|
|
170
|
+
>
|
|
171
|
+
<ValueTable label="Selected task">
|
|
172
|
+
<ValueTableRow label="Status" value="In review" />
|
|
173
|
+
<ValueTableRow label="Owner" value="Mara Chen" />
|
|
174
|
+
<ValueTableRow label="Priority" value="High" />
|
|
175
|
+
</ValueTable>
|
|
176
|
+
</Pane>
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
const render = () => {
|
|
180
|
+
const onePane = !device.value.atLeast('desktop');
|
|
181
|
+
return (
|
|
182
|
+
<List
|
|
183
|
+
fill
|
|
184
|
+
rootAttributes={{
|
|
185
|
+
'data-recipe': 'recipe-app-shell',
|
|
186
|
+
'data-responsive-pane': onePane ? responsivePane.value : 'all',
|
|
187
|
+
}}
|
|
38
188
|
>
|
|
39
189
|
<Toolbar
|
|
40
190
|
label="Atlas workspace"
|
|
191
|
+
safeAreaEdges={appBarEdges}
|
|
41
192
|
leading={<ToolbarText text="Atlas" />}
|
|
42
193
|
trailing={
|
|
43
194
|
<>
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
<button
|
|
50
|
-
type="button"
|
|
51
|
-
aria-label="Show navigation"
|
|
52
|
-
aria-controls="recipe-shell-navigation"
|
|
53
|
-
aria-pressed={String(responsivePane.value === 'navigation')}
|
|
54
|
-
data-action="recipe-action"
|
|
55
|
-
data-recipe-command="show-navigation"
|
|
56
|
-
>
|
|
57
|
-
<LucideIcon icon={Folder} name="folder" />
|
|
58
|
-
</button>
|
|
59
|
-
<button
|
|
60
|
-
type="button"
|
|
61
|
-
aria-label="Show content"
|
|
62
|
-
aria-controls="recipe-shell-content"
|
|
63
|
-
aria-pressed={String(responsivePane.value === 'content')}
|
|
64
|
-
data-action="recipe-action"
|
|
65
|
-
data-recipe-command="show-content"
|
|
66
|
-
>
|
|
67
|
-
<LucideIcon icon={Inbox} name="inbox" />
|
|
68
|
-
</button>
|
|
69
|
-
<button
|
|
70
|
-
type="button"
|
|
71
|
-
aria-label="Show inspector"
|
|
72
|
-
aria-controls="recipe-shell-inspector"
|
|
73
|
-
aria-pressed={String(responsivePane.value === 'inspector')}
|
|
74
|
-
data-action="recipe-action"
|
|
75
|
-
data-recipe-command="show-inspector"
|
|
195
|
+
{onePane ? (
|
|
196
|
+
<ToolbarControlGroup
|
|
197
|
+
appearance="borderless"
|
|
198
|
+
buttonAppearance="push"
|
|
199
|
+
label="Workspace panes"
|
|
76
200
|
>
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
201
|
+
{paneButton(
|
|
202
|
+
'navigation',
|
|
203
|
+
'Show navigation',
|
|
204
|
+
Folder,
|
|
205
|
+
'folder',
|
|
206
|
+
)}
|
|
207
|
+
{paneButton('content', 'Show content', Inbox, 'inbox')}
|
|
208
|
+
{paneButton(
|
|
209
|
+
'inspector',
|
|
210
|
+
'Show inspector',
|
|
211
|
+
Settings,
|
|
212
|
+
'settings',
|
|
213
|
+
)}
|
|
214
|
+
</ToolbarControlGroup>
|
|
215
|
+
) : null}
|
|
80
216
|
<ToolbarControlGroup
|
|
81
217
|
appearance="borderless"
|
|
82
218
|
label="Workspace controls"
|
|
@@ -101,108 +237,28 @@ export const createRecipe: RecipeFactory = (announce) => {
|
|
|
101
237
|
</>
|
|
102
238
|
}
|
|
103
239
|
/>
|
|
104
|
-
|
|
105
|
-
<
|
|
240
|
+
{onePane ? (
|
|
241
|
+
<Grid columns={1} gap="none" flex>
|
|
242
|
+
{responsivePane.value === 'navigation'
|
|
243
|
+
? navigation(soleEdges)
|
|
244
|
+
: responsivePane.value === 'inspector'
|
|
245
|
+
? inspector(soleEdges)
|
|
246
|
+
: content(soleEdges)}
|
|
247
|
+
</Grid>
|
|
248
|
+
) : (
|
|
249
|
+
<Row gap="none" flex>
|
|
106
250
|
<ResizableRegion
|
|
107
251
|
id="recipe-navigation"
|
|
108
252
|
label="Navigation"
|
|
109
253
|
size={navigationSize.value}
|
|
110
254
|
min={180}
|
|
111
255
|
max={320}
|
|
112
|
-
responsiveFillAt="compact"
|
|
113
256
|
>
|
|
114
|
-
|
|
115
|
-
<Pane
|
|
116
|
-
element="aside"
|
|
117
|
-
contentElement="nav"
|
|
118
|
-
contentClassName="recipe-shell__nav-list"
|
|
119
|
-
contentLabel="Workspace"
|
|
120
|
-
>
|
|
121
|
-
<ListHeader label="Workspace" />
|
|
122
|
-
<section>
|
|
123
|
-
<ListItem
|
|
124
|
-
action="recipe-action"
|
|
125
|
-
itemId="inbox"
|
|
126
|
-
label="Inbox"
|
|
127
|
-
icon={<LucideIcon icon={Inbox} name="inbox" />}
|
|
128
|
-
selected={selected.value === 'inbox'}
|
|
129
|
-
/>
|
|
130
|
-
<ListItem
|
|
131
|
-
action="recipe-action"
|
|
132
|
-
itemId="projects"
|
|
133
|
-
label="Projects with a deliberately wrapping title"
|
|
134
|
-
icon={<LucideIcon icon={Folder} name="folder" />}
|
|
135
|
-
selected={selected.value === 'projects'}
|
|
136
|
-
multiline
|
|
137
|
-
/>
|
|
138
|
-
</section>
|
|
139
|
-
</Pane>
|
|
140
|
-
</div>
|
|
257
|
+
{navigation(['block-end', 'inline-start'])}
|
|
141
258
|
</ResizableRegion>
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
element="main"
|
|
146
|
-
id="recipe-shell-content"
|
|
147
|
-
contentClassName="recipe-shell__main-body"
|
|
148
|
-
header={
|
|
149
|
-
<Toolbar
|
|
150
|
-
label="Current workspace view"
|
|
151
|
-
dividerSides=""
|
|
152
|
-
leading={
|
|
153
|
-
<ToolbarText
|
|
154
|
-
text={
|
|
155
|
-
selected.value === 'inbox'
|
|
156
|
-
? 'Inbox triage'
|
|
157
|
-
: 'Active projects'
|
|
158
|
-
}
|
|
159
|
-
size="xlarge"
|
|
160
|
-
id="recipe-shell-main-title"
|
|
161
|
-
/>
|
|
162
|
-
}
|
|
163
|
-
trailing={
|
|
164
|
-
<ToolbarControlGroup
|
|
165
|
-
appearance="borderless"
|
|
166
|
-
content="text"
|
|
167
|
-
single
|
|
168
|
-
>
|
|
169
|
-
<button
|
|
170
|
-
type="button"
|
|
171
|
-
data-action="recipe-action"
|
|
172
|
-
data-recipe-command="new"
|
|
173
|
-
>
|
|
174
|
-
New task
|
|
175
|
-
</button>
|
|
176
|
-
</ToolbarControlGroup>
|
|
177
|
-
}
|
|
178
|
-
/>
|
|
179
|
-
}
|
|
180
|
-
>
|
|
181
|
-
<RecipeOwnershipNote>
|
|
182
|
-
Recipe owns pane geometry and one scroll owner per pane. The app
|
|
183
|
-
owns routing, data, pane visibility, sizes, and persistence.
|
|
184
|
-
</RecipeOwnershipNote>
|
|
185
|
-
<div class="recipe-shell__cards">
|
|
186
|
-
{[
|
|
187
|
-
'Release accessibility audit',
|
|
188
|
-
'Prepare tablet navigation',
|
|
189
|
-
'Review stale-data states',
|
|
190
|
-
'Confirm package boundaries',
|
|
191
|
-
].map((title) => (
|
|
192
|
-
<article class="recipe-shell__card kui-content-item">
|
|
193
|
-
<strong>{title}</strong>
|
|
194
|
-
<RecipeMutedText>
|
|
195
|
-
Assigned to the interface systems team · due this week
|
|
196
|
-
</RecipeMutedText>
|
|
197
|
-
</article>
|
|
198
|
-
))}
|
|
199
|
-
</div>
|
|
200
|
-
</Pane>
|
|
201
|
-
</div>
|
|
202
|
-
<div
|
|
203
|
-
id="recipe-shell-inspector"
|
|
204
|
-
class="recipe-shell__inspector-region"
|
|
205
|
-
>
|
|
259
|
+
<Grid columns={1} gap="none" flex>
|
|
260
|
+
{content(['block-end'])}
|
|
261
|
+
</Grid>
|
|
206
262
|
<ResizableRegion
|
|
207
263
|
id="recipe-inspector"
|
|
208
264
|
label="Inspector"
|
|
@@ -210,45 +266,20 @@ export const createRecipe: RecipeFactory = (announce) => {
|
|
|
210
266
|
min={200}
|
|
211
267
|
max={360}
|
|
212
268
|
edge="start"
|
|
213
|
-
responsiveFillAt="narrow"
|
|
214
269
|
>
|
|
215
|
-
|
|
216
|
-
<Pane
|
|
217
|
-
element="aside"
|
|
218
|
-
contentClassName="recipe-shell__inspector-body"
|
|
219
|
-
header={
|
|
220
|
-
<Toolbar
|
|
221
|
-
label="Inspector"
|
|
222
|
-
dividerSides=""
|
|
223
|
-
leading={
|
|
224
|
-
<ToolbarText
|
|
225
|
-
text="Inspector"
|
|
226
|
-
size="xlarge"
|
|
227
|
-
id="recipe-shell-inspector-title"
|
|
228
|
-
/>
|
|
229
|
-
}
|
|
230
|
-
/>
|
|
231
|
-
}
|
|
232
|
-
>
|
|
233
|
-
<ValueTable label="Selected task">
|
|
234
|
-
<ValueTableRow label="Status" value="In review" />
|
|
235
|
-
<ValueTableRow label="Owner" value="Mara Chen" />
|
|
236
|
-
<ValueTableRow label="Priority" value="High" />
|
|
237
|
-
</ValueTable>
|
|
238
|
-
</Pane>
|
|
239
|
-
</div>
|
|
270
|
+
{inspector(['block-end', 'inline-end'])}
|
|
240
271
|
</ResizableRegion>
|
|
241
|
-
</
|
|
242
|
-
|
|
243
|
-
</
|
|
244
|
-
|
|
245
|
-
|
|
272
|
+
</Row>
|
|
273
|
+
)}
|
|
274
|
+
</List>
|
|
275
|
+
);
|
|
276
|
+
};
|
|
246
277
|
return {
|
|
247
278
|
render,
|
|
248
279
|
action(command, element) {
|
|
249
280
|
const pane = command.match(
|
|
250
281
|
/^show-(navigation|content|inspector)$/,
|
|
251
|
-
)?.[1] as
|
|
282
|
+
)?.[1] as ShellPane | undefined;
|
|
252
283
|
if (pane) responsivePane.value = pane;
|
|
253
284
|
const id = element.dataset.itemId;
|
|
254
285
|
if (id) selected.value = id;
|