@billdog.io/react-native 1.0.0-beta.2

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 (309) hide show
  1. package/BillDogReactNative.podspec +30 -0
  2. package/LICENSE +21 -0
  3. package/README.md +330 -0
  4. package/android/build.gradle +99 -0
  5. package/android/src/main/AndroidManifest.xml +1 -0
  6. package/android/src/main/kotlin/io/billdog/reactnative/BillDogABTestModule.kt +317 -0
  7. package/android/src/main/kotlin/io/billdog/reactnative/BillDogAnalyticsModule.kt +389 -0
  8. package/android/src/main/kotlin/io/billdog/reactnative/BillDogModule.kt +817 -0
  9. package/android/src/main/kotlin/io/billdog/reactnative/BillDogPaywallViewManager.kt +383 -0
  10. package/android/src/main/kotlin/io/billdog/reactnative/BillDogSurveyModule.kt +427 -0
  11. package/android/src/main/kotlin/io/billdog/reactnative/BillDogVirtualCurrencyModule.kt +407 -0
  12. package/android/src/main/kotlin/io/billdog/virtualcurrency/BillDogVirtualCurrencyPackage.kt +44 -0
  13. package/dist/AdvancedPaywallCache.d.ts +70 -0
  14. package/dist/AdvancedPaywallCache.js +344 -0
  15. package/dist/BillDog.d.ts +255 -0
  16. package/dist/BillDog.js +918 -0
  17. package/dist/BillDogConfiguration.d.ts +145 -0
  18. package/dist/BillDogConfiguration.js +229 -0
  19. package/dist/ComponentRenderer.d.ts +17 -0
  20. package/dist/ComponentRenderer.js +886 -0
  21. package/dist/LayoutEngine.d.ts +101 -0
  22. package/dist/LayoutEngine.js +394 -0
  23. package/dist/LocalizationResolver.d.ts +99 -0
  24. package/dist/LocalizationResolver.js +266 -0
  25. package/dist/NativePaywallView.d.ts +36 -0
  26. package/dist/NativePaywallView.js +59 -0
  27. package/dist/PaywallCache.d.ts +74 -0
  28. package/dist/PaywallCache.js +293 -0
  29. package/dist/PaywallStateManager.d.ts +62 -0
  30. package/dist/PaywallStateManager.js +147 -0
  31. package/dist/PaywallView.d.ts +42 -0
  32. package/dist/PaywallView.js +275 -0
  33. package/dist/ProductVariableProvider.d.ts +60 -0
  34. package/dist/ProductVariableProvider.js +239 -0
  35. package/dist/VariableResolver.d.ts +120 -0
  36. package/dist/VariableResolver.js +379 -0
  37. package/dist/WebViewPaywall.d.ts +75 -0
  38. package/dist/WebViewPaywall.js +360 -0
  39. package/dist/animations/presets.d.ts +49 -0
  40. package/dist/animations/presets.js +367 -0
  41. package/dist/components/AccoladeCpsComponent.d.ts +13 -0
  42. package/dist/components/AccoladeCpsComponent.js +248 -0
  43. package/dist/components/AccordionComponent.d.ts +10 -0
  44. package/dist/components/AccordionComponent.js +187 -0
  45. package/dist/components/AnimatedWrapper.d.ts +35 -0
  46. package/dist/components/AnimatedWrapper.js +277 -0
  47. package/dist/components/CarouselComponent.d.ts +23 -0
  48. package/dist/components/CarouselComponent.js +484 -0
  49. package/dist/components/ChartCurveComponent.d.ts +13 -0
  50. package/dist/components/ChartCurveComponent.js +333 -0
  51. package/dist/components/CheckboxComponent.d.ts +9 -0
  52. package/dist/components/CheckboxComponent.js +172 -0
  53. package/dist/components/ConfettiComponent.d.ts +9 -0
  54. package/dist/components/ConfettiComponent.js +172 -0
  55. package/dist/components/CountdownComponent.d.ts +16 -0
  56. package/dist/components/CountdownComponent.js +414 -0
  57. package/dist/components/DelayedXComponent.d.ts +12 -0
  58. package/dist/components/DelayedXComponent.js +240 -0
  59. package/dist/components/DrawerModalComponent.d.ts +20 -0
  60. package/dist/components/DrawerModalComponent.js +286 -0
  61. package/dist/components/GradientView.d.ts +38 -0
  62. package/dist/components/GradientView.js +126 -0
  63. package/dist/components/HapticFeedbackComponent.d.ts +16 -0
  64. package/dist/components/HapticFeedbackComponent.js +64 -0
  65. package/dist/components/HorizontalProductsComponent.d.ts +17 -0
  66. package/dist/components/HorizontalProductsComponent.js +284 -0
  67. package/dist/components/MultiChoiceGridComponent.d.ts +13 -0
  68. package/dist/components/MultiChoiceGridComponent.js +234 -0
  69. package/dist/components/NPSScaleComponent.d.ts +16 -0
  70. package/dist/components/NPSScaleComponent.js +260 -0
  71. package/dist/components/NavigationComponent.d.ts +26 -0
  72. package/dist/components/NavigationComponent.js +302 -0
  73. package/dist/components/OAuthButtonComponent.d.ts +20 -0
  74. package/dist/components/OAuthButtonComponent.js +237 -0
  75. package/dist/components/ProgressLoaderComponent.d.ts +13 -0
  76. package/dist/components/ProgressLoaderComponent.js +308 -0
  77. package/dist/components/ProgressStepperComponent.d.ts +18 -0
  78. package/dist/components/ProgressStepperComponent.js +228 -0
  79. package/dist/components/SegmentedPickerComponent.d.ts +10 -0
  80. package/dist/components/SegmentedPickerComponent.js +221 -0
  81. package/dist/components/ShareButtonsComponent.d.ts +21 -0
  82. package/dist/components/ShareButtonsComponent.js +265 -0
  83. package/dist/components/ShareCodeComponent.d.ts +16 -0
  84. package/dist/components/ShareCodeComponent.js +274 -0
  85. package/dist/components/SingleChoiceGridComponent.d.ts +13 -0
  86. package/dist/components/SingleChoiceGridComponent.js +210 -0
  87. package/dist/components/SliderComponent.d.ts +9 -0
  88. package/dist/components/SliderComponent.js +263 -0
  89. package/dist/components/StarRatingInputComponent.d.ts +20 -0
  90. package/dist/components/StarRatingInputComponent.js +198 -0
  91. package/dist/components/StickerCompositeComponent.d.ts +13 -0
  92. package/dist/components/StickerCompositeComponent.js +136 -0
  93. package/dist/components/TabsComponent.d.ts +19 -0
  94. package/dist/components/TabsComponent.js +431 -0
  95. package/dist/components/TextInputComponent.d.ts +18 -0
  96. package/dist/components/TextInputComponent.js +227 -0
  97. package/dist/components/TimelineComponent.d.ts +19 -0
  98. package/dist/components/TimelineComponent.js +104 -0
  99. package/dist/components/ToggleComponent.d.ts +14 -0
  100. package/dist/components/ToggleComponent.js +132 -0
  101. package/dist/components/VerticalProductsComponent.d.ts +17 -0
  102. package/dist/components/VerticalProductsComponent.js +311 -0
  103. package/dist/dynamicValues.d.ts +36 -0
  104. package/dist/dynamicValues.js +142 -0
  105. package/dist/filters/dateFilters.d.ts +50 -0
  106. package/dist/filters/dateFilters.js +390 -0
  107. package/dist/filters/index.d.ts +18 -0
  108. package/dist/filters/index.js +253 -0
  109. package/dist/hooks/useOfferings.d.ts +76 -0
  110. package/dist/hooks/useOfferings.js +99 -0
  111. package/dist/hooks/usePaywall.d.ts +27 -0
  112. package/dist/hooks/usePaywall.js +114 -0
  113. package/dist/hooks/usePlacement.d.ts +34 -0
  114. package/dist/hooks/usePlacement.js +89 -0
  115. package/dist/hooks/useSubscription.d.ts +40 -0
  116. package/dist/hooks/useSubscription.js +97 -0
  117. package/dist/index.d.ts +98 -0
  118. package/dist/index.js +198 -0
  119. package/dist/models/BillDogError.d.ts +40 -0
  120. package/dist/models/BillDogError.js +11 -0
  121. package/dist/models/CacheFetchPolicy.d.ts +8 -0
  122. package/dist/models/CacheFetchPolicy.js +4 -0
  123. package/dist/models/CustomProduct.d.ts +32 -0
  124. package/dist/models/CustomProduct.js +15 -0
  125. package/dist/models/CustomerInfo.d.ts +17 -0
  126. package/dist/models/CustomerInfo.js +11 -0
  127. package/dist/models/Delegate.d.ts +20 -0
  128. package/dist/models/Delegate.js +11 -0
  129. package/dist/models/EntitlementInfo.d.ts +19 -0
  130. package/dist/models/EntitlementInfo.js +2 -0
  131. package/dist/models/Placement.d.ts +54 -0
  132. package/dist/models/Placement.js +15 -0
  133. package/dist/models/PurchaseParams.d.ts +39 -0
  134. package/dist/models/PurchaseParams.js +60 -0
  135. package/dist/models/PurchaseResult.d.ts +30 -0
  136. package/dist/models/PurchaseResult.js +15 -0
  137. package/dist/models/RestoreResult.d.ts +30 -0
  138. package/dist/models/RestoreResult.js +22 -0
  139. package/dist/models/RestoredItem.d.ts +26 -0
  140. package/dist/models/RestoredItem.js +13 -0
  141. package/dist/modules/ABTest.d.ts +65 -0
  142. package/dist/modules/ABTest.js +113 -0
  143. package/dist/modules/Analytics.d.ts +91 -0
  144. package/dist/modules/Analytics.js +182 -0
  145. package/dist/modules/Survey.d.ts +65 -0
  146. package/dist/modules/Survey.js +82 -0
  147. package/dist/modules/VirtualCurrency.d.ts +63 -0
  148. package/dist/modules/VirtualCurrency.js +147 -0
  149. package/dist/murmur.d.ts +23 -0
  150. package/dist/murmur.js +104 -0
  151. package/dist/notifications/LiveActivitiesManager.d.ts +47 -0
  152. package/dist/notifications/LiveActivitiesManager.js +106 -0
  153. package/dist/notifications/NotificationScheduler.d.ts +55 -0
  154. package/dist/notifications/NotificationScheduler.js +199 -0
  155. package/dist/notifications/PurchaseNotificationHandler.d.ts +24 -0
  156. package/dist/notifications/PurchaseNotificationHandler.js +55 -0
  157. package/dist/notifications/useDeviceToken.d.ts +36 -0
  158. package/dist/notifications/useDeviceToken.js +97 -0
  159. package/dist/notifications/useLiveActivity.d.ts +39 -0
  160. package/dist/notifications/useLiveActivity.js +104 -0
  161. package/dist/review/ReviewAnalytics.d.ts +34 -0
  162. package/dist/review/ReviewAnalytics.js +73 -0
  163. package/dist/review/ReviewManager.d.ts +83 -0
  164. package/dist/review/ReviewManager.js +339 -0
  165. package/dist/review/ReviewTimingManager.d.ts +82 -0
  166. package/dist/review/ReviewTimingManager.js +224 -0
  167. package/dist/survey-core/types.d.ts +215 -0
  168. package/dist/survey-core/types.js +8 -0
  169. package/dist/types.d.ts +438 -0
  170. package/dist/types.js +158 -0
  171. package/dist/utils/ApiClient.d.ts +65 -0
  172. package/dist/utils/ApiClient.js +132 -0
  173. package/dist/utils/CSSConverter.d.ts +49 -0
  174. package/dist/utils/CSSConverter.js +470 -0
  175. package/dist/utils/animations.d.ts +41 -0
  176. package/dist/utils/animations.js +194 -0
  177. package/dist/utils/calendarIntegration.d.ts +36 -0
  178. package/dist/utils/calendarIntegration.js +89 -0
  179. package/dist/utils/configurationResolver.d.ts +23 -0
  180. package/dist/utils/configurationResolver.js +78 -0
  181. package/dist/utils/deviceDetection.d.ts +38 -0
  182. package/dist/utils/deviceDetection.js +59 -0
  183. package/dist/utils/hapticFeedback.d.ts +17 -0
  184. package/dist/utils/hapticFeedback.js +53 -0
  185. package/dist/utils/iconMapper.d.ts +26 -0
  186. package/dist/utils/iconMapper.js +113 -0
  187. package/dist/utils/notificationPermissions.d.ts +13 -0
  188. package/dist/utils/notificationPermissions.js +51 -0
  189. package/dist/utils/priceFormatting.d.ts +19 -0
  190. package/dist/utils/priceFormatting.js +99 -0
  191. package/dist/utils/shareSheet.d.ts +17 -0
  192. package/dist/utils/shareSheet.js +42 -0
  193. package/dist/utils/subscriptionUpgrade.d.ts +84 -0
  194. package/dist/utils/subscriptionUpgrade.js +100 -0
  195. package/dist/valueUtils.d.ts +48 -0
  196. package/dist/valueUtils.js +129 -0
  197. package/dist/xFlowTags.d.ts +18 -0
  198. package/dist/xFlowTags.js +385 -0
  199. package/ios/BillDogABTest.m +50 -0
  200. package/ios/BillDogABTest.swift +188 -0
  201. package/ios/BillDogAnalytics.m +105 -0
  202. package/ios/BillDogAnalytics.swift +324 -0
  203. package/ios/BillDogBridge.m +222 -0
  204. package/ios/BillDogBridge.swift +715 -0
  205. package/ios/BillDogLiveActivities.m +41 -0
  206. package/ios/BillDogLiveActivities.swift +104 -0
  207. package/ios/BillDogPaywallViewManager.m +39 -0
  208. package/ios/BillDogPaywallViewManager.swift +361 -0
  209. package/ios/BillDogSurvey.m +34 -0
  210. package/ios/BillDogSurvey.swift +257 -0
  211. package/ios/BillDogVirtualCurrencyBridge.m +63 -0
  212. package/ios/BillDogVirtualCurrencyBridge.swift +511 -0
  213. package/junit.xml +25 -0
  214. package/package.json +61 -0
  215. package/react-native.config.js +13 -0
  216. package/src/AdvancedPaywallCache.ts +433 -0
  217. package/src/BillDog.ts +983 -0
  218. package/src/BillDogConfiguration.ts +318 -0
  219. package/src/ComponentRenderer.tsx +1325 -0
  220. package/src/LayoutEngine.ts +459 -0
  221. package/src/LocalizationResolver.ts +311 -0
  222. package/src/NativePaywallView.tsx +132 -0
  223. package/src/PaywallCache.ts +358 -0
  224. package/src/PaywallStateManager.ts +154 -0
  225. package/src/PaywallView.tsx +328 -0
  226. package/src/ProductVariableProvider.ts +282 -0
  227. package/src/VariableResolver.ts +516 -0
  228. package/src/WebViewPaywall.tsx +454 -0
  229. package/src/animations/presets.ts +421 -0
  230. package/src/components/AccoladeCpsComponent.tsx +259 -0
  231. package/src/components/AccordionComponent.tsx +213 -0
  232. package/src/components/AnimatedWrapper.tsx +316 -0
  233. package/src/components/CarouselComponent.tsx +615 -0
  234. package/src/components/ChartCurveComponent.tsx +452 -0
  235. package/src/components/CheckboxComponent.tsx +185 -0
  236. package/src/components/ConfettiComponent.tsx +178 -0
  237. package/src/components/CountdownComponent.tsx +454 -0
  238. package/src/components/DelayedXComponent.tsx +266 -0
  239. package/src/components/DrawerModalComponent.tsx +324 -0
  240. package/src/components/GradientView.tsx +129 -0
  241. package/src/components/HapticFeedbackComponent.tsx +39 -0
  242. package/src/components/HorizontalProductsComponent.tsx +329 -0
  243. package/src/components/MultiChoiceGridComponent.tsx +265 -0
  244. package/src/components/NPSScaleComponent.tsx +294 -0
  245. package/src/components/NavigationComponent.tsx +329 -0
  246. package/src/components/OAuthButtonComponent.tsx +266 -0
  247. package/src/components/ProgressLoaderComponent.tsx +366 -0
  248. package/src/components/ProgressStepperComponent.tsx +250 -0
  249. package/src/components/SegmentedPickerComponent.tsx +245 -0
  250. package/src/components/ShareButtonsComponent.tsx +299 -0
  251. package/src/components/ShareCodeComponent.tsx +303 -0
  252. package/src/components/SingleChoiceGridComponent.tsx +229 -0
  253. package/src/components/SliderComponent.tsx +280 -0
  254. package/src/components/StarRatingInputComponent.tsx +223 -0
  255. package/src/components/StickerCompositeComponent.tsx +168 -0
  256. package/src/components/TabsComponent.tsx +496 -0
  257. package/src/components/TextInputComponent.tsx +258 -0
  258. package/src/components/TimelineComponent.tsx +129 -0
  259. package/src/components/ToggleComponent.tsx +142 -0
  260. package/src/components/VerticalProductsComponent.tsx +357 -0
  261. package/src/dynamicValues.ts +180 -0
  262. package/src/filters/dateFilters.ts +411 -0
  263. package/src/filters/index.ts +281 -0
  264. package/src/hooks/useOfferings.ts +192 -0
  265. package/src/hooks/usePaywall.ts +154 -0
  266. package/src/hooks/usePlacement.ts +143 -0
  267. package/src/hooks/useSubscription.ts +154 -0
  268. package/src/index.ts +245 -0
  269. package/src/models/BillDogError.ts +24 -0
  270. package/src/models/CacheFetchPolicy.ts +13 -0
  271. package/src/models/CustomProduct.ts +33 -0
  272. package/src/models/CustomerInfo.ts +26 -0
  273. package/src/models/Delegate.ts +22 -0
  274. package/src/models/EntitlementInfo.ts +27 -0
  275. package/src/models/Placement.ts +50 -0
  276. package/src/models/PurchaseParams.ts +81 -0
  277. package/src/models/PurchaseResult.ts +32 -0
  278. package/src/models/RestoreResult.ts +27 -0
  279. package/src/models/RestoredItem.ts +25 -0
  280. package/src/modules/ABTest.ts +131 -0
  281. package/src/modules/Analytics.ts +227 -0
  282. package/src/modules/Survey.ts +126 -0
  283. package/src/modules/VirtualCurrency.ts +223 -0
  284. package/src/murmur.ts +102 -0
  285. package/src/notifications/LiveActivitiesManager.ts +140 -0
  286. package/src/notifications/NotificationScheduler.ts +292 -0
  287. package/src/notifications/PurchaseNotificationHandler.ts +67 -0
  288. package/src/notifications/useDeviceToken.ts +116 -0
  289. package/src/notifications/useLiveActivity.ts +125 -0
  290. package/src/review/ReviewAnalytics.ts +89 -0
  291. package/src/review/ReviewManager.ts +355 -0
  292. package/src/review/ReviewTimingManager.ts +265 -0
  293. package/src/survey-core/types.ts +244 -0
  294. package/src/types/ambient.d.ts +9 -0
  295. package/src/types.ts +680 -0
  296. package/src/utils/ApiClient.ts +163 -0
  297. package/src/utils/CSSConverter.ts +552 -0
  298. package/src/utils/animations.ts +232 -0
  299. package/src/utils/calendarIntegration.ts +113 -0
  300. package/src/utils/configurationResolver.ts +106 -0
  301. package/src/utils/deviceDetection.ts +83 -0
  302. package/src/utils/hapticFeedback.ts +55 -0
  303. package/src/utils/iconMapper.ts +102 -0
  304. package/src/utils/notificationPermissions.ts +48 -0
  305. package/src/utils/priceFormatting.ts +119 -0
  306. package/src/utils/shareSheet.ts +55 -0
  307. package/src/utils/subscriptionUpgrade.ts +183 -0
  308. package/src/valueUtils.ts +108 -0
  309. package/src/xFlowTags.ts +463 -0
@@ -0,0 +1,459 @@
1
+ /**
2
+ * Layout Engine - Converts JSON layout to React Native StyleSheet
3
+ *
4
+ * PHASE 5 SIMPLIFIED: All colors are now pre-resolved to hex by the web exporter.
5
+ * Removed ThemeColorResolver, CSS variable resolution, and HSL parsing.
6
+ */
7
+
8
+ import { ViewStyle, TextStyle, ImageStyle } from 'react-native';
9
+ import { Layout, Appearance, Size, SizeValue, BorderConfig, Shadow, BorderSide } from './types';
10
+ import { convertCSSToReactNative, validateCSSForNative } from './utils/CSSConverter';
11
+
12
+ export interface CustomCSSConfig {
13
+ styles?: string;
14
+ transitions?: string;
15
+ animations?: string;
16
+ }
17
+
18
+ /**
19
+ * Normalize a size value from any format to { type, value }
20
+ */
21
+ function normalizeSizeValue(size: any): { type: string; value?: number } {
22
+ // Already normalized format
23
+ if (size && typeof size === 'object' && 'type' in size) {
24
+ // Migrate 'hug' to 'fit' for consistency
25
+ const type = size.type === 'hug' ? 'fit' : size.type;
26
+ return { type, value: size.value };
27
+ }
28
+
29
+ // Number value = fixed
30
+ if (typeof size === 'number') {
31
+ return { type: 'fixed', value: size };
32
+ }
33
+
34
+ // String value
35
+ if (typeof size === 'string') {
36
+ const lower = size.toLowerCase();
37
+ if (lower === 'fill' || lower === '100%') return { type: 'fill' };
38
+ if (lower === 'fit' || lower === 'auto' || lower === 'hug') return { type: 'fit' };
39
+
40
+ // Try to parse as number
41
+ const num = parseFloat(size);
42
+ if (!isNaN(num)) return { type: 'fixed', value: num };
43
+
44
+ return { type: 'fit' };
45
+ }
46
+
47
+ // Default
48
+ return { type: 'fit' };
49
+ }
50
+
51
+ export class LayoutEngine {
52
+ /**
53
+ * Normalize size value (exported for external use)
54
+ */
55
+ static normalizeSizeValue = normalizeSizeValue;
56
+
57
+ /**
58
+ * Convert JSON layout and size to React Native flex layout
59
+ */
60
+ static getFlexLayout(layout: Layout, size?: Size): ViewStyle {
61
+ const style: ViewStyle = {};
62
+
63
+ // Normalize size values
64
+ const normalizedWidth = size?.width ? normalizeSizeValue(size.width) : { type: 'fit' };
65
+ const normalizedHeight = size?.height ? normalizeSizeValue(size.height) : { type: 'fit' };
66
+
67
+ // Width handling
68
+ switch (normalizedWidth.type) {
69
+ case 'fill':
70
+ style.alignSelf = 'stretch';
71
+ style.width = '100%';
72
+ break;
73
+ case 'fixed':
74
+ if (normalizedWidth.value && normalizedWidth.value > 0) {
75
+ style.width = normalizedWidth.value;
76
+ }
77
+ break;
78
+ case 'fit':
79
+ default:
80
+ break;
81
+ }
82
+
83
+ // Height handling
84
+ switch (normalizedHeight.type) {
85
+ case 'fill':
86
+ style.flex = 1;
87
+ break;
88
+ case 'fixed':
89
+ if (normalizedHeight.value && normalizedHeight.value > 0) {
90
+ style.height = normalizedHeight.value;
91
+ }
92
+ break;
93
+ case 'fit':
94
+ default:
95
+ break;
96
+ }
97
+
98
+ // Padding
99
+ if (layout.padding) {
100
+ if (layout.padding.top !== undefined) style.paddingTop = layout.padding.top;
101
+ if (layout.padding.right !== undefined) style.paddingRight = layout.padding.right;
102
+ if (layout.padding.bottom !== undefined) style.paddingBottom = layout.padding.bottom;
103
+ if (layout.padding.left !== undefined) style.paddingLeft = layout.padding.left;
104
+ }
105
+
106
+ // Margin
107
+ if (layout.margin) {
108
+ if (layout.margin.top !== undefined) style.marginTop = layout.margin.top;
109
+ if (layout.margin.right !== undefined) style.marginRight = layout.margin.right;
110
+ if (layout.margin.bottom !== undefined) style.marginBottom = layout.margin.bottom;
111
+ if (layout.margin.left !== undefined) style.marginLeft = layout.margin.left;
112
+ }
113
+
114
+ return style;
115
+ }
116
+
117
+ /**
118
+ * Convert size to React Native dimensions
119
+ * @deprecated Use getFlexLayout with size parameter instead
120
+ */
121
+ static getSize(size: Size, layout: Layout): ViewStyle {
122
+ const style: ViewStyle = {};
123
+
124
+ const normalizedWidth = normalizeSizeValue(size.width);
125
+ const normalizedHeight = normalizeSizeValue(size.height);
126
+
127
+ // Width
128
+ if (normalizedWidth.type === 'fixed' && normalizedWidth.value) {
129
+ style.width = normalizedWidth.value;
130
+ } else if (normalizedWidth.type === 'fill') {
131
+ style.width = '100%';
132
+ }
133
+
134
+ // Height
135
+ if (normalizedHeight.type === 'fixed' && normalizedHeight.value) {
136
+ style.height = normalizedHeight.value;
137
+ }
138
+
139
+ return style;
140
+ }
141
+
142
+ /**
143
+ * Parse a color value - PHASE 5 SIMPLIFIED
144
+ * All colors are now pre-resolved to hex by the web exporter
145
+ */
146
+ private static parseColorValue(color: any): string | undefined {
147
+ if (!color) return undefined;
148
+
149
+ if (typeof color === 'string') {
150
+ // Handle 8-character hex colors (#RRGGBBAA format)
151
+ if (color.length === 9 && color.startsWith('#')) {
152
+ // Convert RRGGBBAA to rgba for React Native
153
+ const r = parseInt(color.substring(1, 3), 16);
154
+ const g = parseInt(color.substring(3, 5), 16);
155
+ const b = parseInt(color.substring(5, 7), 16);
156
+ const a = parseInt(color.substring(7, 9), 16) / 255;
157
+ return `rgba(${r}, ${g}, ${b}, ${a.toFixed(2)})`;
158
+ }
159
+
160
+ return color;
161
+ }
162
+
163
+ // Handle object format { type: 'color'|'gradient', color?: string, gradient?: {...} }
164
+ if (typeof color === 'object') {
165
+ // Check resolvedColor first (pre-computed hex from web exporter)
166
+ if (color.resolvedColor) return this.parseColorValue(color.resolvedColor);
167
+
168
+ // Direct color type with nested color
169
+ if (color.type === 'color' && color.color) {
170
+ return this.parseColorValue(color.color);
171
+ }
172
+
173
+ // Gradient type - fallback to first stop color
174
+ if (color.type === 'gradient' && color.gradient?.stops?.length) {
175
+ const firstStop = color.gradient.stops[0];
176
+ if (firstStop?.color) {
177
+ return this.parseColorValue(firstStop.color);
178
+ }
179
+ }
180
+
181
+ // Fallback fields
182
+ if (color.color && typeof color.color === 'string') return this.parseColorValue(color.color);
183
+ if (color.hex) return color.hex;
184
+ if (color.value) return color.value;
185
+ }
186
+
187
+ return undefined;
188
+ }
189
+
190
+ /**
191
+ * Convert JSON appearance to React Native ViewStyle
192
+ */
193
+ static getAppearanceStyle(appearance: Appearance): ViewStyle {
194
+ const style: ViewStyle = {};
195
+
196
+ // Background color - check resolvedColor first.
197
+ // `fill` may be a plain color string or a structured fill object; only the
198
+ // object branch carries resolvedColor/color, so narrow before accessing.
199
+ const fillObj = typeof appearance.fill === 'object' ? appearance.fill : undefined;
200
+ const bgColor = this.parseColorValue(fillObj?.resolvedColor)
201
+ || this.parseColorValue(fillObj?.color)
202
+ || this.parseColorValue(typeof appearance.fill === 'string' ? appearance.fill : undefined)
203
+ || this.parseColorValue(appearance.backgroundColor);
204
+
205
+ if (bgColor) {
206
+ style.backgroundColor = bgColor;
207
+ }
208
+
209
+ // Border radius
210
+ const borderRadius = appearance.cornerRadius ?? appearance.borderRadius;
211
+ if (borderRadius !== undefined && borderRadius > 0) {
212
+ style.borderRadius = borderRadius;
213
+ }
214
+
215
+ // Opacity
216
+ if (appearance.opacity !== undefined) {
217
+ style.opacity = appearance.opacity;
218
+ }
219
+
220
+ // Border
221
+ if (appearance.borderWidth !== undefined && appearance.borderWidth > 0) {
222
+ style.borderWidth = appearance.borderWidth;
223
+
224
+ const borderColor = this.parseColorValue(appearance.borderColorResolved)
225
+ || this.parseColorValue(appearance.borderColor);
226
+ if (borderColor) {
227
+ style.borderColor = borderColor;
228
+ }
229
+ }
230
+
231
+ return style;
232
+ }
233
+
234
+ /**
235
+ * Get appearance style with border config support
236
+ */
237
+ static getAppearanceStyleWithBorder(appearance: Appearance, border?: BorderConfig): ViewStyle {
238
+ const style = this.getAppearanceStyle(appearance);
239
+
240
+ if (border) {
241
+ if (border.width !== undefined && border.width > 0) {
242
+ style.borderWidth = border.width;
243
+ }
244
+
245
+ // Use resolvedColor first (pre-computed hex)
246
+ const borderColor = border.resolvedColor || border.color;
247
+ if (borderColor) {
248
+ style.borderColor = this.parseColorValue(borderColor);
249
+ }
250
+
251
+ if (border.radius?.uniform !== undefined) {
252
+ style.borderRadius = border.radius.uniform;
253
+ }
254
+ }
255
+
256
+ return style;
257
+ }
258
+
259
+ /**
260
+ * Apply shadow to style
261
+ */
262
+ static applyShadow(style: ViewStyle, shadow: Shadow): ViewStyle {
263
+ const result = { ...style };
264
+
265
+ const shadowColor = this.parseColorValue(shadow.color);
266
+ if (shadowColor) {
267
+ result.shadowColor = shadowColor;
268
+ }
269
+
270
+ result.shadowOffset = {
271
+ width: shadow.x ?? 0,
272
+ height: shadow.y ?? 0,
273
+ };
274
+ result.shadowOpacity = 1;
275
+ result.shadowRadius = shadow.blur ?? 0;
276
+
277
+ // Android elevation
278
+ (result as any).elevation = Math.max(shadow.blur ?? 0, 1);
279
+
280
+ return result;
281
+ }
282
+
283
+ /**
284
+ * Apply border sides (top, right, bottom, left individual borders)
285
+ */
286
+ static applyBorderSides(style: ViewStyle, appearance: Appearance): ViewStyle {
287
+ const result = { ...style };
288
+
289
+ const applyBorderSide = (side: BorderSide | undefined, prefix: 'Top' | 'Right' | 'Bottom' | 'Left') => {
290
+ if (!side) return;
291
+
292
+ if (side.width !== undefined && side.width > 0) {
293
+ (result as any)[`border${prefix}Width`] = side.width;
294
+ }
295
+
296
+ const color = side.resolvedColor || side.color;
297
+ if (color) {
298
+ (result as any)[`border${prefix}Color`] = this.parseColorValue(color);
299
+ }
300
+ };
301
+
302
+ applyBorderSide(appearance.borderTop, 'Top');
303
+ applyBorderSide(appearance.borderRight, 'Right');
304
+ applyBorderSide(appearance.borderBottom, 'Bottom');
305
+ applyBorderSide(appearance.borderLeft, 'Left');
306
+
307
+ return result;
308
+ }
309
+
310
+ /**
311
+ * Apply custom CSS styles (for native rendering)
312
+ */
313
+ static applyCustomCSS(style: ViewStyle, customCSS?: CustomCSSConfig): { style: ViewStyle; warnings: string[] } {
314
+ if (!customCSS?.styles) {
315
+ return { style, warnings: [] };
316
+ }
317
+
318
+ const result = convertCSSToReactNative(customCSS.styles);
319
+
320
+ return {
321
+ style: { ...style, ...result.style },
322
+ warnings: result.warnings,
323
+ };
324
+ }
325
+
326
+ /**
327
+ * Validate if custom CSS can be rendered natively
328
+ */
329
+ static validateCustomCSSForNative(customCSS?: CustomCSSConfig): { isValid: boolean; warnings: string[] } {
330
+ if (!customCSS?.styles) {
331
+ return { isValid: true, warnings: [] };
332
+ }
333
+
334
+ const warnings = validateCSSForNative(customCSS.styles);
335
+ return { isValid: warnings.length === 0, warnings };
336
+ }
337
+
338
+ /**
339
+ * Get container style for stack/group components
340
+ */
341
+ static getContainerStyle(
342
+ layout: Layout,
343
+ size: Size,
344
+ appearance: Appearance,
345
+ containerLayout?: { direction?: string; distribution?: string; alignment?: string; gap?: number }
346
+ ): ViewStyle {
347
+ const style: ViewStyle = {
348
+ ...this.getFlexLayout(layout, size),
349
+ ...this.getAppearanceStyle(appearance),
350
+ };
351
+
352
+ if (containerLayout) {
353
+ // Flex direction - uses canonical 'direction' property
354
+ style.flexDirection = containerLayout.direction === 'horizontal' ? 'row' : 'column';
355
+
356
+ // Distribution (justify-content)
357
+ switch (containerLayout.distribution) {
358
+ case 'start':
359
+ style.justifyContent = 'flex-start';
360
+ break;
361
+ case 'center':
362
+ style.justifyContent = 'center';
363
+ break;
364
+ case 'end':
365
+ style.justifyContent = 'flex-end';
366
+ break;
367
+ case 'space-between':
368
+ style.justifyContent = 'space-between';
369
+ break;
370
+ case 'space-around':
371
+ style.justifyContent = 'space-around';
372
+ break;
373
+ case 'space-evenly':
374
+ style.justifyContent = 'space-evenly';
375
+ break;
376
+ }
377
+
378
+ // Alignment (align-items)
379
+ switch (containerLayout.alignment) {
380
+ case 'start':
381
+ style.alignItems = 'flex-start';
382
+ break;
383
+ case 'center':
384
+ style.alignItems = 'center';
385
+ break;
386
+ case 'end':
387
+ style.alignItems = 'flex-end';
388
+ break;
389
+ case 'stretch':
390
+ style.alignItems = 'stretch';
391
+ break;
392
+ }
393
+
394
+ // Gap
395
+ if (containerLayout.gap !== undefined) {
396
+ style.gap = containerLayout.gap;
397
+ }
398
+ }
399
+
400
+ return style;
401
+ }
402
+
403
+ /**
404
+ * Build a combined ViewStyle for a single rendered component.
405
+ *
406
+ * Composes flex layout + appearance + optional custom CSS, then layers on
407
+ * absolute positioning and z-index when present. This delegates to the
408
+ * existing helpers so runtime behavior matches the per-helper output the
409
+ * renderer previously relied on.
410
+ */
411
+ static getComponentStyle(
412
+ layout: Layout,
413
+ appearance: Appearance,
414
+ size: Size,
415
+ _type?: string,
416
+ _properties?: Record<string, any>,
417
+ absolutePosition?: { x: number; y: number },
418
+ zIndex?: number,
419
+ customCSS?: CustomCSSConfig
420
+ ): ViewStyle {
421
+ let style: ViewStyle = {
422
+ ...this.getFlexLayout(layout, size),
423
+ ...this.getAppearanceStyle(appearance),
424
+ };
425
+
426
+ if (customCSS) {
427
+ style = this.applyCustomCSS(style, customCSS).style;
428
+ }
429
+
430
+ if (absolutePosition) {
431
+ style.position = 'absolute';
432
+ style.left = absolutePosition.x;
433
+ style.top = absolutePosition.y;
434
+ }
435
+
436
+ if (zIndex !== undefined) {
437
+ style.zIndex = zIndex;
438
+ }
439
+
440
+ return style;
441
+ }
442
+ }
443
+
444
+ // Export for backward compatibility
445
+ export const ThemeColorResolver = {
446
+ setTheme: (_config: any) => {
447
+ console.log('[ThemeColorResolver] Phase 5: Colors pre-resolved, theme setup skipped');
448
+ },
449
+ setResolvedColors: (_colors: any) => {},
450
+ clearTheme: () => {},
451
+ isThemingEnabled: () => false,
452
+ getThemingMode: () => 'disabled' as const,
453
+ // Phase 5: colors are pre-resolved upstream, so this runtime stub performs no
454
+ // variable resolution. resolveVariable returns undefined (caller falls through
455
+ // to its own fallback) and getDefaultVariableColor returns a neutral
456
+ // transparent default to keep the renderer's string-typed color pipeline valid.
457
+ resolveVariable: (_name: string): string | undefined => undefined,
458
+ getDefaultVariableColor: (_name: string): string => 'transparent',
459
+ };