@developer_tribe/react-builder 1.2.7 → 1.2.9

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 (204) hide show
  1. package/dist/AttributesEditor.d.ts +2 -11
  2. package/dist/attribute-analyser/style/native/useExtractImageStyle.d.ts +10 -0
  3. package/dist/attribute-analyser/style/native/useExtractTextStyle.d.ts +9 -0
  4. package/dist/attribute-analyser/style/native/useExtractViewStyle.d.ts +8 -0
  5. package/dist/attribute-analyser/style/web/useExtractImageStyle.d.ts +4 -0
  6. package/dist/attribute-analyser/style/web/useExtractTextStyle.d.ts +4 -0
  7. package/dist/attribute-analyser/style/web/useExtractViewStyle.d.ts +4 -0
  8. package/dist/attributes-editor/AttributesEditorFields.d.ts +18 -0
  9. package/dist/attributes-editor/AttributesEditorView.d.ts +4 -0
  10. package/dist/attributes-editor/attributesEditorModelTypes.d.ts +67 -0
  11. package/dist/attributes-editor/attributesEditorUtils.d.ts +19 -0
  12. package/dist/attributes-editor/useAttributesEditorModel.d.ts +2 -0
  13. package/dist/build-components/BIcon/BIconProps.generated.d.ts +41 -38
  14. package/dist/build-components/BackgroundImage/BackgroundImageProps.generated.d.ts +37 -34
  15. package/dist/build-components/Button/ButtonProps.generated.d.ts +39 -36
  16. package/dist/build-components/Carousel/CarouselProps.generated.d.ts +37 -34
  17. package/dist/build-components/CarouselButtons/CarouselButtonsProps.generated.d.ts +37 -34
  18. package/dist/build-components/CarouselDots/CarouselDotsProps.generated.d.ts +37 -34
  19. package/dist/build-components/CarouselItem/CarouselItemProps.generated.d.ts +36 -33
  20. package/dist/build-components/CarouselProvider/CarouselProviderProps.generated.d.ts +36 -33
  21. package/dist/build-components/Image/ImageProps.generated.d.ts +38 -33
  22. package/dist/build-components/Main/MainProps.generated.d.ts +36 -33
  23. package/dist/build-components/Onboard/OnboardProps.generated.d.ts +36 -33
  24. package/dist/build-components/OnboardButton/OnboardButtonProps.generated.d.ts +38 -34
  25. package/dist/build-components/OnboardButtons/OnboardButtonsProps.generated.d.ts +39 -36
  26. package/dist/build-components/OnboardDot/OnboardDotProps.generated.d.ts +43 -34
  27. package/dist/build-components/OnboardFooter/OnboardFooterProps.generated.d.ts +41 -38
  28. package/dist/build-components/OnboardImage/OnboardImageProps.generated.d.ts +36 -31
  29. package/dist/build-components/OnboardItem/OnboardItemProps.generated.d.ts +39 -33
  30. package/dist/build-components/OnboardProvider/OnboardProviderProps.generated.d.ts +38 -34
  31. package/dist/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.d.ts +41 -38
  32. package/dist/build-components/OnboardTitle/OnboardTitleProps.generated.d.ts +41 -38
  33. package/dist/build-components/PaywallBackground/PaywallBackgroundProps.generated.d.ts +36 -33
  34. package/dist/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.d.ts +41 -38
  35. package/dist/build-components/PaywallOptions/PaywallOptionsProps.generated.d.ts +36 -33
  36. package/dist/build-components/PaywallProvider/PaywallProviderProps.generated.d.ts +36 -33
  37. package/dist/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.d.ts +39 -36
  38. package/dist/build-components/RadioButton/RadioButtonProps.generated.d.ts +36 -33
  39. package/dist/build-components/Text/TextProps.generated.d.ts +41 -38
  40. package/dist/build-components/View/ViewProps.generated.d.ts +36 -33
  41. package/dist/build-components/patterns.generated.d.ts +2673 -5787
  42. package/dist/components/BuilderProvider.d.ts +6 -0
  43. package/dist/index.cjs.js +5 -5
  44. package/dist/index.cjs.js.map +1 -1
  45. package/dist/index.d.ts +5 -26
  46. package/dist/index.esm.js +5 -5
  47. package/dist/index.esm.js.map +1 -1
  48. package/dist/index.native.cjs.js +6 -4
  49. package/dist/index.native.cjs.js.map +1 -1
  50. package/dist/index.native.d.ts +6 -3
  51. package/dist/index.native.esm.js +6 -4
  52. package/dist/index.native.esm.js.map +1 -1
  53. package/dist/migrations/migratePipe.d.ts +1 -1
  54. package/dist/migrations/migrations/1.1.2_extract_component_attributes_from_style.d.ts +2 -0
  55. package/dist/mockOS/components/PermissionModal.d.ts +1 -2
  56. package/dist/styles.css +1 -1
  57. package/dist/types/PreviewConfig.d.ts +1 -5
  58. package/dist/utils/extractImageStyle.d.ts +3 -0
  59. package/dist/utils/extractTextStyle/extractTextStyleNative.d.ts +17 -0
  60. package/dist/utils/extractTextStyle.d.ts +2 -0
  61. package/dist/utils/extractViewStyle/extractViewStyleNative.d.ts +12 -0
  62. package/dist/utils/extractViewStyle.d.ts +2 -0
  63. package/dist/utils/getMeta.d.ts +5 -0
  64. package/dist/utils/patterns.d.ts +14 -1
  65. package/package.json +2 -1
  66. package/scripts/prebuild/prebuild.js +14 -0
  67. package/scripts/prebuild/utils/createGeneratedProps.js +51 -3
  68. package/scripts/prebuild/utils/index.js +1 -0
  69. package/scripts/prebuild/utils/updateMetaJson.js +66 -0
  70. package/scripts/prebuild/utils/validateAllComponentsOrThrow.js +37 -3
  71. package/scripts/prebuild/utils/validatePatternJson.js +27 -2
  72. package/scripts/public/scripts/build/index.js +20 -3
  73. package/scripts/public/scripts/build/info.json +6 -0
  74. package/scripts/public/scripts/build/utils/createComponentsIndex.js +9 -3
  75. package/scripts/public/scripts/build/utils/createRenderNodeGenerated.js +66 -8
  76. package/src/AttributesEditor.tsx +8 -944
  77. package/src/assets/meta.json +4 -0
  78. package/src/assets/samples/carousel-sample.json +1 -1
  79. package/src/assets/samples/getSamples.ts +2 -0
  80. package/src/assets/samples/paywall-1.json +11 -7
  81. package/src/assets/samples/simple-1.json +3 -3
  82. package/src/assets/samples/simple-2.json +3 -3
  83. package/src/assets/samples/unmigrated-builder-1.1.1.json +87 -0
  84. package/src/assets/samples/unmigrated-builder1.json +1 -1
  85. package/src/assets/samples/unvalidated-builder1.json +3 -3
  86. package/src/assets/samples/unvalidated-crash1.json +1 -1
  87. package/src/assets/samples/unvalidated-crashcomponent1.json +1 -1
  88. package/src/assets/samples/vpn-onboard-1.json +1 -1
  89. package/src/assets/samples/vpn-onboard-2.json +1 -1
  90. package/src/assets/samples/vpn-onboard-3.json +1 -1
  91. package/src/assets/samples/vpn-onboard-4.json +1 -1
  92. package/src/assets/samples/vpn-onboard-5.json +1 -1
  93. package/src/assets/samples/vpn-onboard-6.json +1 -1
  94. package/src/attribute-analyser/style/native/useExtractImageStyle.ts +46 -0
  95. package/src/attribute-analyser/style/native/useExtractTextStyle.ts +50 -0
  96. package/src/attribute-analyser/style/native/useExtractViewStyle.ts +32 -0
  97. package/src/attribute-analyser/style/web/useExtractImageStyle.ts +20 -0
  98. package/src/{hooks → attribute-analyser/style/web}/useExtractTextStyle.ts +7 -6
  99. package/src/{hooks → attribute-analyser/style/web}/useExtractViewStyle.ts +7 -6
  100. package/src/attributes-editor/AttributesEditorFields.tsx +248 -0
  101. package/src/attributes-editor/AttributesEditorView.tsx +360 -0
  102. package/src/attributes-editor/LayoutPreviewPicker.tsx +4 -3
  103. package/src/attributes-editor/attributesEditorModelTypes.ts +86 -0
  104. package/src/attributes-editor/attributesEditorUtils.ts +102 -0
  105. package/src/attributes-editor/useAttributesEditorModel.ts +477 -0
  106. package/src/build-components/BIcon/BIcon.tsx +4 -3
  107. package/src/build-components/BIcon/BIconProps.generated.ts +42 -38
  108. package/src/build-components/BIcon/pattern.json +5 -6
  109. package/src/build-components/BackgroundImage/BackgroundImage.tsx +7 -4
  110. package/src/build-components/BackgroundImage/BackgroundImageProps.generated.ts +38 -34
  111. package/src/build-components/BackgroundImage/pattern.json +9 -17
  112. package/src/build-components/Button/Button.tsx +7 -6
  113. package/src/build-components/Button/ButtonProps.generated.ts +40 -36
  114. package/src/build-components/Button/pattern.json +17 -15
  115. package/src/build-components/Carousel/Carousel.tsx +1 -1
  116. package/src/build-components/Carousel/CarouselProps.generated.ts +38 -34
  117. package/src/build-components/CarouselButtons/CarouselButtons.tsx +4 -6
  118. package/src/build-components/CarouselButtons/CarouselButtonsProps.generated.ts +41 -37
  119. package/src/build-components/CarouselButtons/pattern.json +2 -1
  120. package/src/build-components/CarouselDots/CarouselDots.tsx +2 -2
  121. package/src/build-components/CarouselDots/CarouselDotsProps.generated.ts +44 -40
  122. package/src/build-components/CarouselItem/CarouselItem.tsx +1 -1
  123. package/src/build-components/CarouselItem/CarouselItemProps.generated.ts +37 -33
  124. package/src/build-components/CarouselProvider/CarouselProvider.tsx +1 -1
  125. package/src/build-components/CarouselProvider/CarouselProviderProps.generated.ts +37 -33
  126. package/src/build-components/Image/Image.tsx +4 -3
  127. package/src/build-components/Image/ImageProps.generated.ts +39 -33
  128. package/src/build-components/Image/pattern.json +5 -11
  129. package/src/build-components/Main/Main.tsx +1 -1
  130. package/src/build-components/Main/MainProps.generated.ts +37 -33
  131. package/src/build-components/Main/pattern.json +2 -1
  132. package/src/build-components/Onboard/OnboardProps.generated.ts +37 -33
  133. package/src/build-components/OnboardButton/OnboardButton.tsx +8 -6
  134. package/src/build-components/OnboardButton/OnboardButtonProps.generated.ts +44 -39
  135. package/src/build-components/OnboardButton/pattern.json +9 -7
  136. package/src/build-components/OnboardButtons/OnboardButtons.tsx +31 -31
  137. package/src/build-components/OnboardButtons/OnboardButtonsProps.generated.ts +43 -39
  138. package/src/build-components/OnboardButtons/pattern.json +9 -7
  139. package/src/build-components/OnboardDot/OnboardDot.tsx +7 -5
  140. package/src/build-components/OnboardDot/OnboardDotProps.generated.ts +55 -34
  141. package/src/build-components/OnboardFooter/OnboardFooter.tsx +19 -23
  142. package/src/build-components/OnboardFooter/OnboardFooterProps.generated.ts +42 -38
  143. package/src/build-components/OnboardFooter/pattern.json +16 -14
  144. package/src/build-components/OnboardImage/OnboardImage.tsx +8 -7
  145. package/src/build-components/OnboardImage/OnboardImageProps.generated.ts +37 -31
  146. package/src/build-components/OnboardImage/pattern.json +2 -1
  147. package/src/build-components/OnboardItem/OnboardItem.tsx +1 -1
  148. package/src/build-components/OnboardItem/OnboardItemProps.generated.ts +40 -33
  149. package/src/build-components/OnboardItem/pattern.json +2 -1
  150. package/src/build-components/OnboardProvider/OnboardProvider.tsx +1 -1
  151. package/src/build-components/OnboardProvider/OnboardProviderProps.generated.ts +39 -34
  152. package/src/build-components/OnboardProvider/pattern.json +2 -1
  153. package/src/build-components/OnboardSubtitle/OnboardSubtitleProps.generated.ts +42 -38
  154. package/src/build-components/OnboardTitle/OnboardTitleProps.generated.ts +42 -38
  155. package/src/build-components/PaywallBackground/PaywallBackground.tsx +1 -1
  156. package/src/build-components/PaywallBackground/PaywallBackgroundProps.generated.ts +37 -33
  157. package/src/build-components/PaywallCloseButton/PaywallCloseButton.tsx +6 -5
  158. package/src/build-components/PaywallCloseButton/PaywallCloseButtonProps.generated.ts +42 -38
  159. package/src/build-components/PaywallOptions/PaywallOptionButton.tsx +1 -1
  160. package/src/build-components/PaywallOptions/PaywallOptionsProps.generated.ts +37 -33
  161. package/src/build-components/PaywallProvider/PaywallProvider.tsx +1 -1
  162. package/src/build-components/PaywallProvider/PaywallProviderProps.generated.ts +37 -33
  163. package/src/build-components/PaywallSubscribeButton/PaywallSubscribeButton.tsx +1 -1
  164. package/src/build-components/PaywallSubscribeButton/PaywallSubscribeButtonProps.generated.ts +40 -36
  165. package/src/build-components/RadioButton/RadioButton.tsx +5 -4
  166. package/src/build-components/RadioButton/RadioButtonProps.generated.ts +37 -33
  167. package/src/build-components/RadioButton/pattern.json +9 -7
  168. package/src/build-components/Text/Text.tsx +6 -8
  169. package/src/build-components/Text/TextProps.generated.ts +42 -38
  170. package/src/build-components/Text/pattern.json +15 -11
  171. package/src/build-components/View/View.tsx +1 -1
  172. package/src/build-components/View/ViewProps.generated.ts +37 -33
  173. package/src/build-components/View/pattern.json +71 -66
  174. package/src/build-components/patterns.generated.ts +3022 -5971
  175. package/src/components/AttributesEditorPanel.tsx +2 -2
  176. package/src/components/BuilderProvider.tsx +15 -1
  177. package/src/index.native.ts +7 -4
  178. package/src/index.ts +6 -77
  179. package/src/migrations/migratePipe.ts +7 -3
  180. package/src/migrations/migrations/1.1.2_extract_component_attributes_from_style.ts +211 -0
  181. package/src/mockOS/components/MockOSRouter.tsx +3 -1
  182. package/src/mockOS/components/PermissionModal.tsx +20 -160
  183. package/src/mockOS/components/SubscriptionModal.tsx +41 -278
  184. package/src/pages/ProjectPage.tsx +12 -6
  185. package/src/styles/components/_attributes-editor.scss +122 -0
  186. package/src/styles/components/_mockos-router.scss +388 -0
  187. package/src/styles/components/_onboard.scss +23 -0
  188. package/src/styles/index.scss +1 -0
  189. package/src/types/PreviewConfig.ts +1 -5
  190. package/src/utils/analyseNodeByPatterns.ts +39 -4
  191. package/src/utils/extractImageStyle.ts +34 -5
  192. package/src/utils/extractTextStyle/extractTextStyle.ts +7 -6
  193. package/src/utils/extractTextStyle/extractTextStyleNative.ts +106 -0
  194. package/src/utils/extractTextStyle.ts +2 -0
  195. package/src/utils/extractViewStyle/extractViewStyle.ts +2 -4
  196. package/src/utils/extractViewStyle/extractViewStyleNative.ts +111 -0
  197. package/src/utils/extractViewStyle.ts +2 -0
  198. package/src/utils/getMeta.ts +15 -0
  199. package/src/utils/patterns.ts +100 -3
  200. package/dist/hooks/useExtractImageStyle.d.ts +0 -3
  201. package/dist/hooks/useExtractTextStyle.d.ts +0 -3
  202. package/dist/hooks/useExtractViewStyle.d.ts +0 -3
  203. package/src/hooks/useExtractImageStyle.ts +0 -19
  204. package/src/migrations/migrations/1.1.0_normalize_style_attributes.ts +0 -80
@@ -166,17 +166,38 @@ async function validatePatternJson(componentDir, componentName) {
166
166
  ...(isPlainObject(source?.defaults) ? source.defaults : {}),
167
167
  });
168
168
 
169
- // Validate attributes accept primitive, enum array, or custom type refs (including X[])
170
- for (const [attrName, attrType] of Object.entries(pattern.attributes)) {
169
+ const validateAttrType = (attrName, attrType, pathLabel) => {
171
170
  const ok =
172
171
  (typeof attrType === 'string' &&
173
172
  (isNeverType(attrType) || isValidTypeRef(attrType))) ||
174
173
  isEnumArray(attrType);
175
174
  if (!ok) {
176
175
  return fail(
177
- `[${componentName}] pattern.json -> 'pattern.attributes.${attrName}' must be 'string' | 'number' | 'boolean' | 'color' | 'never' | string[] | CustomType | CustomType[]`
176
+ `[${componentName}] pattern.json -> '${pathLabel}.${attrName}' must be 'string' | 'number' | 'boolean' | 'color' | 'never' | string[] | CustomType | CustomType[]`
178
177
  );
179
178
  }
179
+ };
180
+
181
+ // Validate attributes accept primitive, enum array, or custom type refs (including X[])
182
+ for (const [attrName, attrType] of Object.entries(pattern.attributes)) {
183
+ if (attrName === 'style') {
184
+ if (!isPlainObject(attrType)) {
185
+ return fail(
186
+ `[${componentName}] pattern.json -> 'pattern.attributes.style' must be an object`
187
+ );
188
+ }
189
+ for (const [styleKey, styleType] of Object.entries(attrType)) {
190
+ const res = validateAttrType(
191
+ styleKey,
192
+ styleType,
193
+ 'pattern.attributes.style'
194
+ );
195
+ if (res) return res;
196
+ }
197
+ continue;
198
+ }
199
+ const res = validateAttrType(attrName, attrType, 'pattern.attributes');
200
+ if (res) return res;
180
201
  }
181
202
 
182
203
  // If types block exists, validate its shape (only primitives or enum arrays for fields)
@@ -291,6 +312,19 @@ async function validatePatternJson(componentDir, componentName) {
291
312
  const parentAttributes = parentData?.pattern?.attributes || {};
292
313
  const childAttributes = data?.pattern?.attributes || {};
293
314
  const mergedAttributes = { ...parentAttributes, ...childAttributes };
315
+ // Deep-merge nested schema `attributes.style` when present (so parent style keys propagate).
316
+ const parentStyle = isPlainObject(parentAttributes?.style)
317
+ ? parentAttributes.style
318
+ : null;
319
+ const childStyle = isPlainObject(childAttributes?.style)
320
+ ? childAttributes.style
321
+ : null;
322
+ if (parentStyle || childStyle) {
323
+ mergedAttributes.style = {
324
+ ...(parentStyle || {}),
325
+ ...(childStyle || {}),
326
+ };
327
+ }
294
328
 
295
329
  // If child does not define children, inherit parent's
296
330
  const childHasChildren = Object.prototype.hasOwnProperty.call(
@@ -70,7 +70,10 @@ export async function validatePatternJson(componentDir, componentName) {
70
70
  value === 'size' ||
71
71
  value === 'iconType';
72
72
 
73
- for (const [attrName, attrType] of Object.entries(pattern.attributes)) {
73
+ const isPlainObject = value =>
74
+ typeof value === 'object' && value != null && !Array.isArray(value);
75
+
76
+ const validateAttrType = (attrName, attrType, pathLabel) => {
74
77
  const isValidType =
75
78
  (typeof attrType === 'string' && isPrimitiveType(attrType)) ||
76
79
  (typeof attrType === 'string' &&
@@ -79,9 +82,31 @@ export async function validatePatternJson(componentDir, componentName) {
79
82
  (Array.isArray(attrType) && attrType.every(v => typeof v === 'string'));
80
83
  if (!isValidType) {
81
84
  return fail(
82
- `[${componentName}] pattern.json -> 'pattern.attributes.${attrName}' must be 'string' | 'number' | 'boolean' | 'color' | 'size' | 'iconType' | string[]`
85
+ `[${componentName}] pattern.json -> '${pathLabel}.${attrName}' must be 'string' | 'number' | 'boolean' | 'color' | 'size' | 'iconType' | string[]`
83
86
  );
84
87
  }
88
+ };
89
+
90
+ for (const [attrName, attrType] of Object.entries(pattern.attributes)) {
91
+ if (attrName === 'style') {
92
+ if (!isPlainObject(attrType)) {
93
+ return fail(
94
+ `[${componentName}] pattern.json -> 'pattern.attributes.style' must be an object`
95
+ );
96
+ }
97
+ for (const [styleKey, styleType] of Object.entries(attrType)) {
98
+ const res = validateAttrType(
99
+ styleKey,
100
+ styleType,
101
+ 'pattern.attributes.style'
102
+ );
103
+ if (res) return res;
104
+ }
105
+ continue;
106
+ }
107
+
108
+ const res = validateAttrType(attrName, attrType, 'pattern.attributes');
109
+ if (res) return res;
85
110
  }
86
111
 
87
112
  return data;
@@ -13,8 +13,22 @@ import { createComponentsIndex } from './utils/createComponentsIndex.js';
13
13
  const argv = yargs(hideBin(process.argv)).argv;
14
14
  export const args = argv;
15
15
  const builderPath = args.path || 'node_modules/@developer_tribe/react-builder';
16
- const selectedComponents = args.components || [];
16
+ const selectedComponents = Array.isArray(args.components)
17
+ ? args.components
18
+ : typeof args.components === 'string'
19
+ ? [args.components]
20
+ : [];
17
21
  const name = args.name || 'build-components';
22
+ function parseBooleanFlag(value, defaultValue) {
23
+ if (typeof value === 'boolean') return value;
24
+ if (typeof value === 'string') {
25
+ const normalized = value.trim().toLowerCase();
26
+ if (['false', '0', 'no', 'off'].includes(normalized)) return false;
27
+ if (['true', '1', 'yes', 'on'].includes(normalized)) return true;
28
+ }
29
+ return defaultValue;
30
+ }
31
+ const component = parseBooleanFlag(args.component, true);
18
32
  const targetPath = process.cwd();
19
33
 
20
34
  function run() {
@@ -37,9 +51,12 @@ function run() {
37
51
  createRenderNodeGenerated(
38
52
  builderComponentsPath,
39
53
  targetComponentsPath,
40
- selectedComponents
54
+ selectedComponents,
55
+ { component }
41
56
  );
42
- createComponentsIndex(targetComponentsPath, selectedComponents);
57
+ createComponentsIndex(targetComponentsPath, selectedComponents, {
58
+ component,
59
+ });
43
60
  }
44
61
 
45
62
  run();
@@ -18,6 +18,12 @@
18
18
  "type": "string",
19
19
  "describe": "name of the structure",
20
20
  "demandOption": false
21
+ },
22
+ "component": {
23
+ "type": "boolean",
24
+ "default": true,
25
+ "describe": "generate RenderNode as a React component (.tsx) when true; generate a plain function (.ts) when false",
26
+ "demandOption": false
21
27
  }
22
28
  }
23
29
  }
@@ -1,7 +1,12 @@
1
1
  import fs from 'fs';
2
2
  import Path from 'path';
3
3
 
4
- export function createComponentsIndex(buildComponentsTarget, components) {
4
+ export function createComponentsIndex(
5
+ buildComponentsTarget,
6
+ components,
7
+ options = {}
8
+ ) {
9
+ const { component = true } = options;
5
10
  if (!fs.existsSync(buildComponentsTarget)) {
6
11
  fs.mkdirSync(buildComponentsTarget, { recursive: true });
7
12
  }
@@ -9,8 +14,9 @@ export function createComponentsIndex(buildComponentsTarget, components) {
9
14
  const targetPath = Path.join(buildComponentsTarget, 'index.ts');
10
15
 
11
16
  const header = '/* AUTO-GENERATED FILE - DO NOT EDIT */\n\n';
12
- const renderNodeExport =
13
- "export { default as RenderNode } from './RenderNode.generated';";
17
+ const renderNodeExport = component
18
+ ? "export { default as RenderNode } from './RenderNode.generated';"
19
+ : "export { renderNode } from './RenderNode.generated';";
14
20
 
15
21
  const componentExports = components
16
22
  .map(name => `export { default as ${name} } from './${name}/${name}';`)
@@ -15,29 +15,42 @@ function readPatternType(builderComponentsPath, componentName) {
15
15
  export function createRenderNodeGenerated(
16
16
  builderComponentsPath,
17
17
  buildComponentsTarget,
18
- components
18
+ components,
19
+ options = {}
19
20
  ) {
21
+ const { component = true } = options;
20
22
  if (!fs.existsSync(buildComponentsTarget)) {
21
23
  fs.mkdirSync(buildComponentsTarget, { recursive: true });
22
24
  }
23
25
 
24
- const targetPath = Path.join(
25
- buildComponentsTarget,
26
- 'RenderNode.generated.tsx'
27
- );
26
+ const tsxPath = Path.join(buildComponentsTarget, 'RenderNode.generated.tsx');
27
+ const tsPath = Path.join(buildComponentsTarget, 'RenderNode.generated.ts');
28
+ const targetPath = component ? tsxPath : tsPath;
28
29
 
29
30
  const imports = components
30
- .map(name => `import ${name} from './${name}/${name}';`)
31
+ .map(name => 'import ' + name + " from './" + name + '/' + name + "';")
31
32
  .join('\n');
32
33
 
33
34
  const cases = components
34
35
  .map(name => {
35
36
  const type = readPatternType(builderComponentsPath, name);
36
- return ` case ${JSON.stringify(type)}:\n return <${name} node={simpleNode} />;`;
37
+ const caseLabel = JSON.stringify(type);
38
+ return component
39
+ ? ' case ' +
40
+ caseLabel +
41
+ ':\n return <' +
42
+ name +
43
+ ' node={simpleNode} />;'
44
+ : ' case ' +
45
+ caseLabel +
46
+ ':\n return React.createElement(' +
47
+ name +
48
+ ', { node: simpleNode });';
37
49
  })
38
50
  .join('\n');
39
51
 
40
- const content = `/* AUTO-GENERATED FILE - DO NOT EDIT */
52
+ const content = component
53
+ ? `/* AUTO-GENERATED FILE - DO NOT EDIT */
41
54
  import React from 'react';
42
55
  import { Node, NodeData, isNodeArray, isNodeNullOrUndefined, isNodeString } from '@developer_tribe/react-builder';
43
56
  import { other } from './other';
@@ -69,9 +82,54 @@ ${cases}
69
82
  }
70
83
 
71
84
  export default React.memo(RenderNode);
85
+ `
86
+ : `/* AUTO-GENERATED FILE - DO NOT EDIT */
87
+ import React from 'react';
88
+ import {
89
+ Node,
90
+ NodeData,
91
+ isNodeArray,
92
+ isNodeNullOrUndefined,
93
+ isNodeString,
94
+ } from '@developer_tribe/react-builder';
95
+ import { other } from './other';
96
+ ${imports}
97
+
98
+ export function renderNode(node: Node): React.ReactNode {
99
+ if (isNodeNullOrUndefined(node)) {
100
+ return null;
101
+ }
102
+ if (isNodeString(node)) {
103
+ // NOTE: In React Native, raw strings must be rendered inside a <Text>.
104
+ // This function mode intentionally returns a string so the caller can decide how to wrap it.
105
+ return node as string;
106
+ }
107
+ if (isNodeArray(node)) {
108
+ return React.createElement(
109
+ React.Fragment,
110
+ null,
111
+ (node as Node[]).map((item: Node, index) =>
112
+ React.createElement(React.Fragment, { key: index }, renderNode(item))
113
+ )
114
+ );
115
+ }
116
+
117
+ const simpleNode = node as NodeData;
118
+ switch (simpleNode?.type) {
119
+ ${cases}
120
+ default:
121
+ return other(simpleNode?.type, node);
122
+ }
123
+ }
72
124
  `;
73
125
 
74
126
  fs.writeFileSync(targetPath, content, 'utf8');
127
+
128
+ // Keep the output stable by removing the opposite file if it exists.
129
+ const stalePath = component ? tsPath : tsxPath;
130
+ if (fs.existsSync(stalePath)) {
131
+ fs.rmSync(stalePath, { force: true });
132
+ }
75
133
  }
76
134
 
77
135
  // no default export