@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,143 @@
1
+ import React, { useEffect } from "react";
2
+ import { View, StyleSheet, TouchableOpacity } from "react-native";
3
+ import Animated, {
4
+ useSharedValue,
5
+ useAnimatedStyle,
6
+ withTiming,
7
+ } from "react-native-reanimated";
8
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
9
+ import { ChevronLeft } from "lucide-react-native";
10
+ import { useRouter } from "expo-router";
11
+ import { defaultTheme, Theme } from "../Theme";
12
+
13
+ interface ProgressBarProps {
14
+ backgroundColor?: string;
15
+ progressColor?: string;
16
+ progressPercentage: number;
17
+ theme?: Theme;
18
+ isProgressBarVisible?: boolean
19
+ }
20
+
21
+ export const ProgressBar: React.FC<ProgressBarProps> = ({
22
+ backgroundColor,
23
+ progressColor,
24
+ progressPercentage = 0,
25
+ theme = defaultTheme,
26
+ isProgressBarVisible = true,
27
+ }) => {
28
+ const animated = true;
29
+ const router = useRouter();
30
+ const { top } = useSafeAreaInsets();
31
+
32
+ const height = 12
33
+ // Use Reanimated shared value for smooth animations
34
+ const progress = useSharedValue(0);
35
+
36
+ useEffect(() => {
37
+ if (animated) {
38
+ progress.value = withTiming(progressPercentage, {
39
+ duration: 300,
40
+ });
41
+ } else {
42
+ progress.value = progressPercentage;
43
+ }
44
+ }, [progressPercentage, animated]);
45
+
46
+ // Animated style for the progress bar
47
+ const animatedStyle = useAnimatedStyle(() => {
48
+ return {
49
+ width: `${progress.value}%`,
50
+ };
51
+ });
52
+
53
+ // Use theme colors with fallback to props
54
+ const trackBgColor = backgroundColor || theme.colors.neutral.lower;
55
+ const barColor = progressColor || theme.colors.primary;
56
+
57
+ return (
58
+ isProgressBarVisible && (
59
+ <View style={[styles.container, { paddingTop: top }]}>
60
+ <View style={styles.progressBarContainer}>
61
+ {/* Left section: Back button */}
62
+ <View style={styles.backButtonSection}>
63
+ {router.canGoBack() && (
64
+ <TouchableOpacity
65
+ onPress={() => router.back()}
66
+ hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
67
+ style={styles.backButton}
68
+ >
69
+ <ChevronLeft
70
+ size={24}
71
+ color={theme.colors.text.primary}
72
+ strokeWidth={2}
73
+ />
74
+ </TouchableOpacity>
75
+ )}
76
+ </View>
77
+
78
+ {/* Center section: Progress bar */}
79
+ <View style={styles.progressSection}>
80
+ <View
81
+ style={[styles.track, { height, backgroundColor: trackBgColor }]}
82
+ >
83
+ <Animated.View
84
+ style={[
85
+ styles.progress,
86
+ {
87
+ height,
88
+ backgroundColor: barColor,
89
+ },
90
+ animatedStyle,
91
+ ]}
92
+ />
93
+ </View>
94
+ </View>
95
+
96
+ {/* Right section: Spacer */}
97
+ <View style={styles.spacerSection} />
98
+ </View>
99
+ </View>
100
+ )
101
+ );
102
+ };
103
+
104
+ const styles = StyleSheet.create({
105
+ container: {
106
+ position: "absolute",
107
+ top: 0,
108
+ left: 0,
109
+ right: 0,
110
+ zIndex: 10,
111
+ justifyContent: "center",
112
+ paddingBottom: 24,
113
+ },
114
+ progressBarContainer: {
115
+ width: "100%",
116
+ flexDirection: "row",
117
+ alignItems: "center",
118
+ gap: 16,
119
+ paddingHorizontal: 16,
120
+ },
121
+ backButtonSection: {
122
+ flex: 1,
123
+ alignItems: "flex-start",
124
+ },
125
+ backButton: {
126
+ padding: 4,
127
+ },
128
+ progressSection: {
129
+ flex: 5,
130
+ alignItems: "flex-end",
131
+ },
132
+ spacerSection: {
133
+ flex: 1,
134
+ },
135
+ track: {
136
+ width: "100%",
137
+ borderRadius: 10,
138
+ overflow: "hidden",
139
+ },
140
+ progress: {
141
+ borderRadius: 10,
142
+ },
143
+ });
@@ -0,0 +1,152 @@
1
+ import React, { useEffect } from "react";
2
+ import { View, StyleSheet } from "react-native";
3
+ import Animated, {
4
+ useSharedValue,
5
+ useAnimatedStyle,
6
+ withTiming,
7
+ withSequence,
8
+ Easing,
9
+ interpolateColor,
10
+ SharedValue,
11
+ } from "react-native-reanimated";
12
+ import { useTheme } from "../Theme/useTheme";
13
+ import { Theme } from "../Theme/types";
14
+
15
+ type TextItem = {
16
+ label: string;
17
+ completed: string;
18
+ };
19
+
20
+ type StaggeredTextListProps = {
21
+ items: TextItem[];
22
+ duration: number;
23
+ };
24
+
25
+ export const StaggeredTextList = ({
26
+ items,
27
+ duration,
28
+ }: StaggeredTextListProps) => {
29
+ const { theme } = useTheme();
30
+ const styles = createStyles(theme);
31
+
32
+ // Create a shared value to track the current active index
33
+ const activeIndex = useSharedValue(0);
34
+
35
+ useEffect(() => {
36
+ // Reset animation
37
+ activeIndex.value = 0;
38
+
39
+ // Animate sequentially through each text
40
+ const animateSequentially = async () => {
41
+ for (let i = 0; i < items.length; i++) {
42
+ activeIndex.value = i;
43
+
44
+ // Wait for duration before moving to next
45
+ // Last item stays longer
46
+ const waitTime = i === items.length - 1 ? duration * 1.5 : duration;
47
+ await new Promise((resolve) => setTimeout(resolve, waitTime));
48
+ }
49
+ };
50
+
51
+ animateSequentially();
52
+ }, [items, duration, activeIndex]);
53
+
54
+ return (
55
+ <View style={styles.container}>
56
+ {items.map((item, index) => (
57
+ <AnimatedTextItem
58
+ key={index}
59
+ item={item}
60
+ index={index}
61
+ activeIndex={activeIndex}
62
+ totalItems={items.length}
63
+ />
64
+ ))}
65
+ </View>
66
+ );
67
+ };
68
+
69
+ type AnimatedTextItemProps = {
70
+ item: TextItem;
71
+ index: number;
72
+ activeIndex: SharedValue<number>;
73
+ totalItems: number;
74
+ };
75
+
76
+ const AnimatedTextItem = ({
77
+ item,
78
+ index,
79
+ activeIndex,
80
+ totalItems,
81
+ }: AnimatedTextItemProps) => {
82
+ const { theme } = useTheme();
83
+ const styles = createStyles(theme);
84
+
85
+ const animatedStyle = useAnimatedStyle(() => {
86
+ const isActive = activeIndex.value === index;
87
+ const wasActive = activeIndex.value > index;
88
+ const willBeActive = activeIndex.value < index;
89
+
90
+ // Opacity animation
91
+ const opacity = withTiming(
92
+ isActive ? 1 : wasActive ? 0.6 : willBeActive ? 0.4 : 0.4,
93
+ {
94
+ duration: 400,
95
+ easing: Easing.bezier(0.25, 0.1, 0.25, 1),
96
+ }
97
+ );
98
+
99
+ // Color interpolation
100
+ const color = interpolateColor(
101
+ isActive ? 1 : 0,
102
+ [0, 1],
103
+ [theme.colors.text.disable, theme.colors.text.primary]
104
+ );
105
+
106
+ // Subtle translateY for active text
107
+ const translateY = withTiming(isActive ? 0 : 2, {
108
+ duration: 300,
109
+ easing: Easing.bezier(0.25, 0.1, 0.25, 1),
110
+ });
111
+
112
+ // Pulse effect for the last active item
113
+ const scale =
114
+ isActive && index === totalItems - 1
115
+ ? withSequence(
116
+ withTiming(1, { duration: 1000 }),
117
+ withTiming(1.05, { duration: 1000 }),
118
+ withTiming(1, { duration: 1000 })
119
+ )
120
+ : 1;
121
+
122
+ return {
123
+ opacity,
124
+ color,
125
+ transform: [{ translateY }, { scale }],
126
+ };
127
+ });
128
+
129
+ return (
130
+ <Animated.Text style={[styles.text, animatedStyle]}>
131
+ {item.label}
132
+ </Animated.Text>
133
+ );
134
+ };
135
+
136
+ const createStyles = (theme: Theme) =>
137
+ StyleSheet.create({
138
+ container: {
139
+ gap: 8,
140
+ alignItems: "center",
141
+ width: "100%",
142
+ },
143
+ text: {
144
+ fontFamily: theme.typography.textStyles.heading3.fontFamily,
145
+ fontSize: theme.typography.textStyles.heading3.fontSize,
146
+ fontWeight: theme.typography.fontWeight.medium,
147
+ textAlign: "center",
148
+ lineHeight:
149
+ theme.typography.textStyles.heading3.fontSize * theme.typography.lineHeight.normal,
150
+ letterSpacing: 0.3,
151
+ },
152
+ });
@@ -0,0 +1,3 @@
1
+ export * from "./ProgressBar";
2
+ export * from "./CircularProgress";
3
+ export * from "./StaggeredTextList";
@@ -0,0 +1,181 @@
1
+ import React, { Component, ReactNode } from 'react';
2
+ import { View, Text, StyleSheet, ScrollView } from 'react-native';
3
+ import { ZodError } from 'zod';
4
+
5
+ interface ErrorBoundaryProps {
6
+ children: ReactNode;
7
+ stepType?: string;
8
+ }
9
+
10
+ interface ErrorBoundaryState {
11
+ hasError: boolean;
12
+ error: Error | null;
13
+ }
14
+
15
+ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
16
+ constructor(props: ErrorBoundaryProps) {
17
+ super(props);
18
+ this.state = { hasError: false, error: null };
19
+ }
20
+
21
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState {
22
+ return { hasError: true, error };
23
+ }
24
+
25
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
26
+ console.error('ErrorBoundary caught an error:', error, errorInfo);
27
+ }
28
+
29
+ formatZodError(error: ZodError<any>): string {
30
+ try {
31
+ // @ts-ignore
32
+ return error.errors
33
+ // @ts-ignore
34
+ .map((err) => {
35
+ const path = err.path.join(' > ');
36
+ return `• ${path || 'root'}: ${err.message}`;
37
+ })
38
+ .join('\n');
39
+ } catch (error) {
40
+ console.error('Error formatting Zod error:', error);
41
+ return 'An error occurred while formatting the Zod error';
42
+ }
43
+ }
44
+
45
+ render() {
46
+ if (this.state.hasError && this.state.error) {
47
+ const isZodError = this.state.error instanceof ZodError;
48
+ const { stepType } = this.props;
49
+
50
+ return (
51
+ <View style={styles.container}>
52
+ <View style={styles.content}>
53
+ <Text style={styles.emoji}>⚠️</Text>
54
+ <Text style={styles.title}>
55
+ {isZodError ? 'Invalid Step Payload' : 'Something went wrong'}
56
+ </Text>
57
+
58
+ {stepType && (
59
+ <Text style={styles.stepType}>Step Type: {stepType}</Text>
60
+ )}
61
+
62
+ <ScrollView style={styles.errorScroll} contentContainerStyle={styles.errorScrollContent}>
63
+ {isZodError ? (
64
+ <View style={styles.errorSection}>
65
+ <Text style={styles.errorLabel}>Validation Errors:</Text>
66
+ <Text style={styles.errorMessage}>
67
+ {this.formatZodError(this.state.error as ZodError<any>)}
68
+ </Text>
69
+ </View>
70
+ ) : (
71
+ <View style={styles.errorSection}>
72
+ <Text style={styles.errorLabel}>Error Message:</Text>
73
+ <Text style={styles.errorMessage}>
74
+ {this.state.error.message}
75
+ </Text>
76
+ {this.state.error.stack && (
77
+ <>
78
+ <Text style={styles.errorLabel}>Stack Trace:</Text>
79
+ <Text style={styles.errorStack}>
80
+ {this.state.error.stack}
81
+ </Text>
82
+ </>
83
+ )}
84
+ </View>
85
+ )}
86
+ </ScrollView>
87
+
88
+ {isZodError && (
89
+ <View style={styles.hint}>
90
+ <Text style={styles.hintText}>
91
+ 💡 Check the step payload structure and ensure all required fields match the schema.
92
+ </Text>
93
+ </View>
94
+ )}
95
+ </View>
96
+ </View>
97
+ );
98
+ }
99
+
100
+ return this.props.children;
101
+ }
102
+ }
103
+
104
+ const styles = StyleSheet.create({
105
+ container: {
106
+ flex: 1,
107
+ backgroundColor: '#fff',
108
+ justifyContent: 'center',
109
+ alignItems: 'center',
110
+ padding: 20,
111
+ },
112
+ content: {
113
+ maxWidth: 600,
114
+ width: '100%',
115
+ alignItems: 'center',
116
+ },
117
+ emoji: {
118
+ fontSize: 48,
119
+ marginBottom: 16,
120
+ },
121
+ title: {
122
+ fontSize: 24,
123
+ fontWeight: '600',
124
+ color: '#dc2626',
125
+ marginBottom: 8,
126
+ textAlign: 'center',
127
+ },
128
+ stepType: {
129
+ fontSize: 16,
130
+ fontWeight: '500',
131
+ color: '#6b7280',
132
+ marginBottom: 24,
133
+ textAlign: 'center',
134
+ },
135
+ errorScroll: {
136
+ maxHeight: 400,
137
+ width: '100%',
138
+ },
139
+ errorScrollContent: {
140
+ paddingVertical: 16,
141
+ },
142
+ errorSection: {
143
+ backgroundColor: '#fef2f2',
144
+ borderRadius: 12,
145
+ padding: 16,
146
+ borderLeftWidth: 4,
147
+ borderLeftColor: '#dc2626',
148
+ },
149
+ errorLabel: {
150
+ fontSize: 14,
151
+ fontWeight: '600',
152
+ color: '#991b1b',
153
+ marginBottom: 8,
154
+ },
155
+ errorMessage: {
156
+ fontSize: 14,
157
+ color: '#7f1d1d',
158
+ fontFamily: 'Courier',
159
+ lineHeight: 20,
160
+ },
161
+ errorStack: {
162
+ fontSize: 12,
163
+ color: '#991b1b',
164
+ fontFamily: 'Courier',
165
+ lineHeight: 16,
166
+ marginTop: 8,
167
+ },
168
+ hint: {
169
+ marginTop: 24,
170
+ backgroundColor: '#eff6ff',
171
+ borderRadius: 8,
172
+ padding: 12,
173
+ borderLeftWidth: 3,
174
+ borderLeftColor: '#3b82f6',
175
+ },
176
+ hintText: {
177
+ fontSize: 14,
178
+ color: '#1e40af',
179
+ lineHeight: 20,
180
+ },
181
+ });
@@ -0,0 +1,71 @@
1
+ # Error Boundary
2
+
3
+ The Error Boundary is a Higher Order Component (HOC) that wraps all renderers to catch and display errors gracefully, especially Zod validation errors.
4
+
5
+ ## Features
6
+
7
+ - **Automatic Error Catching**: Catches all errors thrown by renderers
8
+ - **Zod Error Formatting**: Specially formats Zod validation errors to show which fields are invalid
9
+ - **Developer-Friendly Display**: Shows error messages, stack traces, and validation details
10
+ - **Type-Specific Context**: Displays which step type caused the error
11
+
12
+ ## How It Works
13
+
14
+ All renderers are automatically wrapped with the `withErrorBoundary` HOC:
15
+
16
+ ```typescript
17
+ import { QuestionRenderer as QuestionRendererBase } from './Renderer';
18
+ import { withErrorBoundary } from '../../ErrorBoundary';
19
+
20
+ export const QuestionRenderer = withErrorBoundary(QuestionRendererBase, 'Question');
21
+ ```
22
+
23
+ When a Zod validation error occurs (e.g., missing required fields, wrong types), the error boundary will display:
24
+
25
+ 1. Step Type (e.g., "Question", "Ratings")
26
+ 2. Validation Errors (formatted list of field paths and messages)
27
+ 3. Helpful hints for fixing the payload
28
+
29
+ ## Example
30
+
31
+ If you pass an invalid payload:
32
+
33
+ ```typescript
34
+ const invalidStep = {
35
+ id: 'test',
36
+ type: 'Question',
37
+ payload: {
38
+ title: 'Test',
39
+ // Missing required 'answers' field
40
+ // Missing required 'multipleAnswer' field
41
+ }
42
+ } as any;
43
+ ```
44
+
45
+ The error boundary will show:
46
+ ```
47
+ ⚠️ Invalid Step Payload
48
+ Step Type: Question
49
+
50
+ Validation Errors:
51
+ • payload > answers: Required
52
+ • payload > multipleAnswer: Required
53
+
54
+ 💡 Check the step payload structure and ensure all required fields match the schema.
55
+ ```
56
+
57
+ ## Manual Usage
58
+
59
+ You can also use the ErrorBoundary component directly:
60
+
61
+ ```typescript
62
+ import { ErrorBoundary } from '@rocapine/react-native-onboarding-studio';
63
+
64
+ <ErrorBoundary stepType="MyCustomComponent">
65
+ <MyCustomComponent />
66
+ </ErrorBoundary>
67
+ ```
68
+
69
+ ## Testing
70
+
71
+ An error test example is available at `/example/error-test` in the example app to see the error boundary in action.
@@ -0,0 +1,2 @@
1
+ export { ErrorBoundary } from './ErrorBoundary';
2
+ export { withErrorBoundary } from './withErrorBoundary';
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ import { ErrorBoundary } from './ErrorBoundary';
3
+
4
+ export function withErrorBoundary<P extends object>(
5
+ Component: React.ComponentType<P>,
6
+ stepType?: string
7
+ ) {
8
+ const WrappedComponent = (props: P) => {
9
+ return (
10
+ <ErrorBoundary stepType={stepType}>
11
+ <Component {...props} />
12
+ </ErrorBoundary>
13
+ );
14
+ };
15
+
16
+ WrappedComponent.displayName = `withErrorBoundary(${Component.displayName || Component.name || 'Component'})`;
17
+
18
+ return WrappedComponent;
19
+ }
@@ -0,0 +1,53 @@
1
+ import { OnboardingStepType } from "./types";
2
+ import { RatingsRenderer, PickerRenderer, CommitmentRenderer, CarouselRenderer, LoaderRenderer, MediaContentRenderer, QuestionRenderer, QuestionAnswerButtonProps, QuestionAnswersListProps } from "./Pages";
3
+ import { View, Text, Button } from 'react-native';
4
+ import { useTheme } from "./Theme/useTheme";
5
+ import { Theme } from "./Theme";
6
+
7
+
8
+ interface OnboardingPageProps {
9
+ step: OnboardingStepType;
10
+ onContinue: (args?: any) => void;
11
+ isSandbox?: boolean;
12
+ theme?: Theme;
13
+ customComponents?: {
14
+ QuestionAnswerButton?: React.ComponentType<QuestionAnswerButtonProps>;
15
+ QuestionAnswersList?: React.ComponentType<QuestionAnswersListProps>;
16
+ };
17
+ }
18
+
19
+ export const OnboardingPage = ({ step, onContinue, isSandbox }: OnboardingPageProps) => {
20
+ const { theme } = useTheme();
21
+
22
+ switch (step.type) {
23
+ case 'Ratings':
24
+ return <RatingsRenderer step={step} onContinue={onContinue} theme={theme} />;
25
+ case 'Picker':
26
+ return <PickerRenderer step={step} onContinue={onContinue} theme={theme} />;
27
+ case 'Commitment':
28
+ return <CommitmentRenderer step={step} onContinue={onContinue} theme={theme} />;
29
+ case 'Carousel':
30
+ return <CarouselRenderer step={step} onContinue={onContinue} theme={theme} />;
31
+ case 'MediaContent':
32
+ return <MediaContentRenderer step={step} onContinue={onContinue} theme={theme} />;
33
+ case 'Loader':
34
+ return <LoaderRenderer step={step} onContinue={onContinue} theme={theme} />;
35
+ case 'Question':
36
+ return <QuestionRenderer step={step} onContinue={onContinue} theme={theme} />;
37
+ default:
38
+ if (isSandbox) {
39
+ // @ts-ignore
40
+ const stepType = step.type;
41
+ return <View>
42
+ <Text>Screen {stepType} not implemented</Text>
43
+ <Button title="Continue" onPress={onContinue} />
44
+ </View>
45
+ } else {
46
+ onContinue("onboarding_screen_not_implemented");
47
+ return <View>
48
+ <Text>You are almost done</Text>
49
+ <Button title="Continue" onPress={onContinue} />
50
+ </View>
51
+ }
52
+ }
53
+ };