@pushframe/sdk 0.1.5 → 0.1.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 (288) hide show
  1. package/lib/commonjs/PushframeProvider.js +69 -0
  2. package/lib/commonjs/PushframeProvider.js.map +1 -0
  3. package/lib/commonjs/PushframeScreen.js +69 -0
  4. package/lib/commonjs/PushframeScreen.js.map +1 -0
  5. package/lib/commonjs/bindings.js +73 -0
  6. package/lib/commonjs/bindings.js.map +1 -0
  7. package/lib/commonjs/components/ButtonComponent.js +72 -0
  8. package/lib/commonjs/components/ButtonComponent.js.map +1 -0
  9. package/lib/commonjs/components/FlatListComponent.js +73 -0
  10. package/lib/commonjs/components/FlatListComponent.js.map +1 -0
  11. package/lib/commonjs/components/ImageComponent.js +67 -0
  12. package/lib/commonjs/components/ImageComponent.js.map +1 -0
  13. package/lib/commonjs/components/PushFrameComponent.js +179 -0
  14. package/lib/commonjs/components/PushFrameComponent.js.map +1 -0
  15. package/lib/commonjs/components/PushFrameProvider.js +115 -0
  16. package/lib/commonjs/components/PushFrameProvider.js.map +1 -0
  17. package/lib/commonjs/components/PushFrameScreen.js +39 -0
  18. package/lib/commonjs/components/PushFrameScreen.js.map +1 -0
  19. package/lib/commonjs/components/ScrollViewComponent.js +64 -0
  20. package/lib/commonjs/components/ScrollViewComponent.js.map +1 -0
  21. package/lib/commonjs/components/StackComponent.js +61 -0
  22. package/lib/commonjs/components/StackComponent.js.map +1 -0
  23. package/lib/commonjs/components/TextComponent.js +62 -0
  24. package/lib/commonjs/components/TextComponent.js.map +1 -0
  25. package/lib/commonjs/conditions.js +44 -0
  26. package/lib/commonjs/conditions.js.map +1 -0
  27. package/lib/commonjs/context/PushFrameContext.js +33 -0
  28. package/lib/commonjs/context/PushFrameContext.js.map +1 -0
  29. package/lib/commonjs/index.js +200 -0
  30. package/lib/commonjs/index.js.map +1 -0
  31. package/lib/commonjs/overlays/BottomSheetHost.js +144 -0
  32. package/lib/commonjs/overlays/BottomSheetHost.js.map +1 -0
  33. package/lib/commonjs/overlays/ToastHost.js +135 -0
  34. package/lib/commonjs/overlays/ToastHost.js.map +1 -0
  35. package/lib/commonjs/package.json +1 -0
  36. package/lib/commonjs/primitives/ActivityIndicator.js +24 -0
  37. package/lib/commonjs/primitives/ActivityIndicator.js.map +1 -0
  38. package/lib/commonjs/primitives/FlatList.js +34 -0
  39. package/lib/commonjs/primitives/FlatList.js.map +1 -0
  40. package/lib/commonjs/primitives/Image.js +33 -0
  41. package/lib/commonjs/primitives/Image.js.map +1 -0
  42. package/lib/commonjs/primitives/KeyboardAvoidingView.js +24 -0
  43. package/lib/commonjs/primitives/KeyboardAvoidingView.js.map +1 -0
  44. package/lib/commonjs/primitives/Modal.js +24 -0
  45. package/lib/commonjs/primitives/Modal.js.map +1 -0
  46. package/lib/commonjs/primitives/Pressable.js +26 -0
  47. package/lib/commonjs/primitives/Pressable.js.map +1 -0
  48. package/lib/commonjs/primitives/SafeAreaView.js +38 -0
  49. package/lib/commonjs/primitives/SafeAreaView.js.map +1 -0
  50. package/lib/commonjs/primitives/ScrollView.js +26 -0
  51. package/lib/commonjs/primitives/ScrollView.js.map +1 -0
  52. package/lib/commonjs/primitives/StatusBar.js +24 -0
  53. package/lib/commonjs/primitives/StatusBar.js.map +1 -0
  54. package/lib/commonjs/primitives/Switch.js +28 -0
  55. package/lib/commonjs/primitives/Switch.js.map +1 -0
  56. package/lib/commonjs/primitives/Text.js +37 -0
  57. package/lib/commonjs/primitives/Text.js.map +1 -0
  58. package/lib/commonjs/primitives/TextInput.js +31 -0
  59. package/lib/commonjs/primitives/TextInput.js.map +1 -0
  60. package/lib/commonjs/primitives/View.js +24 -0
  61. package/lib/commonjs/primitives/View.js.map +1 -0
  62. package/lib/commonjs/primitives/index.js +97 -0
  63. package/lib/commonjs/primitives/index.js.map +1 -0
  64. package/lib/commonjs/registry/ComponentRegistry.js +70 -0
  65. package/lib/commonjs/registry/ComponentRegistry.js.map +1 -0
  66. package/lib/commonjs/registry.js +94 -0
  67. package/lib/commonjs/registry.js.map +1 -0
  68. package/lib/commonjs/renderer/RecursiveRenderer.js +202 -0
  69. package/lib/commonjs/renderer/RecursiveRenderer.js.map +1 -0
  70. package/lib/commonjs/renderer/bindingResolver.js +98 -0
  71. package/lib/commonjs/renderer/bindingResolver.js.map +1 -0
  72. package/lib/commonjs/renderer/conditionalEvaluator.js +31 -0
  73. package/lib/commonjs/renderer/conditionalEvaluator.js.map +1 -0
  74. package/lib/commonjs/renderer.js +107 -0
  75. package/lib/commonjs/renderer.js.map +1 -0
  76. package/lib/commonjs/schema.js +79 -0
  77. package/lib/commonjs/schema.js.map +1 -0
  78. package/lib/commonjs/transformer/index.js +1055 -0
  79. package/lib/commonjs/transformer/index.js.map +1 -0
  80. package/lib/commonjs/transport.js +86 -0
  81. package/lib/commonjs/transport.js.map +1 -0
  82. package/lib/module/PushframeProvider.js +62 -0
  83. package/lib/module/PushframeProvider.js.map +1 -0
  84. package/lib/module/PushframeScreen.js +65 -0
  85. package/lib/module/PushframeScreen.js.map +1 -0
  86. package/lib/module/bindings.js +68 -0
  87. package/lib/module/bindings.js.map +1 -0
  88. package/lib/module/components/ButtonComponent.js +67 -0
  89. package/lib/module/components/ButtonComponent.js.map +1 -0
  90. package/lib/module/components/FlatListComponent.js +68 -0
  91. package/lib/module/components/FlatListComponent.js.map +1 -0
  92. package/lib/module/components/ImageComponent.js +62 -0
  93. package/lib/module/components/ImageComponent.js.map +1 -0
  94. package/lib/module/components/PushFrameComponent.js +174 -0
  95. package/lib/module/components/PushFrameComponent.js.map +1 -0
  96. package/lib/module/components/PushFrameProvider.js +110 -0
  97. package/lib/module/components/PushFrameProvider.js.map +1 -0
  98. package/lib/module/components/PushFrameScreen.js +34 -0
  99. package/lib/module/components/PushFrameScreen.js.map +1 -0
  100. package/lib/module/components/ScrollViewComponent.js +59 -0
  101. package/lib/module/components/ScrollViewComponent.js.map +1 -0
  102. package/lib/module/components/StackComponent.js +56 -0
  103. package/lib/module/components/StackComponent.js.map +1 -0
  104. package/lib/module/components/TextComponent.js +57 -0
  105. package/lib/module/components/TextComponent.js.map +1 -0
  106. package/lib/module/conditions.js +40 -0
  107. package/lib/module/conditions.js.map +1 -0
  108. package/lib/module/context/PushFrameContext.js +29 -0
  109. package/lib/module/context/PushFrameContext.js.map +1 -0
  110. package/lib/module/index.js +99 -0
  111. package/lib/module/index.js.map +1 -0
  112. package/lib/module/overlays/BottomSheetHost.js +139 -0
  113. package/lib/module/overlays/BottomSheetHost.js.map +1 -0
  114. package/lib/module/overlays/ToastHost.js +130 -0
  115. package/lib/module/overlays/ToastHost.js.map +1 -0
  116. package/lib/module/primitives/ActivityIndicator.js +19 -0
  117. package/lib/module/primitives/ActivityIndicator.js.map +1 -0
  118. package/lib/module/primitives/FlatList.js +29 -0
  119. package/lib/module/primitives/FlatList.js.map +1 -0
  120. package/lib/module/primitives/Image.js +28 -0
  121. package/lib/module/primitives/Image.js.map +1 -0
  122. package/lib/module/primitives/KeyboardAvoidingView.js +19 -0
  123. package/lib/module/primitives/KeyboardAvoidingView.js.map +1 -0
  124. package/lib/module/primitives/Modal.js +19 -0
  125. package/lib/module/primitives/Modal.js.map +1 -0
  126. package/lib/module/primitives/Pressable.js +21 -0
  127. package/lib/module/primitives/Pressable.js.map +1 -0
  128. package/lib/module/primitives/SafeAreaView.js +33 -0
  129. package/lib/module/primitives/SafeAreaView.js.map +1 -0
  130. package/lib/module/primitives/ScrollView.js +21 -0
  131. package/lib/module/primitives/ScrollView.js.map +1 -0
  132. package/lib/module/primitives/StatusBar.js +19 -0
  133. package/lib/module/primitives/StatusBar.js.map +1 -0
  134. package/lib/module/primitives/Switch.js +23 -0
  135. package/lib/module/primitives/Switch.js.map +1 -0
  136. package/lib/module/primitives/Text.js +32 -0
  137. package/lib/module/primitives/Text.js.map +1 -0
  138. package/lib/module/primitives/TextInput.js +26 -0
  139. package/lib/module/primitives/TextInput.js.map +1 -0
  140. package/lib/module/primitives/View.js +19 -0
  141. package/lib/module/primitives/View.js.map +1 -0
  142. package/lib/module/primitives/index.js +16 -0
  143. package/lib/module/primitives/index.js.map +1 -0
  144. package/lib/module/registry/ComponentRegistry.js +66 -0
  145. package/lib/module/registry/ComponentRegistry.js.map +1 -0
  146. package/lib/module/registry.js +88 -0
  147. package/lib/module/registry.js.map +1 -0
  148. package/lib/module/renderer/RecursiveRenderer.js +197 -0
  149. package/lib/module/renderer/RecursiveRenderer.js.map +1 -0
  150. package/lib/module/renderer/bindingResolver.js +92 -0
  151. package/lib/module/renderer/bindingResolver.js.map +1 -0
  152. package/lib/module/renderer/conditionalEvaluator.js +28 -0
  153. package/lib/module/renderer/conditionalEvaluator.js.map +1 -0
  154. package/lib/module/renderer.js +103 -0
  155. package/lib/module/renderer.js.map +1 -0
  156. package/lib/module/schema.js +74 -0
  157. package/lib/module/schema.js.map +1 -0
  158. package/lib/module/transformer/index.js +1051 -0
  159. package/lib/module/transformer/index.js.map +1 -0
  160. package/lib/module/transport.js +82 -0
  161. package/lib/module/transport.js.map +1 -0
  162. package/lib/typescript/PushframeProvider.d.ts +58 -0
  163. package/lib/typescript/PushframeProvider.d.ts.map +1 -0
  164. package/lib/typescript/PushframeScreen.d.ts +36 -0
  165. package/lib/typescript/PushframeScreen.d.ts.map +1 -0
  166. package/lib/typescript/bindings.d.ts +29 -0
  167. package/lib/typescript/bindings.d.ts.map +1 -0
  168. package/lib/typescript/components/ButtonComponent.d.ts +11 -0
  169. package/lib/typescript/components/ButtonComponent.d.ts.map +1 -0
  170. package/lib/typescript/components/FlatListComponent.d.ts +28 -0
  171. package/lib/typescript/components/FlatListComponent.d.ts.map +1 -0
  172. package/lib/typescript/components/ImageComponent.d.ts +12 -0
  173. package/lib/typescript/components/ImageComponent.d.ts.map +1 -0
  174. package/lib/typescript/components/PushFrameComponent.d.ts +48 -0
  175. package/lib/typescript/components/PushFrameComponent.d.ts.map +1 -0
  176. package/lib/typescript/components/PushFrameProvider.d.ts +51 -0
  177. package/lib/typescript/components/PushFrameProvider.d.ts.map +1 -0
  178. package/lib/typescript/components/PushFrameScreen.d.ts +15 -0
  179. package/lib/typescript/components/PushFrameScreen.d.ts.map +1 -0
  180. package/lib/typescript/components/ScrollViewComponent.d.ts +19 -0
  181. package/lib/typescript/components/ScrollViewComponent.d.ts.map +1 -0
  182. package/lib/typescript/components/StackComponent.d.ts +16 -0
  183. package/lib/typescript/components/StackComponent.d.ts.map +1 -0
  184. package/lib/typescript/components/TextComponent.d.ts +13 -0
  185. package/lib/typescript/components/TextComponent.d.ts.map +1 -0
  186. package/lib/typescript/conditions.d.ts +12 -0
  187. package/lib/typescript/conditions.d.ts.map +1 -0
  188. package/lib/typescript/context/PushFrameContext.d.ts +57 -0
  189. package/lib/typescript/context/PushFrameContext.d.ts.map +1 -0
  190. package/lib/typescript/index.d.ts +74 -0
  191. package/lib/typescript/index.d.ts.map +1 -0
  192. package/lib/typescript/overlays/BottomSheetHost.d.ts +21 -0
  193. package/lib/typescript/overlays/BottomSheetHost.d.ts.map +1 -0
  194. package/lib/typescript/overlays/ToastHost.d.ts +12 -0
  195. package/lib/typescript/overlays/ToastHost.d.ts.map +1 -0
  196. package/lib/typescript/primitives/ActivityIndicator.d.ts +12 -0
  197. package/lib/typescript/primitives/ActivityIndicator.d.ts.map +1 -0
  198. package/lib/typescript/primitives/FlatList.d.ts +29 -0
  199. package/lib/typescript/primitives/FlatList.d.ts.map +1 -0
  200. package/lib/typescript/primitives/Image.d.ts +20 -0
  201. package/lib/typescript/primitives/Image.d.ts.map +1 -0
  202. package/lib/typescript/primitives/KeyboardAvoidingView.d.ts +12 -0
  203. package/lib/typescript/primitives/KeyboardAvoidingView.d.ts.map +1 -0
  204. package/lib/typescript/primitives/Modal.d.ts +12 -0
  205. package/lib/typescript/primitives/Modal.d.ts.map +1 -0
  206. package/lib/typescript/primitives/Pressable.d.ts +14 -0
  207. package/lib/typescript/primitives/Pressable.d.ts.map +1 -0
  208. package/lib/typescript/primitives/SafeAreaView.d.ts +20 -0
  209. package/lib/typescript/primitives/SafeAreaView.d.ts.map +1 -0
  210. package/lib/typescript/primitives/ScrollView.d.ts +15 -0
  211. package/lib/typescript/primitives/ScrollView.d.ts.map +1 -0
  212. package/lib/typescript/primitives/StatusBar.d.ts +12 -0
  213. package/lib/typescript/primitives/StatusBar.d.ts.map +1 -0
  214. package/lib/typescript/primitives/Switch.d.ts +19 -0
  215. package/lib/typescript/primitives/Switch.d.ts.map +1 -0
  216. package/lib/typescript/primitives/Text.d.ts +25 -0
  217. package/lib/typescript/primitives/Text.d.ts.map +1 -0
  218. package/lib/typescript/primitives/TextInput.d.ts +25 -0
  219. package/lib/typescript/primitives/TextInput.d.ts.map +1 -0
  220. package/lib/typescript/primitives/View.d.ts +12 -0
  221. package/lib/typescript/primitives/View.d.ts.map +1 -0
  222. package/lib/typescript/primitives/index.d.ts +27 -0
  223. package/lib/typescript/primitives/index.d.ts.map +1 -0
  224. package/lib/typescript/registry/ComponentRegistry.d.ts +21 -0
  225. package/lib/typescript/registry/ComponentRegistry.d.ts.map +1 -0
  226. package/lib/typescript/registry.d.ts +57 -0
  227. package/lib/typescript/registry.d.ts.map +1 -0
  228. package/lib/typescript/renderer/RecursiveRenderer.d.ts +32 -0
  229. package/lib/typescript/renderer/RecursiveRenderer.d.ts.map +1 -0
  230. package/lib/typescript/renderer/bindingResolver.d.ts +26 -0
  231. package/lib/typescript/renderer/bindingResolver.d.ts.map +1 -0
  232. package/lib/typescript/renderer/conditionalEvaluator.d.ts +15 -0
  233. package/lib/typescript/renderer/conditionalEvaluator.d.ts.map +1 -0
  234. package/lib/typescript/renderer.d.ts +29 -0
  235. package/lib/typescript/renderer.d.ts.map +1 -0
  236. package/lib/typescript/schema.d.ts +84 -0
  237. package/lib/typescript/schema.d.ts.map +1 -0
  238. package/lib/typescript/transformer/index.d.ts +49 -0
  239. package/lib/typescript/transformer/index.d.ts.map +1 -0
  240. package/lib/typescript/transport.d.ts +19 -0
  241. package/lib/typescript/transport.d.ts.map +1 -0
  242. package/package.json +20 -18
  243. package/src/PushframeProvider.tsx +119 -0
  244. package/src/PushframeScreen.tsx +107 -0
  245. package/src/bindings.ts +72 -0
  246. package/src/components/ButtonComponent.tsx +87 -0
  247. package/src/components/FlatListComponent.tsx +86 -0
  248. package/src/components/ImageComponent.tsx +70 -0
  249. package/src/components/PushFrameComponent.tsx +221 -0
  250. package/src/components/PushFrameProvider.tsx +177 -0
  251. package/src/components/PushFrameScreen.tsx +30 -0
  252. package/src/components/ScrollViewComponent.tsx +65 -0
  253. package/src/components/StackComponent.tsx +69 -0
  254. package/src/components/TextComponent.tsx +60 -0
  255. package/src/conditions.ts +46 -0
  256. package/src/context/PushFrameContext.ts +89 -0
  257. package/src/index.ts +119 -0
  258. package/src/overlays/BottomSheetHost.tsx +175 -0
  259. package/src/overlays/ToastHost.tsx +147 -0
  260. package/src/primitives/ActivityIndicator.tsx +21 -0
  261. package/src/primitives/FlatList.tsx +49 -0
  262. package/src/primitives/Image.tsx +26 -0
  263. package/src/primitives/KeyboardAvoidingView.tsx +21 -0
  264. package/src/primitives/Modal.tsx +17 -0
  265. package/src/primitives/Pressable.tsx +19 -0
  266. package/src/primitives/SafeAreaView.tsx +42 -0
  267. package/src/primitives/ScrollView.tsx +21 -0
  268. package/src/primitives/StatusBar.tsx +17 -0
  269. package/src/primitives/Switch.tsx +24 -0
  270. package/src/primitives/Text.tsx +43 -0
  271. package/src/primitives/TextInput.tsx +42 -0
  272. package/src/primitives/View.tsx +17 -0
  273. package/src/primitives/index.ts +38 -0
  274. package/src/registry/ComponentRegistry.ts +99 -0
  275. package/src/registry.ts +99 -0
  276. package/src/renderer/RecursiveRenderer.tsx +242 -0
  277. package/src/renderer/bindingResolver.ts +94 -0
  278. package/src/renderer/conditionalEvaluator.ts +29 -0
  279. package/src/renderer.tsx +124 -0
  280. package/src/schema.ts +132 -0
  281. package/src/transformer/index.ts +1016 -0
  282. package/src/transport.ts +104 -0
  283. package/dist/index.d.mts +0 -534
  284. package/dist/index.d.ts +0 -534
  285. package/dist/index.js +0 -1572
  286. package/dist/index.js.map +0 -1
  287. package/dist/index.mjs +0 -1541
  288. package/dist/index.mjs.map +0 -1
@@ -0,0 +1,1051 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Craft.js → PushFrame SDUI transformer
5
+ *
6
+ * Converts a Craft.js editor schema (produced by the dashboard) into the
7
+ * SDUINode tree consumed by the SDK's RecursiveRenderer at runtime.
8
+ *
9
+ * This module is intended for use by the backend/service layer or the
10
+ * dashboard — it is NOT executed inside the React Native app at runtime.
11
+ */
12
+
13
+ // ─── Craft input types ────────────────────────────────────────────────────────
14
+
15
+ // ─── Output types ─────────────────────────────────────────────────────────────
16
+
17
+ /**
18
+ * The SDUI node shape produced by this transformer and consumed by the SDK's
19
+ * RecursiveRenderer. Aligned with `SchemaNode` from the SDK context.
20
+ */
21
+
22
+ // ─── Constants ────────────────────────────────────────────────────────────────
23
+
24
+ const BRIDGE_KEYS = new Set(['_schemaId', '_schemaType', '_schemaActions', '_schemaIf', '_schemaRenderItem']);
25
+ const ALIGN_MAP = {
26
+ start: 'flex-start',
27
+ center: 'center',
28
+ end: 'flex-end',
29
+ stretch: 'stretch',
30
+ baseline: 'baseline'
31
+ };
32
+ const DISTRIBUTE_MAP = {
33
+ start: 'flex-start',
34
+ center: 'center',
35
+ end: 'flex-end',
36
+ 'space-between': 'space-between',
37
+ 'space-around': 'space-around',
38
+ 'space-evenly': 'space-evenly'
39
+ };
40
+ const FIT_TO_RESIZE_MODE = {
41
+ cover: 'cover',
42
+ contain: 'contain',
43
+ fill: 'stretch',
44
+ // RN uses 'stretch', not 'fill'
45
+ center: 'center'
46
+ };
47
+ const FONT_WEIGHT_MAP = {
48
+ regular: '400',
49
+ medium: '500',
50
+ semibold: '600',
51
+ bold: '700'
52
+ };
53
+ const TEXT_STYLE_PRESETS = {
54
+ 'heading-1': {
55
+ fontSize: 28,
56
+ fontWeight: '700'
57
+ },
58
+ 'heading-2': {
59
+ fontSize: 22,
60
+ fontWeight: '700'
61
+ },
62
+ 'heading-3': {
63
+ fontSize: 18,
64
+ fontWeight: '600'
65
+ },
66
+ 'body': {
67
+ fontSize: 16,
68
+ fontWeight: '400'
69
+ },
70
+ 'body-sm': {
71
+ fontSize: 14,
72
+ fontWeight: '400'
73
+ },
74
+ 'caption': {
75
+ fontSize: 12,
76
+ fontWeight: '400'
77
+ },
78
+ 'label': {
79
+ fontSize: 13,
80
+ fontWeight: '500'
81
+ },
82
+ 'overline': {
83
+ fontSize: 11,
84
+ fontWeight: '500',
85
+ textTransform: 'uppercase',
86
+ letterSpacing: 0.8
87
+ }
88
+ };
89
+
90
+ // inputType → RN keyboard + behaviour props
91
+ const INPUT_TYPE_MAP = {
92
+ text: {
93
+ keyboardType: 'default',
94
+ secureTextEntry: false,
95
+ autoCapitalize: 'sentences',
96
+ autoCorrect: true
97
+ },
98
+ email: {
99
+ keyboardType: 'email-address',
100
+ secureTextEntry: false,
101
+ autoCapitalize: 'none',
102
+ autoCorrect: false
103
+ },
104
+ password: {
105
+ keyboardType: 'default',
106
+ secureTextEntry: true,
107
+ autoCapitalize: 'none',
108
+ autoCorrect: false
109
+ },
110
+ number: {
111
+ keyboardType: 'numeric',
112
+ secureTextEntry: false,
113
+ autoCapitalize: 'none',
114
+ autoCorrect: false
115
+ },
116
+ decimal: {
117
+ keyboardType: 'decimal-pad',
118
+ secureTextEntry: false,
119
+ autoCapitalize: 'none',
120
+ autoCorrect: false
121
+ },
122
+ phone: {
123
+ keyboardType: 'phone-pad',
124
+ secureTextEntry: false,
125
+ autoCapitalize: 'none',
126
+ autoCorrect: false
127
+ },
128
+ url: {
129
+ keyboardType: 'url',
130
+ secureTextEntry: false,
131
+ autoCapitalize: 'none',
132
+ autoCorrect: false
133
+ },
134
+ search: {
135
+ keyboardType: 'default',
136
+ secureTextEntry: false,
137
+ autoCapitalize: 'none',
138
+ autoCorrect: false
139
+ }
140
+ };
141
+
142
+ // ─── Prop helpers ─────────────────────────────────────────────────────────────
143
+
144
+ function stripBridgeKeys(props) {
145
+ const out = {};
146
+ for (const k in props) {
147
+ if (!BRIDGE_KEYS.has(k)) out[k] = props[k];
148
+ }
149
+ return out;
150
+ }
151
+ function extractMeta(raw) {
152
+ return {
153
+ actions: raw._schemaActions,
154
+ condition: raw._schemaIf
155
+ };
156
+ }
157
+
158
+ // ─── RN style sub-builders ────────────────────────────────────────────────────
159
+
160
+ function resolveSizeModeRN(value, axis, out, parentDirection) {
161
+ if (value === undefined) return;
162
+ if (value === 'fill') {
163
+ const isMainAxis = parentDirection === 'vertical' && axis === 'height' || parentDirection === 'horizontal' && axis === 'width';
164
+ if (isMainAxis) {
165
+ out.flex = 1;
166
+ } else {
167
+ out.alignSelf = 'stretch';
168
+ }
169
+ } else if (value === 'hug') {
170
+ out.alignSelf = 'flex-start';
171
+ } else {
172
+ out[axis] = value;
173
+ }
174
+ }
175
+ function resolvePaddingRN(padding) {
176
+ if (padding === undefined) return {};
177
+ if (typeof padding === 'number') return {
178
+ padding
179
+ };
180
+ const {
181
+ top,
182
+ right,
183
+ bottom,
184
+ left
185
+ } = padding;
186
+ if (top === bottom && left === right && top !== undefined && left !== undefined) {
187
+ return {
188
+ paddingVertical: top,
189
+ paddingHorizontal: left
190
+ };
191
+ }
192
+ return {
193
+ ...(top !== undefined ? {
194
+ paddingTop: top
195
+ } : {}),
196
+ ...(right !== undefined ? {
197
+ paddingRight: right
198
+ } : {}),
199
+ ...(bottom !== undefined ? {
200
+ paddingBottom: bottom
201
+ } : {}),
202
+ ...(left !== undefined ? {
203
+ paddingLeft: left
204
+ } : {})
205
+ };
206
+ }
207
+ function resolveRadiusRN(radius) {
208
+ if (radius === undefined) return {};
209
+ if (typeof radius === 'number') return {
210
+ borderRadius: radius
211
+ };
212
+ return {
213
+ ...(radius.tl !== undefined ? {
214
+ borderTopLeftRadius: radius.tl
215
+ } : {}),
216
+ ...(radius.tr !== undefined ? {
217
+ borderTopRightRadius: radius.tr
218
+ } : {}),
219
+ ...(radius.br !== undefined ? {
220
+ borderBottomRightRadius: radius.br
221
+ } : {}),
222
+ ...(radius.bl !== undefined ? {
223
+ borderBottomLeftRadius: radius.bl
224
+ } : {})
225
+ };
226
+ }
227
+ function resolveBorderRN(border) {
228
+ if (!border) return {};
229
+ const out = {};
230
+ if (border.style) out.borderStyle = border.style;
231
+ if (border.color) out.borderColor = border.color;
232
+ if (border.widths) {
233
+ const w = border.widths;
234
+ if (w.top !== undefined) out.borderTopWidth = w.top;
235
+ if (w.right !== undefined) out.borderRightWidth = w.right;
236
+ if (w.bottom !== undefined) out.borderBottomWidth = w.bottom;
237
+ if (w.left !== undefined) out.borderLeftWidth = w.left;
238
+ } else if (border.width !== undefined) {
239
+ out.borderWidth = border.width;
240
+ }
241
+ return out;
242
+ }
243
+ function resolveShadowRN(shadow) {
244
+ if (!shadow) return {};
245
+ return {
246
+ shadowColor: shadow.color,
247
+ shadowOffset: {
248
+ width: shadow.offsetX,
249
+ height: shadow.offsetY
250
+ },
251
+ shadowRadius: shadow.blur,
252
+ shadowOpacity: shadow.opacity,
253
+ elevation: Math.round(shadow.blur / 2)
254
+ };
255
+ }
256
+ function resolveTransformRN(props) {
257
+ const transforms = [];
258
+ if (props.rotate !== undefined && props.rotate !== 0) transforms.push({
259
+ rotate: `${props.rotate}deg`
260
+ });
261
+ if (props.scale !== undefined && props.scale !== 1) transforms.push({
262
+ scale: props.scale
263
+ });
264
+ if (props.translateX !== undefined && props.translateX !== 0) transforms.push({
265
+ translateX: props.translateX
266
+ });
267
+ if (props.translateY !== undefined && props.translateY !== 0) transforms.push({
268
+ translateY: props.translateY
269
+ });
270
+ return transforms.length ? {
271
+ transform: transforms
272
+ } : {};
273
+ }
274
+ function resolvePositionRN(props) {
275
+ const out = {};
276
+ if (props.position) out.position = props.position;
277
+ if (props.position === 'absolute') {
278
+ if (props.top !== undefined) out.top = props.top;
279
+ if (props.right !== undefined) out.right = props.right;
280
+ if (props.bottom !== undefined) out.bottom = props.bottom;
281
+ if (props.left !== undefined) out.left = props.left;
282
+ }
283
+ if (props.zIndex !== undefined) out.zIndex = props.zIndex;
284
+ return out;
285
+ }
286
+ function resolveAccessibilityProps(props) {
287
+ const out = {};
288
+ if (props.accessible !== undefined) out.accessible = props.accessible;
289
+ if (props.accessibilityLabel) out.accessibilityLabel = props.accessibilityLabel;
290
+ if (props.accessibilityRole) out.accessibilityRole = props.accessibilityRole;
291
+ if (props.testID) out.testID = props.testID;
292
+ return out;
293
+ }
294
+
295
+ // ─── Full frame-style builder ─────────────────────────────────────────────────
296
+
297
+ function buildFrameStyle(props, parentDirection) {
298
+ const style = {};
299
+ const frameType = props.type ?? 'stack';
300
+ if (frameType === 'grid') {
301
+ if (props.align) style.alignItems = ALIGN_MAP[props.align] ?? props.align;
302
+ } else {
303
+ style.flexDirection = props.direction === 'horizontal' ? 'row' : 'column';
304
+ if (props.align) style.alignItems = ALIGN_MAP[props.align] ?? props.align;
305
+ if (props.distribute) style.justifyContent = DISTRIBUTE_MAP[props.distribute] ?? props.distribute;
306
+ if (props.gap !== undefined && props.gap !== 0) style.gap = props.gap;
307
+ if (props.wrap === 'yes') style.flexWrap = 'wrap';
308
+ }
309
+ resolveSizeModeRN(props.width, 'width', style, parentDirection);
310
+ resolveSizeModeRN(props.height, 'height', style, parentDirection);
311
+ if (props.minWidth !== undefined) style.minWidth = props.minWidth;
312
+ if (props.maxWidth !== undefined) style.maxWidth = props.maxWidth;
313
+ if (props.minHeight !== undefined) style.minHeight = props.minHeight;
314
+ if (props.maxHeight !== undefined) style.maxHeight = props.maxHeight;
315
+ if (props.aspectRatio !== undefined) style.aspectRatio = props.aspectRatio;
316
+ Object.assign(style, resolvePaddingRN(props.padding));
317
+ if (props.fill && props.fill !== 'transparent') style.backgroundColor = props.fill;
318
+ Object.assign(style, resolveRadiusRN(props.radius));
319
+ Object.assign(style, resolveBorderRN(props.border));
320
+ Object.assign(style, resolveShadowRN(props.shadow));
321
+ if (props.opacity !== undefined) style.opacity = props.opacity / 100;
322
+ if (props.overflow === true) style.overflow = 'hidden';
323
+ Object.assign(style, resolvePositionRN(props));
324
+ Object.assign(style, resolveTransformRN(props));
325
+ return style;
326
+ }
327
+ function splitFrameStyle(style) {
328
+ const OUTER_KEYS = new Set(['flex', 'alignSelf', 'width', 'height', 'minWidth', 'maxWidth', 'minHeight', 'maxHeight', 'aspectRatio', 'position', 'top', 'right', 'bottom', 'left', 'zIndex', 'transform']);
329
+ const outer = {};
330
+ const inner = {};
331
+ for (const [k, v] of Object.entries(style)) {
332
+ if (OUTER_KEYS.has(k)) outer[k] = v;else inner[k] = v;
333
+ }
334
+ return {
335
+ outer,
336
+ inner
337
+ };
338
+ }
339
+ function splitScrollStyle(style) {
340
+ const CONTENT_KEYS = new Set(['flexDirection', 'justifyContent', 'alignItems', 'flexWrap', 'gap', 'padding', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft', 'paddingVertical', 'paddingHorizontal']);
341
+ const containerStyle = {};
342
+ const contentStyle = {};
343
+ for (const [k, v] of Object.entries(style)) {
344
+ if (CONTENT_KEYS.has(k)) contentStyle[k] = v;else containerStyle[k] = v;
345
+ }
346
+ return {
347
+ containerStyle,
348
+ contentStyle
349
+ };
350
+ }
351
+
352
+ // ─── Safe area helper ─────────────────────────────────────────────────────────
353
+
354
+ function safeAreaEdges(safeArea) {
355
+ if (!safeArea) return [];
356
+ return Object.entries(safeArea).filter(([, v]) => v === true).map(([edge]) => edge);
357
+ }
358
+
359
+ // ─── Custom component definition ──────────────────────────────────────────────
360
+
361
+ // ─── Node transformers ────────────────────────────────────────────────────────
362
+
363
+ function transformScreen(id, raw, children) {
364
+ const {
365
+ actions,
366
+ condition
367
+ } = extractMeta(raw);
368
+ const props = stripBridgeKeys(raw);
369
+ const edges = safeAreaEdges(props.safeArea);
370
+ const hasSafeArea = edges.length > 0;
371
+ const vis = props.visible !== undefined && props.visible !== true ? {
372
+ visible: props.visible
373
+ } : {};
374
+ const style = {
375
+ flex: 1
376
+ };
377
+ if (props.backgroundColor) style.backgroundColor = props.backgroundColor;
378
+ let content;
379
+ if (props.scrollable) {
380
+ const paddingStyle = resolvePaddingRN(props.padding);
381
+ const scrollNode = {
382
+ id: `${id}__scroll`,
383
+ type: 'scrollview',
384
+ props: {
385
+ style: {
386
+ flex: 1
387
+ },
388
+ ...(Object.keys(paddingStyle).length ? {
389
+ contentContainerStyle: paddingStyle
390
+ } : {}),
391
+ showsVerticalScrollIndicator: false,
392
+ showsHorizontalScrollIndicator: false
393
+ },
394
+ children
395
+ };
396
+ content = [scrollNode];
397
+ } else {
398
+ Object.assign(style, resolvePaddingRN(props.padding));
399
+ content = children;
400
+ }
401
+ const statusBar = props.statusBarStyle && props.statusBarStyle !== 'dark' ? {
402
+ statusBarStyle: props.statusBarStyle
403
+ } : {};
404
+ const node = {
405
+ id,
406
+ type: hasSafeArea ? 'safeareaview' : 'view',
407
+ props: {
408
+ style,
409
+ ...(hasSafeArea ? {
410
+ edges
411
+ } : {}),
412
+ ...statusBar,
413
+ ...vis
414
+ },
415
+ children: content
416
+ };
417
+ if (condition !== undefined) node.if = condition;
418
+ if (actions) node.actions = actions;
419
+ return node;
420
+ }
421
+ function transformFrame(id, raw, children, parentDirection) {
422
+ const {
423
+ actions,
424
+ condition
425
+ } = extractMeta(raw);
426
+ const p = stripBridgeKeys(raw);
427
+ const isGrid = (p.type ?? 'stack') === 'grid';
428
+ const isScrollable = p.scrollable === true;
429
+ const isPressable = p.pressable === true;
430
+ const direction = p.direction === 'horizontal' ? 'horizontal' : 'vertical';
431
+ const edges = safeAreaEdges(p.safeArea);
432
+ const hasSafeArea = edges.length > 0;
433
+ const access = resolveAccessibilityProps(p);
434
+ const vis = p.visible !== undefined && p.visible !== true ? {
435
+ visible: p.visible
436
+ } : {};
437
+ const fullStyle = buildFrameStyle(p, parentDirection);
438
+ const {
439
+ outer: sizingStyle,
440
+ inner: appearanceStyle
441
+ } = splitFrameStyle(fullStyle);
442
+ const {
443
+ containerStyle: scrollOuter,
444
+ contentStyle: scrollContent
445
+ } = splitScrollStyle(fullStyle);
446
+ function finalize(node) {
447
+ if (condition !== undefined) node.if = condition;
448
+ if (actions && node.type === 'pressable') node.actions = actions;else if (actions && !isPressable) node.actions = actions;
449
+ return node;
450
+ }
451
+
452
+ // ── Grid ──────────────────────────────────────────────────────────────────
453
+ if (isGrid) {
454
+ const gridStyle = {
455
+ ...fullStyle,
456
+ flexDirection: 'row',
457
+ flexWrap: 'wrap'
458
+ };
459
+ delete gridStyle.gap;
460
+ if (p.columnGap !== undefined) gridStyle.columnGap = p.columnGap;
461
+ if (p.rowGap !== undefined) gridStyle.rowGap = p.rowGap;
462
+ const gridView = {
463
+ id: hasSafeArea || isPressable ? `${id}__grid` : id,
464
+ type: 'view',
465
+ props: {
466
+ ...(Object.keys(gridStyle).length ? {
467
+ style: gridStyle
468
+ } : {}),
469
+ numColumns: p.columns ?? 2,
470
+ ...access,
471
+ ...(hasSafeArea || isPressable ? {} : vis)
472
+ },
473
+ children
474
+ };
475
+ if (!hasSafeArea && !isPressable) return finalize(gridView);
476
+ let inner = gridView;
477
+ if (hasSafeArea) {
478
+ inner = {
479
+ id: isPressable ? `${id}__sav` : id,
480
+ type: 'safeareaview',
481
+ props: {
482
+ edges,
483
+ ...(isPressable ? {} : vis)
484
+ },
485
+ children: [gridView]
486
+ };
487
+ }
488
+ if (!isPressable) return finalize(inner);
489
+ return finalize({
490
+ id,
491
+ type: 'pressable',
492
+ props: {
493
+ ...(Object.keys(sizingStyle).length ? {
494
+ style: sizingStyle
495
+ } : {}),
496
+ ...(actions ? {
497
+ actions
498
+ } : {}),
499
+ ...vis
500
+ },
501
+ children: [inner]
502
+ });
503
+ }
504
+
505
+ // ── Scrollable ────────────────────────────────────────────────────────────
506
+ if (isScrollable) {
507
+ const scrollNode = {
508
+ id: hasSafeArea || isPressable ? `${id}__scroll` : id,
509
+ type: 'scrollview',
510
+ props: {
511
+ ...(Object.keys(scrollOuter).length ? {
512
+ style: scrollOuter
513
+ } : {}),
514
+ ...(Object.keys(scrollContent).length ? {
515
+ contentContainerStyle: scrollContent
516
+ } : {}),
517
+ horizontal: direction === 'horizontal',
518
+ showsHorizontalScrollIndicator: p.showScrollIndicator === true,
519
+ showsVerticalScrollIndicator: p.showScrollIndicator === true,
520
+ ...access,
521
+ ...(hasSafeArea || isPressable ? {} : vis)
522
+ },
523
+ children
524
+ };
525
+ if (!hasSafeArea && !isPressable) return finalize(scrollNode);
526
+ let inner = scrollNode;
527
+ if (hasSafeArea) {
528
+ inner = {
529
+ id: isPressable ? `${id}__sav` : id,
530
+ type: 'safeareaview',
531
+ props: {
532
+ edges,
533
+ ...(Object.keys(sizingStyle).length ? {
534
+ style: sizingStyle
535
+ } : {}),
536
+ ...(isPressable ? {} : vis)
537
+ },
538
+ children: [scrollNode]
539
+ };
540
+ }
541
+ if (!isPressable) return finalize(inner);
542
+ return finalize({
543
+ id,
544
+ type: 'pressable',
545
+ props: {
546
+ ...(Object.keys(sizingStyle).length ? {
547
+ style: sizingStyle
548
+ } : {}),
549
+ ...(actions ? {
550
+ actions
551
+ } : {}),
552
+ ...vis
553
+ },
554
+ children: [inner]
555
+ });
556
+ }
557
+
558
+ // ── Plain view / safeareaview ─────────────────────────────────────────────
559
+
560
+ if (!isPressable && !hasSafeArea) {
561
+ return finalize({
562
+ id,
563
+ type: 'view',
564
+ props: {
565
+ ...(Object.keys(fullStyle).length ? {
566
+ style: fullStyle
567
+ } : {}),
568
+ ...access,
569
+ ...vis
570
+ },
571
+ children
572
+ });
573
+ }
574
+ if (!isPressable && hasSafeArea) {
575
+ return finalize({
576
+ id,
577
+ type: 'safeareaview',
578
+ props: {
579
+ edges,
580
+ ...(Object.keys(fullStyle).length ? {
581
+ style: fullStyle
582
+ } : {}),
583
+ ...access,
584
+ ...vis
585
+ },
586
+ children
587
+ });
588
+ }
589
+
590
+ // isPressable === true
591
+ const innerNode = hasSafeArea ? {
592
+ id: `${id}__sav`,
593
+ type: 'safeareaview',
594
+ props: {
595
+ edges,
596
+ ...(Object.keys(appearanceStyle).length ? {
597
+ style: appearanceStyle
598
+ } : {}),
599
+ ...access
600
+ },
601
+ children
602
+ } : {
603
+ id: `${id}__content`,
604
+ type: 'view',
605
+ props: {
606
+ ...(Object.keys(appearanceStyle).length ? {
607
+ style: appearanceStyle
608
+ } : {}),
609
+ ...access
610
+ },
611
+ children
612
+ };
613
+ return finalize({
614
+ id,
615
+ type: 'pressable',
616
+ props: {
617
+ ...(Object.keys(sizingStyle).length ? {
618
+ style: sizingStyle
619
+ } : {}),
620
+ ...(actions ? {
621
+ actions
622
+ } : {}),
623
+ ...vis
624
+ },
625
+ children: [innerNode]
626
+ });
627
+ }
628
+ function transformText(id, raw, parentDirection) {
629
+ const {
630
+ actions,
631
+ condition
632
+ } = extractMeta(raw);
633
+ const props = stripBridgeKeys(raw);
634
+ const style = {};
635
+ if (props.textStyle) {
636
+ const preset = TEXT_STYLE_PRESETS[props.textStyle];
637
+ if (preset) {
638
+ style.fontSize = preset.fontSize;
639
+ style.fontWeight = preset.fontWeight;
640
+ if (preset.lineHeight !== undefined) style.lineHeight = preset.lineHeight;
641
+ if (preset.textTransform) style.textTransform = preset.textTransform;
642
+ if (preset.letterSpacing !== undefined) style.letterSpacing = preset.letterSpacing;
643
+ }
644
+ }
645
+ if (props.color) style.color = props.color;
646
+ if (props.fontSize !== undefined) style.fontSize = props.fontSize;
647
+ if (props.fontWeight) style.fontWeight = FONT_WEIGHT_MAP[props.fontWeight] ?? props.fontWeight;
648
+ if (props.fontFamily) style.fontFamily = props.fontFamily;
649
+ if (props.fontStyle) style.fontStyle = props.fontStyle;
650
+ if (props.lineHeight !== undefined) style.lineHeight = props.lineHeight;
651
+ if (props.letterSpacing !== undefined) style.letterSpacing = props.letterSpacing;
652
+ if (props.align) style.textAlign = props.align;
653
+ if (props.transform && props.transform !== 'none') style.textTransform = props.transform;
654
+ if (props.decoration && props.decoration !== 'none') style.textDecorationLine = props.decoration;
655
+ if (props.opacity !== undefined) style.opacity = props.opacity / 100;
656
+ Object.assign(style, resolvePositionRN(props));
657
+ resolveSizeModeRN(props.width, 'width', style, parentDirection);
658
+ const textProps = {};
659
+ if (typeof props.truncate === 'number' && props.truncate > 0) {
660
+ textProps.numberOfLines = props.truncate;
661
+ textProps.ellipsizeMode = 'tail';
662
+ }
663
+ if (props.adjustFontSize === true) {
664
+ textProps.adjustsFontSizeToFit = true;
665
+ if (props.minFontSize !== undefined) textProps.minimumFontScale = props.minFontSize;
666
+ }
667
+ if (props.selectable !== undefined) textProps.selectable = props.selectable;
668
+ const node = {
669
+ id,
670
+ type: 'text',
671
+ props: {
672
+ // SDK contract: text content lives in the `value` prop.
673
+ // The Craft editor stores text in `content`; map it to `value` here.
674
+ value: props.content ?? '',
675
+ ...(Object.keys(style).length ? {
676
+ style
677
+ } : {}),
678
+ ...textProps,
679
+ ...resolveAccessibilityProps(props),
680
+ ...(props.visible !== undefined && props.visible !== true ? {
681
+ visible: props.visible
682
+ } : {})
683
+ }
684
+ };
685
+ if (condition !== undefined) node.if = condition;
686
+ if (actions) node.actions = actions;
687
+ return node;
688
+ }
689
+ function transformImage(id, raw, children, parentDirection) {
690
+ const {
691
+ actions,
692
+ condition
693
+ } = extractMeta(raw);
694
+ const props = stripBridgeKeys(raw);
695
+ const style = {};
696
+ resolveSizeModeRN(props.width, 'width', style, parentDirection);
697
+ resolveSizeModeRN(props.height, 'height', style, parentDirection);
698
+ if (props.aspectRatio !== undefined) style.aspectRatio = props.aspectRatio;
699
+ Object.assign(style, resolveRadiusRN(props.radius));
700
+ if (props.opacity !== undefined) style.opacity = props.opacity / 100;
701
+ Object.assign(style, resolvePositionRN(props));
702
+ const imageProps = {};
703
+ if (props.src) imageProps.source = {
704
+ uri: props.src
705
+ };
706
+ if (props.placeholder) imageProps.defaultSource = {
707
+ uri: props.placeholder
708
+ };
709
+ if (props.fallback) imageProps.fallback = {
710
+ uri: props.fallback
711
+ };
712
+ imageProps.resizeMode = FIT_TO_RESIZE_MODE[props.fit ?? 'cover'] ?? 'cover';
713
+ if (props.background === true) imageProps.background = true;
714
+ if (props.decorative) {
715
+ imageProps.accessible = false;
716
+ imageProps.accessibilityElementsHidden = true;
717
+ } else if (props.alt) {
718
+ imageProps.accessible = true;
719
+ imageProps.accessibilityLabel = props.alt;
720
+ }
721
+ if (props.testID) imageProps.testID = props.testID;
722
+ const node = {
723
+ id,
724
+ type: 'image',
725
+ props: {
726
+ ...(Object.keys(style).length ? {
727
+ style
728
+ } : {}),
729
+ ...imageProps,
730
+ ...(props.visible !== undefined && props.visible !== true ? {
731
+ visible: props.visible
732
+ } : {})
733
+ },
734
+ ...(props.background === true && children.length ? {
735
+ children
736
+ } : {})
737
+ };
738
+ if (condition !== undefined) node.if = condition;
739
+ if (actions) node.actions = actions;
740
+ return node;
741
+ }
742
+ function transformInput(id, raw, parentDirection) {
743
+ const {
744
+ actions,
745
+ condition
746
+ } = extractMeta(raw);
747
+ const props = stripBridgeKeys(raw);
748
+ const style = {};
749
+ resolveSizeModeRN(props.width ?? 'fill', 'width', style, parentDirection);
750
+ Object.assign(style, resolvePaddingRN(props.padding));
751
+ if (props.opacity !== undefined) style.opacity = props.opacity / 100;
752
+ Object.assign(style, resolvePositionRN(props));
753
+ const inputTypeDefaults = INPUT_TYPE_MAP[props.inputType ?? 'text'] ?? INPUT_TYPE_MAP.text;
754
+ const node = {
755
+ id,
756
+ type: 'textinput',
757
+ props: {
758
+ ...(Object.keys(style).length ? {
759
+ style
760
+ } : {}),
761
+ ...(props.label !== undefined ? {
762
+ label: props.label
763
+ } : {}),
764
+ ...(props.placeholder !== undefined ? {
765
+ placeholder: props.placeholder
766
+ } : {}),
767
+ ...(props.value !== undefined ? {
768
+ value: props.value
769
+ } : {}),
770
+ ...(props.helperText !== undefined ? {
771
+ helperText: props.helperText
772
+ } : {}),
773
+ ...(props.errorText !== undefined ? {
774
+ errorText: props.errorText
775
+ } : {}),
776
+ ...inputTypeDefaults,
777
+ ...(props.autoCapitalize ? {
778
+ autoCapitalize: props.autoCapitalize
779
+ } : {}),
780
+ returnKeyType: props.returnKey ?? 'done',
781
+ multiline: props.multiline ?? false,
782
+ ...(props.multiline && props.minLines ? {
783
+ numberOfLines: props.minLines
784
+ } : {}),
785
+ ...(props.multiline && props.maxLines ? {
786
+ maxNumberOfLines: props.maxLines
787
+ } : {}),
788
+ variant: props.variant ?? 'outline',
789
+ size: props.size ?? 'md',
790
+ ...(props.leadingIcon ? {
791
+ leadingIcon: props.leadingIcon
792
+ } : {}),
793
+ ...(props.trailingIcon ? {
794
+ trailingIcon: props.trailingIcon
795
+ } : {}),
796
+ ...resolveAccessibilityProps(props),
797
+ ...(props.visible !== undefined && props.visible !== true ? {
798
+ visible: props.visible
799
+ } : {})
800
+ }
801
+ };
802
+ if (condition !== undefined) node.if = condition;
803
+ if (actions) node.actions = actions;
804
+ return node;
805
+ }
806
+ function transformList(id, raw, children, parentDirection) {
807
+ const {
808
+ actions,
809
+ condition
810
+ } = extractMeta(raw);
811
+ const props = stripBridgeKeys(raw);
812
+ const listType = props.type ?? 'stack';
813
+ const direction = props.direction === 'horizontal' ? 'horizontal' : 'vertical';
814
+ const edges = safeAreaEdges(props.safeArea);
815
+ const hasSafeArea = edges.length > 0;
816
+ const vis = props.visible !== undefined && props.visible !== true ? {
817
+ visible: props.visible
818
+ } : {};
819
+ const fullStyle = buildFrameStyle(props, parentDirection);
820
+ const {
821
+ containerStyle,
822
+ contentStyle
823
+ } = splitScrollStyle(fullStyle);
824
+
825
+ // Children of PF.List are the per-item template.
826
+ let itemTemplate;
827
+ if (children.length === 1) {
828
+ itemTemplate = children[0];
829
+ } else if (children.length > 1) {
830
+ itemTemplate = {
831
+ id: `${id}__template`,
832
+ type: 'view',
833
+ props: {},
834
+ children
835
+ };
836
+ }
837
+ const flatlistNode = {
838
+ id: hasSafeArea ? `${id}__list` : id,
839
+ type: 'flatlist',
840
+ props: {
841
+ ...(Object.keys(containerStyle).length ? {
842
+ style: containerStyle
843
+ } : {}),
844
+ ...(Object.keys(contentStyle).length ? {
845
+ contentContainerStyle: contentStyle
846
+ } : {}),
847
+ // `data` holds the binding expression for the list items array.
848
+ // RecursiveRenderer resolves it and passes items to the FlatList primitive.
849
+ data: props.data,
850
+ keyExtractor: props.keyExtractor ?? 'id',
851
+ ...(listType === 'grid' ? {
852
+ numColumns: props.columns ?? 2
853
+ } : {}),
854
+ ...(listType === 'grid' && props.columnGap ? {
855
+ columnGap: props.columnGap
856
+ } : {}),
857
+ ...(listType === 'grid' && props.rowGap ? {
858
+ rowGap: props.rowGap
859
+ } : {}),
860
+ horizontal: direction === 'horizontal',
861
+ showsHorizontalScrollIndicator: props.showScrollIndicator === true,
862
+ showsVerticalScrollIndicator: props.showScrollIndicator === true,
863
+ ...resolveAccessibilityProps(props),
864
+ ...(hasSafeArea ? {} : vis)
865
+ },
866
+ ...(itemTemplate ? {
867
+ itemTemplate
868
+ } : {})
869
+ };
870
+ if (!hasSafeArea) {
871
+ if (condition !== undefined) flatlistNode.if = condition;
872
+ if (actions) flatlistNode.actions = actions;
873
+ return flatlistNode;
874
+ }
875
+ const {
876
+ outer: sizingStyle
877
+ } = splitFrameStyle(fullStyle);
878
+ const savNode = {
879
+ id,
880
+ type: 'safeareaview',
881
+ props: {
882
+ edges,
883
+ ...(Object.keys(sizingStyle).length ? {
884
+ style: sizingStyle
885
+ } : {}),
886
+ ...vis
887
+ },
888
+ children: [flatlistNode]
889
+ };
890
+ if (condition !== undefined) savNode.if = condition;
891
+ if (actions) savNode.actions = actions;
892
+ return savNode;
893
+ }
894
+ function transformIcon(id, raw) {
895
+ const {
896
+ actions,
897
+ condition
898
+ } = extractMeta(raw);
899
+ const props = stripBridgeKeys(raw);
900
+ const style = {};
901
+ if (props.opacity !== undefined) style.opacity = props.opacity / 100;
902
+ Object.assign(style, resolvePositionRN(props));
903
+ const node = {
904
+ id,
905
+ type: 'icon',
906
+ props: {
907
+ name: props.name,
908
+ set: props.set ?? 'default',
909
+ size: props.size ?? 24,
910
+ ...(props.color ? {
911
+ color: props.color
912
+ } : {}),
913
+ ...(Object.keys(style).length ? {
914
+ style
915
+ } : {}),
916
+ ...resolveAccessibilityProps(props),
917
+ ...(props.visible !== undefined && props.visible !== true ? {
918
+ visible: props.visible
919
+ } : {})
920
+ }
921
+ };
922
+ if (condition !== undefined) node.if = condition;
923
+ if (actions) node.actions = actions;
924
+ return node;
925
+ }
926
+
927
+ // ─── Core recursive builder ───────────────────────────────────────────────────
928
+
929
+ function buildNodeFromSchema(nodeId, schema, customComponents, visited, parentId) {
930
+ if (visited.has(nodeId)) {
931
+ throw new Error(`Circular reference detected at node ${nodeId}`);
932
+ }
933
+ visited.add(nodeId);
934
+ const node = schema[nodeId];
935
+ if (!node) throw new Error(`Node not found: ${nodeId}`);
936
+ const resolvedName = node.type?.resolvedName;
937
+ if (!resolvedName) throw new Error(`Invalid node type at ${nodeId}`);
938
+ const raw = node.props ?? {};
939
+ const parentDirection = parentId ? schema[parentId]?.props?.['direction'] === 'horizontal' ? 'horizontal' : 'vertical' : 'vertical';
940
+ const outputId = nodeId === 'ROOT' ? 'root' : nodeId;
941
+ const childNodes = (node.nodes ?? []).map(childId => buildNodeFromSchema(childId, schema, customComponents, visited, nodeId));
942
+ switch (resolvedName) {
943
+ case 'PF.Screen':
944
+ return transformScreen(outputId, raw, childNodes);
945
+ case 'PF.Frame':
946
+ return transformFrame(outputId, raw, childNodes, parentDirection);
947
+ case 'PF.Text':
948
+ return transformText(outputId, raw, parentDirection);
949
+ case 'PF.Image':
950
+ return transformImage(outputId, raw, childNodes, parentDirection);
951
+ case 'PF.Input':
952
+ return transformInput(outputId, raw, parentDirection);
953
+ case 'PF.List':
954
+ return transformList(outputId, raw, childNodes, parentDirection);
955
+ case 'PF.Icon':
956
+ return transformIcon(outputId, raw);
957
+ case 'Component':
958
+ return resolveCustomComponent(outputId, raw, parentDirection, customComponents);
959
+ default:
960
+ return {
961
+ id: outputId,
962
+ type: 'view',
963
+ props: {},
964
+ children: childNodes
965
+ };
966
+ }
967
+ }
968
+
969
+ // ─── Custom component inliner ─────────────────────────────────────────────────
970
+
971
+ function resolveCustomComponent(id, raw, parentDirection, customComponents) {
972
+ const {
973
+ actions,
974
+ condition
975
+ } = extractMeta(raw);
976
+ const props = stripBridgeKeys(raw);
977
+ const {
978
+ componentId,
979
+ componentKey,
980
+ propValues,
981
+ ...frameProps
982
+ } = props;
983
+ const key = componentKey ?? componentId;
984
+ const def = key ? customComponents[key] : undefined;
985
+ const wrapperStyle = buildFrameStyle(frameProps, parentDirection);
986
+ const vis = props.visible !== undefined && props.visible !== true ? {
987
+ visible: props.visible
988
+ } : {};
989
+ if (!def) {
990
+ return {
991
+ id,
992
+ type: 'view',
993
+ props: {
994
+ ...(Object.keys(wrapperStyle).length ? {
995
+ style: wrapperStyle
996
+ } : {}),
997
+ ...vis
998
+ },
999
+ children: []
1000
+ };
1001
+ }
1002
+ const componentVisited = new Set();
1003
+ const componentRoot = buildNodeFromSchema(def.rootNodeId, def.nodes, customComponents, componentVisited);
1004
+ if (propValues && Object.keys(propValues).length) {
1005
+ componentRoot.props = {
1006
+ ...componentRoot.props,
1007
+ _propValues: propValues
1008
+ };
1009
+ }
1010
+ if (Object.keys(wrapperStyle).length > 0) {
1011
+ const wrapper = {
1012
+ id,
1013
+ type: 'view',
1014
+ props: {
1015
+ style: wrapperStyle,
1016
+ ...vis
1017
+ },
1018
+ children: [componentRoot]
1019
+ };
1020
+ if (condition !== undefined) wrapper.if = condition;
1021
+ if (actions) wrapper.actions = actions;
1022
+ return wrapper;
1023
+ }
1024
+ componentRoot.id = id;
1025
+ componentRoot.props = {
1026
+ ...componentRoot.props,
1027
+ ...vis
1028
+ };
1029
+ if (condition !== undefined) componentRoot.if = condition;
1030
+ if (actions) componentRoot.actions = actions;
1031
+ return componentRoot;
1032
+ }
1033
+
1034
+ // ─── Main entry ───────────────────────────────────────────────────────────────
1035
+
1036
+ /**
1037
+ * Convert a Craft.js editor schema into an SDUINode tree ready for the SDK's
1038
+ * RecursiveRenderer.
1039
+ *
1040
+ * @param craftJson - The full Craft.js node map (keyed by node ID, must include "ROOT").
1041
+ * @param customComponents - Optional map of reusable component definitions.
1042
+ * @returns The root SDUINode.
1043
+ */
1044
+ export function transformCraftToSDUI(craftJson, customComponents = {}) {
1045
+ if (!craftJson || typeof craftJson !== 'object') {
1046
+ throw new Error('Invalid craft schema');
1047
+ }
1048
+ const visited = new Set();
1049
+ return buildNodeFromSchema('ROOT', craftJson, customComponents, visited);
1050
+ }
1051
+ //# sourceMappingURL=index.js.map