view-contracts 0.4.4 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli-contract.yaml +1 -1
- package/dist/preview.mjs +272 -159
- package/dist/preview.mjs.map +4 -4
- package/dist/view-contracts.bundle.mjs +308 -195
- package/dist/view-contracts.bundle.mjs.map +4 -4
- package/docs/cli-reference.md +1 -1
- package/package.json +1 -1
- package/renderers/compose/README.md +7 -8
- package/renderers/compose/element-config.meta.json +20 -0
- package/renderers/compose/elementMap.ts +44 -0
- package/renderers/compose/elements.yaml +82 -0
- package/renderers/compose/index.ts +5 -0
- package/renderers/compose/lowering/lowerToCompose.ts +1062 -0
- package/renderers/compose/lowering/modifiers.ts +449 -0
- package/renderers/compose/properties.yaml +34 -0
- package/renderers/compose/renderComponents.ts +118 -0
- package/renderers/compose/renderRuntime.ts +78 -13
- package/renderers/compose/renderTheme.ts +304 -0
- package/renderers/compose/routes.yaml +7 -0
- package/renderers/compose/templates/Screen.kt.hbs +3 -4
- package/renderers/react/routes.yaml +10 -6
- package/renderers/registry.ts +12 -1
package/docs/cli-reference.md
CHANGED
package/package.json
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
# Compose renderer
|
|
1
|
+
# Compose renderer
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Jetpack Compose renderer implemented as a SwiftUI-parity lowering path:
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- Full vocabulary map in `elements.yaml` (schema-backed).
|
|
6
|
+
- Lowering implementation in `lowering/lowerToCompose.ts`.
|
|
7
|
+
- Modifier synthesis in `lowering/modifiers.ts`.
|
|
8
|
+
- Component emitter in `renderComponents.ts`.
|
|
9
|
+
- Runtime emitter (screens, partials, theme, sample JSON, dispatch stub) in `renderRuntime.ts`.
|
|
6
10
|
|
|
7
11
|
- Maps: `elements.yaml`, `properties.yaml` (hand-maintained under this directory)
|
|
8
12
|
- Routes: `routes.yaml`
|
|
9
13
|
- Templates: `templates/`
|
|
10
14
|
- Theme codegen spec: [../NATIVE_THEME_EMIT.md](../NATIVE_THEME_EMIT.md)
|
|
11
|
-
|
|
12
|
-
Implement Compose code generation by reading View IR + renderer maps.
|
|
13
|
-
Theme is emitted at build time via `src/design/emit/compose.ts` and `templates/theme/*.hbs` — same Token IR + Theme IR as React `theme.css`, not runtime JSON.
|
|
14
|
-
|
|
15
|
-
Vocabulary: `spec/ui-dsl.schema.json` (from `ui-dsl-*.csv`).
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"title": "Compose element map metadata",
|
|
4
|
+
"description": "Auxiliary metadata for renderers/compose/elements.yaml validation and docs.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["elements"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"elements": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"additionalProperties": {
|
|
11
|
+
"type": "object",
|
|
12
|
+
"properties": {
|
|
13
|
+
"container": { "type": "string" },
|
|
14
|
+
"leaf": { "type": "string" },
|
|
15
|
+
"spacingProp": { "type": "string" }
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { ALLOWED_COMPONENTS } from '../../src/schema/dsl-catalog.js';
|
|
3
|
+
import { packageRoot } from '../../src/lib/packageRoot.js';
|
|
4
|
+
import { loadYamlFile, validateVocabularyElementNames } from '../../src/renderer/elementMapValidation.js';
|
|
5
|
+
|
|
6
|
+
export interface ComposeElementConfig {
|
|
7
|
+
container?: 'group' | 'vstack' | 'hstack' | 'navstack' | 'scrollview' | 'field' | 'cellgroup' | 'tablestack';
|
|
8
|
+
leaf?: 'text' | 'button' | 'textfield' | 'texteditor' | 'picker' | 'spacer' | 'divider' | 'image' | 'progressview' | 'toggle';
|
|
9
|
+
spacingProp?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ComposeElementMap {
|
|
13
|
+
elements: Record<string, ComposeElementConfig>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const SOURCE_LABEL = 'renderers/compose/elements.yaml';
|
|
17
|
+
|
|
18
|
+
let cachedMap: ComposeElementMap | null = null;
|
|
19
|
+
|
|
20
|
+
function validateComposeElementMap(map: ComposeElementMap): void {
|
|
21
|
+
validateVocabularyElementNames(Object.keys(map.elements), ALLOWED_COMPONENTS, SOURCE_LABEL);
|
|
22
|
+
for (const [name, entry] of Object.entries(map.elements)) {
|
|
23
|
+
const hasContainer = entry.container !== undefined && entry.container !== null;
|
|
24
|
+
const hasLeaf = entry.leaf !== undefined && entry.leaf !== null;
|
|
25
|
+
if (hasContainer === hasLeaf) {
|
|
26
|
+
throw new Error(
|
|
27
|
+
`${SOURCE_LABEL}: element "${name}" must have exactly one of "container" or "leaf"`,
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function loadComposeElementMap(customPath?: string): Promise<ComposeElementMap> {
|
|
34
|
+
if (!customPath && cachedMap) return cachedMap;
|
|
35
|
+
const mapPath = customPath ?? resolve(packageRoot(), 'renderers/compose/elements.yaml');
|
|
36
|
+
const raw = await loadYamlFile<ComposeElementMap>(mapPath);
|
|
37
|
+
validateComposeElementMap(raw);
|
|
38
|
+
if (!customPath) cachedMap = raw;
|
|
39
|
+
return raw;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function isComposeVocabulary(name: string, map: ComposeElementMap, allowlistExtra: string[] = []): boolean {
|
|
43
|
+
return name in map.elements && !allowlistExtra.includes(name);
|
|
44
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Compose renderer element map — maps DSL elements to Jetpack Compose primitives.
|
|
2
|
+
|
|
3
|
+
elements:
|
|
4
|
+
App:
|
|
5
|
+
container: group
|
|
6
|
+
Page:
|
|
7
|
+
container: navstack
|
|
8
|
+
SafeArea:
|
|
9
|
+
container: group
|
|
10
|
+
Box:
|
|
11
|
+
container: group
|
|
12
|
+
Row:
|
|
13
|
+
container: hstack
|
|
14
|
+
spacingProp: gap
|
|
15
|
+
Column:
|
|
16
|
+
container: vstack
|
|
17
|
+
spacingProp: gap
|
|
18
|
+
Stack:
|
|
19
|
+
container: vstack
|
|
20
|
+
spacingProp: gap
|
|
21
|
+
Spacer:
|
|
22
|
+
leaf: spacer
|
|
23
|
+
Divider:
|
|
24
|
+
leaf: divider
|
|
25
|
+
ScrollArea:
|
|
26
|
+
container: scrollview
|
|
27
|
+
List:
|
|
28
|
+
container: vstack
|
|
29
|
+
spacingProp: gap
|
|
30
|
+
ListItem:
|
|
31
|
+
container: group
|
|
32
|
+
Text:
|
|
33
|
+
leaf: text
|
|
34
|
+
Link:
|
|
35
|
+
leaf: text
|
|
36
|
+
Image:
|
|
37
|
+
leaf: image
|
|
38
|
+
Icon:
|
|
39
|
+
leaf: image
|
|
40
|
+
Button:
|
|
41
|
+
leaf: button
|
|
42
|
+
IconButton:
|
|
43
|
+
leaf: button
|
|
44
|
+
Form:
|
|
45
|
+
container: vstack
|
|
46
|
+
spacingProp: gap
|
|
47
|
+
Field:
|
|
48
|
+
container: field
|
|
49
|
+
TextInput:
|
|
50
|
+
leaf: textfield
|
|
51
|
+
TextArea:
|
|
52
|
+
leaf: texteditor
|
|
53
|
+
Select:
|
|
54
|
+
leaf: picker
|
|
55
|
+
Checkbox:
|
|
56
|
+
leaf: toggle
|
|
57
|
+
Radio:
|
|
58
|
+
leaf: picker
|
|
59
|
+
Switch:
|
|
60
|
+
leaf: toggle
|
|
61
|
+
Modal:
|
|
62
|
+
container: group
|
|
63
|
+
Drawer:
|
|
64
|
+
container: group
|
|
65
|
+
Popover:
|
|
66
|
+
container: group
|
|
67
|
+
Tooltip:
|
|
68
|
+
leaf: text
|
|
69
|
+
Progress:
|
|
70
|
+
leaf: progressview
|
|
71
|
+
Spinner:
|
|
72
|
+
leaf: progressview
|
|
73
|
+
Table:
|
|
74
|
+
container: tablestack
|
|
75
|
+
TableHeader:
|
|
76
|
+
container: hstack
|
|
77
|
+
TableColumn:
|
|
78
|
+
container: cellgroup
|
|
79
|
+
TableRow:
|
|
80
|
+
container: hstack
|
|
81
|
+
TableCell:
|
|
82
|
+
container: cellgroup
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { loadComposeElementMap, isComposeVocabulary } from './elementMap.js';
|
|
2
|
+
export type { ComposeElementConfig, ComposeElementMap } from './elementMap.js';
|
|
3
|
+
export { renderComposeComponent } from './renderComponents.js';
|
|
4
|
+
export { mergeVisualProps } from '../../src/renderer/style/mergeVisualProps.js';
|
|
5
|
+
export { visualPropSetToModifiers } from './lowering/modifiers.js';
|