@rocapine/react-native-onboarding-ui 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. package/dist/UI/Components/CircularProgress.d.ts +8 -0
  2. package/dist/UI/Components/CircularProgress.d.ts.map +1 -0
  3. package/dist/UI/Components/CircularProgress.js +104 -0
  4. package/dist/UI/Components/CircularProgress.js.map +1 -0
  5. package/dist/UI/Components/ProgressBar.d.ts +12 -0
  6. package/dist/UI/Components/ProgressBar.d.ts.map +1 -0
  7. package/dist/UI/Components/ProgressBar.js +121 -0
  8. package/dist/UI/Components/ProgressBar.js.map +1 -0
  9. package/dist/UI/Components/StaggeredTextList.d.ts +11 -0
  10. package/dist/UI/Components/StaggeredTextList.d.ts.map +1 -0
  11. package/dist/UI/Components/StaggeredTextList.js +111 -0
  12. package/dist/UI/Components/StaggeredTextList.js.map +1 -0
  13. package/dist/UI/Components/index.d.ts +4 -0
  14. package/dist/UI/Components/index.d.ts.map +1 -0
  15. package/dist/UI/Components/index.js +20 -0
  16. package/dist/UI/Components/index.js.map +1 -0
  17. package/dist/UI/ErrorBoundary/ErrorBoundary.d.ts +19 -0
  18. package/dist/UI/ErrorBoundary/ErrorBoundary.d.ts.map +1 -0
  19. package/dist/UI/ErrorBoundary/ErrorBoundary.js +123 -0
  20. package/dist/UI/ErrorBoundary/ErrorBoundary.js.map +1 -0
  21. package/dist/UI/ErrorBoundary/index.d.ts +3 -0
  22. package/dist/UI/ErrorBoundary/index.d.ts.map +1 -0
  23. package/dist/UI/ErrorBoundary/index.js +8 -0
  24. package/dist/UI/ErrorBoundary/index.js.map +1 -0
  25. package/dist/UI/ErrorBoundary/withErrorBoundary.d.ts +6 -0
  26. package/dist/UI/ErrorBoundary/withErrorBoundary.d.ts.map +1 -0
  27. package/dist/UI/ErrorBoundary/withErrorBoundary.js +13 -0
  28. package/dist/UI/ErrorBoundary/withErrorBoundary.js.map +1 -0
  29. package/dist/UI/OnboardingPage.d.ts +16 -0
  30. package/dist/UI/OnboardingPage.d.ts.map +1 -0
  31. package/dist/UI/OnboardingPage.js +38 -0
  32. package/dist/UI/OnboardingPage.js.map +1 -0
  33. package/dist/UI/Pages/Carousel/Renderer.d.ts +13 -0
  34. package/dist/UI/Pages/Carousel/Renderer.d.ts.map +1 -0
  35. package/dist/UI/Pages/Carousel/Renderer.js +121 -0
  36. package/dist/UI/Pages/Carousel/Renderer.js.map +1 -0
  37. package/dist/UI/Pages/Carousel/index.d.ts +3 -0
  38. package/dist/UI/Pages/Carousel/index.d.ts.map +1 -0
  39. package/dist/UI/Pages/Carousel/index.js +19 -0
  40. package/dist/UI/Pages/Carousel/index.js.map +1 -0
  41. package/dist/UI/Pages/Carousel/types.d.ts +32 -0
  42. package/dist/UI/Pages/Carousel/types.d.ts.map +1 -0
  43. package/dist/UI/Pages/Carousel/types.js +24 -0
  44. package/dist/UI/Pages/Carousel/types.js.map +1 -0
  45. package/dist/UI/Pages/Commitment/Renderer.d.ts +13 -0
  46. package/dist/UI/Pages/Commitment/Renderer.d.ts.map +1 -0
  47. package/dist/UI/Pages/Commitment/Renderer.js +173 -0
  48. package/dist/UI/Pages/Commitment/Renderer.js.map +1 -0
  49. package/dist/UI/Pages/Commitment/index.d.ts +3 -0
  50. package/dist/UI/Pages/Commitment/index.d.ts.map +1 -0
  51. package/dist/UI/Pages/Commitment/index.js +19 -0
  52. package/dist/UI/Pages/Commitment/index.js.map +1 -0
  53. package/dist/UI/Pages/Commitment/types.d.ts +41 -0
  54. package/dist/UI/Pages/Commitment/types.d.ts.map +1 -0
  55. package/dist/UI/Pages/Commitment/types.js +27 -0
  56. package/dist/UI/Pages/Commitment/types.js.map +1 -0
  57. package/dist/UI/Pages/Loader/Renderer.d.ts +10 -0
  58. package/dist/UI/Pages/Loader/Renderer.d.ts.map +1 -0
  59. package/dist/UI/Pages/Loader/Renderer.js +215 -0
  60. package/dist/UI/Pages/Loader/Renderer.js.map +1 -0
  61. package/dist/UI/Pages/Loader/index.d.ts +3 -0
  62. package/dist/UI/Pages/Loader/index.d.ts.map +1 -0
  63. package/dist/UI/Pages/Loader/index.js +19 -0
  64. package/dist/UI/Pages/Loader/index.js.map +1 -0
  65. package/dist/UI/Pages/Loader/types.d.ts +57 -0
  66. package/dist/UI/Pages/Loader/types.d.ts.map +1 -0
  67. package/dist/UI/Pages/Loader/types.js +30 -0
  68. package/dist/UI/Pages/Loader/types.js.map +1 -0
  69. package/dist/UI/Pages/MediaContent/Renderer.d.ts +13 -0
  70. package/dist/UI/Pages/MediaContent/Renderer.d.ts.map +1 -0
  71. package/dist/UI/Pages/MediaContent/Renderer.js +76 -0
  72. package/dist/UI/Pages/MediaContent/Renderer.js.map +1 -0
  73. package/dist/UI/Pages/MediaContent/index.d.ts +3 -0
  74. package/dist/UI/Pages/MediaContent/index.d.ts.map +1 -0
  75. package/dist/UI/Pages/MediaContent/index.js +19 -0
  76. package/dist/UI/Pages/MediaContent/index.js.map +1 -0
  77. package/dist/UI/Pages/MediaContent/types.d.ts +44 -0
  78. package/dist/UI/Pages/MediaContent/types.d.ts.map +1 -0
  79. package/dist/UI/Pages/MediaContent/types.js +22 -0
  80. package/dist/UI/Pages/MediaContent/types.js.map +1 -0
  81. package/dist/UI/Pages/Picker/Renderer.d.ts +13 -0
  82. package/dist/UI/Pages/Picker/Renderer.d.ts.map +1 -0
  83. package/dist/UI/Pages/Picker/Renderer.js +268 -0
  84. package/dist/UI/Pages/Picker/Renderer.js.map +1 -0
  85. package/dist/UI/Pages/Picker/index.d.ts +3 -0
  86. package/dist/UI/Pages/Picker/index.d.ts.map +1 -0
  87. package/dist/UI/Pages/Picker/index.js +19 -0
  88. package/dist/UI/Pages/Picker/index.js.map +1 -0
  89. package/dist/UI/Pages/Picker/types.d.ts +49 -0
  90. package/dist/UI/Pages/Picker/types.d.ts.map +1 -0
  91. package/dist/UI/Pages/Picker/types.js +30 -0
  92. package/dist/UI/Pages/Picker/types.js.map +1 -0
  93. package/dist/UI/Pages/Question/Renderer.d.ts +18 -0
  94. package/dist/UI/Pages/Question/Renderer.d.ts.map +1 -0
  95. package/dist/UI/Pages/Question/Renderer.js +128 -0
  96. package/dist/UI/Pages/Question/Renderer.js.map +1 -0
  97. package/dist/UI/Pages/Question/components.d.ts +57 -0
  98. package/dist/UI/Pages/Question/components.d.ts.map +1 -0
  99. package/dist/UI/Pages/Question/components.js +57 -0
  100. package/dist/UI/Pages/Question/components.js.map +1 -0
  101. package/dist/UI/Pages/Question/index.d.ts +4 -0
  102. package/dist/UI/Pages/Question/index.d.ts.map +1 -0
  103. package/dist/UI/Pages/Question/index.js +20 -0
  104. package/dist/UI/Pages/Question/index.js.map +1 -0
  105. package/dist/UI/Pages/Question/types.d.ts +47 -0
  106. package/dist/UI/Pages/Question/types.d.ts.map +1 -0
  107. package/dist/UI/Pages/Question/types.js +28 -0
  108. package/dist/UI/Pages/Question/types.js.map +1 -0
  109. package/dist/UI/Pages/Ratings/Renderer.d.ts +13 -0
  110. package/dist/UI/Pages/Ratings/Renderer.d.ts.map +1 -0
  111. package/dist/UI/Pages/Ratings/Renderer.js +201 -0
  112. package/dist/UI/Pages/Ratings/Renderer.js.map +1 -0
  113. package/dist/UI/Pages/Ratings/index.d.ts +3 -0
  114. package/dist/UI/Pages/Ratings/index.d.ts.map +1 -0
  115. package/dist/UI/Pages/Ratings/index.js +19 -0
  116. package/dist/UI/Pages/Ratings/index.js.map +1 -0
  117. package/dist/UI/Pages/Ratings/types.d.ts +32 -0
  118. package/dist/UI/Pages/Ratings/types.d.ts.map +1 -0
  119. package/dist/UI/Pages/Ratings/types.js +25 -0
  120. package/dist/UI/Pages/Ratings/types.js.map +1 -0
  121. package/dist/UI/Pages/index.d.ts +9 -0
  122. package/dist/UI/Pages/index.d.ts.map +1 -0
  123. package/dist/UI/Pages/index.js +26 -0
  124. package/dist/UI/Pages/index.js.map +1 -0
  125. package/dist/UI/Pages/types.d.ts +19 -0
  126. package/dist/UI/Pages/types.d.ts.map +1 -0
  127. package/dist/UI/Pages/types.js +25 -0
  128. package/dist/UI/Pages/types.js.map +1 -0
  129. package/dist/UI/Provider/OnboardingProgressProvider.d.ts +18 -0
  130. package/dist/UI/Provider/OnboardingProgressProvider.d.ts.map +1 -0
  131. package/dist/UI/Provider/OnboardingProgressProvider.js +23 -0
  132. package/dist/UI/Provider/OnboardingProgressProvider.js.map +1 -0
  133. package/dist/UI/Provider/index.d.ts +2 -0
  134. package/dist/UI/Provider/index.d.ts.map +1 -0
  135. package/dist/UI/Provider/index.js +7 -0
  136. package/dist/UI/Provider/index.js.map +1 -0
  137. package/dist/UI/Templates/OnboardingTemplate.d.ts +15 -0
  138. package/dist/UI/Templates/OnboardingTemplate.d.ts.map +1 -0
  139. package/dist/UI/Templates/OnboardingTemplate.js +48 -0
  140. package/dist/UI/Templates/OnboardingTemplate.js.map +1 -0
  141. package/dist/UI/Templates/index.d.ts +2 -0
  142. package/dist/UI/Templates/index.d.ts.map +1 -0
  143. package/dist/UI/Templates/index.js +6 -0
  144. package/dist/UI/Templates/index.js.map +1 -0
  145. package/dist/UI/Theme/ThemeProvider.d.ts +27 -0
  146. package/dist/UI/Theme/ThemeProvider.d.ts.map +1 -0
  147. package/dist/UI/Theme/ThemeProvider.js +49 -0
  148. package/dist/UI/Theme/ThemeProvider.js.map +1 -0
  149. package/dist/UI/Theme/defaultTheme.d.ts +7 -0
  150. package/dist/UI/Theme/defaultTheme.d.ts.map +1 -0
  151. package/dist/UI/Theme/defaultTheme.js +14 -0
  152. package/dist/UI/Theme/defaultTheme.js.map +1 -0
  153. package/dist/UI/Theme/helpers.d.ts +12 -0
  154. package/dist/UI/Theme/helpers.d.ts.map +1 -0
  155. package/dist/UI/Theme/helpers.js +21 -0
  156. package/dist/UI/Theme/helpers.js.map +1 -0
  157. package/dist/UI/Theme/index.d.ts +8 -0
  158. package/dist/UI/Theme/index.d.ts.map +1 -0
  159. package/dist/UI/Theme/index.js +24 -0
  160. package/dist/UI/Theme/index.js.map +1 -0
  161. package/dist/UI/Theme/token.d.ts +107 -0
  162. package/dist/UI/Theme/token.d.ts.map +1 -0
  163. package/dist/UI/Theme/token.js +108 -0
  164. package/dist/UI/Theme/token.js.map +1 -0
  165. package/dist/UI/Theme/tokens/darkTokens.d.ts +24 -0
  166. package/dist/UI/Theme/tokens/darkTokens.d.ts.map +1 -0
  167. package/dist/UI/Theme/tokens/darkTokens.js +27 -0
  168. package/dist/UI/Theme/tokens/darkTokens.js.map +1 -0
  169. package/dist/UI/Theme/tokens/index.d.ts +4 -0
  170. package/dist/UI/Theme/tokens/index.d.ts.map +1 -0
  171. package/dist/UI/Theme/tokens/index.js +20 -0
  172. package/dist/UI/Theme/tokens/index.js.map +1 -0
  173. package/dist/UI/Theme/tokens/lightTokens.d.ts +24 -0
  174. package/dist/UI/Theme/tokens/lightTokens.d.ts.map +1 -0
  175. package/dist/UI/Theme/tokens/lightTokens.js +27 -0
  176. package/dist/UI/Theme/tokens/lightTokens.js.map +1 -0
  177. package/dist/UI/Theme/tokens/typography.d.ts +65 -0
  178. package/dist/UI/Theme/tokens/typography.d.ts.map +1 -0
  179. package/dist/UI/Theme/tokens/typography.js +68 -0
  180. package/dist/UI/Theme/tokens/typography.js.map +1 -0
  181. package/dist/UI/Theme/types.d.ts +65 -0
  182. package/dist/UI/Theme/types.d.ts.map +1 -0
  183. package/dist/UI/Theme/types.js +3 -0
  184. package/dist/UI/Theme/types.js.map +1 -0
  185. package/dist/UI/Theme/useTheme.d.ts +7 -0
  186. package/dist/UI/Theme/useTheme.d.ts.map +1 -0
  187. package/dist/UI/Theme/useTheme.js +23 -0
  188. package/dist/UI/Theme/useTheme.js.map +1 -0
  189. package/dist/UI/Theme/utils.d.ts +12 -0
  190. package/dist/UI/Theme/utils.d.ts.map +1 -0
  191. package/dist/UI/Theme/utils.js +55 -0
  192. package/dist/UI/Theme/utils.js.map +1 -0
  193. package/dist/UI/index.d.ts +8 -0
  194. package/dist/UI/index.d.ts.map +1 -0
  195. package/dist/UI/index.js +24 -0
  196. package/dist/UI/index.js.map +1 -0
  197. package/dist/UI/types.d.ts +23 -0
  198. package/dist/UI/types.d.ts.map +1 -0
  199. package/dist/UI/types.js +3 -0
  200. package/dist/UI/types.js.map +1 -0
  201. package/dist/assets/laurel-left.png +0 -0
  202. package/dist/assets/laurel-right.png +0 -0
  203. package/dist/assets/star-filled.png +0 -0
  204. package/dist/index.d.ts +9 -0
  205. package/dist/index.d.ts.map +1 -0
  206. package/dist/index.js +33 -0
  207. package/dist/index.js.map +1 -0
  208. package/dist/provider/CustomComponentsContext.d.ts +57 -0
  209. package/dist/provider/CustomComponentsContext.d.ts.map +1 -0
  210. package/dist/provider/CustomComponentsContext.js +19 -0
  211. package/dist/provider/CustomComponentsContext.js.map +1 -0
  212. package/dist/provider/OnboardingUIProvider.d.ts +44 -0
  213. package/dist/provider/OnboardingUIProvider.d.ts.map +1 -0
  214. package/dist/provider/OnboardingUIProvider.js +33 -0
  215. package/dist/provider/OnboardingUIProvider.js.map +1 -0
  216. package/dist/provider/OnboardingUIProvider.old.d.ts +60 -0
  217. package/dist/provider/OnboardingUIProvider.old.d.ts.map +1 -0
  218. package/dist/provider/OnboardingUIProvider.old.js +53 -0
  219. package/dist/provider/OnboardingUIProvider.old.js.map +1 -0
  220. package/package.json +77 -0
  221. package/src/UI/Components/CircularProgress.tsx +146 -0
  222. package/src/UI/Components/ProgressBar.tsx +143 -0
  223. package/src/UI/Components/StaggeredTextList.tsx +152 -0
  224. package/src/UI/Components/index.ts +3 -0
  225. package/src/UI/ErrorBoundary/ErrorBoundary.tsx +181 -0
  226. package/src/UI/ErrorBoundary/README.md +71 -0
  227. package/src/UI/ErrorBoundary/index.ts +2 -0
  228. package/src/UI/ErrorBoundary/withErrorBoundary.tsx +19 -0
  229. package/src/UI/OnboardingPage.tsx +53 -0
  230. package/src/UI/Pages/Carousel/Renderer.tsx +210 -0
  231. package/src/UI/Pages/Carousel/index.ts +2 -0
  232. package/src/UI/Pages/Carousel/types.ts +26 -0
  233. package/src/UI/Pages/Commitment/Renderer.tsx +312 -0
  234. package/src/UI/Pages/Commitment/index.ts +2 -0
  235. package/src/UI/Pages/Commitment/types.ts +28 -0
  236. package/src/UI/Pages/Loader/Renderer.tsx +417 -0
  237. package/src/UI/Pages/Loader/index.ts +2 -0
  238. package/src/UI/Pages/Loader/types.ts +32 -0
  239. package/src/UI/Pages/MediaContent/Renderer.tsx +130 -0
  240. package/src/UI/Pages/MediaContent/index.ts +2 -0
  241. package/src/UI/Pages/MediaContent/types.ts +26 -0
  242. package/src/UI/Pages/Picker/Renderer.tsx +618 -0
  243. package/src/UI/Pages/Picker/index.ts +2 -0
  244. package/src/UI/Pages/Picker/types.ts +34 -0
  245. package/src/UI/Pages/Question/Renderer.tsx +208 -0
  246. package/src/UI/Pages/Question/components.tsx +130 -0
  247. package/src/UI/Pages/Question/index.ts +3 -0
  248. package/src/UI/Pages/Question/types.ts +29 -0
  249. package/src/UI/Pages/Ratings/Renderer.tsx +282 -0
  250. package/src/UI/Pages/Ratings/index.ts +2 -0
  251. package/src/UI/Pages/Ratings/types.ts +22 -0
  252. package/src/UI/Pages/index.ts +10 -0
  253. package/src/UI/Pages/types.ts +25 -0
  254. package/src/UI/Provider/OnboardingProgressProvider.tsx +40 -0
  255. package/src/UI/Provider/index.ts +1 -0
  256. package/src/UI/Templates/OnboardingTemplate.tsx +86 -0
  257. package/src/UI/Templates/index.ts +1 -0
  258. package/src/UI/Theme/ThemeProvider.tsx +100 -0
  259. package/src/UI/Theme/defaultTheme.ts +12 -0
  260. package/src/UI/Theme/helpers.ts +24 -0
  261. package/src/UI/Theme/index.ts +7 -0
  262. package/src/UI/Theme/token.ts +106 -0
  263. package/src/UI/Theme/tokens/darkTokens.ts +25 -0
  264. package/src/UI/Theme/tokens/index.ts +3 -0
  265. package/src/UI/Theme/tokens/lightTokens.ts +25 -0
  266. package/src/UI/Theme/tokens/typography.ts +66 -0
  267. package/src/UI/Theme/types.ts +72 -0
  268. package/src/UI/Theme/useTheme.ts +22 -0
  269. package/src/UI/Theme/utils.ts +67 -0
  270. package/src/UI/index.ts +7 -0
  271. package/src/UI/types.ts +41 -0
  272. package/src/assets/laurel-left.png +0 -0
  273. package/src/assets/laurel-right.png +0 -0
  274. package/src/assets/star-filled.png +0 -0
  275. package/src/index.ts +28 -0
@@ -0,0 +1,417 @@
1
+ import { OnboardingTemplate } from "../../Templates/OnboardingTemplate";
2
+ import { LoaderStepType, LoaderStepTypeSchema, LoaderStep } from "./types";
3
+ import {
4
+ View,
5
+ Text,
6
+ StyleSheet,
7
+ Animated,
8
+ ScrollView,
9
+ useWindowDimensions,
10
+ Image,
11
+ } from "react-native";
12
+ import { useRef, useEffect, useState, useCallback } from "react";
13
+ import { Theme } from "../../Theme/types";
14
+ import { defaultTheme } from "../../Theme/defaultTheme";
15
+ import { CircularProgress } from "../../Components/CircularProgress";
16
+ import { StaggeredTextList } from "../../Components/StaggeredTextList";
17
+
18
+ type ContentProps = {
19
+ step: LoaderStepType;
20
+ onContinue: () => void;
21
+ theme?: Theme;
22
+ };
23
+
24
+ const LoaderRendererBase = ({ step, onContinue, theme = defaultTheme }: ContentProps) => {
25
+ const validatedData = LoaderStepTypeSchema.parse(step);
26
+ const { title, steps, didYouKnowImages, duration, variant } =
27
+ validatedData.payload;
28
+
29
+ // Route to appropriate variant
30
+ if (variant === "circle") {
31
+ return (
32
+ <CircleVariant
33
+ step={step}
34
+ onContinue={onContinue}
35
+ validatedData={validatedData}
36
+ theme={theme}
37
+ />
38
+ );
39
+ }
40
+
41
+ // Default to bars variant
42
+ return (
43
+ <BarsVariant
44
+ step={step}
45
+ onContinue={onContinue}
46
+ validatedData={validatedData}
47
+ theme={theme}
48
+ />
49
+ );
50
+ };
51
+
52
+ // Bars Variant (original implementation)
53
+ const BarsVariant = ({
54
+ step,
55
+ onContinue,
56
+ validatedData,
57
+ theme,
58
+ }: {
59
+ step: LoaderStepType;
60
+ onContinue: () => void;
61
+ validatedData: LoaderStepType;
62
+ theme: Theme;
63
+ }) => {
64
+ const { title, steps, didYouKnowImages, duration } = validatedData.payload;
65
+
66
+ const [isComplete, setIsComplete] = useState(false);
67
+ const buttonFadeAnim = useRef(new Animated.Value(0)).current;
68
+
69
+ // Create animated values for each step
70
+ const progressValues = useRef(steps.map(() => new Animated.Value(0))).current;
71
+
72
+ const handleAnimationComplete = useCallback(() => {
73
+ setIsComplete(true);
74
+ Animated.timing(buttonFadeAnim, {
75
+ toValue: 1,
76
+ duration: 500,
77
+ useNativeDriver: true,
78
+ }).start();
79
+ }, [buttonFadeAnim]);
80
+
81
+ useEffect(() => {
82
+ // Animate each step sequentially
83
+ const animations = progressValues.map((progress, index) =>
84
+ Animated.timing(progress, {
85
+ toValue: 1,
86
+ duration: duration,
87
+ delay: (index * duration) / 2,
88
+ useNativeDriver: false,
89
+ })
90
+ );
91
+
92
+ Animated.sequence(animations).start(() => {
93
+ handleAnimationComplete();
94
+ });
95
+ }, [progressValues, duration, handleAnimationComplete]);
96
+
97
+ const styles = createStyles(theme);
98
+
99
+ return (
100
+ <OnboardingTemplate
101
+ step={step}
102
+ onContinue={onContinue}
103
+ theme={theme}
104
+ button={
105
+ isComplete ? { text: validatedData.continueButtonLabel } : undefined
106
+ }
107
+ >
108
+ <ScrollView
109
+ contentContainerStyle={styles.scrollContent}
110
+ showsVerticalScrollIndicator={false}
111
+ >
112
+ <View style={styles.container}>
113
+ {/* Title */}
114
+ <Text style={styles.title}>{title}</Text>
115
+
116
+ {/* Steps */}
117
+ <View style={styles.stepsContainer}>
118
+ {steps.map((stepItem, index) => (
119
+ <StepProgress
120
+ key={index}
121
+ step={stepItem}
122
+ progress={progressValues[index]}
123
+ theme={theme}
124
+ />
125
+ ))}
126
+ </View>
127
+
128
+ {/* Did you know carousel */}
129
+ {didYouKnowImages && didYouKnowImages.length > 0 && (
130
+ <View style={styles.carouselSection}>
131
+ <Text style={styles.carouselTitle}>Did you know?</Text>
132
+ <DidYouKnowCarousel images={didYouKnowImages} theme={theme} />
133
+ </View>
134
+ )}
135
+ </View>
136
+ </ScrollView>
137
+
138
+ {/* Animated button */}
139
+ {isComplete && (
140
+ <Animated.View
141
+ style={[styles.buttonContainer, { opacity: buttonFadeAnim }]}
142
+ />
143
+ )}
144
+ </OnboardingTemplate>
145
+ );
146
+ };
147
+
148
+ // Circle Variant
149
+ const CircleVariant = ({
150
+ step,
151
+ onContinue,
152
+ validatedData,
153
+ theme,
154
+ }: {
155
+ step: LoaderStepType;
156
+ onContinue: () => void;
157
+ validatedData: LoaderStepType;
158
+ theme: Theme;
159
+ }) => {
160
+ const { title, steps, didYouKnowImages, duration } = validatedData.payload;
161
+
162
+ const handleAnimationComplete = useCallback(() => {
163
+ onContinue();
164
+ }, [onContinue]);
165
+
166
+ const styles = createStyles(theme);
167
+
168
+ return (
169
+ <OnboardingTemplate step={step} onContinue={onContinue} theme={theme}>
170
+ <ScrollView
171
+ contentContainerStyle={styles.scrollContent}
172
+ showsVerticalScrollIndicator={false}
173
+ >
174
+ <View style={styles.container}>
175
+ {/* Circular Progress */}
176
+ <View style={styles.circleSection}>
177
+ <CircularProgress
178
+ onProgressComplete={handleAnimationComplete}
179
+ duration={duration}
180
+ totalSteps={steps.length}
181
+ />
182
+ </View>
183
+
184
+ {/* Staggered Text List */}
185
+ <View style={styles.textListSection}>
186
+ <StaggeredTextList items={steps} duration={duration} />
187
+ </View>
188
+
189
+ {/* Did you know carousel */}
190
+ {didYouKnowImages && didYouKnowImages.length > 0 && (
191
+ <View style={styles.carouselSection}>
192
+ <Text style={styles.carouselTitle}>Did you know?</Text>
193
+ <DidYouKnowCarousel images={didYouKnowImages} theme={theme} />
194
+ </View>
195
+ )}
196
+ </View>
197
+ </ScrollView>
198
+ </OnboardingTemplate>
199
+ );
200
+ };
201
+
202
+ type StepProgressProps = {
203
+ step: LoaderStep;
204
+ progress: Animated.Value;
205
+ theme: Theme;
206
+ };
207
+
208
+ const StepProgress = ({ step, progress, theme }: StepProgressProps) => {
209
+ const [barStarted, setBarStarted] = useState(false);
210
+ const [barComplete, setBarComplete] = useState(false);
211
+ const styles = createStyles(theme);
212
+
213
+ useEffect(() => {
214
+ const listenerId = progress.addListener(({ value }) => {
215
+ if (value > 0 && !barStarted) {
216
+ setBarStarted(true);
217
+ }
218
+ if (value >= 1 && !barComplete) {
219
+ setBarComplete(true);
220
+ }
221
+ });
222
+
223
+ return () => {
224
+ progress.removeListener(listenerId);
225
+ };
226
+ }, [progress, barStarted, barComplete]);
227
+
228
+ const progressWidth = progress.interpolate({
229
+ inputRange: [0, 1],
230
+ outputRange: ["0%", "100%"],
231
+ });
232
+
233
+ const textColor = barStarted
234
+ ? theme.colors.text.secondary
235
+ : theme.colors.text.disable;
236
+
237
+ return (
238
+ <View style={styles.stepContainer}>
239
+ <View style={styles.stepHeader}>
240
+ <Text style={[styles.stepLabel, { color: textColor }]}>
241
+ {barComplete ? step.completed : step.label}
242
+ </Text>
243
+ {barComplete ? (
244
+ <View style={styles.checkmark}>
245
+ <Text style={styles.checkmarkText}>✓</Text>
246
+ </View>
247
+ ) : (
248
+ <View style={styles.checkmarkPlaceholder} />
249
+ )}
250
+ </View>
251
+ <View style={styles.progressBar}>
252
+ <Animated.View
253
+ style={[styles.progressFill, { width: progressWidth }]}
254
+ />
255
+ </View>
256
+ </View>
257
+ );
258
+ };
259
+
260
+ type DidYouKnowCarouselProps = {
261
+ images: Array<{ type: string; url?: string; localPathId?: string }>;
262
+ theme: Theme;
263
+ };
264
+
265
+ const DidYouKnowCarousel = ({ images, theme }: DidYouKnowCarouselProps) => {
266
+ const { width } = useWindowDimensions();
267
+ const styles = createStyles(theme);
268
+
269
+ return (
270
+ <ScrollView
271
+ horizontal
272
+ showsHorizontalScrollIndicator={false}
273
+ contentContainerStyle={styles.carouselContent}
274
+ >
275
+ {images.map((image, index) => {
276
+ if (image.type === "image" && "url" in image && image.url) {
277
+ return (
278
+ <Image
279
+ key={index}
280
+ source={{ uri: image.url }}
281
+ style={styles.carouselImage}
282
+ resizeMode="cover"
283
+ />
284
+ );
285
+ }
286
+ // Placeholder for local images or other types
287
+ return (
288
+ <View key={index} style={styles.carouselPlaceholder}>
289
+ <Text style={styles.placeholderText}>Image {index + 1}</Text>
290
+ </View>
291
+ );
292
+ })}
293
+ </ScrollView>
294
+ );
295
+ };
296
+
297
+ const createStyles = (theme: Theme) =>
298
+ StyleSheet.create({
299
+ scrollContent: {
300
+ flexGrow: 1,
301
+ paddingTop: 20,
302
+ },
303
+ container: {
304
+ flex: 1,
305
+ paddingHorizontal: 24,
306
+ gap: 40,
307
+ },
308
+ title: {
309
+ fontFamily: theme.typography.textStyles.heading2.fontFamily,
310
+ fontSize: theme.typography.textStyles.heading2.fontSize,
311
+ fontWeight: theme.typography.fontWeight.semibold,
312
+ lineHeight:
313
+ theme.typography.textStyles.heading2.fontSize * theme.typography.lineHeight.tight,
314
+ color: theme.colors.text.primary,
315
+ textAlign: "center",
316
+ letterSpacing: -0.76,
317
+ },
318
+ stepsContainer: {
319
+ gap: 24,
320
+ },
321
+ stepContainer: {
322
+ gap: 8,
323
+ },
324
+ stepHeader: {
325
+ flexDirection: "row",
326
+ justifyContent: "space-between",
327
+ alignItems: "center",
328
+ },
329
+ stepLabel: {
330
+ fontFamily: theme.typography.textStyles.body.fontFamily,
331
+ fontSize: theme.typography.textStyles.body.fontSize,
332
+ fontWeight: theme.typography.fontWeight.regular,
333
+ letterSpacing: -0.32,
334
+ lineHeight:
335
+ theme.typography.textStyles.body.fontSize * theme.typography.lineHeight.normal,
336
+ },
337
+ checkmark: {
338
+ width: 24,
339
+ height: 24,
340
+ borderRadius: 12,
341
+ backgroundColor: theme.colors.primary,
342
+ justifyContent: "center",
343
+ alignItems: "center",
344
+ },
345
+ checkmarkPlaceholder: {
346
+ width: 24,
347
+ height: 24,
348
+ backgroundColor: "transparent",
349
+ },
350
+ checkmarkText: {
351
+ fontSize: 16,
352
+ color: theme.colors.text.opposite,
353
+ fontWeight: theme.typography.fontWeight.semibold,
354
+ },
355
+ progressBar: {
356
+ height: 12,
357
+ backgroundColor: theme.colors.neutral.lowest,
358
+ borderRadius: 200,
359
+ overflow: "hidden",
360
+ },
361
+ progressFill: {
362
+ height: "100%",
363
+ backgroundColor: theme.colors.primary,
364
+ borderRadius: 200,
365
+ },
366
+ carouselSection: {
367
+ gap: 16,
368
+ marginTop: 20,
369
+ },
370
+ carouselTitle: {
371
+ fontFamily: theme.typography.textStyles.body.fontFamily,
372
+ fontSize: theme.typography.textStyles.body.fontSize,
373
+ fontWeight: theme.typography.fontWeight.medium,
374
+ color: theme.colors.text.disable,
375
+ textAlign: "center",
376
+ },
377
+ carouselContent: {
378
+ gap: 16,
379
+ paddingHorizontal: 8,
380
+ },
381
+ carouselImage: {
382
+ width: 300,
383
+ height: 200,
384
+ borderRadius: 16,
385
+ },
386
+ carouselPlaceholder: {
387
+ width: 300,
388
+ height: 200,
389
+ borderRadius: 16,
390
+ backgroundColor: theme.colors.neutral.lowest,
391
+ justifyContent: "center",
392
+ alignItems: "center",
393
+ },
394
+ placeholderText: {
395
+ fontFamily: theme.typography.textStyles.body.fontFamily,
396
+ fontSize: theme.typography.textStyles.body.fontSize,
397
+ color: theme.colors.text.disable,
398
+ },
399
+ buttonContainer: {
400
+ position: "absolute",
401
+ bottom: 0,
402
+ left: 0,
403
+ right: 0,
404
+ },
405
+ // Circle variant styles
406
+ circleSection: {
407
+ alignItems: "center",
408
+ justifyContent: "center",
409
+ },
410
+ textListSection: {
411
+ alignItems: "center",
412
+ justifyContent: "center",
413
+ minHeight: 100,
414
+ },
415
+ });
416
+
417
+ export const LoaderRenderer = LoaderRendererBase;
@@ -0,0 +1,2 @@
1
+ export * from "./Renderer";
2
+ export * from "./types";
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+ import { CustomPayloadSchema, MediaSourceSchema } from "../types";
3
+
4
+ export const LoaderStepSchema = z.object({
5
+ label: z.string(),
6
+ completed: z.string(),
7
+ });
8
+
9
+ export const LoaderStepPayloadSchema = z.object({
10
+ title: z.string(),
11
+ steps: z.array(LoaderStepSchema),
12
+ didYouKnowImages: z.array(MediaSourceSchema).nullish(),
13
+ duration: z.number().optional().default(2000),
14
+ variant: z
15
+ .enum(["bars", "circle", "texts_fading"])
16
+ .optional()
17
+ .default("bars"),
18
+ });
19
+
20
+ export const LoaderStepTypeSchema = z.object({
21
+ id: z.string(),
22
+ type: z.literal("Loader"),
23
+ name: z.string(),
24
+ displayProgressHeader: z.boolean(),
25
+ payload: LoaderStepPayloadSchema,
26
+ customPayload: CustomPayloadSchema,
27
+ continueButtonLabel: z.string().optional().default("Continue"),
28
+ figmaUrl: z.string().nullish(),
29
+ });
30
+
31
+ export type LoaderStepType = z.infer<typeof LoaderStepTypeSchema>;
32
+ export type LoaderStep = z.infer<typeof LoaderStepSchema>;
@@ -0,0 +1,130 @@
1
+ import { OnboardingTemplate } from "../../Templates/OnboardingTemplate";
2
+ import { MediaContentStepType, MediaContentStepTypeSchema } from "./types";
3
+ import { View, Text, StyleSheet, Image, ScrollView } from "react-native";
4
+ import { Theme } from "../../Theme/types";
5
+ import { defaultTheme } from "../../Theme/defaultTheme";
6
+ import { getTextStyle } from "../../Theme/helpers";
7
+
8
+ type ContentProps = {
9
+ step: MediaContentStepType;
10
+ onContinue: () => void;
11
+ theme?: Theme;
12
+ };
13
+
14
+ const MediaContentRendererBase = ({ step, onContinue, theme = defaultTheme }: ContentProps) => {
15
+ // Validate the schema
16
+ const validatedData = MediaContentStepTypeSchema.parse(step);
17
+ const { mediaSource, title, description } = validatedData.payload;
18
+
19
+ const renderMedia = () => {
20
+ if (mediaSource.type === "image") {
21
+ // Check if it's a local path or URL
22
+ if ("localPathId" in mediaSource) {
23
+ // TODO: Map localPathId to actual local image path
24
+ return (
25
+ <View style={[styles.mediaPlaceholder, { backgroundColor: theme.colors.neutral.lowest }]}>
26
+ <Text style={[getTextStyle(theme, "body"), styles.placeholderText, { color: theme.colors.text.disable }]}>
27
+ Image: {mediaSource.localPathId}
28
+ </Text>
29
+ </View>
30
+ );
31
+ } else if ("url" in mediaSource) {
32
+ return (
33
+ <Image
34
+ source={{ uri: mediaSource.url }}
35
+ style={styles.mediaImage}
36
+ resizeMode="cover"
37
+ />
38
+ );
39
+ }
40
+ } else if (mediaSource.type === "lottie") {
41
+ // TODO: Implement Lottie animation support
42
+ return (
43
+ <View style={[styles.mediaPlaceholder, { backgroundColor: theme.colors.neutral.lowest }]}>
44
+ <Text style={[getTextStyle(theme, "body"), styles.placeholderText, { color: theme.colors.text.disable }]}>Lottie Animation</Text>
45
+ </View>
46
+ );
47
+ } else if (mediaSource.type === "rive") {
48
+ // Rive animation placeholder
49
+ return (
50
+ <View style={[styles.mediaPlaceholder, { backgroundColor: theme.colors.neutral.lowest }]}>
51
+ <Text style={[getTextStyle(theme, "body"), styles.placeholderText, { color: theme.colors.text.disable }]}>Rive Animation</Text>
52
+ </View>
53
+ );
54
+ }
55
+
56
+ return (
57
+ <View style={[styles.mediaPlaceholder, { backgroundColor: theme.colors.neutral.lowest }]}>
58
+ <Text style={[getTextStyle(theme, "body"), styles.placeholderText, { color: theme.colors.text.disable }]}>Media</Text>
59
+ </View>
60
+ );
61
+ };
62
+
63
+ return (
64
+ <OnboardingTemplate
65
+ step={step}
66
+ onContinue={onContinue}
67
+ theme={theme}
68
+ button={{ text: validatedData.continueButtonLabel }}
69
+ >
70
+ <ScrollView
71
+ contentContainerStyle={styles.scrollContent}
72
+ showsVerticalScrollIndicator={false}
73
+ alwaysBounceVertical={false}
74
+ >
75
+ <View style={styles.container}>
76
+ {/* Title */}
77
+ <Text style={[getTextStyle(theme, "heading1"), styles.title, { color: theme.colors.text.primary }]}>{title}</Text>
78
+
79
+ {/* Media Content */}
80
+ <View style={styles.mediaContainer}>{renderMedia()}</View>
81
+
82
+ {/* Description/Subtitle */}
83
+ {description && <Text style={[getTextStyle(theme, "heading3"), styles.subtitle, { color: theme.colors.text.secondary }]}>{description}</Text>}
84
+ </View>
85
+ </ScrollView>
86
+ </OnboardingTemplate>
87
+ );
88
+ };
89
+
90
+ const styles = StyleSheet.create({
91
+ scrollContent: {
92
+ flexGrow: 1,
93
+ paddingTop: 20,
94
+ paddingBottom: 24,
95
+ },
96
+ container: {
97
+ flex: 1,
98
+ paddingHorizontal: 24,
99
+ gap: 24,
100
+ alignItems: "center",
101
+ },
102
+ title: {
103
+ textAlign: "center",
104
+ letterSpacing: -0.76,
105
+ },
106
+ mediaContainer: {
107
+ width: "100%",
108
+ height: 400,
109
+ borderRadius: 32,
110
+ overflow: "hidden",
111
+ },
112
+ mediaImage: {
113
+ width: "100%",
114
+ height: "100%",
115
+ },
116
+ mediaPlaceholder: {
117
+ width: "100%",
118
+ height: "100%",
119
+ justifyContent: "center",
120
+ alignItems: "center",
121
+ },
122
+ placeholderText: {},
123
+ subtitle: {
124
+ textAlign: "center",
125
+ },
126
+ });
127
+
128
+ import { withErrorBoundary } from '../../ErrorBoundary';
129
+
130
+ export const MediaContentRenderer = withErrorBoundary(MediaContentRendererBase, 'MediaContent');
@@ -0,0 +1,2 @@
1
+ export * from "./Renderer";
2
+ export * from "./types";
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ import {
3
+ CustomPayloadSchema,
4
+ MediaSourceSchema,
5
+ SocialProofSchema,
6
+ } from "../types";
7
+
8
+ export const MediaContentStepPayloadSchema = z.object({
9
+ mediaSource: MediaSourceSchema,
10
+ title: z.string(),
11
+ description: z.string().nullish(),
12
+ socialProof: SocialProofSchema.nullish(),
13
+ });
14
+
15
+ export const MediaContentStepTypeSchema = z.object({
16
+ id: z.string(),
17
+ type: z.literal("MediaContent"),
18
+ name: z.string(),
19
+ displayProgressHeader: z.boolean(),
20
+ payload: MediaContentStepPayloadSchema,
21
+ customPayload: CustomPayloadSchema,
22
+ continueButtonLabel: z.string().optional().default("Continue"),
23
+ figmaUrl: z.string().nullish(),
24
+ });
25
+
26
+ export type MediaContentStepType = z.infer<typeof MediaContentStepTypeSchema>;