@json-render/react-native 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/{chunk-T27PQA6P.mjs → chunk-TAJ5ASZ5.mjs} +6 -3
- package/dist/chunk-TAJ5ASZ5.mjs.map +1 -0
- package/dist/index.js +38 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +36 -11
- package/dist/index.mjs.map +1 -1
- package/dist/schema.d.mts +22 -2
- package/dist/schema.d.ts +22 -2
- package/dist/schema.js +5 -2
- package/dist/schema.js.map +1 -1
- package/dist/schema.mjs +1 -1
- package/package.json +4 -4
- package/dist/chunk-T27PQA6P.mjs.map +0 -1
package/dist/schema.d.mts
CHANGED
|
@@ -20,7 +20,17 @@ declare const schema: _json_render_core.Schema<{
|
|
|
20
20
|
/** Child element keys (flat reference) */
|
|
21
21
|
children: _json_render_core.SchemaType<"array", _json_render_core.SchemaType<"string", unknown>>;
|
|
22
22
|
/** Visibility condition */
|
|
23
|
-
visible:
|
|
23
|
+
visible: {
|
|
24
|
+
optional: true;
|
|
25
|
+
kind: "any";
|
|
26
|
+
inner?: unknown;
|
|
27
|
+
};
|
|
28
|
+
/** Repeat children from a state array */
|
|
29
|
+
repeat: {
|
|
30
|
+
optional: true;
|
|
31
|
+
kind: "any";
|
|
32
|
+
inner?: unknown;
|
|
33
|
+
};
|
|
24
34
|
}>>;
|
|
25
35
|
}>;
|
|
26
36
|
catalog: _json_render_core.SchemaType<"object", {
|
|
@@ -70,7 +80,17 @@ declare const elementTreeSchema: _json_render_core.Schema<{
|
|
|
70
80
|
/** Child element keys (flat reference) */
|
|
71
81
|
children: _json_render_core.SchemaType<"array", _json_render_core.SchemaType<"string", unknown>>;
|
|
72
82
|
/** Visibility condition */
|
|
73
|
-
visible:
|
|
83
|
+
visible: {
|
|
84
|
+
optional: true;
|
|
85
|
+
kind: "any";
|
|
86
|
+
inner?: unknown;
|
|
87
|
+
};
|
|
88
|
+
/** Repeat children from a state array */
|
|
89
|
+
repeat: {
|
|
90
|
+
optional: true;
|
|
91
|
+
kind: "any";
|
|
92
|
+
inner?: unknown;
|
|
93
|
+
};
|
|
74
94
|
}>>;
|
|
75
95
|
}>;
|
|
76
96
|
catalog: _json_render_core.SchemaType<"object", {
|
package/dist/schema.d.ts
CHANGED
|
@@ -20,7 +20,17 @@ declare const schema: _json_render_core.Schema<{
|
|
|
20
20
|
/** Child element keys (flat reference) */
|
|
21
21
|
children: _json_render_core.SchemaType<"array", _json_render_core.SchemaType<"string", unknown>>;
|
|
22
22
|
/** Visibility condition */
|
|
23
|
-
visible:
|
|
23
|
+
visible: {
|
|
24
|
+
optional: true;
|
|
25
|
+
kind: "any";
|
|
26
|
+
inner?: unknown;
|
|
27
|
+
};
|
|
28
|
+
/** Repeat children from a state array */
|
|
29
|
+
repeat: {
|
|
30
|
+
optional: true;
|
|
31
|
+
kind: "any";
|
|
32
|
+
inner?: unknown;
|
|
33
|
+
};
|
|
24
34
|
}>>;
|
|
25
35
|
}>;
|
|
26
36
|
catalog: _json_render_core.SchemaType<"object", {
|
|
@@ -70,7 +80,17 @@ declare const elementTreeSchema: _json_render_core.Schema<{
|
|
|
70
80
|
/** Child element keys (flat reference) */
|
|
71
81
|
children: _json_render_core.SchemaType<"array", _json_render_core.SchemaType<"string", unknown>>;
|
|
72
82
|
/** Visibility condition */
|
|
73
|
-
visible:
|
|
83
|
+
visible: {
|
|
84
|
+
optional: true;
|
|
85
|
+
kind: "any";
|
|
86
|
+
inner?: unknown;
|
|
87
|
+
};
|
|
88
|
+
/** Repeat children from a state array */
|
|
89
|
+
repeat: {
|
|
90
|
+
optional: true;
|
|
91
|
+
kind: "any";
|
|
92
|
+
inner?: unknown;
|
|
93
|
+
};
|
|
74
94
|
}>>;
|
|
75
95
|
}>;
|
|
76
96
|
catalog: _json_render_core.SchemaType<"object", {
|
package/dist/schema.js
CHANGED
|
@@ -41,7 +41,9 @@ var schema = (0, import_core.defineSchema)(
|
|
|
41
41
|
/** Child element keys (flat reference) */
|
|
42
42
|
children: s.array(s.string()),
|
|
43
43
|
/** Visibility condition */
|
|
44
|
-
visible: s.any()
|
|
44
|
+
visible: { ...s.any(), ...s.optional() },
|
|
45
|
+
/** Repeat children from a state array */
|
|
46
|
+
repeat: { ...s.any(), ...s.optional() }
|
|
45
47
|
})
|
|
46
48
|
)
|
|
47
49
|
}),
|
|
@@ -75,7 +77,8 @@ var schema = (0, import_core.defineSchema)(
|
|
|
75
77
|
// Element integrity
|
|
76
78
|
"CRITICAL INTEGRITY CHECK: Before outputting ANY element that references children, you MUST have already output (or will output) each child as its own element. If an element has children: ['a', 'b'], then elements 'a' and 'b' MUST exist. A missing child element causes that entire branch of the UI to be invisible.",
|
|
77
79
|
"SELF-CHECK: After generating all elements, mentally walk the tree from root. Every key in every children array must resolve to a defined element. If you find a gap, output the missing element immediately.",
|
|
78
|
-
'
|
|
80
|
+
'REQUIRED FIELDS: Every element MUST include a "children" array. Leaf elements (text, badges, inputs, images) use an empty array: "children": []. Omitting "children" fails validation.',
|
|
81
|
+
'When building repeating content backed by a state array (e.g. todos, posts, cart items), use the "repeat" field on a container element from the AVAILABLE COMPONENTS list. Example: { "type": "<ContainerComponent>", "props": { "gap": 8 }, "repeat": { "statePath": "/todos", "key": "id" }, "children": ["todo-item"] }. For a nested list stored on the enclosing item, use "repeat": { "statePath": { "$item": "comments" }, "key": "id" }. The $item statePath form is valid only inside another repeat. Inside repeated children, use { "$item": "field" } to read a field from the current item, and { "$index": true } for the current array index. For two-way binding to an item field use { "$bindItem": "completed" }. Do NOT hardcode individual elements for each array item.',
|
|
79
82
|
// Visible field placement
|
|
80
83
|
'CRITICAL: The "visible" field goes on the ELEMENT object, NOT inside "props". Correct: {"type":"<ComponentName>","props":{},"visible":{"$state":"/activeTab","eq":"home"},"children":[...]}. WRONG: {"type":"<ComponentName>","props":{},"visible":{...},"children":[...]} with visible inside props.',
|
|
81
84
|
// Tab navigation pattern
|
package/dist/schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schema.ts"],"sourcesContent":["import { defineSchema } from \"@json-render/core\";\n\n/**\n * The schema for @json-render/react-native\n *\n * Defines:\n * - Spec: A flat tree of elements with keys, types, props, and children references\n * - Catalog: Components with props schemas, and optional actions\n */\nexport const schema = defineSchema(\n (s) => ({\n // What the AI-generated SPEC looks like\n spec: s.object({\n /** Root element key */\n root: s.string(),\n /** Flat map of elements by key */\n elements: s.record(\n s.object({\n /** Component type from catalog */\n type: s.ref(\"catalog.components\"),\n /** Component props */\n props: s.propsOf(\"catalog.components\"),\n /** Child element keys (flat reference) */\n children: s.array(s.string()),\n /** Visibility condition */\n visible: s.any(),\n }),\n ),\n }),\n\n // What the CATALOG must provide\n catalog: s.object({\n /** Component definitions */\n components: s.map({\n /** Zod schema for component props */\n props: s.zod(),\n /** Slots for this component. Use ['default'] for children, or named slots like ['header', 'footer'] */\n slots: s.array(s.string()),\n /** Description for AI generation hints */\n description: s.string(),\n /** Example prop values used in prompt examples (auto-generated from Zod schema if omitted) */\n example: s.any(),\n }),\n /** Action definitions (optional) */\n actions: s.map({\n /** Zod schema for action params */\n params: s.zod(),\n /** Description for AI generation hints */\n description: s.string(),\n }),\n }),\n }),\n {\n defaultRules: [\n // Layout patterns\n \"FIXED BOTTOM BAR PATTERN: When building a screen with a fixed header and/or fixed bottom tab bar, the outermost vertical layout component must have flex:1 so it fills the screen. The scrollable content area must also have flex:1. Structure: screen wrapper > vertical layout(flex:1, gap:0) > [header, content wrapper(flex:1) > [scroll container(...)], bottom-tabs]. Both the outer layout AND the content wrapper need flex:1. ONLY use components from the AVAILABLE COMPONENTS list.\",\n \"NEVER place a bottom tab bar or fixed footer inside a scroll container. It must be a sibling AFTER the flex:1 container that holds the scroll content.\",\n\n // Element integrity\n \"CRITICAL INTEGRITY CHECK: Before outputting ANY element that references children, you MUST have already output (or will output) each child as its own element. If an element has children: ['a', 'b'], then elements 'a' and 'b' MUST exist. A missing child element causes that entire branch of the UI to be invisible.\",\n \"SELF-CHECK: After generating all elements, mentally walk the tree from root. Every key in every children array must resolve to a defined element. If you find a gap, output the missing element immediately.\",\n 'When building repeating content backed by a state array (e.g. todos, posts, cart items), use the \"repeat\" field on a container element from the AVAILABLE COMPONENTS list. Example: { \"type\": \"<ContainerComponent>\", \"props\": { \"gap\": 8 }, \"repeat\": { \"statePath\": \"/todos\", \"key\": \"id\" }, \"children\": [\"todo-item\"] }. Inside repeated children, use { \"$item\": \"field\" } to read a field from the current item, and { \"$index\": true } for the current array index. For two-way binding to an item field use { \"$bindItem\": \"completed\" }. Do NOT hardcode individual elements for each array item.',\n\n // Visible field placement\n 'CRITICAL: The \"visible\" field goes on the ELEMENT object, NOT inside \"props\". Correct: {\"type\":\"<ComponentName>\",\"props\":{},\"visible\":{\"$state\":\"/activeTab\",\"eq\":\"home\"},\"children\":[...]}. WRONG: {\"type\":\"<ComponentName>\",\"props\":{},\"visible\":{...},\"children\":[...]} with visible inside props.',\n\n // Tab navigation pattern\n \"TAB NAVIGATION PATTERN: When building a UI with multiple tabs, use a pressable/tappable component + setState action + visible conditions to make tabs functional. ONLY use components from the AVAILABLE COMPONENTS list.\",\n 'Each tab button should be a pressable component wrapping its icon/label children, with action \"setState\" and actionParams { \"statePath\": \"/activeTab\", \"value\": \"tabName\" }.',\n 'Each tab\\'s content section should have a visible condition: { \"$state\": \"/activeTab\", \"eq\": \"tabName\" }.',\n \"The first tab's content should NOT have a visible condition (so it shows by default when no tab is selected yet). All other tabs MUST have a visible condition.\",\n\n // Tab active state highlighting (using dynamic props)\n \"TAB ACTIVE STYLING: Use $cond dynamic props on icon elements inside each tab button so a single icon changes appearance based on the active tab.\",\n ' - For the icon name: { \"$cond\": { \"$state\": \"/activeTab\", \"eq\": \"thisTabName\" }, \"$then\": \"home\", \"$else\": \"home-outline\" }',\n ' - For the icon color: { \"$cond\": { \"$state\": \"/activeTab\", \"eq\": \"thisTabName\" }, \"$then\": \"#007AFF\", \"$else\": \"#8E8E93\" }',\n \" - For labels, use $cond on the color prop similarly.\",\n ' - For the FIRST/DEFAULT tab, use { \"$cond\": [{ \"$state\": \"/activeTab\", \"eq\": \"thisTabName\" }], \"$then\": \"#007AFF\", \"$else\": \"#8E8E93\" } so it appears active before any tab is tapped. When no tab is selected yet, include a default tab with no visible condition.',\n\n // Push/pop screen navigation (all screens in one spec)\n 'SCREEN NAVIGATION: Use a pressable component with action \"push\" and actionParams { \"screen\": \"screenName\" } to navigate to a new screen. Use action \"pop\" to go back. All screens must be defined in the SAME spec. ONLY use components from the AVAILABLE COMPONENTS list.',\n 'Each screen section uses a visible condition on /currentScreen: { \"$state\": \"/currentScreen\", \"eq\": \"screenName\" }. The default/home screen should show by default (no visible condition) and all other screens should have the appropriate visible condition.',\n \"push automatically maintains a /navStack in the state model so pop always returns to the previous screen.\",\n 'Include a back button on pushed screens using action \"pop\". Example: pressable(action:\"pop\") > row layout > back icon + back label. ONLY use components from the AVAILABLE COMPONENTS list.',\n \"Use push/pop for drill-down flows: tapping a list item to see details, opening a profile, etc. Use setState + visible conditions for tab switching within a screen.\",\n 'Example: A list screen with items that push to detail: a pressable component with action:\"push\" and actionParams:{screen:\"detail\"} wrapping each list item. The detail screen section has visible:{\"$state\":\"/currentScreen\",\"eq\":\"detail\"} and contains a back button with action:\"pop\". ONLY use components from the AVAILABLE COMPONENTS list.',\n ],\n },\n);\n\n/**\n * Type for the React Native schema\n */\nexport type ReactNativeSchema = typeof schema;\n\n/**\n * Infer the spec type from a catalog\n */\nexport type ReactNativeSpec<TCatalog> = typeof schema extends {\n createCatalog: (catalog: TCatalog) => { _specType: infer S };\n}\n ? S\n : never;\n\n// Backward compatibility aliases\n/** @deprecated Use `schema` instead */\nexport const elementTreeSchema = schema;\n/** @deprecated Use `ReactNativeSchema` instead */\nexport type ElementTreeSchema = ReactNativeSchema;\n/** @deprecated Use `ReactNativeSpec` instead */\nexport type ElementTreeSpec<T> = ReactNativeSpec<T>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAA6B;AAStB,IAAM,aAAS;AAAA,EACpB,CAAC,OAAO;AAAA;AAAA,IAEN,MAAM,EAAE,OAAO;AAAA;AAAA,MAEb,MAAM,EAAE,OAAO;AAAA;AAAA,MAEf,UAAU,EAAE;AAAA,QACV,EAAE,OAAO;AAAA;AAAA,UAEP,MAAM,EAAE,IAAI,oBAAoB;AAAA;AAAA,UAEhC,OAAO,EAAE,QAAQ,oBAAoB;AAAA;AAAA,UAErC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA;AAAA,UAE5B,SAAS,EAAE,IAAI;AAAA,
|
|
1
|
+
{"version":3,"sources":["../src/schema.ts"],"sourcesContent":["import { defineSchema } from \"@json-render/core\";\n\n/**\n * The schema for @json-render/react-native\n *\n * Defines:\n * - Spec: A flat tree of elements with keys, types, props, and children references\n * - Catalog: Components with props schemas, and optional actions\n */\nexport const schema = defineSchema(\n (s) => ({\n // What the AI-generated SPEC looks like\n spec: s.object({\n /** Root element key */\n root: s.string(),\n /** Flat map of elements by key */\n elements: s.record(\n s.object({\n /** Component type from catalog */\n type: s.ref(\"catalog.components\"),\n /** Component props */\n props: s.propsOf(\"catalog.components\"),\n /** Child element keys (flat reference) */\n children: s.array(s.string()),\n /** Visibility condition */\n visible: { ...s.any(), ...s.optional() },\n /** Repeat children from a state array */\n repeat: { ...s.any(), ...s.optional() },\n }),\n ),\n }),\n\n // What the CATALOG must provide\n catalog: s.object({\n /** Component definitions */\n components: s.map({\n /** Zod schema for component props */\n props: s.zod(),\n /** Slots for this component. Use ['default'] for children, or named slots like ['header', 'footer'] */\n slots: s.array(s.string()),\n /** Description for AI generation hints */\n description: s.string(),\n /** Example prop values used in prompt examples (auto-generated from Zod schema if omitted) */\n example: s.any(),\n }),\n /** Action definitions (optional) */\n actions: s.map({\n /** Zod schema for action params */\n params: s.zod(),\n /** Description for AI generation hints */\n description: s.string(),\n }),\n }),\n }),\n {\n defaultRules: [\n // Layout patterns\n \"FIXED BOTTOM BAR PATTERN: When building a screen with a fixed header and/or fixed bottom tab bar, the outermost vertical layout component must have flex:1 so it fills the screen. The scrollable content area must also have flex:1. Structure: screen wrapper > vertical layout(flex:1, gap:0) > [header, content wrapper(flex:1) > [scroll container(...)], bottom-tabs]. Both the outer layout AND the content wrapper need flex:1. ONLY use components from the AVAILABLE COMPONENTS list.\",\n \"NEVER place a bottom tab bar or fixed footer inside a scroll container. It must be a sibling AFTER the flex:1 container that holds the scroll content.\",\n\n // Element integrity\n \"CRITICAL INTEGRITY CHECK: Before outputting ANY element that references children, you MUST have already output (or will output) each child as its own element. If an element has children: ['a', 'b'], then elements 'a' and 'b' MUST exist. A missing child element causes that entire branch of the UI to be invisible.\",\n \"SELF-CHECK: After generating all elements, mentally walk the tree from root. Every key in every children array must resolve to a defined element. If you find a gap, output the missing element immediately.\",\n 'REQUIRED FIELDS: Every element MUST include a \"children\" array. Leaf elements (text, badges, inputs, images) use an empty array: \"children\": []. Omitting \"children\" fails validation.',\n 'When building repeating content backed by a state array (e.g. todos, posts, cart items), use the \"repeat\" field on a container element from the AVAILABLE COMPONENTS list. Example: { \"type\": \"<ContainerComponent>\", \"props\": { \"gap\": 8 }, \"repeat\": { \"statePath\": \"/todos\", \"key\": \"id\" }, \"children\": [\"todo-item\"] }. For a nested list stored on the enclosing item, use \"repeat\": { \"statePath\": { \"$item\": \"comments\" }, \"key\": \"id\" }. The $item statePath form is valid only inside another repeat. Inside repeated children, use { \"$item\": \"field\" } to read a field from the current item, and { \"$index\": true } for the current array index. For two-way binding to an item field use { \"$bindItem\": \"completed\" }. Do NOT hardcode individual elements for each array item.',\n\n // Visible field placement\n 'CRITICAL: The \"visible\" field goes on the ELEMENT object, NOT inside \"props\". Correct: {\"type\":\"<ComponentName>\",\"props\":{},\"visible\":{\"$state\":\"/activeTab\",\"eq\":\"home\"},\"children\":[...]}. WRONG: {\"type\":\"<ComponentName>\",\"props\":{},\"visible\":{...},\"children\":[...]} with visible inside props.',\n\n // Tab navigation pattern\n \"TAB NAVIGATION PATTERN: When building a UI with multiple tabs, use a pressable/tappable component + setState action + visible conditions to make tabs functional. ONLY use components from the AVAILABLE COMPONENTS list.\",\n 'Each tab button should be a pressable component wrapping its icon/label children, with action \"setState\" and actionParams { \"statePath\": \"/activeTab\", \"value\": \"tabName\" }.',\n 'Each tab\\'s content section should have a visible condition: { \"$state\": \"/activeTab\", \"eq\": \"tabName\" }.',\n \"The first tab's content should NOT have a visible condition (so it shows by default when no tab is selected yet). All other tabs MUST have a visible condition.\",\n\n // Tab active state highlighting (using dynamic props)\n \"TAB ACTIVE STYLING: Use $cond dynamic props on icon elements inside each tab button so a single icon changes appearance based on the active tab.\",\n ' - For the icon name: { \"$cond\": { \"$state\": \"/activeTab\", \"eq\": \"thisTabName\" }, \"$then\": \"home\", \"$else\": \"home-outline\" }',\n ' - For the icon color: { \"$cond\": { \"$state\": \"/activeTab\", \"eq\": \"thisTabName\" }, \"$then\": \"#007AFF\", \"$else\": \"#8E8E93\" }',\n \" - For labels, use $cond on the color prop similarly.\",\n ' - For the FIRST/DEFAULT tab, use { \"$cond\": [{ \"$state\": \"/activeTab\", \"eq\": \"thisTabName\" }], \"$then\": \"#007AFF\", \"$else\": \"#8E8E93\" } so it appears active before any tab is tapped. When no tab is selected yet, include a default tab with no visible condition.',\n\n // Push/pop screen navigation (all screens in one spec)\n 'SCREEN NAVIGATION: Use a pressable component with action \"push\" and actionParams { \"screen\": \"screenName\" } to navigate to a new screen. Use action \"pop\" to go back. All screens must be defined in the SAME spec. ONLY use components from the AVAILABLE COMPONENTS list.',\n 'Each screen section uses a visible condition on /currentScreen: { \"$state\": \"/currentScreen\", \"eq\": \"screenName\" }. The default/home screen should show by default (no visible condition) and all other screens should have the appropriate visible condition.',\n \"push automatically maintains a /navStack in the state model so pop always returns to the previous screen.\",\n 'Include a back button on pushed screens using action \"pop\". Example: pressable(action:\"pop\") > row layout > back icon + back label. ONLY use components from the AVAILABLE COMPONENTS list.',\n \"Use push/pop for drill-down flows: tapping a list item to see details, opening a profile, etc. Use setState + visible conditions for tab switching within a screen.\",\n 'Example: A list screen with items that push to detail: a pressable component with action:\"push\" and actionParams:{screen:\"detail\"} wrapping each list item. The detail screen section has visible:{\"$state\":\"/currentScreen\",\"eq\":\"detail\"} and contains a back button with action:\"pop\". ONLY use components from the AVAILABLE COMPONENTS list.',\n ],\n },\n);\n\n/**\n * Type for the React Native schema\n */\nexport type ReactNativeSchema = typeof schema;\n\n/**\n * Infer the spec type from a catalog\n */\nexport type ReactNativeSpec<TCatalog> = typeof schema extends {\n createCatalog: (catalog: TCatalog) => { _specType: infer S };\n}\n ? S\n : never;\n\n// Backward compatibility aliases\n/** @deprecated Use `schema` instead */\nexport const elementTreeSchema = schema;\n/** @deprecated Use `ReactNativeSchema` instead */\nexport type ElementTreeSchema = ReactNativeSchema;\n/** @deprecated Use `ReactNativeSpec` instead */\nexport type ElementTreeSpec<T> = ReactNativeSpec<T>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAA6B;AAStB,IAAM,aAAS;AAAA,EACpB,CAAC,OAAO;AAAA;AAAA,IAEN,MAAM,EAAE,OAAO;AAAA;AAAA,MAEb,MAAM,EAAE,OAAO;AAAA;AAAA,MAEf,UAAU,EAAE;AAAA,QACV,EAAE,OAAO;AAAA;AAAA,UAEP,MAAM,EAAE,IAAI,oBAAoB;AAAA;AAAA,UAEhC,OAAO,EAAE,QAAQ,oBAAoB;AAAA;AAAA,UAErC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA;AAAA,UAE5B,SAAS,EAAE,GAAG,EAAE,IAAI,GAAG,GAAG,EAAE,SAAS,EAAE;AAAA;AAAA,UAEvC,QAAQ,EAAE,GAAG,EAAE,IAAI,GAAG,GAAG,EAAE,SAAS,EAAE;AAAA,QACxC,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA;AAAA,IAGD,SAAS,EAAE,OAAO;AAAA;AAAA,MAEhB,YAAY,EAAE,IAAI;AAAA;AAAA,QAEhB,OAAO,EAAE,IAAI;AAAA;AAAA,QAEb,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA;AAAA,QAEzB,aAAa,EAAE,OAAO;AAAA;AAAA,QAEtB,SAAS,EAAE,IAAI;AAAA,MACjB,CAAC;AAAA;AAAA,MAED,SAAS,EAAE,IAAI;AAAA;AAAA,QAEb,QAAQ,EAAE,IAAI;AAAA;AAAA,QAEd,aAAa,EAAE,OAAO;AAAA,MACxB,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EACA;AAAA,IACE,cAAc;AAAA;AAAA,MAEZ;AAAA,MACA;AAAA;AAAA,MAGA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAGA;AAAA;AAAA,MAGA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAGA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAGA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAkBO,IAAM,oBAAoB;","names":[]}
|
package/dist/schema.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@json-render/react-native",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "React Native renderer for @json-render/core. JSON becomes React Native components.",
|
|
6
6
|
"keywords": [
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"dist"
|
|
51
51
|
],
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@json-render/core": "0.
|
|
53
|
+
"@json-render/core": "0.20.0"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@types/react": "19.2.3",
|
|
@@ -58,8 +58,8 @@
|
|
|
58
58
|
"tsup": "^8.0.2",
|
|
59
59
|
"typescript": "^5.4.5",
|
|
60
60
|
"zod": "^4.3.6",
|
|
61
|
-
"@internal/
|
|
62
|
-
"@internal/
|
|
61
|
+
"@internal/react-state": "0.8.11",
|
|
62
|
+
"@internal/typescript-config": "0.0.0"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
65
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/schema.ts"],"sourcesContent":["import { defineSchema } from \"@json-render/core\";\n\n/**\n * The schema for @json-render/react-native\n *\n * Defines:\n * - Spec: A flat tree of elements with keys, types, props, and children references\n * - Catalog: Components with props schemas, and optional actions\n */\nexport const schema = defineSchema(\n (s) => ({\n // What the AI-generated SPEC looks like\n spec: s.object({\n /** Root element key */\n root: s.string(),\n /** Flat map of elements by key */\n elements: s.record(\n s.object({\n /** Component type from catalog */\n type: s.ref(\"catalog.components\"),\n /** Component props */\n props: s.propsOf(\"catalog.components\"),\n /** Child element keys (flat reference) */\n children: s.array(s.string()),\n /** Visibility condition */\n visible: s.any(),\n }),\n ),\n }),\n\n // What the CATALOG must provide\n catalog: s.object({\n /** Component definitions */\n components: s.map({\n /** Zod schema for component props */\n props: s.zod(),\n /** Slots for this component. Use ['default'] for children, or named slots like ['header', 'footer'] */\n slots: s.array(s.string()),\n /** Description for AI generation hints */\n description: s.string(),\n /** Example prop values used in prompt examples (auto-generated from Zod schema if omitted) */\n example: s.any(),\n }),\n /** Action definitions (optional) */\n actions: s.map({\n /** Zod schema for action params */\n params: s.zod(),\n /** Description for AI generation hints */\n description: s.string(),\n }),\n }),\n }),\n {\n defaultRules: [\n // Layout patterns\n \"FIXED BOTTOM BAR PATTERN: When building a screen with a fixed header and/or fixed bottom tab bar, the outermost vertical layout component must have flex:1 so it fills the screen. The scrollable content area must also have flex:1. Structure: screen wrapper > vertical layout(flex:1, gap:0) > [header, content wrapper(flex:1) > [scroll container(...)], bottom-tabs]. Both the outer layout AND the content wrapper need flex:1. ONLY use components from the AVAILABLE COMPONENTS list.\",\n \"NEVER place a bottom tab bar or fixed footer inside a scroll container. It must be a sibling AFTER the flex:1 container that holds the scroll content.\",\n\n // Element integrity\n \"CRITICAL INTEGRITY CHECK: Before outputting ANY element that references children, you MUST have already output (or will output) each child as its own element. If an element has children: ['a', 'b'], then elements 'a' and 'b' MUST exist. A missing child element causes that entire branch of the UI to be invisible.\",\n \"SELF-CHECK: After generating all elements, mentally walk the tree from root. Every key in every children array must resolve to a defined element. If you find a gap, output the missing element immediately.\",\n 'When building repeating content backed by a state array (e.g. todos, posts, cart items), use the \"repeat\" field on a container element from the AVAILABLE COMPONENTS list. Example: { \"type\": \"<ContainerComponent>\", \"props\": { \"gap\": 8 }, \"repeat\": { \"statePath\": \"/todos\", \"key\": \"id\" }, \"children\": [\"todo-item\"] }. Inside repeated children, use { \"$item\": \"field\" } to read a field from the current item, and { \"$index\": true } for the current array index. For two-way binding to an item field use { \"$bindItem\": \"completed\" }. Do NOT hardcode individual elements for each array item.',\n\n // Visible field placement\n 'CRITICAL: The \"visible\" field goes on the ELEMENT object, NOT inside \"props\". Correct: {\"type\":\"<ComponentName>\",\"props\":{},\"visible\":{\"$state\":\"/activeTab\",\"eq\":\"home\"},\"children\":[...]}. WRONG: {\"type\":\"<ComponentName>\",\"props\":{},\"visible\":{...},\"children\":[...]} with visible inside props.',\n\n // Tab navigation pattern\n \"TAB NAVIGATION PATTERN: When building a UI with multiple tabs, use a pressable/tappable component + setState action + visible conditions to make tabs functional. ONLY use components from the AVAILABLE COMPONENTS list.\",\n 'Each tab button should be a pressable component wrapping its icon/label children, with action \"setState\" and actionParams { \"statePath\": \"/activeTab\", \"value\": \"tabName\" }.',\n 'Each tab\\'s content section should have a visible condition: { \"$state\": \"/activeTab\", \"eq\": \"tabName\" }.',\n \"The first tab's content should NOT have a visible condition (so it shows by default when no tab is selected yet). All other tabs MUST have a visible condition.\",\n\n // Tab active state highlighting (using dynamic props)\n \"TAB ACTIVE STYLING: Use $cond dynamic props on icon elements inside each tab button so a single icon changes appearance based on the active tab.\",\n ' - For the icon name: { \"$cond\": { \"$state\": \"/activeTab\", \"eq\": \"thisTabName\" }, \"$then\": \"home\", \"$else\": \"home-outline\" }',\n ' - For the icon color: { \"$cond\": { \"$state\": \"/activeTab\", \"eq\": \"thisTabName\" }, \"$then\": \"#007AFF\", \"$else\": \"#8E8E93\" }',\n \" - For labels, use $cond on the color prop similarly.\",\n ' - For the FIRST/DEFAULT tab, use { \"$cond\": [{ \"$state\": \"/activeTab\", \"eq\": \"thisTabName\" }], \"$then\": \"#007AFF\", \"$else\": \"#8E8E93\" } so it appears active before any tab is tapped. When no tab is selected yet, include a default tab with no visible condition.',\n\n // Push/pop screen navigation (all screens in one spec)\n 'SCREEN NAVIGATION: Use a pressable component with action \"push\" and actionParams { \"screen\": \"screenName\" } to navigate to a new screen. Use action \"pop\" to go back. All screens must be defined in the SAME spec. ONLY use components from the AVAILABLE COMPONENTS list.',\n 'Each screen section uses a visible condition on /currentScreen: { \"$state\": \"/currentScreen\", \"eq\": \"screenName\" }. The default/home screen should show by default (no visible condition) and all other screens should have the appropriate visible condition.',\n \"push automatically maintains a /navStack in the state model so pop always returns to the previous screen.\",\n 'Include a back button on pushed screens using action \"pop\". Example: pressable(action:\"pop\") > row layout > back icon + back label. ONLY use components from the AVAILABLE COMPONENTS list.',\n \"Use push/pop for drill-down flows: tapping a list item to see details, opening a profile, etc. Use setState + visible conditions for tab switching within a screen.\",\n 'Example: A list screen with items that push to detail: a pressable component with action:\"push\" and actionParams:{screen:\"detail\"} wrapping each list item. The detail screen section has visible:{\"$state\":\"/currentScreen\",\"eq\":\"detail\"} and contains a back button with action:\"pop\". ONLY use components from the AVAILABLE COMPONENTS list.',\n ],\n },\n);\n\n/**\n * Type for the React Native schema\n */\nexport type ReactNativeSchema = typeof schema;\n\n/**\n * Infer the spec type from a catalog\n */\nexport type ReactNativeSpec<TCatalog> = typeof schema extends {\n createCatalog: (catalog: TCatalog) => { _specType: infer S };\n}\n ? S\n : never;\n\n// Backward compatibility aliases\n/** @deprecated Use `schema` instead */\nexport const elementTreeSchema = schema;\n/** @deprecated Use `ReactNativeSchema` instead */\nexport type ElementTreeSchema = ReactNativeSchema;\n/** @deprecated Use `ReactNativeSpec` instead */\nexport type ElementTreeSpec<T> = ReactNativeSpec<T>;\n"],"mappings":";AAAA,SAAS,oBAAoB;AAStB,IAAM,SAAS;AAAA,EACpB,CAAC,OAAO;AAAA;AAAA,IAEN,MAAM,EAAE,OAAO;AAAA;AAAA,MAEb,MAAM,EAAE,OAAO;AAAA;AAAA,MAEf,UAAU,EAAE;AAAA,QACV,EAAE,OAAO;AAAA;AAAA,UAEP,MAAM,EAAE,IAAI,oBAAoB;AAAA;AAAA,UAEhC,OAAO,EAAE,QAAQ,oBAAoB;AAAA;AAAA,UAErC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA;AAAA,UAE5B,SAAS,EAAE,IAAI;AAAA,QACjB,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAAA;AAAA,IAGD,SAAS,EAAE,OAAO;AAAA;AAAA,MAEhB,YAAY,EAAE,IAAI;AAAA;AAAA,QAEhB,OAAO,EAAE,IAAI;AAAA;AAAA,QAEb,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC;AAAA;AAAA,QAEzB,aAAa,EAAE,OAAO;AAAA;AAAA,QAEtB,SAAS,EAAE,IAAI;AAAA,MACjB,CAAC;AAAA;AAAA,MAED,SAAS,EAAE,IAAI;AAAA;AAAA,QAEb,QAAQ,EAAE,IAAI;AAAA;AAAA,QAEd,aAAa,EAAE,OAAO;AAAA,MACxB,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EACA;AAAA,IACE,cAAc;AAAA;AAAA,MAEZ;AAAA,MACA;AAAA;AAAA,MAGA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAGA;AAAA;AAAA,MAGA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAGA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,MAGA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACF;AAkBO,IAAM,oBAAoB;","names":[]}
|