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