ignite-parse-auth-kit 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 (241) hide show
  1. package/CONTRIBUTING.md +0 -0
  2. package/LICENSE +21 -0
  3. package/README.md +492 -0
  4. package/app/app.tsx +116 -0
  5. package/app/components/AlertTongle.tsx +105 -0
  6. package/app/components/AutoImage.tsx +89 -0
  7. package/app/components/Button.tsx +248 -0
  8. package/app/components/Card.tsx +314 -0
  9. package/app/components/EmptyState.tsx +248 -0
  10. package/app/components/Header.tsx +332 -0
  11. package/app/components/Icon.tsx +140 -0
  12. package/app/components/ListItem.tsx +243 -0
  13. package/app/components/ListView.tsx +42 -0
  14. package/app/components/Screen.tsx +305 -0
  15. package/app/components/Text.test.tsx +23 -0
  16. package/app/components/Text.tsx +116 -0
  17. package/app/components/TextField.tsx +292 -0
  18. package/app/components/Toggle/Checkbox.tsx +123 -0
  19. package/app/components/Toggle/Radio.tsx +106 -0
  20. package/app/components/Toggle/Switch.tsx +264 -0
  21. package/app/components/Toggle/Toggle.tsx +285 -0
  22. package/app/components/index copy.ts +15 -0
  23. package/app/components/index.ts +18 -0
  24. package/app/config/config.base.ts +26 -0
  25. package/app/config/config.dev.ts +10 -0
  26. package/app/config/config.prod.ts +10 -0
  27. package/app/config/index.ts +28 -0
  28. package/app/context/AuthContext.tsx +14 -0
  29. package/app/context/EpisodeContext.tsx +136 -0
  30. package/app/context/auth/AuthProvider.tsx +340 -0
  31. package/app/context/auth/hooks.ts +29 -0
  32. package/app/context/auth/index.ts +38 -0
  33. package/app/context/auth/reducer.ts +68 -0
  34. package/app/context/auth/services.ts +394 -0
  35. package/app/context/auth/types.ts +99 -0
  36. package/app/context/auth/validation.ts +45 -0
  37. package/app/devtools/ReactotronClient.ts +9 -0
  38. package/app/devtools/ReactotronClient.web.ts +12 -0
  39. package/app/devtools/ReactotronConfig.ts +139 -0
  40. package/app/i18n/ar.ts +126 -0
  41. package/app/i18n/demo-ar.ts +464 -0
  42. package/app/i18n/demo-en.ts +462 -0
  43. package/app/i18n/demo-es.ts +469 -0
  44. package/app/i18n/demo-fr.ts +471 -0
  45. package/app/i18n/demo-hi.ts +468 -0
  46. package/app/i18n/demo-ja.ts +464 -0
  47. package/app/i18n/demo-ko.ts +457 -0
  48. package/app/i18n/en.ts +146 -0
  49. package/app/i18n/es.ts +132 -0
  50. package/app/i18n/fr.ts +132 -0
  51. package/app/i18n/hi.ts +131 -0
  52. package/app/i18n/index.ts +86 -0
  53. package/app/i18n/ja.ts +130 -0
  54. package/app/i18n/ko.ts +129 -0
  55. package/app/i18n/translate.ts +33 -0
  56. package/app/lib/Parse/index.ts +2 -0
  57. package/app/lib/Parse/parse.ts +62 -0
  58. package/app/navigators/AppNavigator.tsx +145 -0
  59. package/app/navigators/DemoNavigator.tsx +137 -0
  60. package/app/navigators/navigationUtilities.ts +208 -0
  61. package/app/screens/ChooseAuthScreen.tsx +224 -0
  62. package/app/screens/DemoCommunityScreen.tsx +141 -0
  63. package/app/screens/DemoDebugScreen.tsx +192 -0
  64. package/app/screens/DemoPodcastListScreen.tsx +387 -0
  65. package/app/screens/DemoShowroomScreen/DemoDivider.tsx +66 -0
  66. package/app/screens/DemoShowroomScreen/DemoShowroomScreen.tsx +313 -0
  67. package/app/screens/DemoShowroomScreen/DemoUseCase.tsx +52 -0
  68. package/app/screens/DemoShowroomScreen/DrawerIconButton.tsx +120 -0
  69. package/app/screens/DemoShowroomScreen/SectionListWithKeyboardAwareScrollView.tsx +59 -0
  70. package/app/screens/DemoShowroomScreen/demos/DemoAutoImage.tsx +230 -0
  71. package/app/screens/DemoShowroomScreen/demos/DemoButton.tsx +234 -0
  72. package/app/screens/DemoShowroomScreen/demos/DemoCard.tsx +181 -0
  73. package/app/screens/DemoShowroomScreen/demos/DemoEmptyState.tsx +78 -0
  74. package/app/screens/DemoShowroomScreen/demos/DemoHeader.tsx +151 -0
  75. package/app/screens/DemoShowroomScreen/demos/DemoIcon.tsx +115 -0
  76. package/app/screens/DemoShowroomScreen/demos/DemoListItem.tsx +218 -0
  77. package/app/screens/DemoShowroomScreen/demos/DemoText.tsx +144 -0
  78. package/app/screens/DemoShowroomScreen/demos/DemoTextField.tsx +233 -0
  79. package/app/screens/DemoShowroomScreen/demos/DemoToggle.tsx +354 -0
  80. package/app/screens/DemoShowroomScreen/demos/index.ts +12 -0
  81. package/app/screens/ErrorScreen/ErrorBoundary.tsx +76 -0
  82. package/app/screens/ErrorScreen/ErrorDetails.tsx +98 -0
  83. package/app/screens/ForgetPasswordScreen.tsx +180 -0
  84. package/app/screens/LoginScreen.tsx +260 -0
  85. package/app/screens/RegisterScreen.tsx +395 -0
  86. package/app/screens/WelcomeScreen.tsx +114 -0
  87. package/app/services/api/apiProblem.test.ts +73 -0
  88. package/app/services/api/apiProblem.ts +74 -0
  89. package/app/services/api/index.ts +91 -0
  90. package/app/services/api/types.ts +50 -0
  91. package/app/theme/colors.ts +85 -0
  92. package/app/theme/colorsDark.ts +50 -0
  93. package/app/theme/context.tsx +145 -0
  94. package/app/theme/context.utils.ts +25 -0
  95. package/app/theme/spacing.ts +14 -0
  96. package/app/theme/spacingDark.ts +14 -0
  97. package/app/theme/styles.ts +24 -0
  98. package/app/theme/theme.ts +23 -0
  99. package/app/theme/timing.ts +6 -0
  100. package/app/theme/types.ts +64 -0
  101. package/app/theme/typography.ts +71 -0
  102. package/app/utils/crashReporting.ts +62 -0
  103. package/app/utils/delay.ts +6 -0
  104. package/app/utils/formatDate.ts +49 -0
  105. package/app/utils/gestureHandler.native.ts +3 -0
  106. package/app/utils/gestureHandler.ts +6 -0
  107. package/app/utils/hasValidStringProp.ts +11 -0
  108. package/app/utils/openLinkInBrowser.ts +8 -0
  109. package/app/utils/storage/index.ts +82 -0
  110. package/app/utils/storage/storage.test.ts +61 -0
  111. package/app/utils/useHeader.tsx +37 -0
  112. package/app/utils/useIsMounted.ts +18 -0
  113. package/app/utils/useSafeAreaInsetsStyle.ts +46 -0
  114. package/app.config.ts +39 -0
  115. package/app.json +67 -0
  116. package/assets/icons/back.png +0 -0
  117. package/assets/icons/back@2x.png +0 -0
  118. package/assets/icons/back@3x.png +0 -0
  119. package/assets/icons/bell.png +0 -0
  120. package/assets/icons/bell@2x.png +0 -0
  121. package/assets/icons/bell@3x.png +0 -0
  122. package/assets/icons/caretLeft.png +0 -0
  123. package/assets/icons/caretLeft@2x.png +0 -0
  124. package/assets/icons/caretLeft@3x.png +0 -0
  125. package/assets/icons/caretRight.png +0 -0
  126. package/assets/icons/caretRight@2x.png +0 -0
  127. package/assets/icons/caretRight@3x.png +0 -0
  128. package/assets/icons/check.png +0 -0
  129. package/assets/icons/check@2x.png +0 -0
  130. package/assets/icons/check@3x.png +0 -0
  131. package/assets/icons/demo/clap.png +0 -0
  132. package/assets/icons/demo/clap@2x.png +0 -0
  133. package/assets/icons/demo/clap@3x.png +0 -0
  134. package/assets/icons/demo/community.png +0 -0
  135. package/assets/icons/demo/community@2x.png +0 -0
  136. package/assets/icons/demo/community@3x.png +0 -0
  137. package/assets/icons/demo/components.png +0 -0
  138. package/assets/icons/demo/components@2x.png +0 -0
  139. package/assets/icons/demo/components@3x.png +0 -0
  140. package/assets/icons/demo/debug.png +0 -0
  141. package/assets/icons/demo/debug@2x.png +0 -0
  142. package/assets/icons/demo/debug@3x.png +0 -0
  143. package/assets/icons/demo/github.png +0 -0
  144. package/assets/icons/demo/github@2x.png +0 -0
  145. package/assets/icons/demo/github@3x.png +0 -0
  146. package/assets/icons/demo/heart.png +0 -0
  147. package/assets/icons/demo/heart@2x.png +0 -0
  148. package/assets/icons/demo/heart@3x.png +0 -0
  149. package/assets/icons/demo/pin.png +0 -0
  150. package/assets/icons/demo/pin@2x.png +0 -0
  151. package/assets/icons/demo/pin@3x.png +0 -0
  152. package/assets/icons/demo/podcast.png +0 -0
  153. package/assets/icons/demo/podcast@2x.png +0 -0
  154. package/assets/icons/demo/podcast@3x.png +0 -0
  155. package/assets/icons/demo/slack.png +0 -0
  156. package/assets/icons/demo/slack@2x.png +0 -0
  157. package/assets/icons/demo/slack@3x.png +0 -0
  158. package/assets/icons/google.png +0 -0
  159. package/assets/icons/hidden.png +0 -0
  160. package/assets/icons/hidden@2x.png +0 -0
  161. package/assets/icons/hidden@3x.png +0 -0
  162. package/assets/icons/ladybug.png +0 -0
  163. package/assets/icons/ladybug@2x.png +0 -0
  164. package/assets/icons/ladybug@3x.png +0 -0
  165. package/assets/icons/lock.png +0 -0
  166. package/assets/icons/lock@2x.png +0 -0
  167. package/assets/icons/lock@3x.png +0 -0
  168. package/assets/icons/menu.png +0 -0
  169. package/assets/icons/menu@2x.png +0 -0
  170. package/assets/icons/menu@3x.png +0 -0
  171. package/assets/icons/more.png +0 -0
  172. package/assets/icons/more@2x.png +0 -0
  173. package/assets/icons/more@3x.png +0 -0
  174. package/assets/icons/settings.png +0 -0
  175. package/assets/icons/settings@2x.png +0 -0
  176. package/assets/icons/settings@3x.png +0 -0
  177. package/assets/icons/view.png +0 -0
  178. package/assets/icons/view@2x.png +0 -0
  179. package/assets/icons/view@3x.png +0 -0
  180. package/assets/icons/x.png +0 -0
  181. package/assets/icons/x@2x.png +0 -0
  182. package/assets/icons/x@3x.png +0 -0
  183. package/assets/images/app-icon-all.png +0 -0
  184. package/assets/images/app-icon-android-adaptive-background.png +0 -0
  185. package/assets/images/app-icon-android-adaptive-foreground.png +0 -0
  186. package/assets/images/app-icon-android-legacy.png +0 -0
  187. package/assets/images/app-icon-ios.png +0 -0
  188. package/assets/images/app-icon-web-favicon.png +0 -0
  189. package/assets/images/demo/cr-logo.png +0 -0
  190. package/assets/images/demo/cr-logo@2x.png +0 -0
  191. package/assets/images/demo/cr-logo@3x.png +0 -0
  192. package/assets/images/demo/rnl-logo.png +0 -0
  193. package/assets/images/demo/rnl-logo@2x.png +0 -0
  194. package/assets/images/demo/rnl-logo@3x.png +0 -0
  195. package/assets/images/demo/rnn-logo.png +0 -0
  196. package/assets/images/demo/rnn-logo@2x.png +0 -0
  197. package/assets/images/demo/rnn-logo@3x.png +0 -0
  198. package/assets/images/demo/rnr-image-1.png +0 -0
  199. package/assets/images/demo/rnr-image-1@2x.png +0 -0
  200. package/assets/images/demo/rnr-image-1@3x.png +0 -0
  201. package/assets/images/demo/rnr-image-2.png +0 -0
  202. package/assets/images/demo/rnr-image-2@2x.png +0 -0
  203. package/assets/images/demo/rnr-image-2@3x.png +0 -0
  204. package/assets/images/demo/rnr-image-3.png +0 -0
  205. package/assets/images/demo/rnr-image-3@2x.png +0 -0
  206. package/assets/images/demo/rnr-image-3@3x.png +0 -0
  207. package/assets/images/demo/rnr-logo.png +0 -0
  208. package/assets/images/demo/rnr-logo@2x.png +0 -0
  209. package/assets/images/demo/rnr-logo@3x.png +0 -0
  210. package/assets/images/logo.png +0 -0
  211. package/assets/images/logo@2x.png +0 -0
  212. package/assets/images/logo@3x.png +0 -0
  213. package/assets/images/sad-face.png +0 -0
  214. package/assets/images/sad-face@2x.png +0 -0
  215. package/assets/images/sad-face@3x.png +0 -0
  216. package/assets/images/welcome-face.png +0 -0
  217. package/assets/images/welcome-face@2x.png +0 -0
  218. package/assets/images/welcome-face@3x.png +0 -0
  219. package/babel.config.js +7 -0
  220. package/bin/cli.js +196 -0
  221. package/ignite/templates/app-icon/android-adaptive-background.png +0 -0
  222. package/ignite/templates/app-icon/android-adaptive-foreground.png +0 -0
  223. package/ignite/templates/app-icon/android-legacy.png +0 -0
  224. package/ignite/templates/app-icon/ios-universal.png +0 -0
  225. package/ignite/templates/component/NAME.tsx.ejs +39 -0
  226. package/ignite/templates/navigator/NAMENavigator.tsx.ejs +18 -0
  227. package/ignite/templates/screen/NAMEScreen.tsx.ejs +29 -0
  228. package/ignite/templates/splash-screen/logo.png +0 -0
  229. package/index.tsx +9 -0
  230. package/jest.config.js +5 -0
  231. package/metro.config.js +31 -0
  232. package/package.json +166 -0
  233. package/plugins/withSplashScreen.ts +69 -0
  234. package/src/app/_layout.tsx +58 -0
  235. package/src/app/index.tsx +5 -0
  236. package/test/i18n.test.ts +75 -0
  237. package/test/mockFile.ts +6 -0
  238. package/test/setup.ts +58 -0
  239. package/test/test-tsconfig.json +8 -0
  240. package/tsconfig.json +52 -0
  241. package/types/lib.es5.d.ts +25 -0
@@ -0,0 +1,264 @@
1
+ import { useEffect, useMemo, useRef, useCallback } from "react"
2
+ import { Animated, Image, ImageStyle, Platform, StyleProp, View, ViewStyle } from "react-native"
3
+
4
+ import { iconRegistry } from "@/components/Icon"
5
+ import { isRTL } from "@/i18n"
6
+ import type { ThemedStyle } from "@/theme/types"
7
+ import { useAppTheme } from "@/theme/context"
8
+ import { $styles } from "@/theme/styles"
9
+
10
+ import { $inputOuterBase, BaseToggleInputProps, Toggle, ToggleProps } from "./Toggle"
11
+
12
+ export interface SwitchToggleProps extends Omit<ToggleProps<SwitchInputProps>, "ToggleInput"> {
13
+ /**
14
+ * Switch-only prop that adds a text/icon label for on/off states.
15
+ */
16
+ accessibilityMode?: "text" | "icon"
17
+ /**
18
+ * Optional style prop that affects the knob View.
19
+ * Note: `width` and `height` rules should be points (numbers), not percentages.
20
+ */
21
+ inputDetailStyle?: Omit<ViewStyle, "width" | "height"> & { width?: number; height?: number }
22
+ }
23
+
24
+ interface SwitchInputProps extends BaseToggleInputProps<SwitchToggleProps> {
25
+ accessibilityMode?: SwitchToggleProps["accessibilityMode"]
26
+ }
27
+
28
+ /**
29
+ * @param {SwitchToggleProps} props - The props for the `Switch` component.
30
+ * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/Switch}
31
+ * @returns {JSX.Element} The rendered `Switch` component.
32
+ */
33
+ export function Switch(props: SwitchToggleProps) {
34
+ const { accessibilityMode, ...rest } = props
35
+ const switchInput = useCallback(
36
+ (toggleProps: SwitchInputProps) => (
37
+ <SwitchInput {...toggleProps} accessibilityMode={accessibilityMode} />
38
+ ),
39
+ [accessibilityMode],
40
+ )
41
+ return <Toggle accessibilityRole="switch" {...rest} ToggleInput={switchInput} />
42
+ }
43
+
44
+ function SwitchInput(props: SwitchInputProps) {
45
+ const {
46
+ on,
47
+ status,
48
+ disabled,
49
+ outerStyle: $outerStyleOverride,
50
+ innerStyle: $innerStyleOverride,
51
+ detailStyle: $detailStyleOverride,
52
+ } = props
53
+
54
+ const {
55
+ theme: { colors },
56
+ themed,
57
+ } = useAppTheme()
58
+
59
+ const animate = useRef(new Animated.Value(on ? 1 : 0)) // Initial value is set based on isActive
60
+ const opacity = useRef(new Animated.Value(0))
61
+
62
+ useEffect(() => {
63
+ Animated.timing(animate.current, {
64
+ toValue: on ? 1 : 0,
65
+ duration: 300,
66
+ useNativeDriver: true, // Enable native driver for smoother animations
67
+ }).start()
68
+ }, [on])
69
+
70
+ useEffect(() => {
71
+ Animated.timing(opacity.current, {
72
+ toValue: on ? 1 : 0,
73
+ duration: 300,
74
+ useNativeDriver: true,
75
+ }).start()
76
+ }, [on])
77
+
78
+ const knobSizeFallback = 2
79
+
80
+ const knobWidth = [$detailStyleOverride?.width, $switchDetail?.width, knobSizeFallback].find(
81
+ (v) => typeof v === "number",
82
+ )
83
+
84
+ const knobHeight = [$detailStyleOverride?.height, $switchDetail?.height, knobSizeFallback].find(
85
+ (v) => typeof v === "number",
86
+ )
87
+
88
+ const offBackgroundColor = [
89
+ disabled && colors.palette.neutral400,
90
+ status === "error" && colors.errorBackground,
91
+ colors.palette.neutral300,
92
+ ].filter(Boolean)[0]
93
+
94
+ const onBackgroundColor = [
95
+ disabled && colors.transparent,
96
+ status === "error" && colors.errorBackground,
97
+ colors.palette.secondary500,
98
+ ].filter(Boolean)[0]
99
+
100
+ const knobBackgroundColor = (function () {
101
+ if (on) {
102
+ return [
103
+ $detailStyleOverride?.backgroundColor,
104
+ status === "error" && colors.error,
105
+ disabled && colors.palette.neutral600,
106
+ colors.palette.neutral100,
107
+ ].filter(Boolean)[0]
108
+ } else {
109
+ return [
110
+ $innerStyleOverride?.backgroundColor,
111
+ disabled && colors.palette.neutral600,
112
+ status === "error" && colors.error,
113
+ colors.palette.neutral200,
114
+ ].filter(Boolean)[0]
115
+ }
116
+ })()
117
+
118
+ const rtlAdjustment = isRTL ? -1 : 1
119
+ const $themedSwitchInner = useMemo(() => themed([$styles.toggleInner, $switchInner]), [themed])
120
+
121
+ const offsetLeft = ($innerStyleOverride?.paddingStart ||
122
+ $innerStyleOverride?.paddingLeft ||
123
+ $themedSwitchInner?.paddingStart ||
124
+ $themedSwitchInner?.paddingLeft ||
125
+ 0) as number
126
+
127
+ const offsetRight = ($innerStyleOverride?.paddingEnd ||
128
+ $innerStyleOverride?.paddingRight ||
129
+ $themedSwitchInner?.paddingEnd ||
130
+ $themedSwitchInner?.paddingRight ||
131
+ 0) as number
132
+
133
+ const outputRange =
134
+ Platform.OS === "web"
135
+ ? isRTL
136
+ ? [+(knobWidth || 0) + offsetRight, offsetLeft]
137
+ : [offsetLeft, +(knobWidth || 0) + offsetRight]
138
+ : [rtlAdjustment * offsetLeft, rtlAdjustment * (+(knobWidth || 0) + offsetRight)]
139
+
140
+ const $animatedSwitchKnob = animate.current.interpolate({
141
+ inputRange: [0, 1],
142
+ outputRange,
143
+ })
144
+
145
+ return (
146
+ <View style={[$inputOuter, { backgroundColor: offBackgroundColor }, $outerStyleOverride]}>
147
+ <Animated.View
148
+ style={[
149
+ $themedSwitchInner,
150
+ { backgroundColor: onBackgroundColor },
151
+ $innerStyleOverride,
152
+ { opacity: opacity.current },
153
+ ]}
154
+ />
155
+
156
+ <SwitchAccessibilityLabel {...props} role="on" />
157
+ <SwitchAccessibilityLabel {...props} role="off" />
158
+
159
+ <Animated.View
160
+ style={[
161
+ $switchDetail,
162
+ $detailStyleOverride,
163
+ { transform: [{ translateX: $animatedSwitchKnob }] },
164
+ { width: knobWidth, height: knobHeight },
165
+ { backgroundColor: knobBackgroundColor },
166
+ ]}
167
+ />
168
+ </View>
169
+ )
170
+ }
171
+
172
+ /**
173
+ * @param {ToggleInputProps & { role: "on" | "off" }} props - The props for the `SwitchAccessibilityLabel` component.
174
+ * @returns {JSX.Element} The rendered `SwitchAccessibilityLabel` component.
175
+ */
176
+ function SwitchAccessibilityLabel(props: SwitchInputProps & { role: "on" | "off" }) {
177
+ const { on, disabled, status, accessibilityMode, role, innerStyle, detailStyle } = props
178
+
179
+ const {
180
+ theme: { colors },
181
+ } = useAppTheme()
182
+
183
+ if (!accessibilityMode) return null
184
+
185
+ const shouldLabelBeVisible = (on && role === "on") || (!on && role === "off")
186
+
187
+ const $switchAccessibilityStyle: StyleProp<ViewStyle> = [
188
+ $switchAccessibility,
189
+ role === "off" && { end: "5%" },
190
+ role === "on" && { left: "5%" },
191
+ ]
192
+
193
+ const color = (function () {
194
+ if (disabled) return colors.palette.neutral600
195
+ if (status === "error") return colors.error
196
+ if (!on) return innerStyle?.backgroundColor || colors.palette.secondary500
197
+ return detailStyle?.backgroundColor || colors.palette.neutral100
198
+ })()
199
+
200
+ return (
201
+ <View style={$switchAccessibilityStyle}>
202
+ {accessibilityMode === "text" && shouldLabelBeVisible && (
203
+ <View
204
+ style={[
205
+ role === "on" && $switchAccessibilityLine,
206
+ role === "on" && { backgroundColor: color },
207
+ role === "off" && $switchAccessibilityCircle,
208
+ role === "off" && { borderColor: color },
209
+ ]}
210
+ />
211
+ )}
212
+
213
+ {accessibilityMode === "icon" && shouldLabelBeVisible && (
214
+ <Image
215
+ style={[$switchAccessibilityIcon, { tintColor: color }]}
216
+ source={role === "off" ? iconRegistry.hidden : iconRegistry.view}
217
+ />
218
+ )}
219
+ </View>
220
+ )
221
+ }
222
+
223
+ const $inputOuter: StyleProp<ViewStyle> = [
224
+ $inputOuterBase,
225
+ { height: 32, width: 56, borderRadius: 16, borderWidth: 0 },
226
+ ]
227
+
228
+ const $switchInner: ThemedStyle<ViewStyle> = ({ colors }) => ({
229
+ borderColor: colors.transparent,
230
+ position: "absolute",
231
+ paddingStart: 4,
232
+ paddingEnd: 4,
233
+ })
234
+
235
+ const $switchDetail: SwitchToggleProps["inputDetailStyle"] = {
236
+ borderRadius: 12,
237
+ position: "absolute",
238
+ width: 24,
239
+ height: 24,
240
+ }
241
+
242
+ const $switchAccessibility: ViewStyle = {
243
+ width: "40%",
244
+ justifyContent: "center",
245
+ alignItems: "center",
246
+ }
247
+
248
+ const $switchAccessibilityIcon: ImageStyle = {
249
+ width: 14,
250
+ height: 14,
251
+ resizeMode: "contain",
252
+ }
253
+
254
+ const $switchAccessibilityLine: ViewStyle = {
255
+ width: 2,
256
+ height: 12,
257
+ }
258
+
259
+ const $switchAccessibilityCircle: ViewStyle = {
260
+ borderWidth: 2,
261
+ width: 12,
262
+ height: 12,
263
+ borderRadius: 6,
264
+ }
@@ -0,0 +1,285 @@
1
+ import { ComponentType, FC, useMemo } from "react"
2
+ import {
3
+ GestureResponderEvent,
4
+ ImageStyle,
5
+ StyleProp,
6
+ SwitchProps,
7
+ TextInputProps,
8
+ TextStyle,
9
+ TouchableOpacity,
10
+ TouchableOpacityProps,
11
+ View,
12
+ ViewProps,
13
+ ViewStyle,
14
+ } from "react-native"
15
+
16
+ import type { ThemedStyle } from "@/theme/types"
17
+ import { useAppTheme } from "@/theme/context"
18
+ import { $styles } from "@/theme/styles"
19
+
20
+ import { Text, TextProps } from "../Text"
21
+
22
+ export interface ToggleProps<T> extends Omit<TouchableOpacityProps, "style"> {
23
+ /**
24
+ * A style modifier for different input states.
25
+ */
26
+ status?: "error" | "disabled"
27
+ /**
28
+ * If false, input is not editable. The default value is true.
29
+ */
30
+ editable?: TextInputProps["editable"]
31
+ /**
32
+ * The value of the field. If true the component will be turned on.
33
+ */
34
+ value?: boolean
35
+ /**
36
+ * Invoked with the new value when the value changes.
37
+ */
38
+ onValueChange?: SwitchProps["onValueChange"]
39
+ /**
40
+ * Style overrides for the container
41
+ */
42
+ containerStyle?: StyleProp<ViewStyle>
43
+ /**
44
+ * Style overrides for the input wrapper
45
+ */
46
+ inputWrapperStyle?: StyleProp<ViewStyle>
47
+ /**
48
+ * Optional input wrapper style override.
49
+ * This gives the inputs their size, shape, "off" background-color, and outer border.
50
+ */
51
+ inputOuterStyle?: ViewStyle
52
+ /**
53
+ * Optional input style override.
54
+ * This gives the inputs their inner characteristics and "on" background-color.
55
+ */
56
+ inputInnerStyle?: ViewStyle
57
+ /**
58
+ * Optional detail style override.
59
+ * See Checkbox, Radio, and Switch for more details
60
+ */
61
+ inputDetailStyle?: ViewStyle
62
+ /**
63
+ * The position of the label relative to the action component.
64
+ * Default: right
65
+ */
66
+ labelPosition?: "left" | "right"
67
+ /**
68
+ * The label text to display if not using `labelTx`.
69
+ */
70
+ label?: TextProps["text"]
71
+ /**
72
+ * Label text which is looked up via i18n.
73
+ */
74
+ labelTx?: TextProps["tx"]
75
+ /**
76
+ * Optional label options to pass to i18n. Useful for interpolation
77
+ * as well as explicitly setting locale or translation fallbacks.
78
+ */
79
+ labelTxOptions?: TextProps["txOptions"]
80
+ /**
81
+ * Style overrides for label text.
82
+ */
83
+ labelStyle?: StyleProp<TextStyle>
84
+ /**
85
+ * Pass any additional props directly to the label Text component.
86
+ */
87
+ LabelTextProps?: TextProps
88
+ /**
89
+ * The helper text to display if not using `helperTx`.
90
+ */
91
+ helper?: TextProps["text"]
92
+ /**
93
+ * Helper text which is looked up via i18n.
94
+ */
95
+ helperTx?: TextProps["tx"]
96
+ /**
97
+ * Optional helper options to pass to i18n. Useful for interpolation
98
+ * as well as explicitly setting locale or translation fallbacks.
99
+ */
100
+ helperTxOptions?: TextProps["txOptions"]
101
+ /**
102
+ * Pass any additional props directly to the helper Text component.
103
+ */
104
+ HelperTextProps?: TextProps
105
+ /**
106
+ * The input control for the type of toggle component
107
+ */
108
+ ToggleInput: FC<BaseToggleInputProps<T>>
109
+ }
110
+
111
+ export interface BaseToggleInputProps<T> {
112
+ on: boolean
113
+ status: ToggleProps<T>["status"]
114
+ disabled: boolean
115
+ outerStyle: ViewStyle
116
+ innerStyle: ViewStyle
117
+ detailStyle: ViewStyle | ImageStyle
118
+ }
119
+
120
+ /**
121
+ * Renders a boolean input.
122
+ * This is a controlled component that requires an onValueChange callback that updates the value prop in order for the component to reflect user actions. If the value prop is not updated, the component will continue to render the supplied value prop instead of the expected result of any user actions.
123
+ * @param {ToggleProps} props - The props for the `Toggle` component.
124
+ * @returns {JSX.Element} The rendered `Toggle` component.
125
+ */
126
+ export function Toggle<T>(props: ToggleProps<T>) {
127
+ const {
128
+ editable = true,
129
+ status,
130
+ value,
131
+ onPress,
132
+ onValueChange,
133
+ labelPosition = "right",
134
+ helper,
135
+ helperTx,
136
+ helperTxOptions,
137
+ HelperTextProps,
138
+ containerStyle: $containerStyleOverride,
139
+ inputWrapperStyle: $inputWrapperStyleOverride,
140
+ ToggleInput,
141
+ accessibilityRole,
142
+ ...WrapperProps
143
+ } = props
144
+
145
+ const {
146
+ theme: { colors },
147
+ themed,
148
+ } = useAppTheme()
149
+
150
+ const disabled = editable === false || status === "disabled" || props.disabled
151
+
152
+ const Wrapper = useMemo(
153
+ () => (disabled ? View : TouchableOpacity) as ComponentType<TouchableOpacityProps | ViewProps>,
154
+ [disabled],
155
+ )
156
+
157
+ const $containerStyles = [$containerStyleOverride]
158
+ const $inputWrapperStyles = [$styles.row, $inputWrapper, $inputWrapperStyleOverride]
159
+ const $helperStyles = themed([
160
+ $helper,
161
+ status === "error" && { color: colors.error },
162
+ HelperTextProps?.style,
163
+ ])
164
+
165
+ /**
166
+ * @param {GestureResponderEvent} e - The event object.
167
+ */
168
+ function handlePress(e: GestureResponderEvent) {
169
+ if (disabled) return
170
+ onValueChange?.(!value)
171
+ onPress?.(e)
172
+ }
173
+
174
+ return (
175
+ <Wrapper
176
+ activeOpacity={1}
177
+ accessibilityRole={accessibilityRole}
178
+ accessibilityState={{ checked: value, disabled }}
179
+ {...WrapperProps}
180
+ style={$containerStyles}
181
+ onPress={handlePress}
182
+ >
183
+ <View style={$inputWrapperStyles}>
184
+ {labelPosition === "left" && <FieldLabel<T> {...props} labelPosition={labelPosition} />}
185
+
186
+ <ToggleInput
187
+ on={!!value}
188
+ disabled={!!disabled}
189
+ status={status}
190
+ outerStyle={props.inputOuterStyle ?? {}}
191
+ innerStyle={props.inputInnerStyle ?? {}}
192
+ detailStyle={props.inputDetailStyle ?? {}}
193
+ />
194
+
195
+ {labelPosition === "right" && <FieldLabel<T> {...props} labelPosition={labelPosition} />}
196
+ </View>
197
+
198
+ {!!(helper || helperTx) && (
199
+ <Text
200
+ preset="formHelper"
201
+ text={helper}
202
+ tx={helperTx}
203
+ txOptions={helperTxOptions}
204
+ {...HelperTextProps}
205
+ style={$helperStyles}
206
+ />
207
+ )}
208
+ </Wrapper>
209
+ )
210
+ }
211
+
212
+ /**
213
+ * @param {ToggleProps} props - The props for the `FieldLabel` component.
214
+ * @returns {JSX.Element} The rendered `FieldLabel` component.
215
+ */
216
+ function FieldLabel<T>(props: ToggleProps<T>) {
217
+ const {
218
+ status,
219
+ label,
220
+ labelTx,
221
+ labelTxOptions,
222
+ LabelTextProps,
223
+ labelPosition,
224
+ labelStyle: $labelStyleOverride,
225
+ } = props
226
+
227
+ const {
228
+ theme: { colors },
229
+ themed,
230
+ } = useAppTheme()
231
+
232
+ if (!label && !labelTx && !LabelTextProps?.children) return null
233
+
234
+ const $labelStyle = themed([
235
+ $label,
236
+ status === "error" && { color: colors.error },
237
+ labelPosition === "right" && $labelRight,
238
+ labelPosition === "left" && $labelLeft,
239
+ $labelStyleOverride,
240
+ LabelTextProps?.style,
241
+ ])
242
+
243
+ return (
244
+ <Text
245
+ preset="formLabel"
246
+ text={label}
247
+ tx={labelTx}
248
+ txOptions={labelTxOptions}
249
+ {...LabelTextProps}
250
+ style={$labelStyle}
251
+ />
252
+ )
253
+ }
254
+
255
+ const $inputWrapper: ViewStyle = {
256
+ alignItems: "center",
257
+ }
258
+
259
+ export const $inputOuterBase: ViewStyle = {
260
+ height: 24,
261
+ width: 24,
262
+ borderWidth: 2,
263
+ alignItems: "center",
264
+ overflow: "hidden",
265
+ flexGrow: 0,
266
+ flexShrink: 0,
267
+ justifyContent: "space-between",
268
+ flexDirection: "row",
269
+ }
270
+
271
+ const $helper: ThemedStyle<TextStyle> = ({ spacing }) => ({
272
+ marginTop: spacing.xs,
273
+ })
274
+
275
+ const $label: TextStyle = {
276
+ flex: 1,
277
+ }
278
+
279
+ const $labelRight: ThemedStyle<TextStyle> = ({ spacing }) => ({
280
+ marginStart: spacing.md,
281
+ })
282
+
283
+ const $labelLeft: ThemedStyle<TextStyle> = ({ spacing }) => ({
284
+ marginEnd: spacing.md,
285
+ })
@@ -0,0 +1,15 @@
1
+ export * from "./AutoImage"
2
+ export * from "./Button"
3
+ export * from "./Card"
4
+ export * from "./Header"
5
+ export * from "./Icon"
6
+ export * from "./ListItem"
7
+ export * from "./ListView"
8
+ export * from "./Screen"
9
+ export * from "./Text"
10
+ export * from "./TextField"
11
+ export * from "./Toggle"
12
+ export * from "./EmptyState"
13
+ export * from "./Calendar"
14
+ export * from "./TaskModal"
15
+ export * from "./AlertTongle"
@@ -0,0 +1,18 @@
1
+ export * from "./Button"
2
+ export * from "./Icon"
3
+ export * from "./Screen"
4
+ export * from "./Text"
5
+ export * from "./AutoImage"
6
+ export * from "./Button"
7
+ export * from "./Card"
8
+ export * from "./Header"
9
+ export * from "./Icon"
10
+ export * from "./ListItem"
11
+ export * from "./ListView"
12
+ export * from "./Screen"
13
+ export * from "./Text"
14
+ export * from "./TextField"
15
+
16
+ export * from "./EmptyState"
17
+
18
+ export * from "./AlertTongle"
@@ -0,0 +1,26 @@
1
+ export interface ConfigBaseProps {
2
+ persistNavigation: "always" | "dev" | "prod" | "never"
3
+ catchErrors: "always" | "dev" | "prod" | "never"
4
+ exitRoutes: string[]
5
+ }
6
+
7
+ export type PersistNavigationConfig = ConfigBaseProps["persistNavigation"]
8
+
9
+ const BaseConfig: ConfigBaseProps = {
10
+ // This feature is particularly useful in development mode, but
11
+ // can be used in production as well if you prefer.
12
+ persistNavigation: "dev",
13
+
14
+ /**
15
+ * Only enable if we're catching errors in the right environment
16
+ */
17
+ catchErrors: "always",
18
+
19
+ /**
20
+ * This is a list of all the route names that will exit the app if the back button
21
+ * is pressed while in that screen. Only affects Android.
22
+ */
23
+ exitRoutes: ["Welcome"],
24
+ }
25
+
26
+ export default BaseConfig
@@ -0,0 +1,10 @@
1
+ /**
2
+ * These are configuration settings for the dev environment.
3
+ *
4
+ * Do not include API secrets in this file or anywhere in your JS.
5
+ *
6
+ * https://reactnative.dev/docs/security#storing-sensitive-info
7
+ */
8
+ export default {
9
+ API_URL: "https://api.rss2json.com/v1/",
10
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * These are configuration settings for the production environment.
3
+ *
4
+ * Do not include API secrets in this file or anywhere in your JS.
5
+ *
6
+ * https://reactnative.dev/docs/security#storing-sensitive-info
7
+ */
8
+ export default {
9
+ API_URL: "https://api.rss2json.com/v1/",
10
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * This file imports configuration objects from either the config.dev.js file
3
+ * or the config.prod.js file depending on whether we are in __DEV__ or not.
4
+ *
5
+ * Note that we do not gitignore these files. Unlike on web servers, just because
6
+ * these are not checked into your repo doesn't mean that they are secure.
7
+ * In fact, you're shipping a JavaScript bundle with every
8
+ * config variable in plain text. Anyone who downloads your app can easily
9
+ * extract them.
10
+ *
11
+ * If you doubt this, just bundle your app, and then go look at the bundle and
12
+ * search it for one of your config variable values. You'll find it there.
13
+ *
14
+ * Read more here: https://reactnative.dev/docs/security#storing-sensitive-info
15
+ */
16
+ import BaseConfig from "./config.base"
17
+ import DevConfig from "./config.dev"
18
+ import ProdConfig from "./config.prod"
19
+
20
+ let ExtraConfig = ProdConfig
21
+
22
+ if (__DEV__) {
23
+ ExtraConfig = DevConfig
24
+ }
25
+
26
+ const Config = { ...BaseConfig, ...ExtraConfig }
27
+
28
+ export default Config
@@ -0,0 +1,14 @@
1
+ /**
2
+ * AuthContext - Legacy re-export
3
+ * This file maintains backward compatibility by re-exporting from the new modular structure.
4
+ * All authentication logic has been refactored into dedicated modules in the ./auth folder:
5
+ * - types.ts: Type definitions
6
+ * - validation.ts: Validation utilities
7
+ * - services.ts: Parse API calls and auth operations
8
+ * - reducer.ts: State management reducer
9
+ * - AuthProvider.tsx: Provider component
10
+ * - hooks.ts: Custom hooks
11
+ * - index.ts: Main export point
12
+ */
13
+
14
+ export * from "./auth";