view-contracts 0.2.0 → 0.3.2

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 (36) hide show
  1. package/README.md +7 -9
  2. package/cli-contract.yaml +1 -38
  3. package/dist/view-contracts.bundle.mjs +208 -254
  4. package/dist/view-contracts.bundle.mjs.map +4 -4
  5. package/docs/cli-reference.md +1 -38
  6. package/package.json +7 -4
  7. package/renderers/compose/templates/Screen.kt.hbs +15 -0
  8. package/renderers/compose/templates/VcTheme.kt.hbs +19 -0
  9. package/renderers/react/README.md +1 -0
  10. package/renderers/react/defaults/theme.yaml +26 -0
  11. package/renderers/react/defaults/tokens.yaml +59 -0
  12. package/renderers/react/element-config.meta.json +2 -1
  13. package/renderers/react/elementMap.ts +4 -2
  14. package/renderers/react/elements.yaml +76 -21
  15. package/renderers/react/lowering/lowerToJsx.ts +183 -28
  16. package/renderers/react/renderComponents.ts +23 -8
  17. package/renderers/react/renderRuntime.ts +24 -75
  18. package/renderers/react/routes.yaml +1 -1
  19. package/renderers/react/runtime/style.ts +45 -36
  20. package/renderers/react/runtime/theme.css +51 -54
  21. package/renderers/react/runtime/types.ts +20 -43
  22. package/renderers/react/syncGeneratedRuntime.ts +77 -0
  23. package/renderers/react/templates/components-index.ts.hbs +1 -1
  24. package/renderers/react/templates/runtime-types.ts.hbs +5 -0
  25. package/renderers/react/templates/style-helpers.ts.hbs +1 -1
  26. package/renderers/swiftui/templates/Screen.swift.hbs +21 -0
  27. package/renderers/swiftui/templates/VcTheme.swift.hbs +21 -0
  28. package/spec/ui-dsl-extensions.meta.json +62 -0
  29. package/spec/ui-dsl.schema.json +24 -16
  30. package/src/generated/schema/allowed-components.ts +1 -1
  31. package/src/generated/schema/{tokens.ts → dsl-enums.ts} +1 -1
  32. package/src/generated/schema/dsl-properties.ts +3 -2
  33. package/src/generated/schema/index.ts +2 -2
  34. package/src/generated/schema/lowering-style-properties.ts +1 -9
  35. package/src/generated/schema/react-renderer-element-config.ts +3 -2
  36. package/src/generated/schema/schema-document.ts +2 -2
@@ -2,7 +2,7 @@
2
2
 
3
3
  Contract-first UI design toolchain. Compiles restricted view-contract TSX to language-neutral View IR and renders platform targets (React, SwiftUI, Compose).
4
4
 
5
- **Version:** 0.1.0
5
+ **Version:** 0.3.2
6
6
 
7
7
  ## Table of Contents
8
8
 
@@ -13,7 +13,6 @@ Contract-first UI design toolchain. Compiles restricted view-contract TSX to lan
13
13
  - [build](#view-contracts-build)
14
14
  - [contracts.generate](#view-contracts-contracts-generate)
15
15
  - [contracts.check](#view-contracts-contracts-check)
16
- - [catalog.build](#view-contracts-catalog-build)
17
16
 
18
17
  ---
19
18
 
@@ -201,39 +200,3 @@ view-contracts contracts check -c view-contracts.config.yaml
201
200
  **Exit 1:** Lint failed.
202
201
 
203
202
  ---
204
-
205
- ### catalog.build
206
-
207
- Build static catalog HTML for design review.
208
-
209
- Renders all registered views with mock ViewModels into a single HTML file for design review, screenshot baselines, and accessibility checks.
210
-
211
- **Usage:**
212
-
213
- ```
214
- view-contracts catalog build
215
- ```
216
- ```
217
- view-contracts catalog build -c view-contracts.config.yaml
218
- ```
219
- ```
220
- view-contracts catalog build -o dist/catalog.html
221
- ```
222
-
223
- #### Options
224
-
225
- | Option | Aliases | Required | Default | Description |
226
- |---|---|---|---|---|
227
- | `--config` | -c | No | | Path to view-contracts.config.yaml (discovered upward from cwd when omitted). |
228
- | `--output` | -o | No | | Output HTML path (defaults to dist/catalog.html next to bindings). |
229
-
230
- #### Exit Codes
231
-
232
- **Exit 0:** Catalog built.
233
-
234
- - **Generated files:**
235
- - `dist/catalog.html` (text/html) *(optional)*
236
-
237
- **Exit 1:** Build failed.
238
-
239
- ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "view-contracts",
3
- "version": "0.2.0",
3
+ "version": "0.3.2",
4
4
  "description": "Contract-first UI design toolchain — restricted TSX to View IR to platform renderers",
5
5
  "type": "module",
6
6
  "workspaces": [
@@ -13,6 +13,7 @@
13
13
  "dist/view-contracts.bundle.mjs",
14
14
  "dist/view-contracts.bundle.mjs.map",
15
15
  "renderers/react/runtime",
16
+ "renderers/react/defaults",
16
17
  "src/generated/schema",
17
18
  "spec",
18
19
  "renderers",
@@ -23,9 +24,9 @@
23
24
  ],
24
25
  "scripts": {
25
26
  "generate": "cli-contracts generate",
26
- "dev": "npm run build:views && npm run dev:both --prefix examples/admin-dashboard",
27
+ "dev": "npm run dev:both --prefix examples/admin-dashboard",
27
28
  "dev:preview": "npm run dev:preview --prefix examples/admin-dashboard",
28
- "dev:app": "npm run dev:app --prefix examples/admin-dashboard",
29
+ "dev:app": "npm run build:views && npm run dev:app --prefix examples/admin-dashboard",
29
30
  "dev:both": "npm run build:views && npm run dev:both --prefix examples/admin-dashboard",
30
31
  "check:both": "npm run check:both --prefix examples/admin-dashboard",
31
32
  "serve:built": "npm run serve:built --prefix examples/admin-dashboard",
@@ -35,7 +36,6 @@
35
36
  "bundle": "node esbuild.bundle.mjs",
36
37
  "bundle:min": "node esbuild.bundle.mjs --minify",
37
38
  "build:views": "tsx src/cli.ts build -c examples/admin-dashboard/view-contracts.config.yaml",
38
- "build:catalog": "tsx src/cli.ts catalog build -c examples/admin-dashboard/view-contracts.config.yaml",
39
39
  "build:example": "vite build --config examples/admin-dashboard/.vite/vite.config.ts",
40
40
  "compile": "tsx src/cli.ts compile -c examples/admin-dashboard/view-contracts.config.yaml",
41
41
  "render:react": "tsx src/cli.ts render react -c examples/admin-dashboard/view-contracts.config.yaml",
@@ -93,6 +93,9 @@
93
93
  "ajv": "^8.18.0",
94
94
  "cli-contracts": "^0.33.13",
95
95
  "esbuild": "^0.28.0",
96
+ "pixelmatch": "^7.2.0",
97
+ "playwright": "^1.61.0",
98
+ "pngjs": "^7.0.0",
96
99
  "tsx": "^4.21.0",
97
100
  "vite": "^6.4.1",
98
101
  "vitest": "^4.1.9"
@@ -0,0 +1,15 @@
1
+ // {{screenName}} — Jetpack Compose scaffold (Phase 5)
2
+ // Theme IR: {{themeJsonPath}}
3
+ // Token IR: {{tokensJsonPath}}
4
+ //
5
+ // TODO(Phase C): Load theme.json and emit Modifier.primaryButton(), vcTextMuted(), etc.
6
+
7
+ package {{packageName}}
8
+
9
+ import androidx.compose.material3.Text
10
+ import androidx.compose.runtime.Composable
11
+
12
+ @Composable
13
+ fun {{screenName}}Screen() {
14
+ Text("{{screenName}} — Compose scaffold")
15
+ }
@@ -0,0 +1,19 @@
1
+ // VcTheme — Compose theme scaffold (Phase 5)
2
+ // Load Token IR + Theme IR from assets:
3
+ // {{tokensJsonPath}}
4
+ // {{themeJsonPath}}
5
+ //
6
+ // TODO(Phase C): Map Theme IR variants to Modifier extensions and ColorScheme.
7
+
8
+ package {{packageName}}
9
+
10
+ import android.content.Context
11
+
12
+ object VcTheme {
13
+ const val TOKENS_ASSET = "{{tokensJsonPath}}"
14
+ const val THEME_ASSET = "{{themeJsonPath}}"
15
+
16
+ /** Placeholder — read theme.json from assets in Phase C. */
17
+ fun loadThemeJson(context: Context): String? =
18
+ context.assets.open(THEME_ASSET).bufferedReader().use { it.readText() }
19
+ }
@@ -12,6 +12,7 @@ Per-target mapping for view-contracts UI DSL → React.
12
12
 
13
13
  Vocabulary (elements/properties) is defined in `spec/ui-dsl.schema.json` (from `ui-dsl-*.csv`).
14
14
  Preview vocabulary stubs are generated to `src/generated/preview/vocabulary.tsx`.
15
+ React `elements.yaml` now covers the full UI DSL vocabulary (33/33 elements).
15
16
  Sample-only preview helpers (Sidebar, Card, etc.) are **not** part of the vocabulary — they live in project `src/components/extensions.tsx`.
16
17
 
17
18
  Generic renderer utilities (template engine, YAML element-map validation) live under `src/renderer/`.
@@ -0,0 +1,26 @@
1
+ # Default theme variants — generic vocabulary only (no sample-specific layouts).
2
+ variants:
3
+ Button:
4
+ primary:
5
+ background: "{ui.primary}"
6
+ foreground: "{ui.on-primary}"
7
+ secondary:
8
+ background: "{ui.button-secondary}"
9
+ foreground: "{ui.text}"
10
+ ghost:
11
+ background: "{ui.transparent}"
12
+ foreground: "{ui.text}"
13
+ danger:
14
+ background: "{ui.danger}"
15
+ foreground: "{ui.on-primary}"
16
+ Text:
17
+ muted:
18
+ foreground: "{ui.text-muted}"
19
+ primary:
20
+ foreground: "{ui.primary}"
21
+ success:
22
+ foreground: "{ui.success}"
23
+ warning:
24
+ foreground: "{ui.warning}"
25
+ danger:
26
+ foreground: "{ui.danger}"
@@ -0,0 +1,59 @@
1
+ # Default design tokens — mirrors renderers/react/runtime/theme.css :root variables.
2
+ ui:
3
+ bg:
4
+ $type: color
5
+ $value: "#f6f8fb"
6
+ surface:
7
+ $type: color
8
+ $value: "#ffffff"
9
+ surface-muted:
10
+ $type: color
11
+ $value: "#f8fafc"
12
+ text:
13
+ $type: color
14
+ $value: "#111827"
15
+ text-muted:
16
+ $type: color
17
+ $value: "#6b7280"
18
+ primary:
19
+ $type: color
20
+ $value: "#2563eb"
21
+ primary-weak:
22
+ $type: color
23
+ $value: "#dbeafe"
24
+ success:
25
+ $type: color
26
+ $value: "#047857"
27
+ success-weak:
28
+ $type: color
29
+ $value: "#d1fae5"
30
+ warning:
31
+ $type: color
32
+ $value: "#b45309"
33
+ warning-weak:
34
+ $type: color
35
+ $value: "#fef3c7"
36
+ danger:
37
+ $type: color
38
+ $value: "#dc2626"
39
+ danger-weak:
40
+ $type: color
41
+ $value: "#fee2e2"
42
+ on-primary:
43
+ $type: color
44
+ $value: "#ffffff"
45
+ button-secondary:
46
+ $type: color
47
+ $value: "#eef2f7"
48
+ transparent:
49
+ $type: color
50
+ $value: "transparent"
51
+ border:
52
+ $type: color
53
+ $value: "#e5e7eb"
54
+ shadow:
55
+ $type: shadow
56
+ $value: "0 10px 30px rgba(15, 23, 42, 0.08)"
57
+ font:
58
+ $type: typography
59
+ $value: 'Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif'
@@ -12,12 +12,13 @@
12
12
  "levelProp": { "type": "string" },
13
13
  "defaultLevel": { "type": "number" },
14
14
  "actionEvent": { "type": "enum", "values": ["onClick", "onSubmit"] },
15
- "variantClass": { "type": "boolean" },
16
15
  "fieldWrap": { "type": "boolean" },
17
16
  "inputType": { "type": "string" },
18
17
  "sizeClass": { "type": "string" },
19
18
  "optionsProp": { "type": "string" },
20
19
  "checkbox": { "type": "boolean" },
20
+ "fieldContainer": { "type": "boolean" },
21
+ "scrollContainer": { "type": "boolean" },
21
22
  "defaultRole": { "type": "string" }
22
23
  }
23
24
  }
@@ -40,16 +40,18 @@ export function isLowerableVocabularyElement(
40
40
  return ALLOWED_COMPONENTS.has(name) && !allowlistExtra.includes(name) && name in map.elements;
41
41
  }
42
42
 
43
- export async function assertElementMapCoversImplementedVocabulary(customPath?: string): Promise<void> {
43
+ export async function validateElementMapCoversVocabulary(customPath?: string): Promise<void> {
44
44
  const [schema, map] = await Promise.all([loadUiDslSchema(), loadReactElementMap(customPath)]);
45
45
  const missing = Object.keys(schema.elements).filter((name) => !(name in map.elements));
46
46
  if (missing.length > 0) {
47
- console.warn(
47
+ throw new Error(
48
48
  `${SOURCE_LABEL}: ${missing.length} DSL element(s) have no React HTML map yet: ${missing.join(', ')}`,
49
49
  );
50
50
  }
51
51
  }
52
52
 
53
+ export const assertElementMapCoversImplementedVocabulary = validateElementMapCoversVocabulary;
54
+
53
55
  export function isVocabularyElement(name: string, map: ReactElementMapFile, allowlistExtra: string[] = []): boolean {
54
56
  return name in map.elements && !allowlistExtra.includes(name);
55
57
  }
@@ -3,85 +3,140 @@
3
3
  # (allowlistExtra) and stay as React component imports — not listed here.
4
4
 
5
5
  elements:
6
+ App:
7
+ tag: div
8
+ className: vc-app
6
9
  Page:
7
10
  tag: main
8
- className: ui-page
11
+ className: vc-page
9
12
  ariaLabel: true
13
+ SafeArea:
14
+ tag: div
15
+ className: vc-safe-area
10
16
  Box:
11
17
  tag: div
12
- className: ui-box
18
+ className: vc-box
13
19
  ariaLabel: true
14
20
  Column:
15
21
  tag: div
16
- className: ui-column
22
+ className: vc-column
17
23
  flex: column
18
24
  ariaLabel: true
19
25
  Row:
20
26
  tag: div
21
- className: ui-row
27
+ className: vc-row
22
28
  flex: row
23
29
  wrapProp: wrap
24
30
  ariaLabel: true
25
31
  Stack:
26
32
  tag: div
27
- className: ui-stack
33
+ className: vc-stack
28
34
  ariaLabel: true
35
+ ScrollArea:
36
+ tag: div
37
+ className: vc-scroll-area
38
+ scrollContainer: true
29
39
  Spacer:
30
40
  tag: div
31
- className: ui-spacer
41
+ className: vc-spacer
32
42
  ariaHidden: true
33
43
  flexGrowProp: weight
34
44
  Divider:
35
45
  tag: hr
36
- className: ui-divider
46
+ className: vc-divider
37
47
  void: true
38
48
  Heading:
39
49
  tag: dynamic-heading
40
- className: ui-heading
50
+ className: vc-heading
41
51
  levelProp: level
42
52
  defaultLevel: 2
43
53
  Text:
44
54
  tag: p
45
- className: ui-text
55
+ className: vc-text
56
+ Image:
57
+ tag: img
58
+ className: vc-image
59
+ void: true
60
+ Icon:
61
+ tag: span
62
+ className: vc-icon
63
+ ariaHidden: true
46
64
  Link:
47
65
  tag: a
48
- className: ui-link
66
+ className: vc-link
49
67
  actionEvent: onClick
50
68
  Button:
51
69
  tag: button
52
- className: ui-button
53
- variantClass: true
70
+ className: vc-button
71
+ actionEvent: onClick
72
+ IconButton:
73
+ tag: button
74
+ className: vc-icon-button
54
75
  actionEvent: onClick
76
+ ariaLabel: true
55
77
  Form:
56
78
  tag: form
57
- className: ui-form
79
+ className: vc-form
58
80
  actionEvent: onSubmit
59
81
  ariaLabel: true
82
+ Field:
83
+ tag: div
84
+ className: vc-field-container
85
+ fieldContainer: true
60
86
  TextInput:
61
87
  tag: input
62
- className: ui-input
88
+ className: vc-text-input
63
89
  fieldWrap: true
64
90
  inputType: text
65
- sizeClass: ui-field
91
+ sizeClass: vc-field
66
92
  TextArea:
67
93
  tag: textarea
68
- className: ui-textarea
94
+ className: vc-text-area
69
95
  fieldWrap: true
70
96
  Select:
71
97
  tag: select
72
- className: ui-select
98
+ className: vc-select
73
99
  fieldWrap: true
74
- sizeClass: ui-field
100
+ sizeClass: vc-field
75
101
  optionsProp: options
76
102
  Checkbox:
77
103
  tag: label
78
- className: ui-check
104
+ className: vc-checkbox
79
105
  checkbox: true
106
+ Radio:
107
+ tag: label
108
+ className: vc-radio
109
+ Switch:
110
+ tag: label
111
+ className: vc-switch
112
+ Modal:
113
+ tag: dialog
114
+ className: vc-modal
115
+ defaultRole: dialog
116
+ Drawer:
117
+ tag: aside
118
+ className: vc-drawer
119
+ defaultRole: dialog
120
+ Popover:
121
+ tag: div
122
+ className: vc-popover
123
+ defaultRole: dialog
124
+ Tooltip:
125
+ tag: span
126
+ className: vc-tooltip
127
+ defaultRole: tooltip
128
+ Progress:
129
+ tag: progress
130
+ className: vc-progress
131
+ void: true
132
+ Spinner:
133
+ tag: div
134
+ className: vc-spinner
80
135
  List:
81
136
  tag: ul
82
- className: ui-list
137
+ className: vc-list
83
138
  defaultRole: list
84
139
  ListItem:
85
140
  tag: li
86
- className: ui-list-item
141
+ className: vc-list-item
87
142
  defaultRole: listitem