@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.
Files changed (50) hide show
  1. package/README.md +92 -0
  2. package/dist/index.cjs +1620 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.css +149 -0
  5. package/dist/index.css.map +1 -0
  6. package/dist/index.d.ts +24 -0
  7. package/dist/index.js +1546 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/layout-system/builders.d.ts +13 -0
  10. package/dist/layout-system/index.d.ts +24 -0
  11. package/dist/layout-system/inference/context.d.ts +33 -0
  12. package/dist/layout-system/inference/responsive.d.ts +21 -0
  13. package/dist/layout-system/inference/style.d.ts +15 -0
  14. package/dist/layout-system/page-layouts/index.d.ts +8 -0
  15. package/dist/layout-system/primitives/index.d.ts +6 -0
  16. package/dist/layout-system/regions/index.d.ts +4 -0
  17. package/dist/layout-system/registry/builtins.d.ts +8 -0
  18. package/dist/layout-system/registry/registry.d.ts +20 -0
  19. package/dist/layout-system/renderer/context.d.ts +41 -0
  20. package/dist/layout-system/renderer/region.d.ts +10 -0
  21. package/dist/layout-system/renderer/renderer.d.ts +13 -0
  22. package/dist/layout-system/renderer/root.d.ts +24 -0
  23. package/dist/layout-system/runtime/state.d.ts +17 -0
  24. package/dist/layout-system/runtime/viewport.d.ts +9 -0
  25. package/dist/layout-system/schema/types.d.ts +488 -0
  26. package/dist/layout-system/schema/validate.d.ts +15 -0
  27. package/dist/layout-system/tokens/preset-tokens.d.ts +11 -0
  28. package/package.json +47 -0
  29. package/src/index.tsx +42 -0
  30. package/src/layout-system/__tests__/layout-system.test.tsx +169 -0
  31. package/src/layout-system/builders.ts +46 -0
  32. package/src/layout-system/index.ts +87 -0
  33. package/src/layout-system/inference/context.ts +158 -0
  34. package/src/layout-system/inference/responsive.ts +147 -0
  35. package/src/layout-system/inference/style.ts +128 -0
  36. package/src/layout-system/page-layouts/index.tsx +405 -0
  37. package/src/layout-system/primitives/index.tsx +266 -0
  38. package/src/layout-system/regions/index.tsx +90 -0
  39. package/src/layout-system/registry/builtins.ts +19 -0
  40. package/src/layout-system/registry/registry.ts +47 -0
  41. package/src/layout-system/renderer/context.tsx +89 -0
  42. package/src/layout-system/renderer/region.tsx +34 -0
  43. package/src/layout-system/renderer/renderer.tsx +200 -0
  44. package/src/layout-system/renderer/root.tsx +95 -0
  45. package/src/layout-system/runtime/state.ts +80 -0
  46. package/src/layout-system/runtime/viewport.ts +71 -0
  47. package/src/layout-system/schema/types.ts +706 -0
  48. package/src/layout-system/schema/validate.ts +168 -0
  49. package/src/layout-system/tokens/preset-tokens.ts +77 -0
  50. package/src/styles.css +178 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,1620 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.tsx
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ LayoutContextProvider: () => LayoutContextProvider,
34
+ LayoutEngineProvider: () => LayoutEngineProvider,
35
+ LayoutRegistry: () => LayoutRegistry,
36
+ LayoutRenderer: () => LayoutRenderer,
37
+ LayoutRoot: () => LayoutRoot,
38
+ SlotContentRenderer: () => SlotContentRenderer,
39
+ StyleScope: () => import_style4.StyleScope,
40
+ breakpointForWidth: () => breakpointForWidth,
41
+ breakpointRank: () => breakpointRank,
42
+ buildEngine: () => buildEngine,
43
+ buildStyleInferenceInput: () => buildStyleInferenceInput,
44
+ builtinLayouts: () => builtinLayouts,
45
+ componentSlot: () => componentSlot,
46
+ composeLayoutContext: () => composeLayoutContext,
47
+ createDefaultLayoutRegistry: () => createDefaultLayoutRegistry,
48
+ createMemoryLayoutStateStore: () => createMemoryLayoutStateStore,
49
+ createRootContext: () => createRootContext,
50
+ defaultComponentStyle: () => defaultComponentStyle,
51
+ defaultContextPolicy: () => defaultContextPolicy,
52
+ defaultStylePreset: () => import_style4.defaultStylePreset,
53
+ defaultViewport: () => defaultViewport,
54
+ emptySlot: () => emptySlot,
55
+ ethBreakpoints: () => ethBreakpoints,
56
+ ethDensityModes: () => import_style4.ethDensityModes,
57
+ ethStylePresetDescriptions: () => import_style4.ethStylePresetDescriptions,
58
+ ethStylePresetLabels: () => import_style4.ethStylePresetLabels,
59
+ ethStylePresets: () => import_style4.ethStylePresets,
60
+ ethTypeScales: () => import_style4.ethTypeScales,
61
+ fragmentSlot: () => fragmentSlot,
62
+ hasErrors: () => hasErrors,
63
+ inferComponentStyle: () => inferComponentStyle,
64
+ inferDensity: () => inferDensity,
65
+ inferTypeScale: () => inferTypeScale,
66
+ isNarrow: () => isNarrow,
67
+ layout: () => layout,
68
+ layoutSlot: () => layoutSlot,
69
+ pageLayouts: () => pageLayouts,
70
+ presetTokenMap: () => presetTokenMap,
71
+ primitiveLayouts: () => primitiveLayouts,
72
+ regionFor: () => regionFor,
73
+ regionLayouts: () => regionLayouts,
74
+ resolvePhysicalPlan: () => resolvePhysicalPlan,
75
+ resolveTokens: () => resolveTokens,
76
+ templateSlot: () => templateSlot,
77
+ useLayoutContext: () => useLayoutContext,
78
+ useLayoutEngine: () => useLayoutEngine,
79
+ useViewport: () => useViewport,
80
+ validateLayout: () => validateLayout
81
+ });
82
+ module.exports = __toCommonJS(index_exports);
83
+ var import_style4 = require("@echothink-ui/style");
84
+
85
+ // src/layout-system/schema/validate.ts
86
+ var DEFAULT_MAX_DEPTH = 8;
87
+ function acceptsContent(accepts, content) {
88
+ return accepts.some((spec) => {
89
+ switch (content.kind) {
90
+ case "component":
91
+ return spec.kind === "component" && (!spec.componentTypes || spec.componentTypes.includes(content.component));
92
+ case "layout":
93
+ return spec.kind === "layout" && (!spec.layoutTypes || spec.layoutTypes.includes(content.layout.type));
94
+ case "template":
95
+ return spec.kind === "template" && (!spec.templateTypes || spec.templateTypes.includes(content.template));
96
+ case "fragment":
97
+ return spec.kind === "fragment";
98
+ case "empty":
99
+ return spec.kind === "empty";
100
+ default:
101
+ return false;
102
+ }
103
+ });
104
+ }
105
+ function* childLayouts(content) {
106
+ if (content.kind === "layout") {
107
+ yield content.layout;
108
+ } else if (content.kind === "fragment") {
109
+ for (const item of content.items) yield* childLayouts(item);
110
+ }
111
+ }
112
+ function validateLayout(root, registry, opts = {}) {
113
+ const diagnostics = [];
114
+ const maxDepth = opts.maxDepth ?? DEFAULT_MAX_DEPTH;
115
+ const visiting = /* @__PURE__ */ new Set();
116
+ function walk(node, path, depth) {
117
+ const nodePath = [...path, node.id];
118
+ if (depth > maxDepth) {
119
+ diagnostics.push({
120
+ level: "error",
121
+ code: "MAX_DEPTH_EXCEEDED",
122
+ path: nodePath,
123
+ message: `Layout nesting exceeds maxDepth=${maxDepth}.`
124
+ });
125
+ return;
126
+ }
127
+ if (visiting.has(node.id)) {
128
+ diagnostics.push({
129
+ level: "error",
130
+ code: "CYCLE_DETECTED",
131
+ path: nodePath,
132
+ message: `Cycle detected at node "${node.id}".`
133
+ });
134
+ return;
135
+ }
136
+ visiting.add(node.id);
137
+ const item = registry.get(node.type);
138
+ if (!item) {
139
+ diagnostics.push({
140
+ level: "error",
141
+ code: "UNKNOWN_LAYOUT_TYPE",
142
+ path: nodePath,
143
+ message: `Unknown layout type "${node.type}".`,
144
+ suggestion: `Register "${node.type}" or use one of: ${registry.types().slice(0, 8).join(", ")}\u2026`
145
+ });
146
+ visiting.delete(node.id);
147
+ return;
148
+ }
149
+ const slotByName = new Map(
150
+ item.slots.map((s) => [s.name, s])
151
+ );
152
+ for (const slotName of Object.keys(node.slots)) {
153
+ if (!slotByName.has(slotName)) {
154
+ diagnostics.push({
155
+ level: "warning",
156
+ code: "UNKNOWN_SLOT",
157
+ path: [...nodePath, slotName],
158
+ message: `Slot "${slotName}" is not declared by "${node.type}".`
159
+ });
160
+ }
161
+ }
162
+ for (const slot of item.slots) {
163
+ const content = node.slots[slot.name];
164
+ if (content === void 0) {
165
+ if (slot.required && !slot.fallback?.empty) {
166
+ diagnostics.push({
167
+ level: "error",
168
+ code: "SLOT_REQUIRED",
169
+ path: [...nodePath, slot.name],
170
+ message: `Required slot "${slot.name}" of "${node.type}" has no content or fallback.`
171
+ });
172
+ }
173
+ continue;
174
+ }
175
+ if (!acceptsContent(slot.accepts, content)) {
176
+ diagnostics.push({
177
+ level: "error",
178
+ code: "SLOT_ACCEPTS_VIOLATION",
179
+ path: [...nodePath, slot.name],
180
+ message: `Slot "${slot.name}" of "${node.type}" does not accept ${content.kind} content.`
181
+ });
182
+ }
183
+ if (content.kind === "fragment" && slot.cardinality?.max && slot.cardinality.max !== "unbounded") {
184
+ if (content.items.length > slot.cardinality.max) {
185
+ diagnostics.push({
186
+ level: "error",
187
+ code: "SLOT_CARDINALITY_VIOLATION",
188
+ path: [...nodePath, slot.name],
189
+ message: `Slot "${slot.name}" allows at most ${slot.cardinality.max} items.`
190
+ });
191
+ }
192
+ }
193
+ for (const child of childLayouts(content)) {
194
+ walk(child, [...nodePath, slot.name], depth + 1);
195
+ }
196
+ }
197
+ visiting.delete(node.id);
198
+ }
199
+ walk(root, [], 0);
200
+ return diagnostics;
201
+ }
202
+ function hasErrors(diagnostics) {
203
+ return diagnostics.some((d) => d.level === "error");
204
+ }
205
+
206
+ // src/layout-system/tokens/preset-tokens.ts
207
+ var presetTokenMap = {
208
+ "carbon-like": {
209
+ surface: "var(--eth-surface, var(--eth-color-surface))",
210
+ surfaceMuted: "var(--eth-surface-muted, var(--eth-color-surface-muted))",
211
+ border: "var(--eth-border-subtle, var(--eth-color-border))",
212
+ text: "var(--eth-text-primary, var(--eth-color-text))",
213
+ textMuted: "var(--eth-text-secondary, var(--eth-color-text-secondary))",
214
+ accent: "var(--eth-accent, var(--eth-color-accent))",
215
+ radius: "var(--eth-radius-sm, 0.125rem)",
216
+ shadow: "var(--eth-shadow-none, none)"
217
+ },
218
+ "soft-card": {
219
+ surface: "var(--eth-surface, var(--eth-color-surface))",
220
+ surfaceMuted: "var(--eth-surface-muted, var(--eth-color-surface-muted))",
221
+ border: "var(--eth-border-soft, var(--eth-color-border))",
222
+ text: "var(--eth-text-primary, var(--eth-color-text))",
223
+ textMuted: "var(--eth-text-secondary, var(--eth-color-text-secondary))",
224
+ accent: "var(--eth-accent, var(--eth-color-accent))",
225
+ radius: "var(--eth-radius-lg, 0.75rem)",
226
+ shadow: "var(--eth-shadow-card, 0 1px 2px rgba(15,23,42,0.08))"
227
+ },
228
+ glass: {
229
+ surface: "var(--eth-surface-glass, var(--eth-color-surface))",
230
+ surfaceMuted: "var(--eth-surface-glass-muted, var(--eth-color-surface-muted))",
231
+ border: "var(--eth-border-glass, var(--eth-color-border))",
232
+ text: "var(--eth-text-on-glass, var(--eth-color-text))",
233
+ textMuted: "var(--eth-text-on-glass-muted, var(--eth-color-text-secondary))",
234
+ accent: "var(--eth-accent, var(--eth-color-accent))",
235
+ radius: "var(--eth-radius-xl, 1rem)",
236
+ shadow: "var(--eth-shadow-floating, 0 8px 32px rgba(15,23,42,0.18))",
237
+ backdrop: "blur(16px)"
238
+ },
239
+ bright: {
240
+ surface: "var(--eth-surface, var(--eth-color-surface))",
241
+ surfaceMuted: "var(--eth-surface-muted, var(--eth-color-surface-muted))",
242
+ border: "var(--eth-border-bright, var(--eth-color-border))",
243
+ text: "var(--eth-text-primary, var(--eth-color-text))",
244
+ textMuted: "var(--eth-text-secondary, var(--eth-color-text-secondary))",
245
+ accent: "var(--eth-accent, var(--eth-color-accent))",
246
+ radius: "var(--eth-radius-md, 0.5rem)",
247
+ shadow: "var(--eth-shadow-sm, 0 1px 2px rgba(15,23,42,0.06))"
248
+ },
249
+ "studio-dark": {
250
+ surface: "var(--eth-surface-studio, var(--eth-color-surface))",
251
+ surfaceMuted: "var(--eth-surface-studio-muted, var(--eth-color-surface-muted))",
252
+ border: "var(--eth-border-studio, var(--eth-color-border))",
253
+ text: "var(--eth-text-on-dark, var(--eth-color-text))",
254
+ textMuted: "var(--eth-text-on-dark-muted, var(--eth-color-text-secondary))",
255
+ accent: "var(--eth-accent, var(--eth-color-accent))",
256
+ radius: "var(--eth-radius-sm, 0.125rem)",
257
+ shadow: "var(--eth-shadow-none, none)"
258
+ }
259
+ };
260
+ var densityGap = {
261
+ compact: "var(--eth-space-sm, 0.5rem)",
262
+ standard: "var(--eth-space-md, 0.75rem)",
263
+ comfortable: "var(--eth-space-lg, 1rem)"
264
+ };
265
+ function resolveTokens(style) {
266
+ return { ...presetTokenMap[style.preset], gap: densityGap[style.density] };
267
+ }
268
+
269
+ // src/layout-system/inference/style.ts
270
+ var defaultComponentStyle = {
271
+ preset: "carbon-like",
272
+ palette: "default",
273
+ density: "standard",
274
+ typeScale: "standard"
275
+ };
276
+ function matches(value, candidates) {
277
+ if (!value) return false;
278
+ return candidates.some((c) => value === c || value.endsWith(`.${c}`) || value.includes(c));
279
+ }
280
+ function chooseHighestScore(scores, fallback) {
281
+ let best = fallback;
282
+ let bestScore = -Infinity;
283
+ const order = [
284
+ "carbon-like",
285
+ "soft-card",
286
+ "glass",
287
+ "bright",
288
+ "studio-dark"
289
+ ];
290
+ for (const key of order) {
291
+ if (scores[key] > bestScore) {
292
+ bestScore = scores[key];
293
+ best = key;
294
+ }
295
+ }
296
+ return bestScore <= 0 ? fallback : best;
297
+ }
298
+ function inferDensity(input) {
299
+ if (input.explicit?.density) return input.explicit.density;
300
+ const role = input.slotRole;
301
+ if (input.dataIntensity === "high" || input.dataIntensity === "realtime") return "compact";
302
+ if (matches(role, ["console", "timeline", "filter", "toolbar", "navigation"]) || matches(input.layoutType, ["DataGridInspector", "MonitoringOps"])) {
303
+ return "compact";
304
+ }
305
+ if (input.visualEmphasis === "expressive" || input.visualEmphasis === "immersive") {
306
+ return "comfortable";
307
+ }
308
+ if (matches(role, ["form", "inspector", "summary", "content", "preview"])) return "standard";
309
+ if (input.taskMode === "wizard" || input.taskMode === "copilot") return "comfortable";
310
+ if (input.breakpoint === "mobile" && input.parent?.density === "compact") return "standard";
311
+ return input.parent?.density ?? "standard";
312
+ }
313
+ function inferTypeScale(input) {
314
+ if (input.explicit?.typeScale) return input.explicit.typeScale;
315
+ const role = input.slotRole;
316
+ if (typeof input.containerWidth === "number" && input.containerWidth < 360) return "compact";
317
+ if (matches(role, ["toolbar", "navigation", "console", "timeline"])) return "compact";
318
+ if (matches(input.layoutType, ["DataGridInspector", "MonitoringOps"])) return "compact";
319
+ if (input.taskMode === "wizard" || matches(role, ["summary", "emptyState"])) return "large";
320
+ if (input.breakpoint === "mobile") return "standard";
321
+ if (matches(role, ["form", "inspector", "content", "preview"])) return "standard";
322
+ return input.parent?.typeScale ?? "standard";
323
+ }
324
+ function inferComponentStyle(input) {
325
+ const presetScores = {
326
+ "carbon-like": 0,
327
+ "soft-card": 0,
328
+ glass: 0,
329
+ bright: 0,
330
+ "studio-dark": 0
331
+ };
332
+ if (matches(input.layoutType, ["AdminShell", "DataGridInspector", "SettingsConsole"])) {
333
+ presetScores["carbon-like"] += 4;
334
+ }
335
+ if (matches(input.layoutType, ["DashboardBento", "SearchCatalog"])) {
336
+ presetScores["soft-card"] += 4;
337
+ }
338
+ if (matches(input.layoutType, ["SpatialHud"]) || input.surface === "floating") {
339
+ presetScores.glass += 4;
340
+ }
341
+ if (matches(input.layoutType, ["WizardComposer"]) || input.taskMode === "wizard") {
342
+ presetScores.bright += 4;
343
+ }
344
+ if (matches(input.layoutType, ["Workbench", "CanvasInspector", "MonitoringOps", "Playground"]) || matches(input.slotRole, ["console", "canvas", "timeline"])) {
345
+ presetScores["studio-dark"] += 4;
346
+ }
347
+ if (input.depth >= 2 && matches(input.slotRole, ["form", "filter", "inspector"])) {
348
+ presetScores["carbon-like"] += 2;
349
+ }
350
+ const preset = input.explicit?.preset ?? chooseHighestScore(presetScores, input.parent?.preset ?? defaultComponentStyle.preset);
351
+ return {
352
+ preset,
353
+ palette: input.explicit?.palette ?? input.parent?.palette ?? "default",
354
+ density: inferDensity(input),
355
+ typeScale: inferTypeScale(input)
356
+ };
357
+ }
358
+
359
+ // src/layout-system/inference/context.ts
360
+ var defaultContextPolicy = {
361
+ inheritStyle: true,
362
+ inheritDensity: true,
363
+ inheritTypeScale: true,
364
+ inheritSurface: false,
365
+ isolateState: false,
366
+ isolateScroll: true,
367
+ allowComponentOverride: true,
368
+ maxDepth: 8
369
+ };
370
+ var defaultViewport = {
371
+ breakpoint: "desktop",
372
+ width: 1440,
373
+ height: 900,
374
+ pointer: "fine",
375
+ colorScheme: "light"
376
+ };
377
+ function createRootContext(input = {}) {
378
+ const viewport = { ...defaultViewport, ...input.viewport };
379
+ const componentStyle = {
380
+ ...defaultComponentStyle,
381
+ ...input.style
382
+ };
383
+ return {
384
+ path: [],
385
+ depth: 0,
386
+ ancestry: [],
387
+ viewport,
388
+ container: { width: viewport.width, height: viewport.height },
389
+ route: input.route,
390
+ surface: input.surface ?? "app",
391
+ componentStyle,
392
+ tokens: resolveTokens(componentStyle),
393
+ stateScope: "session",
394
+ permissions: input.permissions ? { granted: new Set(input.permissions) } : void 0
395
+ };
396
+ }
397
+ function inferChildSurface(parent, node, slot) {
398
+ return slot.contextTransform?.surface ?? node.styleIntent?.surface ?? (parent.surface === "app" ? "page" : parent.surface);
399
+ }
400
+ function buildStyleInferenceInput(args) {
401
+ const { parent, node, slot, content } = args;
402
+ const surface = inferChildSurface(parent, node, slot);
403
+ const explicit = {
404
+ ...node.styleIntent,
405
+ ...slot.contextTransform?.styleIntent,
406
+ ...slot.contextTransform?.densityHint ? { density: slot.contextTransform.densityHint } : {},
407
+ ...slot.contextTransform?.typeScaleHint ? { typeScale: slot.contextTransform.typeScaleHint } : {},
408
+ ...content.kind === "component" ? content.styleOverride : void 0
409
+ };
410
+ return {
411
+ parent: parent.componentStyle,
412
+ explicit,
413
+ layoutType: node.type,
414
+ layoutTier: node.tier,
415
+ layoutVariant: node.variant,
416
+ surface,
417
+ slotRole: slot.role,
418
+ taskMode: node.styleIntent?.taskMode ?? parent.taskMode,
419
+ dataIntensity: node.styleIntent?.dataIntensity ?? parent.dataIntensity,
420
+ interactionMode: node.styleIntent?.interactionMode ?? parent.interactionMode,
421
+ visualEmphasis: node.styleIntent?.visualEmphasis ?? parent.visualEmphasis,
422
+ depth: parent.depth + 1,
423
+ breakpoint: parent.viewport.breakpoint,
424
+ containerWidth: parent.container.width
425
+ };
426
+ }
427
+ function composeLayoutContext(args) {
428
+ const { parent, node, slot, content } = args;
429
+ const styleInput = buildStyleInferenceInput(args);
430
+ const componentStyle = inferComponentStyle(styleInput);
431
+ const surface = styleInput.surface;
432
+ return {
433
+ ...parent,
434
+ path: [...parent.path, node.id, slot.name],
435
+ depth: parent.depth + 1,
436
+ ancestry: [
437
+ ...parent.ancestry,
438
+ {
439
+ id: node.id,
440
+ type: node.type,
441
+ tier: node.tier,
442
+ surface: node.styleIntent?.surface,
443
+ slotRole: slot.role
444
+ }
445
+ ],
446
+ slot: {
447
+ name: slot.name,
448
+ role: slot.role,
449
+ priority: slot.priority?.value,
450
+ surface: slot.contextTransform?.surface
451
+ },
452
+ surface,
453
+ taskMode: node.styleIntent?.taskMode ?? parent.taskMode,
454
+ dataIntensity: node.styleIntent?.dataIntensity ?? parent.dataIntensity,
455
+ interactionMode: node.styleIntent?.interactionMode ?? parent.interactionMode,
456
+ visualEmphasis: node.styleIntent?.visualEmphasis ?? parent.visualEmphasis,
457
+ componentStyle,
458
+ tokens: resolveTokens(componentStyle),
459
+ stateScope: node.state?.scope ?? parent.stateScope
460
+ };
461
+ }
462
+
463
+ // src/layout-system/inference/responsive.ts
464
+ var BREAKPOINT_ORDER = [
465
+ "mobile",
466
+ "tablet",
467
+ "laptop",
468
+ "desktop",
469
+ "wide",
470
+ "ultra"
471
+ ];
472
+ function breakpointRank(bp) {
473
+ return BREAKPOINT_ORDER.indexOf(bp);
474
+ }
475
+ function isNarrow(bp) {
476
+ return breakpointRank(bp) <= breakpointRank("tablet");
477
+ }
478
+ var PLACEMENT_BY_ROLE = {
479
+ navigation: "inline-start",
480
+ filter: "inline-start",
481
+ inspector: "inline-end",
482
+ secondary: "inline-end",
483
+ toolbar: "block-start",
484
+ search: "block-start",
485
+ status: "block-start",
486
+ console: "block-end",
487
+ footer: "block-end",
488
+ timeline: "block-end",
489
+ summary: "inline-end",
490
+ preview: "inline-end",
491
+ drawer: "overlay",
492
+ modal: "overlay",
493
+ overlay: "overlay"
494
+ };
495
+ function placementFor(slot) {
496
+ return PLACEMENT_BY_ROLE[slot.role] ?? "center";
497
+ }
498
+ function resolvePhysicalPlan(input) {
499
+ const { node, item, viewport, state } = input;
500
+ const narrow = isNarrow(viewport.breakpoint);
501
+ const bpRank = breakpointRank(viewport.breakpoint);
502
+ const regions = item.slots.map((slot) => {
503
+ const present = node.slots[slot.name] !== void 0;
504
+ const persisted = state?.panels?.[slot.name];
505
+ const placement = placementFor(slot);
506
+ let visible = present;
507
+ let collapsed = persisted?.collapsed ?? false;
508
+ let layer;
509
+ let regionPlacement = placement;
510
+ if (slot.responsive?.hideBelow && bpRank < breakpointRank(slot.responsive.hideBelow)) {
511
+ visible = false;
512
+ }
513
+ if (slot.responsive?.collapseBelow && bpRank < breakpointRank(slot.responsive.collapseBelow)) {
514
+ collapsed = true;
515
+ }
516
+ if (narrow && slot.priority) {
517
+ switch (slot.priority.behaviorOnNarrow) {
518
+ case "collapse":
519
+ collapsed = true;
520
+ break;
521
+ case "hide":
522
+ if (!slot.required) visible = false;
523
+ break;
524
+ case "move-to-drawer":
525
+ regionPlacement = "overlay";
526
+ layer = "drawer";
527
+ break;
528
+ case "move-to-bottom-sheet":
529
+ regionPlacement = "overlay";
530
+ layer = "sheet";
531
+ break;
532
+ case "route-stack":
533
+ case "tabs":
534
+ case "keep":
535
+ default:
536
+ break;
537
+ }
538
+ }
539
+ return {
540
+ slot: slot.name,
541
+ placement: regionPlacement,
542
+ visible,
543
+ collapsed,
544
+ mounted: present,
545
+ layer,
546
+ size: persisted?.width ? { width: persisted.width } : persisted?.height ? { height: persisted.height } : void 0
547
+ };
548
+ });
549
+ const mode = narrow ? regions.some((r) => r.layer === "drawer" || r.layer === "sheet") ? "drawer-assisted" : "single-pane" : "multi-pane";
550
+ return { layoutId: node.id, mode, regions };
551
+ }
552
+ function regionFor(plan, slot) {
553
+ return plan.regions.find((r) => r.slot === slot);
554
+ }
555
+
556
+ // src/layout-system/registry/registry.ts
557
+ var LayoutRegistry = class {
558
+ items = /* @__PURE__ */ new Map();
559
+ register(item) {
560
+ this.items.set(item.type, item);
561
+ return this;
562
+ }
563
+ registerAll(items) {
564
+ for (const item of items) this.register(item);
565
+ return this;
566
+ }
567
+ get(type) {
568
+ return this.items.get(type);
569
+ }
570
+ has(type) {
571
+ return this.items.has(type);
572
+ }
573
+ list() {
574
+ return [...this.items.values()];
575
+ }
576
+ types() {
577
+ return [...this.items.keys()];
578
+ }
579
+ byTier(tier) {
580
+ return this.list().filter((i) => i.tier === tier);
581
+ }
582
+ byCategory(category) {
583
+ return this.list().filter((i) => i.category === category);
584
+ }
585
+ };
586
+
587
+ // src/layout-system/primitives/index.tsx
588
+ var React3 = __toESM(require("react"), 1);
589
+
590
+ // src/layout-system/renderer/renderer.tsx
591
+ var React2 = __toESM(require("react"), 1);
592
+ var import_style2 = require("@echothink-ui/style");
593
+
594
+ // src/layout-system/renderer/context.tsx
595
+ var React = __toESM(require("react"), 1);
596
+
597
+ // src/layout-system/runtime/state.ts
598
+ function emptyState(layoutId) {
599
+ return {
600
+ schemaVersion: 2,
601
+ layoutId,
602
+ panels: {},
603
+ updatedAt: ""
604
+ };
605
+ }
606
+ function createMemoryLayoutStateStore(opts) {
607
+ const cache = /* @__PURE__ */ new Map();
608
+ const persistKey = opts?.persistKey;
609
+ function load() {
610
+ if (!persistKey || typeof localStorage === "undefined") return;
611
+ try {
612
+ const raw = localStorage.getItem(persistKey);
613
+ if (!raw) return;
614
+ const parsed = JSON.parse(raw);
615
+ for (const [id, st] of Object.entries(parsed)) cache.set(id, st);
616
+ } catch {
617
+ }
618
+ }
619
+ function flush() {
620
+ if (!persistKey || typeof localStorage === "undefined") return;
621
+ try {
622
+ localStorage.setItem(persistKey, JSON.stringify(Object.fromEntries(cache)));
623
+ } catch {
624
+ }
625
+ }
626
+ load();
627
+ return {
628
+ get(layoutId) {
629
+ return cache.get(layoutId);
630
+ },
631
+ set(layoutId, state) {
632
+ cache.set(layoutId, state);
633
+ flush();
634
+ },
635
+ patchPanel(layoutId, slot, patch) {
636
+ const current = cache.get(layoutId) ?? emptyState(layoutId);
637
+ const next = {
638
+ ...current,
639
+ panels: { ...current.panels, [slot]: { ...current.panels[slot], ...patch } },
640
+ // `updatedAt` is set by the caller environment; left as a marker here.
641
+ updatedAt: current.updatedAt || "pending"
642
+ };
643
+ cache.set(layoutId, next);
644
+ flush();
645
+ return next;
646
+ }
647
+ };
648
+ }
649
+
650
+ // src/layout-system/renderer/context.tsx
651
+ var import_jsx_runtime = require("react/jsx-runtime");
652
+ var RuntimeContext = React.createContext(createRootContext());
653
+ var EngineContext = React.createContext(null);
654
+ function LayoutContextProvider({
655
+ value,
656
+ children
657
+ }) {
658
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RuntimeContext.Provider, { value, children });
659
+ }
660
+ function useLayoutContext() {
661
+ return React.useContext(RuntimeContext);
662
+ }
663
+ function LayoutEngineProvider({
664
+ value,
665
+ children
666
+ }) {
667
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EngineContext.Provider, { value, children });
668
+ }
669
+ function useLayoutEngine() {
670
+ const engine = React.useContext(EngineContext);
671
+ if (!engine) {
672
+ throw new Error(
673
+ "useLayoutEngine must be used within <LayoutRoot> / <LayoutEngineProvider>."
674
+ );
675
+ }
676
+ return engine;
677
+ }
678
+ function buildEngine(input) {
679
+ return {
680
+ registry: input.registry,
681
+ componentResolver: input.componentResolver,
682
+ templateResolver: input.templateResolver,
683
+ stateStore: input.stateStore ?? createMemoryLayoutStateStore(),
684
+ onDiagnostics: input.onDiagnostics
685
+ };
686
+ }
687
+
688
+ // src/layout-system/renderer/renderer.tsx
689
+ var import_jsx_runtime2 = require("react/jsx-runtime");
690
+ function UnknownLayout({ type }) {
691
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { "data-ls-unknown-layout": type, className: "eth-ls-unknown", role: "note", children: [
692
+ "Unknown layout type: ",
693
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: type })
694
+ ] });
695
+ }
696
+ function UnknownComponent({ name }) {
697
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { "data-ls-unknown-component": name, className: "eth-ls-unknown", role: "note", children: [
698
+ "Unknown component: ",
699
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: name })
700
+ ] });
701
+ }
702
+ function EmptySlot({ reason }) {
703
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { "data-ls-empty": reason ?? "not-configured", className: "eth-ls-empty", "aria-hidden": "true" });
704
+ }
705
+ function ComponentRenderer({
706
+ content,
707
+ context
708
+ }) {
709
+ const engine = useLayoutEngine();
710
+ const Component = engine.componentResolver(content.component);
711
+ if (!Component) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(UnknownComponent, { name: content.component });
712
+ const s = context.componentStyle;
713
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
714
+ import_style2.StyleScope,
715
+ {
716
+ preset: s.preset,
717
+ palette: s.palette,
718
+ density: s.density,
719
+ typeScale: s.typeScale,
720
+ global: false,
721
+ className: "eth-ls-component",
722
+ "data-ls-component": content.component,
723
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Component, { ...content.props ?? {} })
724
+ }
725
+ );
726
+ }
727
+ function renderContent(content, context, engine) {
728
+ switch (content.kind) {
729
+ case "component":
730
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ComponentRenderer, { content, context });
731
+ case "layout":
732
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LayoutRenderer, { node: content.layout });
733
+ case "template": {
734
+ const resolved = engine.templateResolver?.(content.template);
735
+ if (!resolved) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(UnknownComponent, { name: `template:${content.template}` });
736
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LayoutRenderer, { node: resolved });
737
+ }
738
+ case "fragment": {
739
+ const direction = content.composition?.op === "stack" && content.composition.direction === "horizontal" ? "row" : "column";
740
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "eth-ls-fragment", style: { display: "flex", flexDirection: direction, gap: context.tokens.gap }, children: content.items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(React2.Fragment, { children: renderContent(item, context, engine) }, i)) });
741
+ }
742
+ case "empty":
743
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(EmptySlot, { reason: content.reason });
744
+ default:
745
+ return null;
746
+ }
747
+ }
748
+ function SlotContentRenderer({
749
+ node,
750
+ slot,
751
+ content,
752
+ parentContext
753
+ }) {
754
+ const engine = useLayoutEngine();
755
+ const childContext = React2.useMemo(
756
+ () => composeLayoutContext({ parent: parentContext, node, slot, content }),
757
+ [parentContext, node, slot, content]
758
+ );
759
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(LayoutContextProvider, { value: childContext, children: renderContent(content, childContext, engine) });
760
+ }
761
+ function LayoutRenderer({ node }) {
762
+ const parentContext = useLayoutContext();
763
+ const engine = useLayoutEngine();
764
+ const item = engine.registry.get(node.type);
765
+ if (!item) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(UnknownLayout, { type: node.type });
766
+ const slots = {};
767
+ for (const slotDef of item.slots) {
768
+ const content = node.slots[slotDef.name] ?? slotDef.fallback?.empty;
769
+ if (content === void 0) continue;
770
+ slots[slotDef.name] = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
771
+ SlotContentRenderer,
772
+ {
773
+ node,
774
+ slot: slotDef,
775
+ content,
776
+ parentContext
777
+ }
778
+ );
779
+ }
780
+ const plan = resolvePhysicalPlan({
781
+ node,
782
+ item,
783
+ viewport: parentContext.viewport,
784
+ state: engine.stateStore.get(node.id)
785
+ });
786
+ const Renderer = item.renderer;
787
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
788
+ Renderer,
789
+ {
790
+ node,
791
+ variant: node.variant,
792
+ props: { ...item.defaultProps, ...node.props },
793
+ slots,
794
+ context: parentContext,
795
+ composition: node.composition ?? item.defaultComposition,
796
+ plan
797
+ }
798
+ );
799
+ }
800
+
801
+ // src/layout-system/renderer/region.tsx
802
+ var ANY_ACCEPTS = [
803
+ { kind: "component" },
804
+ { kind: "layout" },
805
+ { kind: "template" },
806
+ { kind: "fragment" },
807
+ { kind: "empty" }
808
+ ];
809
+ function inlineSlot(name, role = "content") {
810
+ return { name, role, accepts: ANY_ACCEPTS };
811
+ }
812
+ function isVisible(plan, slot) {
813
+ const region = regionFor(plan, slot);
814
+ return region ? region.visible : true;
815
+ }
816
+ function isCollapsed(plan, slot) {
817
+ return regionFor(plan, slot)?.collapsed ?? false;
818
+ }
819
+
820
+ // src/layout-system/primitives/index.tsx
821
+ var import_jsx_runtime3 = require("react/jsx-runtime");
822
+ function PanelRenderer({ slots, context }) {
823
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
824
+ "section",
825
+ {
826
+ className: "eth-ls-panel",
827
+ style: {
828
+ background: context.tokens.surface,
829
+ border: `1px solid ${context.tokens.border}`,
830
+ borderRadius: context.tokens.radius,
831
+ boxShadow: context.tokens.shadow,
832
+ color: context.tokens.text
833
+ },
834
+ children: [
835
+ slots.header ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("header", { className: "eth-ls-panel__header", children: slots.header }) : null,
836
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "eth-ls-panel__body", children: slots.body }),
837
+ slots.footer ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("footer", { className: "eth-ls-panel__footer", children: slots.footer }) : null
838
+ ]
839
+ }
840
+ );
841
+ }
842
+ var PanelLayout = {
843
+ type: "Primitive.Panel",
844
+ displayName: "Panel",
845
+ tier: "primitive",
846
+ category: "primitive",
847
+ description: "A bounded surface with optional header/body/footer.",
848
+ slots: [
849
+ { name: "header", role: "toolbar", accepts: [{ kind: "component" }, { kind: "fragment" }] },
850
+ {
851
+ name: "body",
852
+ role: "content",
853
+ required: true,
854
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }]
855
+ },
856
+ { name: "footer", role: "footer", accepts: [{ kind: "component" }, { kind: "fragment" }] }
857
+ ],
858
+ defaultStyleIntent: { surface: "panel" },
859
+ renderer: PanelRenderer
860
+ };
861
+ function SplitPaneRenderer({ slots, context, composition, variant }) {
862
+ const orientation = variant === "vertical" ? "vertical" : "horizontal";
863
+ const parallel = composition?.op === "parallel" ? composition : void 0;
864
+ const primaryBasis = parallel?.sizing?.primary?.basis;
865
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
866
+ "div",
867
+ {
868
+ className: `eth-ls-split eth-ls-split--${orientation}`,
869
+ style: {
870
+ display: "grid",
871
+ gap: parallel?.gapToken ? `var(${parallel.gapToken})` : context.tokens.gap,
872
+ gridTemplateColumns: orientation === "horizontal" ? `${primaryBasis ? cssSize(primaryBasis) : "1fr"} 1fr` : void 0,
873
+ gridTemplateRows: orientation === "vertical" ? `${primaryBasis ? cssSize(primaryBasis) : "1fr"} 1fr` : void 0,
874
+ height: "100%",
875
+ minHeight: 0
876
+ },
877
+ children: [
878
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "eth-ls-split__pane eth-ls-split__pane--primary", style: { minWidth: 0, minHeight: 0 }, children: slots.primary }),
879
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
880
+ "div",
881
+ {
882
+ className: "eth-ls-split__pane eth-ls-split__pane--secondary",
883
+ role: "separator",
884
+ "aria-orientation": orientation,
885
+ style: { minWidth: 0, minHeight: 0 },
886
+ children: slots.secondary
887
+ }
888
+ )
889
+ ]
890
+ }
891
+ );
892
+ }
893
+ function cssSize(value) {
894
+ return typeof value === "number" ? `${value}px` : value;
895
+ }
896
+ var SplitPaneLayout = {
897
+ type: "Primitive.SplitPane",
898
+ displayName: "Split Pane",
899
+ tier: "primitive",
900
+ category: "primitive",
901
+ description: "Two resizable panes split horizontally or vertically.",
902
+ variants: [
903
+ { id: "horizontal", label: "Left / Right" },
904
+ { id: "vertical", label: "Top / Bottom" }
905
+ ],
906
+ slots: [
907
+ {
908
+ name: "primary",
909
+ role: "primary",
910
+ required: true,
911
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "template" }, { kind: "fragment" }]
912
+ },
913
+ {
914
+ name: "secondary",
915
+ role: "secondary",
916
+ required: true,
917
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "template" }, { kind: "fragment" }]
918
+ }
919
+ ],
920
+ defaultComposition: {
921
+ op: "parallel",
922
+ axis: "x",
923
+ slots: ["primary", "secondary"],
924
+ sizing: { primary: { basis: "1fr", resizable: true }, secondary: { grow: 1 } }
925
+ },
926
+ renderer: SplitPaneRenderer
927
+ };
928
+ function TabsRenderer({ node, context, composition }) {
929
+ const switchSpec = composition?.op === "switch" ? composition : void 0;
930
+ const items = switchSpec?.items ?? [];
931
+ const initial = switchSpec?.activeKey ?? items[0]?.key;
932
+ const [active, setActive] = React3.useState(initial);
933
+ const activeItem = items.find((i) => i.key === active) ?? items[0];
934
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "eth-ls-tabs", style: { color: context.tokens.text }, children: [
935
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "eth-ls-tabs__list", role: "tablist", children: items.map((item) => {
936
+ const selected = item.key === activeItem?.key;
937
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
938
+ "button",
939
+ {
940
+ type: "button",
941
+ role: "tab",
942
+ id: `tab-${node.id}-${item.key}`,
943
+ "aria-selected": selected,
944
+ "aria-controls": `tabpanel-${node.id}-${item.key}`,
945
+ tabIndex: selected ? 0 : -1,
946
+ className: `eth-ls-tabs__tab${selected ? " eth-ls-tabs__tab--active" : ""}`,
947
+ onClick: () => setActive(item.key),
948
+ children: item.label
949
+ },
950
+ item.key
951
+ );
952
+ }) }),
953
+ activeItem ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
954
+ "div",
955
+ {
956
+ className: "eth-ls-tabs__panel",
957
+ role: "tabpanel",
958
+ id: `tabpanel-${node.id}-${activeItem.key}`,
959
+ "aria-labelledby": `tab-${node.id}-${activeItem.key}`,
960
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
961
+ SlotContentRenderer,
962
+ {
963
+ node,
964
+ slot: inlineSlot(`tab:${activeItem.key}`, "content"),
965
+ content: activeItem.content,
966
+ parentContext: context
967
+ }
968
+ )
969
+ }
970
+ ) : null
971
+ ] });
972
+ }
973
+ var TabsLayout = {
974
+ type: "Primitive.Tabs",
975
+ displayName: "Tabs",
976
+ tier: "primitive",
977
+ category: "primitive",
978
+ description: "Switch composition rendering one panel at a time with tablist semantics.",
979
+ slots: [],
980
+ defaultComposition: { op: "switch", mode: "tabs", items: [] },
981
+ renderer: TabsRenderer
982
+ };
983
+ function StepperRenderer({ node, context, composition }) {
984
+ const stepper = composition?.op === "stepper" ? composition : void 0;
985
+ const steps = stepper?.steps ?? [];
986
+ const firstActive = steps.findIndex((s) => s.status === "active");
987
+ const [activeIndex, setActiveIndex] = React3.useState(firstActive >= 0 ? firstActive : 0);
988
+ const orientation = stepper?.orientation ?? "horizontal";
989
+ const activeStep = steps[activeIndex];
990
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
991
+ "div",
992
+ {
993
+ className: `eth-ls-stepper eth-ls-stepper--${orientation}`,
994
+ style: { display: "flex", flexDirection: orientation === "vertical" ? "row" : "column", gap: context.tokens.gap, color: context.tokens.text },
995
+ children: [
996
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ol", { className: "eth-ls-stepper__steps", "aria-label": "Steps", children: steps.map((step, index) => {
997
+ const current = index === activeIndex;
998
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
999
+ "li",
1000
+ {
1001
+ className: `eth-ls-stepper__step eth-ls-stepper__step--${step.status ?? "pending"}${current ? " eth-ls-stepper__step--current" : ""}`,
1002
+ "aria-current": current ? "step" : void 0,
1003
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("button", { type: "button", className: "eth-ls-stepper__step-button", onClick: () => setActiveIndex(index), children: [
1004
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "eth-ls-stepper__index", children: index + 1 }),
1005
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "eth-ls-stepper__label", children: step.label })
1006
+ ] })
1007
+ },
1008
+ step.id
1009
+ );
1010
+ }) }),
1011
+ activeStep ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "eth-ls-stepper__content", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1012
+ SlotContentRenderer,
1013
+ {
1014
+ node,
1015
+ slot: inlineSlot(`step:${activeStep.id}`, "form"),
1016
+ content: activeStep.content,
1017
+ parentContext: context
1018
+ }
1019
+ ) }) : null
1020
+ ]
1021
+ }
1022
+ );
1023
+ }
1024
+ var StepperLayout = {
1025
+ type: "Primitive.Stepper",
1026
+ displayName: "Stepper",
1027
+ tier: "primitive",
1028
+ category: "primitive",
1029
+ description: "Flow-oriented step container with validation/navigation semantics.",
1030
+ variants: [{ id: "horizontal" }, { id: "vertical" }, { id: "with-preview" }],
1031
+ slots: [],
1032
+ defaultComposition: {
1033
+ op: "stepper",
1034
+ orientation: "horizontal",
1035
+ stepSlot: "stepper",
1036
+ contentSlot: "content",
1037
+ steps: []
1038
+ },
1039
+ defaultStyleIntent: { taskMode: "wizard", visualEmphasis: "balanced" },
1040
+ renderer: StepperRenderer
1041
+ };
1042
+ var primitiveLayouts = [
1043
+ PanelLayout,
1044
+ SplitPaneLayout,
1045
+ TabsLayout,
1046
+ StepperLayout
1047
+ ];
1048
+
1049
+ // src/layout-system/regions/index.tsx
1050
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1051
+ function ToolbarRenderer({ slots, context }) {
1052
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1053
+ "div",
1054
+ {
1055
+ className: "eth-ls-toolbar",
1056
+ role: "toolbar",
1057
+ style: {
1058
+ display: "flex",
1059
+ alignItems: "center",
1060
+ gap: context.tokens.gap,
1061
+ background: context.tokens.surfaceMuted,
1062
+ borderBottom: `1px solid ${context.tokens.border}`,
1063
+ color: context.tokens.text
1064
+ },
1065
+ children: [
1066
+ slots.start ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "eth-ls-toolbar__start", children: slots.start }) : null,
1067
+ slots.center ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "eth-ls-toolbar__center", style: { flex: 1, minWidth: 0 }, children: slots.center }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { flex: 1 } }),
1068
+ slots.end ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "eth-ls-toolbar__end", children: slots.end }) : null
1069
+ ]
1070
+ }
1071
+ );
1072
+ }
1073
+ var ToolbarLayout = {
1074
+ type: "Region.Toolbar",
1075
+ displayName: "Toolbar",
1076
+ tier: "region",
1077
+ category: "region",
1078
+ description: "Horizontal toolbar with start/center/end groups and roving focus.",
1079
+ slots: [
1080
+ { name: "start", role: "toolbar", accepts: [{ kind: "component" }, { kind: "fragment" }] },
1081
+ { name: "center", role: "toolbar", accepts: [{ kind: "component" }, { kind: "fragment" }] },
1082
+ { name: "end", role: "toolbar", accepts: [{ kind: "component" }, { kind: "fragment" }] }
1083
+ ],
1084
+ defaultStyleIntent: { surface: "region" },
1085
+ renderer: ToolbarRenderer
1086
+ };
1087
+ function InspectorRenderer({ slots, context }) {
1088
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1089
+ "aside",
1090
+ {
1091
+ className: "eth-ls-inspector",
1092
+ "aria-label": "Inspector",
1093
+ style: {
1094
+ display: "flex",
1095
+ flexDirection: "column",
1096
+ minHeight: 0,
1097
+ background: context.tokens.surface,
1098
+ borderInlineStart: `1px solid ${context.tokens.border}`,
1099
+ color: context.tokens.text
1100
+ },
1101
+ children: [
1102
+ slots.header ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("header", { className: "eth-ls-inspector__header", children: slots.header }) : null,
1103
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "eth-ls-inspector__body", style: { overflow: "auto", flex: 1, minHeight: 0 }, children: slots.body }),
1104
+ slots.footer ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("footer", { className: "eth-ls-inspector__footer", children: slots.footer }) : null
1105
+ ]
1106
+ }
1107
+ );
1108
+ }
1109
+ var InspectorLayout = {
1110
+ type: "Region.Inspector",
1111
+ displayName: "Inspector",
1112
+ tier: "region",
1113
+ category: "region",
1114
+ description: "An inline-end inspector panel with header/body/footer.",
1115
+ slots: [
1116
+ { name: "header", role: "toolbar", accepts: [{ kind: "component" }, { kind: "fragment" }] },
1117
+ {
1118
+ name: "body",
1119
+ role: "inspector",
1120
+ required: true,
1121
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }]
1122
+ },
1123
+ { name: "footer", role: "footer", accepts: [{ kind: "component" }, { kind: "fragment" }] }
1124
+ ],
1125
+ defaultStyleIntent: { surface: "panel", interactionMode: "edit" },
1126
+ renderer: InspectorRenderer
1127
+ };
1128
+ var regionLayouts = [ToolbarLayout, InspectorLayout];
1129
+
1130
+ // src/layout-system/page-layouts/index.tsx
1131
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1132
+ function frameStyle(context) {
1133
+ return {
1134
+ display: "grid",
1135
+ height: "100%",
1136
+ minHeight: 0,
1137
+ background: context.tokens.surfaceMuted,
1138
+ color: context.tokens.text
1139
+ };
1140
+ }
1141
+ function AdminShellRenderer({ slots, context, plan }) {
1142
+ const navVisible = slots.navigation && isVisible(plan, "navigation");
1143
+ const navCollapsed = isCollapsed(plan, "navigation");
1144
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1145
+ "div",
1146
+ {
1147
+ className: "eth-ls-admin-shell",
1148
+ style: {
1149
+ ...frameStyle(context),
1150
+ gridTemplateRows: "auto 1fr auto",
1151
+ gridTemplateColumns: navVisible ? `${navCollapsed ? "3.5rem" : "16rem"} 1fr` : "1fr",
1152
+ gridTemplateAreas: navVisible ? `"topbar topbar" "nav content" "footer footer"` : `"topbar" "content" "footer"`
1153
+ },
1154
+ children: [
1155
+ slots.topbar ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("header", { className: "eth-ls-admin-shell__topbar", style: { gridArea: "topbar" }, children: slots.topbar }) : null,
1156
+ navVisible ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("nav", { className: "eth-ls-admin-shell__nav", style: { gridArea: "nav", overflow: "auto", borderInlineEnd: `1px solid ${context.tokens.border}` }, children: slots.navigation }) : null,
1157
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("main", { className: "eth-ls-admin-shell__content", style: { gridArea: "content", overflow: "auto", minWidth: 0 }, children: slots.content }),
1158
+ slots.footer ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("footer", { className: "eth-ls-admin-shell__footer", style: { gridArea: "footer", borderBlockStart: `1px solid ${context.tokens.border}` }, children: slots.footer }) : null
1159
+ ]
1160
+ }
1161
+ );
1162
+ }
1163
+ var AdminShellLayout = {
1164
+ type: "PageLayout.AdminShell",
1165
+ displayName: "Admin Shell",
1166
+ tier: "page",
1167
+ category: "app-shell",
1168
+ description: "Enterprise CRUD shell: topbar, navigation rail, content, footer.",
1169
+ slots: [
1170
+ { name: "topbar", role: "toolbar", accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }] },
1171
+ {
1172
+ name: "navigation",
1173
+ role: "navigation",
1174
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }],
1175
+ priority: { value: 40, behaviorOnNarrow: "move-to-drawer" },
1176
+ responsive: { collapseBelow: "laptop" }
1177
+ },
1178
+ {
1179
+ name: "content",
1180
+ role: "content",
1181
+ required: true,
1182
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "template" }, { kind: "fragment" }],
1183
+ priority: { value: 100, behaviorOnNarrow: "keep" }
1184
+ },
1185
+ { name: "footer", role: "footer", accepts: [{ kind: "component" }, { kind: "fragment" }] }
1186
+ ],
1187
+ defaultStyleIntent: { surface: "app", taskMode: "crud" },
1188
+ renderer: AdminShellRenderer
1189
+ };
1190
+ function DataGridInspectorRenderer({ slots, context, plan }) {
1191
+ const inspectorVisible = slots.inspector && isVisible(plan, "inspector");
1192
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1193
+ "div",
1194
+ {
1195
+ className: "eth-ls-datagrid",
1196
+ style: {
1197
+ ...frameStyle(context),
1198
+ gridTemplateRows: "auto 1fr",
1199
+ gridTemplateColumns: inspectorVisible ? "1fr minmax(18rem, 24rem)" : "1fr",
1200
+ gridTemplateAreas: inspectorVisible ? `"toolbar toolbar" "grid inspector"` : `"toolbar" "grid"`
1201
+ },
1202
+ children: [
1203
+ slots.toolbar ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "eth-ls-datagrid__toolbar", style: { gridArea: "toolbar" }, children: slots.toolbar }) : null,
1204
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "eth-ls-datagrid__grid", style: { gridArea: "grid", overflow: "auto", minWidth: 0 }, children: slots.grid }),
1205
+ inspectorVisible ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "eth-ls-datagrid__inspector", style: { gridArea: "inspector", overflow: "auto", borderInlineStart: `1px solid ${context.tokens.border}` }, children: slots.inspector }) : null
1206
+ ]
1207
+ }
1208
+ );
1209
+ }
1210
+ var DataGridInspectorLayout = {
1211
+ type: "PageLayout.DataGridInspector",
1212
+ displayName: "Data Grid + Inspector",
1213
+ tier: "page",
1214
+ category: "page",
1215
+ description: "High-density grid with a toolbar and an inline-end inspector.",
1216
+ slots: [
1217
+ { name: "toolbar", role: "toolbar", accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }] },
1218
+ {
1219
+ name: "grid",
1220
+ role: "content",
1221
+ required: true,
1222
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }],
1223
+ priority: { value: 100, behaviorOnNarrow: "keep" }
1224
+ },
1225
+ {
1226
+ name: "inspector",
1227
+ role: "inspector",
1228
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }],
1229
+ priority: { value: 50, behaviorOnNarrow: "move-to-drawer" }
1230
+ }
1231
+ ],
1232
+ defaultStyleIntent: { surface: "page", taskMode: "crud", dataIntensity: "high" },
1233
+ renderer: DataGridInspectorRenderer
1234
+ };
1235
+ function WorkbenchRenderer({ slots, context, plan }) {
1236
+ const explorerVisible = slots.explorer && isVisible(plan, "explorer");
1237
+ const inspectorVisible = slots.inspector && isVisible(plan, "inspector");
1238
+ const consoleVisible = slots.console && isVisible(plan, "console");
1239
+ const cols = [explorerVisible ? "16rem" : null, "1fr", inspectorVisible ? "minmax(18rem, 22rem)" : null].filter(Boolean).join(" ");
1240
+ const areaMid = [explorerVisible ? "explorer" : null, "primary", inspectorVisible ? "inspector" : null].filter(Boolean).join(" ");
1241
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1242
+ "div",
1243
+ {
1244
+ className: "eth-ls-workbench",
1245
+ style: {
1246
+ ...frameStyle(context),
1247
+ gridTemplateColumns: cols,
1248
+ gridTemplateRows: `auto 1fr ${consoleVisible ? "minmax(8rem, 16rem)" : "0"}`,
1249
+ gridTemplateAreas: `"${new Array(cols.split(" ").length).fill("toolbar").join(" ")}" "${areaMid}" "${new Array(cols.split(" ").length).fill("console").join(" ")}"`
1250
+ },
1251
+ children: [
1252
+ slots.toolbar ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "eth-ls-workbench__toolbar", style: { gridArea: "toolbar" }, children: slots.toolbar }) : null,
1253
+ explorerVisible ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("nav", { className: "eth-ls-workbench__explorer", style: { gridArea: "explorer", overflow: "auto", borderInlineEnd: `1px solid ${context.tokens.border}` }, children: slots.explorer }) : null,
1254
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("main", { className: "eth-ls-workbench__primary", style: { gridArea: "primary", overflow: "auto", minWidth: 0, minHeight: 0 }, children: slots.primary }),
1255
+ inspectorVisible ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "eth-ls-workbench__inspector", style: { gridArea: "inspector", overflow: "auto", borderInlineStart: `1px solid ${context.tokens.border}` }, children: slots.inspector }) : null,
1256
+ consoleVisible ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "eth-ls-workbench__console", style: { gridArea: "console", overflow: "auto", borderBlockStart: `1px solid ${context.tokens.border}` }, children: slots.console }) : null
1257
+ ]
1258
+ }
1259
+ );
1260
+ }
1261
+ var WorkbenchLayout = {
1262
+ type: "PageLayout.Workbench",
1263
+ displayName: "Workbench",
1264
+ tier: "page",
1265
+ category: "page",
1266
+ description: "Authoring workbench: toolbar, explorer, primary canvas, inspector, console.",
1267
+ variants: [{ id: "canvas-primary" }, { id: "split-primary" }],
1268
+ slots: [
1269
+ { name: "toolbar", role: "toolbar", accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }] },
1270
+ {
1271
+ name: "explorer",
1272
+ role: "navigation",
1273
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }],
1274
+ priority: { value: 40, behaviorOnNarrow: "move-to-drawer" },
1275
+ responsive: { collapseBelow: "laptop" }
1276
+ },
1277
+ {
1278
+ name: "primary",
1279
+ role: "primary",
1280
+ required: true,
1281
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "template" }, { kind: "fragment" }],
1282
+ priority: { value: 100, behaviorOnNarrow: "keep" }
1283
+ },
1284
+ {
1285
+ name: "inspector",
1286
+ role: "inspector",
1287
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }],
1288
+ priority: { value: 50, behaviorOnNarrow: "move-to-drawer" }
1289
+ },
1290
+ {
1291
+ name: "console",
1292
+ role: "console",
1293
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }],
1294
+ priority: { value: 30, behaviorOnNarrow: "move-to-bottom-sheet" }
1295
+ }
1296
+ ],
1297
+ defaultStyleIntent: { surface: "workspace", taskMode: "authoring", visualEmphasis: "immersive" },
1298
+ renderer: WorkbenchRenderer
1299
+ };
1300
+ function WizardComposerRenderer({ slots, context, plan }) {
1301
+ const previewVisible = slots.preview && isVisible(plan, "preview");
1302
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1303
+ "div",
1304
+ {
1305
+ className: "eth-ls-wizard",
1306
+ style: {
1307
+ ...frameStyle(context),
1308
+ gridTemplateColumns: previewVisible ? "1fr minmax(20rem, 28rem)" : "1fr",
1309
+ gridTemplateRows: "auto 1fr auto",
1310
+ gridTemplateAreas: previewVisible ? `"stepper stepper" "content preview" "footer footer"` : `"stepper" "content" "footer"`,
1311
+ background: context.tokens.surface
1312
+ },
1313
+ children: [
1314
+ slots.stepper ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "eth-ls-wizard__stepper", style: { gridArea: "stepper" }, children: slots.stepper }) : null,
1315
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("main", { className: "eth-ls-wizard__content", style: { gridArea: "content", overflow: "auto", minWidth: 0 }, children: slots.content }),
1316
+ previewVisible ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "eth-ls-wizard__preview", style: { gridArea: "preview", overflow: "auto", borderInlineStart: `1px solid ${context.tokens.border}` }, children: slots.preview }) : null,
1317
+ slots.footerActions ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("footer", { className: "eth-ls-wizard__footer", style: { gridArea: "footer", borderBlockStart: `1px solid ${context.tokens.border}` }, children: slots.footerActions }) : null
1318
+ ]
1319
+ }
1320
+ );
1321
+ }
1322
+ var WizardComposerLayout = {
1323
+ type: "PageLayout.WizardComposer",
1324
+ displayName: "Wizard Composer",
1325
+ tier: "page",
1326
+ category: "page",
1327
+ description: "Guided multi-step creation flow with optional live preview.",
1328
+ slots: [
1329
+ { name: "stepper", role: "stepper", accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }] },
1330
+ {
1331
+ name: "content",
1332
+ role: "form",
1333
+ required: true,
1334
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "template" }, { kind: "fragment" }],
1335
+ priority: { value: 100, behaviorOnNarrow: "keep" }
1336
+ },
1337
+ {
1338
+ name: "preview",
1339
+ role: "preview",
1340
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }],
1341
+ priority: { value: 40, behaviorOnNarrow: "hide" }
1342
+ },
1343
+ { name: "footerActions", role: "footer", accepts: [{ kind: "component" }, { kind: "fragment" }] }
1344
+ ],
1345
+ defaultStyleIntent: { surface: "page", taskMode: "wizard", visualEmphasis: "balanced" },
1346
+ renderer: WizardComposerRenderer
1347
+ };
1348
+ function MonitoringOpsRenderer({ slots, context, plan }) {
1349
+ const consoleVisible = slots.console && isVisible(plan, "console");
1350
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1351
+ "div",
1352
+ {
1353
+ className: "eth-ls-monitoring",
1354
+ style: {
1355
+ ...frameStyle(context),
1356
+ gridTemplateRows: `auto auto 1fr ${consoleVisible ? "minmax(8rem, 14rem)" : "0"}`,
1357
+ gridTemplateAreas: `"toolbar" "metrics" "primary" "console"`
1358
+ },
1359
+ children: [
1360
+ slots.toolbar ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "eth-ls-monitoring__toolbar", style: { gridArea: "toolbar" }, children: slots.toolbar }) : null,
1361
+ slots.metrics ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "eth-ls-monitoring__metrics", style: { gridArea: "metrics" }, children: slots.metrics }) : null,
1362
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("main", { className: "eth-ls-monitoring__primary", style: { gridArea: "primary", overflow: "auto", minHeight: 0 }, children: slots.primary }),
1363
+ consoleVisible ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "eth-ls-monitoring__console", style: { gridArea: "console", overflow: "auto", borderBlockStart: `1px solid ${context.tokens.border}` }, children: slots.console }) : null
1364
+ ]
1365
+ }
1366
+ );
1367
+ }
1368
+ var MonitoringOpsLayout = {
1369
+ type: "PageLayout.MonitoringOps",
1370
+ displayName: "Monitoring Ops",
1371
+ tier: "page",
1372
+ category: "page",
1373
+ description: "Realtime ops dashboard: toolbar, metric strip, primary view, console.",
1374
+ slots: [
1375
+ { name: "toolbar", role: "toolbar", accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }] },
1376
+ { name: "metrics", role: "summary", accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }] },
1377
+ {
1378
+ name: "primary",
1379
+ role: "content",
1380
+ required: true,
1381
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }],
1382
+ priority: { value: 100, behaviorOnNarrow: "keep" }
1383
+ },
1384
+ {
1385
+ name: "console",
1386
+ role: "console",
1387
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }],
1388
+ priority: { value: 30, behaviorOnNarrow: "move-to-bottom-sheet" }
1389
+ }
1390
+ ],
1391
+ defaultStyleIntent: { surface: "page", taskMode: "monitoring", dataIntensity: "realtime" },
1392
+ renderer: MonitoringOpsRenderer
1393
+ };
1394
+ function CanvasInspectorRenderer({ slots, context, plan }) {
1395
+ const inspectorVisible = slots.inspector && isVisible(plan, "inspector");
1396
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1397
+ "div",
1398
+ {
1399
+ className: "eth-ls-canvas",
1400
+ style: {
1401
+ ...frameStyle(context),
1402
+ gridTemplateRows: "auto 1fr",
1403
+ gridTemplateColumns: inspectorVisible ? "1fr minmax(18rem, 24rem)" : "1fr",
1404
+ gridTemplateAreas: inspectorVisible ? `"toolbar toolbar" "canvas inspector"` : `"toolbar" "canvas"`
1405
+ },
1406
+ children: [
1407
+ slots.toolbar ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "eth-ls-canvas__toolbar", style: { gridArea: "toolbar" }, children: slots.toolbar }) : null,
1408
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "eth-ls-canvas__stage", style: { gridArea: "canvas", overflow: "hidden", minWidth: 0, minHeight: 0 }, children: slots.canvas }),
1409
+ inspectorVisible ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "eth-ls-canvas__inspector", style: { gridArea: "inspector", overflow: "auto", borderInlineStart: `1px solid ${context.tokens.border}` }, children: slots.inspector }) : null
1410
+ ]
1411
+ }
1412
+ );
1413
+ }
1414
+ var CanvasInspectorLayout = {
1415
+ type: "PageLayout.CanvasInspector",
1416
+ displayName: "Canvas + Inspector",
1417
+ tier: "page",
1418
+ category: "page",
1419
+ description: "Full-bleed canvas with a toolbar and inline-end inspector.",
1420
+ slots: [
1421
+ { name: "toolbar", role: "toolbar", accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }] },
1422
+ {
1423
+ name: "canvas",
1424
+ role: "canvas",
1425
+ required: true,
1426
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }],
1427
+ priority: { value: 100, behaviorOnNarrow: "keep" }
1428
+ },
1429
+ {
1430
+ name: "inspector",
1431
+ role: "inspector",
1432
+ accepts: [{ kind: "component" }, { kind: "layout" }, { kind: "fragment" }],
1433
+ priority: { value: 50, behaviorOnNarrow: "move-to-drawer" }
1434
+ }
1435
+ ],
1436
+ defaultStyleIntent: { surface: "canvas", taskMode: "authoring", visualEmphasis: "immersive" },
1437
+ renderer: CanvasInspectorRenderer
1438
+ };
1439
+ var pageLayouts = [
1440
+ AdminShellLayout,
1441
+ DataGridInspectorLayout,
1442
+ WorkbenchLayout,
1443
+ WizardComposerLayout,
1444
+ MonitoringOpsLayout,
1445
+ CanvasInspectorLayout
1446
+ ];
1447
+
1448
+ // src/layout-system/registry/builtins.ts
1449
+ var builtinLayouts = [
1450
+ ...primitiveLayouts,
1451
+ ...regionLayouts,
1452
+ ...pageLayouts
1453
+ ];
1454
+ function createDefaultLayoutRegistry() {
1455
+ return new LayoutRegistry().registerAll(builtinLayouts);
1456
+ }
1457
+
1458
+ // src/layout-system/runtime/viewport.ts
1459
+ var React4 = __toESM(require("react"), 1);
1460
+ var BREAKPOINTS = [
1461
+ { bp: "ultra", minWidth: 1920 },
1462
+ { bp: "wide", minWidth: 1536 },
1463
+ { bp: "desktop", minWidth: 1280 },
1464
+ { bp: "laptop", minWidth: 1024 },
1465
+ { bp: "tablet", minWidth: 768 },
1466
+ { bp: "mobile", minWidth: 0 }
1467
+ ];
1468
+ function breakpointForWidth(width) {
1469
+ for (const { bp, minWidth } of BREAKPOINTS) {
1470
+ if (width >= minWidth) return bp;
1471
+ }
1472
+ return "mobile";
1473
+ }
1474
+ function readViewport() {
1475
+ if (typeof window === "undefined") return defaultViewport;
1476
+ const width = window.innerWidth;
1477
+ const height = window.innerHeight;
1478
+ const pointer = typeof window.matchMedia === "function" && window.matchMedia("(pointer: coarse)").matches ? "coarse" : "fine";
1479
+ const colorScheme = typeof window.matchMedia === "function" && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
1480
+ return { breakpoint: breakpointForWidth(width), width, height, pointer, colorScheme };
1481
+ }
1482
+ function useViewport(opts = {}) {
1483
+ const { initial = defaultViewport, debounceMs = 120 } = opts;
1484
+ const [viewport, setViewport] = React4.useState(initial);
1485
+ React4.useEffect(() => {
1486
+ if (typeof window === "undefined") return void 0;
1487
+ setViewport(readViewport());
1488
+ let timer;
1489
+ const onResize = () => {
1490
+ if (timer) clearTimeout(timer);
1491
+ timer = setTimeout(() => setViewport(readViewport()), debounceMs);
1492
+ };
1493
+ window.addEventListener("resize", onResize);
1494
+ return () => {
1495
+ if (timer) clearTimeout(timer);
1496
+ window.removeEventListener("resize", onResize);
1497
+ };
1498
+ }, [debounceMs]);
1499
+ return viewport;
1500
+ }
1501
+
1502
+ // src/layout-system/renderer/root.tsx
1503
+ var React5 = __toESM(require("react"), 1);
1504
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1505
+ function LayoutRoot({
1506
+ node,
1507
+ componentResolver,
1508
+ templateResolver,
1509
+ registry,
1510
+ context,
1511
+ stateStore,
1512
+ observeViewport = true,
1513
+ onDiagnostics
1514
+ }) {
1515
+ const resolvedRegistry = React5.useMemo(
1516
+ () => registry ?? createDefaultLayoutRegistry(),
1517
+ [registry]
1518
+ );
1519
+ const observed = useViewport({ initial: context?.viewport });
1520
+ const viewport = observeViewport ? observed : context?.viewport;
1521
+ const rootContext = React5.useMemo(
1522
+ () => createRootContext({ ...context, viewport }),
1523
+ [context, viewport]
1524
+ );
1525
+ const engine = React5.useMemo(
1526
+ () => buildEngine({
1527
+ registry: resolvedRegistry,
1528
+ componentResolver,
1529
+ templateResolver,
1530
+ stateStore,
1531
+ onDiagnostics
1532
+ }),
1533
+ [resolvedRegistry, componentResolver, templateResolver, stateStore, onDiagnostics]
1534
+ );
1535
+ React5.useEffect(() => {
1536
+ if (!onDiagnostics) return;
1537
+ onDiagnostics(validateLayout(node, resolvedRegistry));
1538
+ }, [node, resolvedRegistry, onDiagnostics]);
1539
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LayoutEngineProvider, { value: engine, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LayoutContextProvider, { value: rootContext, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LayoutRenderer, { node }) }) });
1540
+ }
1541
+
1542
+ // src/layout-system/builders.ts
1543
+ function layout(input) {
1544
+ return { kind: "layout", ...input };
1545
+ }
1546
+ function componentSlot(component, props, styleOverride) {
1547
+ return { kind: "component", component, props, styleOverride };
1548
+ }
1549
+ function layoutSlot(node) {
1550
+ return { kind: "layout", layout: node };
1551
+ }
1552
+ function templateSlot(template, props) {
1553
+ return { kind: "template", template, props };
1554
+ }
1555
+ function fragmentSlot(items, composition) {
1556
+ return { kind: "fragment", items, composition };
1557
+ }
1558
+ function emptySlot(reason) {
1559
+ return { kind: "empty", reason };
1560
+ }
1561
+
1562
+ // src/index.tsx
1563
+ var ethBreakpoints = {
1564
+ sm: "36rem",
1565
+ md: "48rem",
1566
+ lg: "64rem",
1567
+ xl: "80rem"
1568
+ };
1569
+ // Annotate the CommonJS export names for ESM import in node:
1570
+ 0 && (module.exports = {
1571
+ LayoutContextProvider,
1572
+ LayoutEngineProvider,
1573
+ LayoutRegistry,
1574
+ LayoutRenderer,
1575
+ LayoutRoot,
1576
+ SlotContentRenderer,
1577
+ StyleScope,
1578
+ breakpointForWidth,
1579
+ breakpointRank,
1580
+ buildEngine,
1581
+ buildStyleInferenceInput,
1582
+ builtinLayouts,
1583
+ componentSlot,
1584
+ composeLayoutContext,
1585
+ createDefaultLayoutRegistry,
1586
+ createMemoryLayoutStateStore,
1587
+ createRootContext,
1588
+ defaultComponentStyle,
1589
+ defaultContextPolicy,
1590
+ defaultStylePreset,
1591
+ defaultViewport,
1592
+ emptySlot,
1593
+ ethBreakpoints,
1594
+ ethDensityModes,
1595
+ ethStylePresetDescriptions,
1596
+ ethStylePresetLabels,
1597
+ ethStylePresets,
1598
+ ethTypeScales,
1599
+ fragmentSlot,
1600
+ hasErrors,
1601
+ inferComponentStyle,
1602
+ inferDensity,
1603
+ inferTypeScale,
1604
+ isNarrow,
1605
+ layout,
1606
+ layoutSlot,
1607
+ pageLayouts,
1608
+ presetTokenMap,
1609
+ primitiveLayouts,
1610
+ regionFor,
1611
+ regionLayouts,
1612
+ resolvePhysicalPlan,
1613
+ resolveTokens,
1614
+ templateSlot,
1615
+ useLayoutContext,
1616
+ useLayoutEngine,
1617
+ useViewport,
1618
+ validateLayout
1619
+ });
1620
+ //# sourceMappingURL=index.cjs.map