@echothink-ui/layout 0.2.0
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 +92 -0
- package/dist/index.cjs +1620 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +149 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +1546 -0
- package/dist/index.js.map +1 -0
- package/dist/layout-system/builders.d.ts +13 -0
- package/dist/layout-system/index.d.ts +24 -0
- package/dist/layout-system/inference/context.d.ts +33 -0
- package/dist/layout-system/inference/responsive.d.ts +21 -0
- package/dist/layout-system/inference/style.d.ts +15 -0
- package/dist/layout-system/page-layouts/index.d.ts +8 -0
- package/dist/layout-system/primitives/index.d.ts +6 -0
- package/dist/layout-system/regions/index.d.ts +4 -0
- package/dist/layout-system/registry/builtins.d.ts +8 -0
- package/dist/layout-system/registry/registry.d.ts +20 -0
- package/dist/layout-system/renderer/context.d.ts +41 -0
- package/dist/layout-system/renderer/region.d.ts +10 -0
- package/dist/layout-system/renderer/renderer.d.ts +13 -0
- package/dist/layout-system/renderer/root.d.ts +24 -0
- package/dist/layout-system/runtime/state.d.ts +17 -0
- package/dist/layout-system/runtime/viewport.d.ts +9 -0
- package/dist/layout-system/schema/types.d.ts +488 -0
- package/dist/layout-system/schema/validate.d.ts +15 -0
- package/dist/layout-system/tokens/preset-tokens.d.ts +11 -0
- package/package.json +47 -0
- package/src/index.tsx +42 -0
- package/src/layout-system/__tests__/layout-system.test.tsx +169 -0
- package/src/layout-system/builders.ts +46 -0
- package/src/layout-system/index.ts +87 -0
- package/src/layout-system/inference/context.ts +158 -0
- package/src/layout-system/inference/responsive.ts +147 -0
- package/src/layout-system/inference/style.ts +128 -0
- package/src/layout-system/page-layouts/index.tsx +405 -0
- package/src/layout-system/primitives/index.tsx +266 -0
- package/src/layout-system/regions/index.tsx +90 -0
- package/src/layout-system/registry/builtins.ts +19 -0
- package/src/layout-system/registry/registry.ts +47 -0
- package/src/layout-system/renderer/context.tsx +89 -0
- package/src/layout-system/renderer/region.tsx +34 -0
- package/src/layout-system/renderer/renderer.tsx +200 -0
- package/src/layout-system/renderer/root.tsx +95 -0
- package/src/layout-system/runtime/state.ts +80 -0
- package/src/layout-system/runtime/viewport.ts +71 -0
- package/src/layout-system/schema/types.ts +706 -0
- package/src/layout-system/schema/validate.ts +168 -0
- package/src/layout-system/tokens/preset-tokens.ts +77 -0
- package/src/styles.css +178 -0
|
@@ -0,0 +1,706 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed Layout AST — the type system from `layout-spec.md` §4–§6, §9, §10, §16.
|
|
3
|
+
*
|
|
4
|
+
* A layout is a TYPED STRUCTURE, not a CSS fragment. These types describe the
|
|
5
|
+
* logical layout tree (the AST); the physical plan (placement/visibility per
|
|
6
|
+
* viewport) is derived separately by the responsive resolver. Component style
|
|
7
|
+
* params are INFERRED from the runtime context, never hard-coded by components.
|
|
8
|
+
*/
|
|
9
|
+
import type {
|
|
10
|
+
EthDensityMode,
|
|
11
|
+
EthPalette,
|
|
12
|
+
EthStylePreset,
|
|
13
|
+
EthTypeScale,
|
|
14
|
+
} from "@echothink-ui/style";
|
|
15
|
+
|
|
16
|
+
/* ------------------------------------------------------------------ *
|
|
17
|
+
* 4.1 Base enums
|
|
18
|
+
* ------------------------------------------------------------------ */
|
|
19
|
+
|
|
20
|
+
export type LayoutTier = "primitive" | "region" | "page" | "workspace" | "route";
|
|
21
|
+
|
|
22
|
+
export type NodeKind = "layout" | "component" | "template" | "fragment" | "empty";
|
|
23
|
+
|
|
24
|
+
export type CompositionKind =
|
|
25
|
+
| "parallel"
|
|
26
|
+
| "stack"
|
|
27
|
+
| "embed"
|
|
28
|
+
| "overlay"
|
|
29
|
+
| "switch"
|
|
30
|
+
| "stepper"
|
|
31
|
+
| "portal"
|
|
32
|
+
| "conditional"
|
|
33
|
+
| "responsive";
|
|
34
|
+
|
|
35
|
+
export type Axis = "x" | "y" | "z";
|
|
36
|
+
|
|
37
|
+
export type SurfaceRole =
|
|
38
|
+
| "app"
|
|
39
|
+
| "page"
|
|
40
|
+
| "workspace"
|
|
41
|
+
| "region"
|
|
42
|
+
| "panel"
|
|
43
|
+
| "card"
|
|
44
|
+
| "sheet"
|
|
45
|
+
| "drawer"
|
|
46
|
+
| "modal"
|
|
47
|
+
| "popover"
|
|
48
|
+
| "floating"
|
|
49
|
+
| "console"
|
|
50
|
+
| "canvas";
|
|
51
|
+
|
|
52
|
+
export type SlotRole =
|
|
53
|
+
| "navigation"
|
|
54
|
+
| "primary"
|
|
55
|
+
| "secondary"
|
|
56
|
+
| "inspector"
|
|
57
|
+
| "toolbar"
|
|
58
|
+
| "filter"
|
|
59
|
+
| "search"
|
|
60
|
+
| "content"
|
|
61
|
+
| "canvas"
|
|
62
|
+
| "console"
|
|
63
|
+
| "timeline"
|
|
64
|
+
| "stepper"
|
|
65
|
+
| "form"
|
|
66
|
+
| "preview"
|
|
67
|
+
| "summary"
|
|
68
|
+
| "drawer"
|
|
69
|
+
| "modal"
|
|
70
|
+
| "overlay"
|
|
71
|
+
| "footer"
|
|
72
|
+
| "status"
|
|
73
|
+
| "emptyState";
|
|
74
|
+
|
|
75
|
+
/* ------------------------------------------------------------------ *
|
|
76
|
+
* 4.2 Component style params (the layout system's final output protocol).
|
|
77
|
+
* Re-uses the real `@echothink-ui/style` axes verbatim.
|
|
78
|
+
* ------------------------------------------------------------------ */
|
|
79
|
+
|
|
80
|
+
export type ComponentStylePreset = EthStylePreset;
|
|
81
|
+
export type ComponentPalette = EthPalette;
|
|
82
|
+
export type ComponentDensity = EthDensityMode;
|
|
83
|
+
export type ComponentTypeScale = EthTypeScale;
|
|
84
|
+
|
|
85
|
+
export interface ComponentStyleParams {
|
|
86
|
+
preset: ComponentStylePreset;
|
|
87
|
+
palette: ComponentPalette;
|
|
88
|
+
density: ComponentDensity;
|
|
89
|
+
typeScale: ComponentTypeScale;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* ------------------------------------------------------------------ *
|
|
93
|
+
* Layout style intent + task semantics
|
|
94
|
+
* ------------------------------------------------------------------ */
|
|
95
|
+
|
|
96
|
+
export type LayoutTaskMode =
|
|
97
|
+
| "navigation"
|
|
98
|
+
| "crud"
|
|
99
|
+
| "analytics"
|
|
100
|
+
| "monitoring"
|
|
101
|
+
| "authoring"
|
|
102
|
+
| "review"
|
|
103
|
+
| "wizard"
|
|
104
|
+
| "playground"
|
|
105
|
+
| "copilot"
|
|
106
|
+
| "spatial";
|
|
107
|
+
|
|
108
|
+
export type DataIntensity = "low" | "medium" | "high" | "realtime";
|
|
109
|
+
export type InteractionMode = "read" | "edit" | "operate" | "debug" | "review";
|
|
110
|
+
export type VisualEmphasis = "quiet" | "balanced" | "expressive" | "immersive";
|
|
111
|
+
|
|
112
|
+
export interface LayoutStyleIntent {
|
|
113
|
+
preset?: ComponentStylePreset;
|
|
114
|
+
density?: ComponentDensity;
|
|
115
|
+
typeScale?: ComponentTypeScale;
|
|
116
|
+
surface?: SurfaceRole;
|
|
117
|
+
taskMode?: LayoutTaskMode;
|
|
118
|
+
dataIntensity?: DataIntensity;
|
|
119
|
+
interactionMode?: InteractionMode;
|
|
120
|
+
visualEmphasis?: VisualEmphasis;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* ------------------------------------------------------------------ *
|
|
124
|
+
* 4.3 LayoutNode
|
|
125
|
+
* ------------------------------------------------------------------ */
|
|
126
|
+
|
|
127
|
+
export interface LayoutNode {
|
|
128
|
+
kind: "layout";
|
|
129
|
+
id: string;
|
|
130
|
+
type: string;
|
|
131
|
+
tier?: LayoutTier;
|
|
132
|
+
variant?: string;
|
|
133
|
+
|
|
134
|
+
slots: Record<string, SlotContent>;
|
|
135
|
+
props?: Record<string, unknown>;
|
|
136
|
+
|
|
137
|
+
composition?: CompositionSpec;
|
|
138
|
+
constraints?: LayoutConstraints;
|
|
139
|
+
responsive?: ResponsiveRule[];
|
|
140
|
+
state?: LayoutStateSpec;
|
|
141
|
+
permissions?: PermissionSpec;
|
|
142
|
+
|
|
143
|
+
/** Explicit style intent; NOT the final `ComponentStyleParams`. */
|
|
144
|
+
styleIntent?: Partial<LayoutStyleIntent>;
|
|
145
|
+
/** Context-propagation policy toward children. */
|
|
146
|
+
contextPolicy?: Partial<ContextPolicy>;
|
|
147
|
+
/** Debug / observability / AI-generation explanation. */
|
|
148
|
+
meta?: LayoutNodeMeta;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface LayoutNodeMeta {
|
|
152
|
+
label?: string;
|
|
153
|
+
description?: string;
|
|
154
|
+
generatedBy?: "human" | "ai" | "template";
|
|
155
|
+
notes?: string;
|
|
156
|
+
[key: string]: unknown;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export interface LayoutConstraints {
|
|
160
|
+
minWidth?: number | string;
|
|
161
|
+
maxWidth?: number | string;
|
|
162
|
+
minHeight?: number | string;
|
|
163
|
+
maxHeight?: number | string;
|
|
164
|
+
maxDepth?: number;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export interface LayoutStateSpec {
|
|
168
|
+
scope?: LayoutStateScope;
|
|
169
|
+
key?: string;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface PermissionSpec {
|
|
173
|
+
require?: string[];
|
|
174
|
+
anyOf?: string[];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* ------------------------------------------------------------------ *
|
|
178
|
+
* 4.4 SlotDefinition
|
|
179
|
+
* ------------------------------------------------------------------ */
|
|
180
|
+
|
|
181
|
+
export interface SlotDefinition {
|
|
182
|
+
name: string;
|
|
183
|
+
role: SlotRole;
|
|
184
|
+
|
|
185
|
+
accepts: NodeAcceptSpec[];
|
|
186
|
+
cardinality?: { min?: number; max?: number | "unbounded" };
|
|
187
|
+
|
|
188
|
+
required?: boolean;
|
|
189
|
+
multiple?: boolean;
|
|
190
|
+
|
|
191
|
+
constraints?: SlotConstraints;
|
|
192
|
+
priority?: SlotPriority;
|
|
193
|
+
responsive?: SlotResponsivePolicy;
|
|
194
|
+
|
|
195
|
+
/** How this slot transforms the child component style context. */
|
|
196
|
+
contextTransform?: SlotContextTransform;
|
|
197
|
+
/** Empty/loading/error fallback. */
|
|
198
|
+
fallback?: SlotFallbackSpec;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
export type NodeAcceptSpec =
|
|
202
|
+
| { kind: "component"; componentTypes?: string[]; componentTags?: string[] }
|
|
203
|
+
| {
|
|
204
|
+
kind: "layout";
|
|
205
|
+
layoutTypes?: string[];
|
|
206
|
+
tiers?: LayoutTier[];
|
|
207
|
+
surfaces?: SurfaceRole[];
|
|
208
|
+
}
|
|
209
|
+
| { kind: "template"; templateTypes?: string[] }
|
|
210
|
+
| { kind: "fragment" }
|
|
211
|
+
| { kind: "empty" };
|
|
212
|
+
|
|
213
|
+
export interface SlotConstraints {
|
|
214
|
+
minWidth?: number | string;
|
|
215
|
+
maxWidth?: number | string;
|
|
216
|
+
minHeight?: number | string;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export interface SlotContextTransform {
|
|
220
|
+
surface?: SurfaceRole;
|
|
221
|
+
styleIntent?: Partial<LayoutStyleIntent>;
|
|
222
|
+
densityHint?: ComponentDensity;
|
|
223
|
+
typeScaleHint?: ComponentTypeScale;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export interface SlotFallbackSpec {
|
|
227
|
+
empty?: SlotContent;
|
|
228
|
+
loading?: SlotContent;
|
|
229
|
+
error?: SlotContent;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export interface SlotPriority {
|
|
233
|
+
value: number;
|
|
234
|
+
behaviorOnNarrow:
|
|
235
|
+
| "keep"
|
|
236
|
+
| "collapse"
|
|
237
|
+
| "move-to-drawer"
|
|
238
|
+
| "move-to-bottom-sheet"
|
|
239
|
+
| "hide"
|
|
240
|
+
| "route-stack"
|
|
241
|
+
| "tabs";
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export interface SlotResponsivePolicy {
|
|
245
|
+
collapseBelow?: Breakpoint;
|
|
246
|
+
hideBelow?: Breakpoint;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/* ------------------------------------------------------------------ *
|
|
250
|
+
* 4.5 SlotContent
|
|
251
|
+
* ------------------------------------------------------------------ */
|
|
252
|
+
|
|
253
|
+
export type SlotContent =
|
|
254
|
+
| ComponentSlotContent
|
|
255
|
+
| LayoutSlotContent
|
|
256
|
+
| TemplateSlotContent
|
|
257
|
+
| FragmentSlotContent
|
|
258
|
+
| EmptySlotContent;
|
|
259
|
+
|
|
260
|
+
export interface ComponentSlotContent {
|
|
261
|
+
kind: "component";
|
|
262
|
+
component: string;
|
|
263
|
+
props?: Record<string, unknown>;
|
|
264
|
+
/** Discouraged long-term; special cases only. */
|
|
265
|
+
styleOverride?: Partial<ComponentStyleParams>;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export interface LayoutSlotContent {
|
|
269
|
+
kind: "layout";
|
|
270
|
+
layout: LayoutNode;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export interface TemplateSlotContent {
|
|
274
|
+
kind: "template";
|
|
275
|
+
template: string;
|
|
276
|
+
props?: Record<string, unknown>;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export interface FragmentSlotContent {
|
|
280
|
+
kind: "fragment";
|
|
281
|
+
items: SlotContent[];
|
|
282
|
+
composition?: CompositionSpec;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export interface EmptySlotContent {
|
|
286
|
+
kind: "empty";
|
|
287
|
+
reason?: "not-configured" | "no-data" | "permission-denied" | "loading" | "error";
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/* ------------------------------------------------------------------ *
|
|
291
|
+
* 5. Container composition algebra
|
|
292
|
+
* ------------------------------------------------------------------ */
|
|
293
|
+
|
|
294
|
+
export type CompositionSpec =
|
|
295
|
+
| ParallelComposition
|
|
296
|
+
| StackComposition
|
|
297
|
+
| EmbedComposition
|
|
298
|
+
| OverlayComposition
|
|
299
|
+
| SwitchComposition
|
|
300
|
+
| StepperComposition
|
|
301
|
+
| PortalComposition
|
|
302
|
+
| ConditionalComposition
|
|
303
|
+
| ResponsiveComposition;
|
|
304
|
+
|
|
305
|
+
export interface ParallelSizing {
|
|
306
|
+
basis?: number | string;
|
|
307
|
+
min?: number | string;
|
|
308
|
+
max?: number | string;
|
|
309
|
+
grow?: number;
|
|
310
|
+
shrink?: number;
|
|
311
|
+
resizable?: boolean;
|
|
312
|
+
collapsible?: boolean;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
export interface ParallelComposition {
|
|
316
|
+
op: "parallel";
|
|
317
|
+
axis: "x" | "y";
|
|
318
|
+
slots: string[];
|
|
319
|
+
sizing?: Record<string, ParallelSizing>;
|
|
320
|
+
gapToken?: string;
|
|
321
|
+
align?: "start" | "center" | "end" | "stretch";
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export interface StackComposition {
|
|
325
|
+
op: "stack";
|
|
326
|
+
direction: "vertical" | "horizontal";
|
|
327
|
+
slots: string[];
|
|
328
|
+
gapToken?: string;
|
|
329
|
+
divider?: boolean;
|
|
330
|
+
sticky?: Partial<Record<string, "start" | "end">>;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export interface EmbedComposition {
|
|
334
|
+
op: "embed";
|
|
335
|
+
host: { layoutId: string; slot: string };
|
|
336
|
+
child: { nodeId: string };
|
|
337
|
+
adapter?: EmbedAdapter;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
export interface EmbedAdapter {
|
|
341
|
+
surfaceDemotion?: { from: SurfaceRole; to: SurfaceRole };
|
|
342
|
+
inheritContext?: boolean;
|
|
343
|
+
isolateScroll?: boolean;
|
|
344
|
+
isolateState?: boolean;
|
|
345
|
+
densityAdjustment?: "inherit" | "compact-one-step" | "comfortable-one-step";
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export interface OverlayComposition {
|
|
349
|
+
op: "overlay";
|
|
350
|
+
baseSlot: string;
|
|
351
|
+
overlays: Array<{
|
|
352
|
+
slot: string;
|
|
353
|
+
layer: "floating" | "popover" | "drawer" | "modal" | "toast";
|
|
354
|
+
anchor?: string;
|
|
355
|
+
placement?: "top" | "right" | "bottom" | "left" | "center";
|
|
356
|
+
dismissible?: boolean;
|
|
357
|
+
modal?: boolean;
|
|
358
|
+
}>;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export interface SwitchComposition {
|
|
362
|
+
op: "switch";
|
|
363
|
+
mode: "tabs" | "segmented" | "route-stack" | "accordion";
|
|
364
|
+
activeKey?: string;
|
|
365
|
+
items: Array<{
|
|
366
|
+
key: string;
|
|
367
|
+
label: string;
|
|
368
|
+
content: SlotContent;
|
|
369
|
+
lazy?: boolean;
|
|
370
|
+
keepMounted?: boolean;
|
|
371
|
+
}>;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
export interface StepperComposition {
|
|
375
|
+
op: "stepper";
|
|
376
|
+
orientation: "horizontal" | "vertical";
|
|
377
|
+
stepSlot: string;
|
|
378
|
+
contentSlot: string;
|
|
379
|
+
steps: Array<{
|
|
380
|
+
id: string;
|
|
381
|
+
label: string;
|
|
382
|
+
optional?: boolean;
|
|
383
|
+
status?: "pending" | "active" | "valid" | "invalid" | "complete";
|
|
384
|
+
content: SlotContent;
|
|
385
|
+
validation?: string;
|
|
386
|
+
}>;
|
|
387
|
+
navigation?: {
|
|
388
|
+
allowSkip?: boolean;
|
|
389
|
+
allowBack?: boolean;
|
|
390
|
+
requireValidBeforeNext?: boolean;
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export interface PortalComposition {
|
|
395
|
+
op: "portal";
|
|
396
|
+
slot: string;
|
|
397
|
+
target?: string;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
export interface ConditionalComposition {
|
|
401
|
+
op: "conditional";
|
|
402
|
+
branches: Array<{ when: ConditionExpr; content: SlotContent }>;
|
|
403
|
+
fallback?: SlotContent;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export type ConditionExpr =
|
|
407
|
+
| { kind: "permission"; require: string[] }
|
|
408
|
+
| { kind: "featureFlag"; flag: string }
|
|
409
|
+
| { kind: "dataState"; state: "loading" | "error" | "empty" | "ready" }
|
|
410
|
+
| { kind: "viewport"; atLeast?: Breakpoint; atMost?: Breakpoint };
|
|
411
|
+
|
|
412
|
+
export interface ResponsiveComposition {
|
|
413
|
+
op: "responsive";
|
|
414
|
+
rules: ResponsiveRule[];
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
export interface ResponsiveRule {
|
|
418
|
+
when: ResponsiveCondition;
|
|
419
|
+
transform: ResponsiveTransform;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
export interface ResponsiveCondition {
|
|
423
|
+
breakpoint?: Breakpoint;
|
|
424
|
+
maxBreakpoint?: Breakpoint;
|
|
425
|
+
containerMaxWidth?: number;
|
|
426
|
+
pointer?: "coarse" | "fine";
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export interface ResponsiveTransform {
|
|
430
|
+
mode?: PhysicalLayoutPlan["mode"];
|
|
431
|
+
collapse?: string[];
|
|
432
|
+
moveToDrawer?: string[];
|
|
433
|
+
hide?: string[];
|
|
434
|
+
stack?: boolean;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/* ------------------------------------------------------------------ *
|
|
438
|
+
* 6. Layout context
|
|
439
|
+
* ------------------------------------------------------------------ */
|
|
440
|
+
|
|
441
|
+
export type Breakpoint =
|
|
442
|
+
| "mobile"
|
|
443
|
+
| "tablet"
|
|
444
|
+
| "laptop"
|
|
445
|
+
| "desktop"
|
|
446
|
+
| "wide"
|
|
447
|
+
| "ultra";
|
|
448
|
+
|
|
449
|
+
export interface LayoutViewport {
|
|
450
|
+
breakpoint: Breakpoint;
|
|
451
|
+
width: number;
|
|
452
|
+
height: number;
|
|
453
|
+
pointer: "coarse" | "fine";
|
|
454
|
+
colorScheme: "light" | "dark";
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export interface LayoutRuntimeContext {
|
|
458
|
+
path: string[];
|
|
459
|
+
depth: number;
|
|
460
|
+
ancestry: Array<{
|
|
461
|
+
id: string;
|
|
462
|
+
type: string;
|
|
463
|
+
tier?: LayoutTier;
|
|
464
|
+
surface?: SurfaceRole;
|
|
465
|
+
slotRole?: SlotRole;
|
|
466
|
+
}>;
|
|
467
|
+
|
|
468
|
+
viewport: LayoutViewport;
|
|
469
|
+
container: { width?: number; height?: number; queryName?: string };
|
|
470
|
+
route?: {
|
|
471
|
+
routeId?: string;
|
|
472
|
+
routePattern?: string;
|
|
473
|
+
workspaceId?: string;
|
|
474
|
+
entityType?: string;
|
|
475
|
+
entityId?: string;
|
|
476
|
+
};
|
|
477
|
+
|
|
478
|
+
slot?: {
|
|
479
|
+
name: string;
|
|
480
|
+
role: SlotRole;
|
|
481
|
+
priority?: number;
|
|
482
|
+
surface?: SurfaceRole;
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
surface: SurfaceRole;
|
|
486
|
+
taskMode?: LayoutTaskMode;
|
|
487
|
+
dataIntensity?: DataIntensity;
|
|
488
|
+
interactionMode?: InteractionMode;
|
|
489
|
+
visualEmphasis?: VisualEmphasis;
|
|
490
|
+
|
|
491
|
+
/** Final style params handed to components. */
|
|
492
|
+
componentStyle: ComponentStyleParams;
|
|
493
|
+
tokens: ResolvedLayoutTokens;
|
|
494
|
+
stateScope: LayoutStateScope;
|
|
495
|
+
permissions?: ResolvedPermissionContext;
|
|
496
|
+
telemetry?: Record<string, unknown>;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
export interface ContextPolicy {
|
|
500
|
+
inheritStyle: boolean;
|
|
501
|
+
inheritDensity: boolean;
|
|
502
|
+
inheritTypeScale: boolean;
|
|
503
|
+
inheritSurface: boolean;
|
|
504
|
+
isolateState: boolean;
|
|
505
|
+
isolateScroll: boolean;
|
|
506
|
+
allowComponentOverride: boolean;
|
|
507
|
+
maxDepth: number;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
export interface ResolvedPermissionContext {
|
|
511
|
+
granted: Set<string>;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/* ------------------------------------------------------------------ *
|
|
515
|
+
* 7.1 Style inference input
|
|
516
|
+
* ------------------------------------------------------------------ */
|
|
517
|
+
|
|
518
|
+
export interface StyleInferenceInput {
|
|
519
|
+
parent?: ComponentStyleParams;
|
|
520
|
+
explicit?: Partial<ComponentStyleParams>;
|
|
521
|
+
layoutType: string;
|
|
522
|
+
layoutTier?: LayoutTier;
|
|
523
|
+
layoutVariant?: string;
|
|
524
|
+
surface: SurfaceRole;
|
|
525
|
+
slotRole?: SlotRole;
|
|
526
|
+
taskMode?: LayoutTaskMode;
|
|
527
|
+
dataIntensity?: DataIntensity;
|
|
528
|
+
interactionMode?: InteractionMode;
|
|
529
|
+
visualEmphasis?: VisualEmphasis;
|
|
530
|
+
depth: number;
|
|
531
|
+
breakpoint: Breakpoint;
|
|
532
|
+
containerWidth?: number;
|
|
533
|
+
userPreference?: Partial<ComponentStyleParams>;
|
|
534
|
+
productDefault?: Partial<ComponentStyleParams>;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/* ------------------------------------------------------------------ *
|
|
538
|
+
* 13. Tokens
|
|
539
|
+
* ------------------------------------------------------------------ */
|
|
540
|
+
|
|
541
|
+
export interface PresetTokenSet {
|
|
542
|
+
surface: string;
|
|
543
|
+
surfaceMuted: string;
|
|
544
|
+
border: string;
|
|
545
|
+
text: string;
|
|
546
|
+
textMuted: string;
|
|
547
|
+
accent: string;
|
|
548
|
+
radius: string;
|
|
549
|
+
shadow: string;
|
|
550
|
+
backdrop?: string;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
export type StylePresetTokenMap = Record<ComponentStylePreset, PresetTokenSet>;
|
|
554
|
+
|
|
555
|
+
export interface ResolvedLayoutTokens extends PresetTokenSet {
|
|
556
|
+
gap: string;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/* ------------------------------------------------------------------ *
|
|
560
|
+
* 10. Physical layout plan
|
|
561
|
+
* ------------------------------------------------------------------ */
|
|
562
|
+
|
|
563
|
+
export interface PhysicalLayoutPlan {
|
|
564
|
+
layoutId: string;
|
|
565
|
+
mode:
|
|
566
|
+
| "multi-pane"
|
|
567
|
+
| "single-pane"
|
|
568
|
+
| "drawer-assisted"
|
|
569
|
+
| "sheet-assisted"
|
|
570
|
+
| "route-stack";
|
|
571
|
+
regions: PhysicalRegion[];
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
export interface PhysicalRegion {
|
|
575
|
+
slot: string;
|
|
576
|
+
placement:
|
|
577
|
+
| "inline-start"
|
|
578
|
+
| "inline-end"
|
|
579
|
+
| "block-start"
|
|
580
|
+
| "block-end"
|
|
581
|
+
| "center"
|
|
582
|
+
| "overlay";
|
|
583
|
+
visible: boolean;
|
|
584
|
+
collapsed?: boolean;
|
|
585
|
+
mounted?: boolean;
|
|
586
|
+
layer?: SurfaceRole;
|
|
587
|
+
size?: { width?: number | string; height?: number | string };
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/* ------------------------------------------------------------------ *
|
|
591
|
+
* 11. State persistence
|
|
592
|
+
* ------------------------------------------------------------------ */
|
|
593
|
+
|
|
594
|
+
export type LayoutStateScope =
|
|
595
|
+
| "global"
|
|
596
|
+
| "workspace"
|
|
597
|
+
| "project"
|
|
598
|
+
| "route"
|
|
599
|
+
| "user"
|
|
600
|
+
| "session";
|
|
601
|
+
|
|
602
|
+
export interface PersistedLayoutState {
|
|
603
|
+
schemaVersion: 2;
|
|
604
|
+
layoutId: string;
|
|
605
|
+
userId?: string;
|
|
606
|
+
workspaceId?: string;
|
|
607
|
+
projectId?: string;
|
|
608
|
+
routePattern?: string;
|
|
609
|
+
panels: Record<
|
|
610
|
+
string,
|
|
611
|
+
{
|
|
612
|
+
width?: number;
|
|
613
|
+
height?: number;
|
|
614
|
+
collapsed?: boolean;
|
|
615
|
+
pinned?: boolean;
|
|
616
|
+
activeTab?: string;
|
|
617
|
+
splitRatio?: number;
|
|
618
|
+
}
|
|
619
|
+
>;
|
|
620
|
+
stylePreference?: Partial<ComponentStyleParams>;
|
|
621
|
+
updatedAt: string;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/* ------------------------------------------------------------------ *
|
|
625
|
+
* 16. Validation diagnostics
|
|
626
|
+
* ------------------------------------------------------------------ */
|
|
627
|
+
|
|
628
|
+
export type LayoutDiagnosticCode =
|
|
629
|
+
| "UNKNOWN_LAYOUT_TYPE"
|
|
630
|
+
| "UNKNOWN_SLOT"
|
|
631
|
+
| "SLOT_REQUIRED"
|
|
632
|
+
| "SLOT_CARDINALITY_VIOLATION"
|
|
633
|
+
| "SLOT_ACCEPTS_VIOLATION"
|
|
634
|
+
| "SURFACE_INCOMPATIBLE"
|
|
635
|
+
| "CYCLE_DETECTED"
|
|
636
|
+
| "MAX_DEPTH_EXCEEDED"
|
|
637
|
+
| "RESPONSIVE_FALLBACK_MISSING"
|
|
638
|
+
| "A11Y_SEMANTICS_MISSING"
|
|
639
|
+
| "STYLE_OVERRIDE_REJECTED";
|
|
640
|
+
|
|
641
|
+
export interface LayoutDiagnostic {
|
|
642
|
+
level: "error" | "warning" | "info";
|
|
643
|
+
code: LayoutDiagnosticCode;
|
|
644
|
+
path: string[];
|
|
645
|
+
message: string;
|
|
646
|
+
suggestion?: string;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/* ------------------------------------------------------------------ *
|
|
650
|
+
* 9. Registry item
|
|
651
|
+
* ------------------------------------------------------------------ */
|
|
652
|
+
|
|
653
|
+
export interface LayoutVariant {
|
|
654
|
+
id: string;
|
|
655
|
+
label?: string;
|
|
656
|
+
description?: string;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
export interface LayoutAcceptRule {
|
|
660
|
+
layoutTypes?: string[];
|
|
661
|
+
tiers?: LayoutTier[];
|
|
662
|
+
surfaces?: SurfaceRole[];
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
export type LayoutCategory =
|
|
666
|
+
| "app-shell"
|
|
667
|
+
| "page"
|
|
668
|
+
| "workspace"
|
|
669
|
+
| "region"
|
|
670
|
+
| "primitive";
|
|
671
|
+
|
|
672
|
+
/**
|
|
673
|
+
* Props handed to a registry item's `renderer`. The engine has already resolved
|
|
674
|
+
* each slot's `SlotContent` into a React node (wrapped in the child context),
|
|
675
|
+
* so renderers just arrange the pre-rendered `slots` map into boxes.
|
|
676
|
+
*/
|
|
677
|
+
export interface LayoutRendererProps {
|
|
678
|
+
node: LayoutNode;
|
|
679
|
+
variant?: string;
|
|
680
|
+
props?: Record<string, unknown>;
|
|
681
|
+
/** Pre-rendered slot content, keyed by slot name. */
|
|
682
|
+
slots: Record<string, import("react").ReactNode>;
|
|
683
|
+
/** This node's own runtime context (parent of the slots' contexts). */
|
|
684
|
+
context: LayoutRuntimeContext;
|
|
685
|
+
composition?: CompositionSpec;
|
|
686
|
+
/** Physical plan for this node (placement/visibility per slot). */
|
|
687
|
+
plan: PhysicalLayoutPlan;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
export interface LayoutRegistryItem {
|
|
691
|
+
type: string;
|
|
692
|
+
displayName: string;
|
|
693
|
+
tier: LayoutTier;
|
|
694
|
+
category: LayoutCategory;
|
|
695
|
+
description: string;
|
|
696
|
+
slots: SlotDefinition[];
|
|
697
|
+
variants?: LayoutVariant[];
|
|
698
|
+
defaultProps?: Record<string, unknown>;
|
|
699
|
+
defaultComposition?: CompositionSpec;
|
|
700
|
+
defaultStyleIntent?: Partial<LayoutStyleIntent>;
|
|
701
|
+
contextPolicy?: Partial<ContextPolicy>;
|
|
702
|
+
allowedParents?: LayoutAcceptRule[];
|
|
703
|
+
allowedChildren?: LayoutAcceptRule[];
|
|
704
|
+
/** The React renderer for this layout type. */
|
|
705
|
+
renderer: import("react").ComponentType<LayoutRendererProps>;
|
|
706
|
+
}
|