@topogram/cli 0.3.51 → 0.3.53

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 (77) hide show
  1. package/ARCHITECTURE.md +4 -4
  2. package/CHANGELOG.md +11 -11
  3. package/package.json +1 -1
  4. package/src/adoption/plan.js +2 -2
  5. package/src/agent-ops/query-builders.js +42 -33
  6. package/src/cli.js +174 -129
  7. package/src/generator/adapters.d.ts +1 -0
  8. package/src/generator/adapters.js +64 -39
  9. package/src/generator/check.js +19 -12
  10. package/src/generator/context/diff.js +9 -9
  11. package/src/generator/context/domain-coverage.js +11 -10
  12. package/src/generator/context/domain-page.js +6 -6
  13. package/src/generator/context/shared.js +37 -21
  14. package/src/generator/context/slice.js +70 -65
  15. package/src/generator/index.js +12 -12
  16. package/src/generator/output.js +21 -20
  17. package/src/generator/registry.js +71 -49
  18. package/src/generator/runtime/app-bundle.js +15 -15
  19. package/src/generator/runtime/compile-check.js +7 -7
  20. package/src/generator/runtime/deployment.js +9 -9
  21. package/src/generator/runtime/environment.js +39 -39
  22. package/src/generator/runtime/runtime-check.js +5 -5
  23. package/src/generator/runtime/shared.js +40 -38
  24. package/src/generator/runtime/smoke.js +5 -5
  25. package/src/generator/surfaces/databases/contract.js +1 -1
  26. package/src/generator/surfaces/databases/lifecycle-shared.js +6 -5
  27. package/src/generator/surfaces/databases/postgres/drizzle.js +3 -2
  28. package/src/generator/surfaces/databases/postgres/prisma.js +3 -2
  29. package/src/generator/surfaces/databases/shared.js +3 -2
  30. package/src/generator/surfaces/databases/snapshot.js +1 -1
  31. package/src/generator/surfaces/databases/sqlite/prisma.js +3 -2
  32. package/src/generator/surfaces/native/swiftui-app.js +3 -3
  33. package/src/generator/surfaces/native/swiftui-templates/Package.swift.txt +1 -1
  34. package/src/generator/surfaces/native/swiftui-templates/README.generated.md +3 -3
  35. package/src/generator/surfaces/native/swiftui-templates/runtime/DynamicScreens.swift +3 -3
  36. package/src/generator/surfaces/services/persistence-wiring.js +3 -2
  37. package/src/generator/surfaces/services/server-contract.js +4 -4
  38. package/src/generator/surfaces/shared.js +2 -2
  39. package/src/generator/surfaces/web/design-intent.js +1 -1
  40. package/src/generator/surfaces/web/index.js +7 -7
  41. package/src/generator/surfaces/web/{react-components.js → react-widgets.js} +53 -53
  42. package/src/generator/surfaces/web/react.js +36 -36
  43. package/src/generator/surfaces/web/{sveltekit-components.js → sveltekit-widgets.js} +53 -53
  44. package/src/generator/surfaces/web/sveltekit.js +34 -34
  45. package/src/generator/surfaces/web/{ui-web-contract.js → ui-surface-contract.js} +8 -8
  46. package/src/generator/surfaces/web/vanilla.js +6 -6
  47. package/src/generator/{component-conformance.js → widget-conformance.js} +129 -128
  48. package/src/generator/widgets.js +40 -0
  49. package/src/generator-policy.js +10 -12
  50. package/src/import/core/runner.js +34 -34
  51. package/src/import/core/shared.js +1 -1
  52. package/src/import/extractors/ui/android-compose.js +1 -1
  53. package/src/import/extractors/ui/blazor.js +1 -1
  54. package/src/import/extractors/ui/razor-pages.js +1 -1
  55. package/src/import/extractors/ui/react-router.js +4 -4
  56. package/src/import/extractors/ui/sveltekit.js +4 -4
  57. package/src/import/extractors/ui/swiftui.js +1 -1
  58. package/src/import/extractors/ui/uikit.js +1 -1
  59. package/src/new-project.js +19 -18
  60. package/src/project-config.js +104 -44
  61. package/src/proofs/contract-audit.js +1 -1
  62. package/src/proofs/ios-parity.js +1 -1
  63. package/src/proofs/issues-parity.js +1 -1
  64. package/src/realization/backend/build-backend-runtime-realization.js +2 -2
  65. package/src/realization/ui/build-ui-shared-realization.js +33 -33
  66. package/src/realization/ui/build-web-realization.js +23 -20
  67. package/src/reconcile/journeys.js +1 -1
  68. package/src/resolver/index.js +148 -65
  69. package/src/validator/index.js +509 -423
  70. package/src/validator/kinds.js +36 -36
  71. package/src/validator/per-kind/{component.js → widget.js} +47 -47
  72. package/src/{component-behavior.js → widget-behavior.js} +3 -3
  73. package/src/workflows.js +39 -38
  74. package/template-helpers/react.js +4 -4
  75. package/template-helpers/sveltekit.js +4 -4
  76. package/src/generator/components.js +0 -39
  77. /package/src/resolver/enrich/{component.js → widget.js} +0 -0
@@ -3,12 +3,12 @@
3
3
  import { UI_GENERATOR_RENDERED_COMPONENT_PATTERNS } from "../../../ui/taxonomy.js";
4
4
 
5
5
  /**
6
- * @typedef {{ id?: string, name?: string }} ComponentReference
7
- * @typedef {{ component?: ComponentReference, region?: string, pattern?: string }} ComponentUsage
8
- * @typedef {{ patterns?: string[] }} ComponentContract
9
- * @typedef {Record<string, ComponentContract>} ComponentContractMap
10
- * @typedef {{ itemsExpression?: string, componentContracts?: ComponentContractMap, useTypescript?: boolean }} RenderOptions
11
- * @typedef {{ components?: ComponentUsage[] }} ScreenContract
6
+ * @typedef {{ id?: string, name?: string }} WidgetReference
7
+ * @typedef {{ widget?: WidgetReference, region?: string, pattern?: string }} WidgetUsage
8
+ * @typedef {{ patterns?: string[] }} WidgetContract
9
+ * @typedef {Record<string, WidgetContract>} WidgetContractMap
10
+ * @typedef {{ itemsExpression?: string, widgetContracts?: WidgetContractMap, useTypescript?: boolean }} RenderOptions
11
+ * @typedef {{ widgets?: WidgetUsage[] }} ScreenContract
12
12
  */
13
13
 
14
14
  /**
@@ -33,44 +33,44 @@ function escapeText(value) {
33
33
  }
34
34
 
35
35
  /**
36
- * @param {ComponentUsage} usage
36
+ * @param {WidgetUsage} usage
37
37
  * @returns {string}
38
38
  */
39
- function componentName(usage) {
40
- return usage?.component?.name || usage?.component?.id || "Component";
39
+ function widgetName(usage) {
40
+ return usage?.widget?.name || usage?.widget?.id || "Widget";
41
41
  }
42
42
 
43
43
  /**
44
- * @param {ComponentUsage} usage
44
+ * @param {WidgetUsage} usage
45
45
  * @returns {string}
46
46
  */
47
- function componentId(usage) {
48
- return usage?.component?.id || "component";
47
+ function widgetId(usage) {
48
+ return usage?.widget?.id || "widget";
49
49
  }
50
50
 
51
51
  /**
52
- * @param {ComponentUsage} usage
53
- * @param {ComponentContractMap | undefined} componentContracts
52
+ * @param {WidgetUsage} usage
53
+ * @param {WidgetContractMap | undefined} widgetContracts
54
54
  * @returns {string[]}
55
55
  */
56
- function componentPatterns(usage, componentContracts) {
57
- const id = usage?.component?.id;
58
- const contract = id ? componentContracts?.[id] : null;
56
+ function widgetPatterns(usage, widgetContracts) {
57
+ const id = usage?.widget?.id;
58
+ const contract = id ? widgetContracts?.[id] : null;
59
59
  return Array.isArray(contract?.patterns) ? contract.patterns : [];
60
60
  }
61
61
 
62
62
  /**
63
- * @param {ComponentUsage} usage
64
- * @param {ComponentContractMap | undefined} componentContracts
63
+ * @param {WidgetUsage} usage
64
+ * @param {WidgetContractMap | undefined} widgetContracts
65
65
  * @param {string} pattern
66
66
  * @returns {boolean}
67
67
  */
68
- function usagePattern(usage, componentContracts) {
69
- return usage?.pattern || componentPatterns(usage, componentContracts)[0] || null;
68
+ function usagePattern(usage, widgetContracts) {
69
+ return usage?.pattern || widgetPatterns(usage, widgetContracts)[0] || null;
70
70
  }
71
71
 
72
- export function reactComponentUsageSupport(usage, componentContracts) {
73
- const pattern = usagePattern(usage, componentContracts);
72
+ export function reactWidgetUsageSupport(usage, widgetContracts) {
73
+ const pattern = usagePattern(usage, widgetContracts);
74
74
  return {
75
75
  pattern,
76
76
  supported: UI_GENERATOR_RENDERED_COMPONENT_PATTERNS.has(pattern || "")
@@ -78,16 +78,16 @@ export function reactComponentUsageSupport(usage, componentContracts) {
78
78
  }
79
79
 
80
80
  /**
81
- * @param {ComponentUsage} usage
81
+ * @param {WidgetUsage} usage
82
82
  * @param {RenderOptions} options
83
83
  * @returns {string}
84
84
  */
85
85
  function renderSummaryStats(usage, options) {
86
86
  const items = options.itemsExpression || "items";
87
- return `<section className="component-card component-summary" data-topogram-component="${escapeAttribute(componentId(usage))}">
87
+ return `<section className="widget-card widget-summary" data-topogram-widget="${escapeAttribute(widgetId(usage))}">
88
88
  <div>
89
- <p className="component-eyebrow">Component</p>
90
- <h2>${escapeText(componentName(usage))}</h2>
89
+ <p className="widget-eyebrow">Widget</p>
90
+ <h2>${escapeText(widgetName(usage))}</h2>
91
91
  </div>
92
92
  <div className="summary-grid">
93
93
  <div>
@@ -107,22 +107,22 @@ function renderSummaryStats(usage, options) {
107
107
  }
108
108
 
109
109
  /**
110
- * @param {ComponentUsage} usage
110
+ * @param {WidgetUsage} usage
111
111
  * @param {RenderOptions} options
112
112
  * @returns {string}
113
113
  */
114
114
  function renderCollectionTable(usage, options) {
115
115
  const items = options.itemsExpression || "items";
116
116
  const itemParam = options.useTypescript ? "(item: any)" : "(item)";
117
- return `<div className="component-card component-table" data-topogram-component="${escapeAttribute(componentId(usage))}">
118
- <div className="component-header">
117
+ return `<div className="widget-card widget-table" data-topogram-widget="${escapeAttribute(widgetId(usage))}">
118
+ <div className="widget-header">
119
119
  <div>
120
- <p className="component-eyebrow">Component</p>
121
- <h2>${escapeText(componentName(usage))}</h2>
120
+ <p className="widget-eyebrow">Widget</p>
121
+ <h2>${escapeText(widgetName(usage))}</h2>
122
122
  </div>
123
123
  <span className="badge">{${items}.length} items</span>
124
124
  </div>
125
- <div className="table-wrap component-table-wrap">
125
+ <div className="table-wrap widget-table-wrap">
126
126
  <table className="resource-table data-grid">
127
127
  <thead>
128
128
  <tr>
@@ -146,18 +146,18 @@ function renderCollectionTable(usage, options) {
146
146
  }
147
147
 
148
148
  /**
149
- * @param {ComponentUsage} usage
149
+ * @param {WidgetUsage} usage
150
150
  * @param {RenderOptions} options
151
151
  * @returns {string}
152
152
  */
153
153
  function renderBoard(usage, options) {
154
154
  const items = options.itemsExpression || "items";
155
155
  const itemParam = options.useTypescript ? "(item: any)" : "(item)";
156
- return `<div className="component-card component-board" data-topogram-component="${escapeAttribute(componentId(usage))}">
157
- <div className="component-header">
156
+ return `<div className="widget-card widget-board" data-topogram-widget="${escapeAttribute(widgetId(usage))}">
157
+ <div className="widget-header">
158
158
  <div>
159
- <p className="component-eyebrow">Component</p>
160
- <h2>${escapeText(componentName(usage))}</h2>
159
+ <p className="widget-eyebrow">Widget</p>
160
+ <h2>${escapeText(widgetName(usage))}</h2>
161
161
  </div>
162
162
  </div>
163
163
  <div className="board-grid">
@@ -176,18 +176,18 @@ function renderBoard(usage, options) {
176
176
  }
177
177
 
178
178
  /**
179
- * @param {ComponentUsage} usage
179
+ * @param {WidgetUsage} usage
180
180
  * @param {RenderOptions} options
181
181
  * @returns {string}
182
182
  */
183
183
  function renderCalendar(usage, options) {
184
184
  const items = options.itemsExpression || "items";
185
185
  const itemParam = options.useTypescript ? "(item: any)" : "(item)";
186
- return `<div className="component-card component-calendar" data-topogram-component="${escapeAttribute(componentId(usage))}">
187
- <div className="component-header">
186
+ return `<div className="widget-card widget-calendar" data-topogram-widget="${escapeAttribute(widgetId(usage))}">
187
+ <div className="widget-header">
188
188
  <div>
189
- <p className="component-eyebrow">Component</p>
190
- <h2>${escapeText(componentName(usage))}</h2>
189
+ <p className="widget-eyebrow">Widget</p>
190
+ <h2>${escapeText(widgetName(usage))}</h2>
191
191
  </div>
192
192
  </div>
193
193
  <div className="calendar-list">
@@ -202,13 +202,13 @@ function renderCalendar(usage, options) {
202
202
  }
203
203
 
204
204
  /**
205
- * @param {ComponentUsage} usage
205
+ * @param {WidgetUsage} usage
206
206
  * @param {RenderOptions} options
207
207
  * @returns {string}
208
208
  */
209
209
  function renderUsage(usage, options) {
210
- const componentContracts = options.componentContracts || {};
211
- const { pattern } = reactComponentUsageSupport(usage, componentContracts);
210
+ const widgetContracts = options.widgetContracts || {};
211
+ const { pattern } = reactWidgetUsageSupport(usage, widgetContracts);
212
212
  if (pattern === "summary_stats") {
213
213
  return renderSummaryStats(usage, options);
214
214
  }
@@ -227,10 +227,10 @@ function renderUsage(usage, options) {
227
227
  /**
228
228
  * @param {ScreenContract} screen
229
229
  * @param {string} region
230
- * @returns {ComponentUsage[]}
230
+ * @returns {WidgetUsage[]}
231
231
  */
232
- export function reactComponentUsagesForRegion(screen, region) {
233
- return (screen?.components || []).filter((usage) => usage?.region === region);
232
+ export function reactWidgetUsagesForRegion(screen, region) {
233
+ return (screen?.widgets || []).filter((usage) => usage?.region === region);
234
234
  }
235
235
 
236
236
  /**
@@ -238,8 +238,8 @@ export function reactComponentUsagesForRegion(screen, region) {
238
238
  * @param {string} region
239
239
  * @returns {boolean}
240
240
  */
241
- export function hasReactComponentRegion(screen, region) {
242
- return reactComponentUsagesForRegion(screen, region).length > 0;
241
+ export function hasReactWidgetRegion(screen, region) {
242
+ return reactWidgetUsagesForRegion(screen, region).length > 0;
243
243
  }
244
244
 
245
245
  /**
@@ -248,8 +248,8 @@ export function hasReactComponentRegion(screen, region) {
248
248
  * @param {RenderOptions} [options]
249
249
  * @returns {string}
250
250
  */
251
- export function renderReactComponentRegion(screen, region, options = {}) {
252
- const rendered = reactComponentUsagesForRegion(screen, region)
251
+ export function renderReactWidgetRegion(screen, region, options = {}) {
252
+ const rendered = reactWidgetUsagesForRegion(screen, region)
253
253
  .map((usage) => renderUsage(usage, options))
254
254
  .filter(Boolean);
255
255
  if (rendered.length === 0) {
@@ -1,9 +1,9 @@
1
1
  import { buildWebRealization } from "../../../realization/ui/index.js";
2
2
  import { getExampleImplementation } from "../../../example-implementation.js";
3
3
  import {
4
- reactComponentUsageSupport,
5
- renderReactComponentRegion
6
- } from "./react-components.js";
4
+ reactWidgetUsageSupport,
5
+ renderReactWidgetRegion
6
+ } from "./react-widgets.js";
7
7
  import { buildDesignIntentCoverage, renderDesignIntentCss } from "./design-intent.js";
8
8
  import { renderApiClientModule, renderLookupModule, renderVisibilityModule } from "./shared.js";
9
9
 
@@ -52,7 +52,7 @@ function screenRegions(screen) {
52
52
  for (const region of screen?.regions || []) {
53
53
  if (region?.name) names.add(region.name);
54
54
  }
55
- for (const usage of screen?.components || []) {
55
+ for (const usage of screen?.widgets || []) {
56
56
  if (usage?.region) names.add(usage.region);
57
57
  }
58
58
  return [...names];
@@ -76,7 +76,7 @@ function sampleItemsForScreen(screen) {
76
76
  title: `${title} completed sample`,
77
77
  name: `${title} completed sample`,
78
78
  message: `${title} completed sample`,
79
- description: "Second generated row for component rendering checks.",
79
+ description: "Second generated row for widget rendering checks.",
80
80
  status: "completed",
81
81
  priority: "low",
82
82
  created_at: "2026-01-02"
@@ -137,8 +137,8 @@ function buildReactScreenPage(screen, contract) {
137
137
  const sampleItems = sampleItemsForScreen(screen);
138
138
  const renderedRegions = screenRegions(screen)
139
139
  .map((region) => {
140
- const rendered = renderReactComponentRegion(screen, region, {
141
- componentContracts: contract.components,
140
+ const rendered = renderReactWidgetRegion(screen, region, {
141
+ widgetContracts: contract.widgets,
142
142
  itemsExpression: "items",
143
143
  useTypescript: true
144
144
  });
@@ -188,8 +188,8 @@ ${renderedRegions || ` ${defaultCollection}`}
188
188
  `;
189
189
  }
190
190
 
191
- function screenComponentUsages(screen) {
192
- return Array.isArray(screen?.components) ? screen.components : [];
191
+ function screenWidgetUsages(screen) {
192
+ return Array.isArray(screen?.widgets) ? screen.widgets : [];
193
193
  }
194
194
 
195
195
  function screenPagePath(screen) {
@@ -217,38 +217,38 @@ function buildReactGenerationCoverage(contract, files, routeScreens) {
217
217
  suggested_fix: "Check the React generator contract-complete route emission for this screen."
218
218
  });
219
219
  }
220
- const componentUsages = screenComponentUsages(screen).map((usage) => {
221
- const componentId = usage.component?.id || null;
222
- const marker = componentId ? `data-topogram-component="${componentId}"` : null;
223
- const support = reactComponentUsageSupport(usage, contract.components);
220
+ const widgetUsages = screenWidgetUsages(screen).map((usage) => {
221
+ const widgetId = usage.widget?.id || null;
222
+ const marker = widgetId ? `data-topogram-widget="${widgetId}"` : null;
223
+ const support = reactWidgetUsageSupport(usage, contract.widgets);
224
224
  const usageRendered = Boolean(marker && contents.includes(marker));
225
- if (componentId && rendered && !support.supported) {
225
+ if (widgetId && rendered && !support.supported) {
226
226
  diagnostics.push({
227
- code: "component_pattern_not_supported",
227
+ code: "widget_pattern_not_supported",
228
228
  severity: "error",
229
229
  screen: screen.id,
230
230
  route: screen.route,
231
231
  region: usage.region || null,
232
232
  pattern: support.pattern || null,
233
- component: componentId,
234
- message: `Screen '${screen.id}' uses component '${componentId}' with unsupported React component pattern '${support.pattern || "(missing)"}'.`,
235
- suggested_fix: "Use a supported component pattern for this generator or provide an implementation override."
233
+ widget: widgetId,
234
+ message: `Screen '${screen.id}' uses widget '${widgetId}' with unsupported React widget pattern '${support.pattern || "(missing)"}'.`,
235
+ suggested_fix: "Use a supported widget pattern for this generator or provide an implementation override."
236
236
  });
237
237
  }
238
- if (componentId && rendered && !usageRendered) {
238
+ if (widgetId && rendered && !usageRendered) {
239
239
  diagnostics.push({
240
- code: "component_usage_not_rendered",
240
+ code: "widget_usage_not_rendered",
241
241
  severity: "warning",
242
242
  screen: screen.id,
243
243
  route: screen.route,
244
244
  region: usage.region || null,
245
- component: componentId,
246
- message: `Screen '${screen.id}' uses component '${componentId}' but the generated React page does not contain its component marker.`,
247
- suggested_fix: "Render the component region with renderReactComponentRegion or add a supported component pattern."
245
+ widget: widgetId,
246
+ message: `Screen '${screen.id}' uses widget '${widgetId}' but the generated React page does not contain its widget marker.`,
247
+ suggested_fix: "Render the widget region with renderReactWidgetRegion or add a supported widget pattern."
248
248
  });
249
249
  }
250
250
  return {
251
- component: componentId,
251
+ widget: widgetId,
252
252
  region: usage.region || null,
253
253
  pattern: support.pattern || null,
254
254
  supported: support.supported,
@@ -262,7 +262,7 @@ function buildReactGenerationCoverage(contract, files, routeScreens) {
262
262
  page: pagePath,
263
263
  rendered,
264
264
  renderer: rendered ? "generator" : "missing",
265
- component_usages: componentUsages
265
+ widget_usages: widgetUsages
266
266
  };
267
267
  });
268
268
 
@@ -273,16 +273,16 @@ function buildReactGenerationCoverage(contract, files, routeScreens) {
273
273
  projection: {
274
274
  id: contract.projection.id,
275
275
  name: contract.projection.name,
276
- platform: contract.projection.platform
276
+ type: contract.projection.type
277
277
  },
278
278
  summary: {
279
279
  routed_screens: screens.length,
280
280
  rendered_screens: screens.filter((screen) => screen.rendered).length,
281
281
  implementation_screens: 0,
282
282
  generator_screens: screens.filter((screen) => screen.renderer === "generator").length,
283
- component_usages: screens.reduce((total, screen) => total + screen.component_usages.length, 0),
284
- rendered_component_usages: screens.reduce(
285
- (total, screen) => total + screen.component_usages.filter((usage) => usage.rendered).length,
283
+ widget_usages: screens.reduce((total, screen) => total + screen.widget_usages.length, 0),
284
+ rendered_widget_usages: screens.reduce(
285
+ (total, screen) => total + screen.widget_usages.filter((usage) => usage.rendered).length,
286
286
  0
287
287
  ),
288
288
  diagnostics: diagnostics.length,
@@ -481,7 +481,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
481
481
  );
482
482
  `;
483
483
  files["src/vite-env.d.ts"] = `/// <reference types="vite/client" />\n`;
484
- files["src/app.css"] = `${renderDesignIntentCss(contract.design)}
484
+ files["src/app.css"] = `${renderDesignIntentCss(contract.designTokens)}
485
485
 
486
486
  :root {
487
487
  font-family: system-ui, sans-serif;
@@ -536,11 +536,11 @@ button:focus-visible, .button-link:focus-visible, a:focus-visible, input:focus-v
536
536
  .muted { color: var(--topogram-muted-color); }
537
537
  .empty-state { padding: 1rem 0; }
538
538
  .error-text { color: #b42318; }
539
- .component-card { border: 1px solid var(--topogram-border-color); border-radius: var(--topogram-radius-card); background: var(--topogram-surface-subtle); padding: 1rem; margin-top: 1rem; }
540
- .component-header { display: flex; align-items: center; justify-content: space-between; gap: var(--topogram-space-unit); flex-wrap: wrap; }
541
- .component-eyebrow { margin: 0 0 0.25rem; color: var(--topogram-muted-color); font-size: 0.75rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; }
542
- .component-card h2, .component-card h3 { margin: 0; }
543
- .component-table-wrap { margin-top: 1rem; }
539
+ .widget-card { border: 1px solid var(--topogram-border-color); border-radius: var(--topogram-radius-card); background: var(--topogram-surface-subtle); padding: 1rem; margin-top: 1rem; }
540
+ .widget-header { display: flex; align-items: center; justify-content: space-between; gap: var(--topogram-space-unit); flex-wrap: wrap; }
541
+ .widget-eyebrow { margin: 0 0 0.25rem; color: var(--topogram-muted-color); font-size: 0.75rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; }
542
+ .widget-card h2, .widget-card h3 { margin: 0; }
543
+ .widget-table-wrap { margin-top: 1rem; }
544
544
  .summary-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr)); gap: 0.75rem; }
545
545
  .summary-grid div, .board-column { border: 1px solid #e0e8f1; border-radius: var(--topogram-radius-control); background: white; padding: 0.85rem; }
546
546
  .summary-grid strong { display: block; font-size: 1.5rem; }
@@ -553,7 +553,7 @@ button:focus-visible, .button-link:focus-visible, a:focus-visible, input:focus-v
553
553
  `;
554
554
  files["src/App.tsx"] = buildAppTsx(contract, webReferenceWithDefaults);
555
555
  files["src/lib/topogram/api-contracts.json"] = `${JSON.stringify(realization.apiContracts, null, 2)}\n`;
556
- files["src/lib/topogram/ui-web-contract.json"] = `${JSON.stringify(contract, null, 2)}\n`;
556
+ files["src/lib/topogram/ui-surface-contract.json"] = `${JSON.stringify(contract, null, 2)}\n`;
557
557
  files["src/lib/auth/visibility.ts"] = buildReactVisibilityModule();
558
558
  files["src/lib/api/client.ts"] = buildReactClientModule(webReferenceWithDefaults);
559
559
  files["src/lib/api/lookups.ts"] = buildLookupModule(webReferenceWithDefaults);
@@ -3,12 +3,12 @@
3
3
  import { UI_GENERATOR_RENDERED_COMPONENT_PATTERNS } from "../../../ui/taxonomy.js";
4
4
 
5
5
  /**
6
- * @typedef {{ id?: string, name?: string }} ComponentReference
7
- * @typedef {{ component?: ComponentReference, region?: string, pattern?: string }} ComponentUsage
8
- * @typedef {{ patterns?: string[] }} ComponentContract
9
- * @typedef {Record<string, ComponentContract>} ComponentContractMap
10
- * @typedef {{ itemsExpression?: string, componentContracts?: ComponentContractMap, useTypescript?: boolean }} RenderOptions
11
- * @typedef {{ components?: ComponentUsage[] }} ScreenContract
6
+ * @typedef {{ id?: string, name?: string }} WidgetReference
7
+ * @typedef {{ widget?: WidgetReference, region?: string, pattern?: string }} WidgetUsage
8
+ * @typedef {{ patterns?: string[] }} WidgetContract
9
+ * @typedef {Record<string, WidgetContract>} WidgetContractMap
10
+ * @typedef {{ itemsExpression?: string, widgetContracts?: WidgetContractMap, useTypescript?: boolean }} RenderOptions
11
+ * @typedef {{ widgets?: WidgetUsage[] }} ScreenContract
12
12
  */
13
13
 
14
14
  /**
@@ -24,44 +24,44 @@ function escapeHtml(value) {
24
24
  }
25
25
 
26
26
  /**
27
- * @param {ComponentUsage} usage
27
+ * @param {WidgetUsage} usage
28
28
  * @returns {string}
29
29
  */
30
- function componentName(usage) {
31
- return usage?.component?.name || usage?.component?.id || "Component";
30
+ function widgetName(usage) {
31
+ return usage?.widget?.name || usage?.widget?.id || "Widget";
32
32
  }
33
33
 
34
34
  /**
35
- * @param {ComponentUsage} usage
35
+ * @param {WidgetUsage} usage
36
36
  * @returns {string}
37
37
  */
38
- function componentId(usage) {
39
- return usage?.component?.id || "component";
38
+ function widgetId(usage) {
39
+ return usage?.widget?.id || "widget";
40
40
  }
41
41
 
42
42
  /**
43
- * @param {ComponentUsage} usage
44
- * @param {ComponentContractMap | undefined} componentContracts
43
+ * @param {WidgetUsage} usage
44
+ * @param {WidgetContractMap | undefined} widgetContracts
45
45
  * @returns {string[]}
46
46
  */
47
- function componentPatterns(usage, componentContracts) {
48
- const id = usage?.component?.id;
49
- const contract = id ? componentContracts?.[id] : null;
47
+ function widgetPatterns(usage, widgetContracts) {
48
+ const id = usage?.widget?.id;
49
+ const contract = id ? widgetContracts?.[id] : null;
50
50
  return Array.isArray(contract?.patterns) ? contract.patterns : [];
51
51
  }
52
52
 
53
53
  /**
54
- * @param {ComponentUsage} usage
55
- * @param {ComponentContractMap | undefined} componentContracts
54
+ * @param {WidgetUsage} usage
55
+ * @param {WidgetContractMap | undefined} widgetContracts
56
56
  * @param {string} pattern
57
57
  * @returns {boolean}
58
58
  */
59
- function usagePattern(usage, componentContracts) {
60
- return usage?.pattern || componentPatterns(usage, componentContracts)[0] || null;
59
+ function usagePattern(usage, widgetContracts) {
60
+ return usage?.pattern || widgetPatterns(usage, widgetContracts)[0] || null;
61
61
  }
62
62
 
63
- export function svelteKitComponentUsageSupport(usage, componentContracts) {
64
- const pattern = usagePattern(usage, componentContracts);
63
+ export function svelteKitWidgetUsageSupport(usage, widgetContracts) {
64
+ const pattern = usagePattern(usage, widgetContracts);
65
65
  return {
66
66
  pattern,
67
67
  supported: UI_GENERATOR_RENDERED_COMPONENT_PATTERNS.has(pattern || "")
@@ -69,16 +69,16 @@ export function svelteKitComponentUsageSupport(usage, componentContracts) {
69
69
  }
70
70
 
71
71
  /**
72
- * @param {ComponentUsage} usage
72
+ * @param {WidgetUsage} usage
73
73
  * @param {RenderOptions} options
74
74
  * @returns {string}
75
75
  */
76
76
  function renderSummaryStats(usage, options) {
77
77
  const items = options.itemsExpression || "data.result.items";
78
- return `<section class="component-card component-summary" data-topogram-component="${escapeHtml(componentId(usage))}">
78
+ return `<section class="widget-card widget-summary" data-topogram-widget="${escapeHtml(widgetId(usage))}">
79
79
  <div>
80
- <p class="component-eyebrow">Component</p>
81
- <h2>${escapeHtml(componentName(usage))}</h2>
80
+ <p class="widget-eyebrow">Widget</p>
81
+ <h2>${escapeHtml(widgetName(usage))}</h2>
82
82
  </div>
83
83
  <div class="summary-grid">
84
84
  <div>
@@ -98,21 +98,21 @@ function renderSummaryStats(usage, options) {
98
98
  }
99
99
 
100
100
  /**
101
- * @param {ComponentUsage} usage
101
+ * @param {WidgetUsage} usage
102
102
  * @param {RenderOptions} options
103
103
  * @returns {string}
104
104
  */
105
105
  function renderCollectionTable(usage, options) {
106
106
  const items = options.itemsExpression || "data.result.items";
107
- return `<div class="component-card component-table" data-topogram-component="${escapeHtml(componentId(usage))}">
108
- <div class="component-header">
107
+ return `<div class="widget-card widget-table" data-topogram-widget="${escapeHtml(widgetId(usage))}">
108
+ <div class="widget-header">
109
109
  <div>
110
- <p class="component-eyebrow">Component</p>
111
- <h2>${escapeHtml(componentName(usage))}</h2>
110
+ <p class="widget-eyebrow">Widget</p>
111
+ <h2>${escapeHtml(widgetName(usage))}</h2>
112
112
  </div>
113
113
  <span class="badge">{${items}.length} items</span>
114
114
  </div>
115
- <div class="table-wrap component-table-wrap">
115
+ <div class="table-wrap widget-table-wrap">
116
116
  <table class="resource-table data-grid">
117
117
  <thead>
118
118
  <tr>
@@ -136,17 +136,17 @@ function renderCollectionTable(usage, options) {
136
136
  }
137
137
 
138
138
  /**
139
- * @param {ComponentUsage} usage
139
+ * @param {WidgetUsage} usage
140
140
  * @param {RenderOptions} options
141
141
  * @returns {string}
142
142
  */
143
143
  function renderBoard(usage, options) {
144
144
  const items = options.itemsExpression || "data.result.items";
145
- return `<div class="component-card component-board" data-topogram-component="${escapeHtml(componentId(usage))}">
146
- <div class="component-header">
145
+ return `<div class="widget-card widget-board" data-topogram-widget="${escapeHtml(widgetId(usage))}">
146
+ <div class="widget-header">
147
147
  <div>
148
- <p class="component-eyebrow">Component</p>
149
- <h2>${escapeHtml(componentName(usage))}</h2>
148
+ <p class="widget-eyebrow">Widget</p>
149
+ <h2>${escapeHtml(widgetName(usage))}</h2>
150
150
  </div>
151
151
  </div>
152
152
  <div class="board-grid">
@@ -163,17 +163,17 @@ function renderBoard(usage, options) {
163
163
  }
164
164
 
165
165
  /**
166
- * @param {ComponentUsage} usage
166
+ * @param {WidgetUsage} usage
167
167
  * @param {RenderOptions} options
168
168
  * @returns {string}
169
169
  */
170
170
  function renderCalendar(usage, options) {
171
171
  const items = options.itemsExpression || "data.result.items";
172
- return `<div class="component-card component-calendar" data-topogram-component="${escapeHtml(componentId(usage))}">
173
- <div class="component-header">
172
+ return `<div class="widget-card widget-calendar" data-topogram-widget="${escapeHtml(widgetId(usage))}">
173
+ <div class="widget-header">
174
174
  <div>
175
- <p class="component-eyebrow">Component</p>
176
- <h2>${escapeHtml(componentName(usage))}</h2>
175
+ <p class="widget-eyebrow">Widget</p>
176
+ <h2>${escapeHtml(widgetName(usage))}</h2>
177
177
  </div>
178
178
  </div>
179
179
  <div class="calendar-list">
@@ -188,13 +188,13 @@ function renderCalendar(usage, options) {
188
188
  }
189
189
 
190
190
  /**
191
- * @param {ComponentUsage} usage
191
+ * @param {WidgetUsage} usage
192
192
  * @param {RenderOptions} options
193
193
  * @returns {string}
194
194
  */
195
195
  function renderUsage(usage, options) {
196
- const componentContracts = options.componentContracts || {};
197
- const { pattern } = svelteKitComponentUsageSupport(usage, componentContracts);
196
+ const widgetContracts = options.widgetContracts || {};
197
+ const { pattern } = svelteKitWidgetUsageSupport(usage, widgetContracts);
198
198
  if (pattern === "summary_stats") {
199
199
  return renderSummaryStats(usage, options);
200
200
  }
@@ -213,10 +213,10 @@ function renderUsage(usage, options) {
213
213
  /**
214
214
  * @param {ScreenContract} screen
215
215
  * @param {string} region
216
- * @returns {ComponentUsage[]}
216
+ * @returns {WidgetUsage[]}
217
217
  */
218
- export function svelteKitComponentUsagesForRegion(screen, region) {
219
- return (screen?.components || []).filter((usage) => usage?.region === region);
218
+ export function svelteKitWidgetUsagesForRegion(screen, region) {
219
+ return (screen?.widgets || []).filter((usage) => usage?.region === region);
220
220
  }
221
221
 
222
222
  /**
@@ -224,8 +224,8 @@ export function svelteKitComponentUsagesForRegion(screen, region) {
224
224
  * @param {string} region
225
225
  * @returns {boolean}
226
226
  */
227
- export function hasSvelteKitComponentRegion(screen, region) {
228
- return svelteKitComponentUsagesForRegion(screen, region).length > 0;
227
+ export function hasSvelteKitWidgetRegion(screen, region) {
228
+ return svelteKitWidgetUsagesForRegion(screen, region).length > 0;
229
229
  }
230
230
 
231
231
  /**
@@ -234,8 +234,8 @@ export function hasSvelteKitComponentRegion(screen, region) {
234
234
  * @param {RenderOptions} [options]
235
235
  * @returns {string}
236
236
  */
237
- export function renderSvelteKitComponentRegion(screen, region, options = {}) {
238
- const rendered = svelteKitComponentUsagesForRegion(screen, region)
237
+ export function renderSvelteKitWidgetRegion(screen, region, options = {}) {
238
+ const rendered = svelteKitWidgetUsagesForRegion(screen, region)
239
239
  .map((usage) => renderUsage(usage, options))
240
240
  .filter(Boolean);
241
241
  if (rendered.length === 0) {