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,42 @@
1
+ import { ForwardedRef, forwardRef, PropsWithoutRef, ReactElement, RefObject } from "react"
2
+ import { FlatList } from "react-native"
3
+ import { FlashList, FlashListProps } from "@shopify/flash-list"
4
+
5
+ import { isRTL } from "@/i18n"
6
+
7
+ export type ListViewRef<T> = FlashList<T> | FlatList<T>
8
+
9
+ export type ListViewProps<T> = PropsWithoutRef<FlashListProps<T>>
10
+
11
+ /**
12
+ * This is a Higher Order Component meant to ease the pain of using @shopify/flash-list
13
+ * when there is a chance that a user would have their device language set to an
14
+ * RTL language like Arabic or Persian. This component will use react-native's
15
+ * FlatList if the user's language is RTL or FlashList if the user's language is LTR.
16
+ *
17
+ * Because FlashList's props are a superset of FlatList's, you must pass estimatedItemSize
18
+ * to this component if you want to use it.
19
+ *
20
+ * This is a temporary workaround until the FlashList component supports RTL at
21
+ * which point this component can be removed and we will default to using FlashList everywhere.
22
+ * @see {@link https://github.com/Shopify/flash-list/issues/544|RTL Bug Android}
23
+ * @see {@link https://github.com/Shopify/flash-list/issues/840|Flashlist Not Support RTL}
24
+ * @param {FlashListProps | FlatListProps} props - The props for the `ListView` component.
25
+ * @param {RefObject<ListViewRef>} forwardRef - An optional forwarded ref.
26
+ * @returns {JSX.Element} The rendered `ListView` component.
27
+ */
28
+ const ListViewComponent = forwardRef(
29
+ <T,>(props: ListViewProps<T>, ref: ForwardedRef<ListViewRef<T>>) => {
30
+ const ListComponentWrapper = isRTL ? FlatList : FlashList
31
+
32
+ return <ListComponentWrapper {...props} ref={ref} />
33
+ },
34
+ )
35
+
36
+ ListViewComponent.displayName = "ListView"
37
+
38
+ export const ListView = ListViewComponent as <T>(
39
+ props: ListViewProps<T> & {
40
+ ref?: RefObject<ListViewRef<T> | null>
41
+ },
42
+ ) => ReactElement
@@ -0,0 +1,305 @@
1
+ import { ReactNode, useRef, useState } from "react"
2
+ import {
3
+ KeyboardAvoidingView,
4
+ KeyboardAvoidingViewProps,
5
+ LayoutChangeEvent,
6
+ Platform,
7
+ ScrollView,
8
+ ScrollViewProps,
9
+ StyleProp,
10
+ View,
11
+ ViewStyle,
12
+ } from "react-native"
13
+ import { useScrollToTop } from "@react-navigation/native"
14
+ import { SystemBars, SystemBarsProps, SystemBarStyle } from "react-native-edge-to-edge"
15
+ import { KeyboardAwareScrollView } from "react-native-keyboard-controller"
16
+
17
+ import { useAppTheme } from "@/theme/context"
18
+ import { $styles } from "@/theme/styles"
19
+ import { ExtendedEdge, useSafeAreaInsetsStyle } from "@/utils/useSafeAreaInsetsStyle"
20
+
21
+ export const DEFAULT_BOTTOM_OFFSET = 50
22
+
23
+ interface BaseScreenProps {
24
+ /**
25
+ * Children components.
26
+ */
27
+ children?: ReactNode
28
+ /**
29
+ * Style for the outer content container useful for padding & margin.
30
+ */
31
+ style?: StyleProp<ViewStyle>
32
+ /**
33
+ * Style for the inner content container useful for padding & margin.
34
+ */
35
+ contentContainerStyle?: StyleProp<ViewStyle>
36
+ /**
37
+ * Override the default edges for the safe area.
38
+ */
39
+ safeAreaEdges?: ExtendedEdge[]
40
+ /**
41
+ * Background color
42
+ */
43
+ backgroundColor?: string
44
+ /**
45
+ * System bar setting. Defaults to dark.
46
+ */
47
+ systemBarStyle?: SystemBarStyle
48
+ /**
49
+ * By how much should we offset the keyboard? Defaults to 0.
50
+ */
51
+ keyboardOffset?: number
52
+ /**
53
+ * By how much we scroll up when the keyboard is shown. Defaults to 50.
54
+ */
55
+ keyboardBottomOffset?: number
56
+ /**
57
+ * Pass any additional props directly to the SystemBars component.
58
+ */
59
+ SystemBarsProps?: SystemBarsProps
60
+ /**
61
+ * Pass any additional props directly to the KeyboardAvoidingView component.
62
+ */
63
+ KeyboardAvoidingViewProps?: KeyboardAvoidingViewProps
64
+ }
65
+
66
+ interface FixedScreenProps extends BaseScreenProps {
67
+ preset?: "fixed"
68
+ }
69
+ interface ScrollScreenProps extends BaseScreenProps {
70
+ preset?: "scroll"
71
+ /**
72
+ * Should keyboard persist on screen tap. Defaults to handled.
73
+ * Only applies to scroll preset.
74
+ */
75
+ keyboardShouldPersistTaps?: "handled" | "always" | "never"
76
+ /**
77
+ * Pass any additional props directly to the ScrollView component.
78
+ */
79
+ ScrollViewProps?: ScrollViewProps
80
+ }
81
+
82
+ interface AutoScreenProps extends Omit<ScrollScreenProps, "preset"> {
83
+ preset?: "auto"
84
+ /**
85
+ * Threshold to trigger the automatic disabling/enabling of scroll ability.
86
+ * Defaults to `{ percent: 0.92 }`.
87
+ */
88
+ scrollEnabledToggleThreshold?: { percent?: number; point?: number }
89
+ }
90
+
91
+ export type ScreenProps = ScrollScreenProps | FixedScreenProps | AutoScreenProps
92
+
93
+ const isIos = Platform.OS === "ios"
94
+
95
+ type ScreenPreset = "fixed" | "scroll" | "auto"
96
+
97
+ /**
98
+ * @param {ScreenPreset?} preset - The preset to check.
99
+ * @returns {boolean} - Whether the preset is non-scrolling.
100
+ */
101
+ function isNonScrolling(preset?: ScreenPreset) {
102
+ return !preset || preset === "fixed"
103
+ }
104
+
105
+ /**
106
+ * Custom hook that handles the automatic enabling/disabling of scroll ability based on the content size and screen size.
107
+ * @param {UseAutoPresetProps} props - The props for the `useAutoPreset` hook.
108
+ * @returns {{boolean, Function, Function}} - The scroll state, and the `onContentSizeChange` and `onLayout` functions.
109
+ */
110
+ function useAutoPreset(props: AutoScreenProps): {
111
+ scrollEnabled: boolean
112
+ onContentSizeChange: (w: number, h: number) => void
113
+ onLayout: (e: LayoutChangeEvent) => void
114
+ } {
115
+ const { preset, scrollEnabledToggleThreshold } = props
116
+ const { percent = 0.92, point = 0 } = scrollEnabledToggleThreshold || {}
117
+
118
+ const scrollViewHeight = useRef<null | number>(null)
119
+ const scrollViewContentHeight = useRef<null | number>(null)
120
+ const [scrollEnabled, setScrollEnabled] = useState(true)
121
+
122
+ function updateScrollState() {
123
+ if (scrollViewHeight.current === null || scrollViewContentHeight.current === null) return
124
+
125
+ // check whether content fits the screen then toggle scroll state according to it
126
+ const contentFitsScreen = (function () {
127
+ if (point) {
128
+ return scrollViewContentHeight.current < scrollViewHeight.current - point
129
+ } else {
130
+ return scrollViewContentHeight.current < scrollViewHeight.current * percent
131
+ }
132
+ })()
133
+
134
+ // content is less than the size of the screen, so we can disable scrolling
135
+ if (scrollEnabled && contentFitsScreen) setScrollEnabled(false)
136
+
137
+ // content is greater than the size of the screen, so let's enable scrolling
138
+ if (!scrollEnabled && !contentFitsScreen) setScrollEnabled(true)
139
+ }
140
+
141
+ /**
142
+ * @param {number} w - The width of the content.
143
+ * @param {number} h - The height of the content.
144
+ */
145
+ function onContentSizeChange(w: number, h: number) {
146
+ // update scroll-view content height
147
+ scrollViewContentHeight.current = h
148
+ updateScrollState()
149
+ }
150
+
151
+ /**
152
+ * @param {LayoutChangeEvent} e = The layout change event.
153
+ */
154
+ function onLayout(e: LayoutChangeEvent) {
155
+ const { height } = e.nativeEvent.layout
156
+ // update scroll-view height
157
+ scrollViewHeight.current = height
158
+ updateScrollState()
159
+ }
160
+
161
+ // update scroll state on every render
162
+ if (preset === "auto") updateScrollState()
163
+
164
+ return {
165
+ scrollEnabled: preset === "auto" ? scrollEnabled : true,
166
+ onContentSizeChange,
167
+ onLayout,
168
+ }
169
+ }
170
+
171
+ /**
172
+ * @param {ScreenProps} props - The props for the `ScreenWithoutScrolling` component.
173
+ * @returns {JSX.Element} - The rendered `ScreenWithoutScrolling` component.
174
+ */
175
+ function ScreenWithoutScrolling(props: ScreenProps) {
176
+ const { style, contentContainerStyle, children, preset } = props
177
+ return (
178
+ <View style={[$outerStyle, style]}>
179
+ <View style={[$innerStyle, preset === "fixed" && $justifyFlexEnd, contentContainerStyle]}>
180
+ {children}
181
+ </View>
182
+ </View>
183
+ )
184
+ }
185
+
186
+ /**
187
+ * @param {ScreenProps} props - The props for the `ScreenWithScrolling` component.
188
+ * @returns {JSX.Element} - The rendered `ScreenWithScrolling` component.
189
+ */
190
+ function ScreenWithScrolling(props: ScreenProps) {
191
+ const {
192
+ children,
193
+ keyboardShouldPersistTaps = "handled",
194
+ keyboardBottomOffset = DEFAULT_BOTTOM_OFFSET,
195
+ contentContainerStyle,
196
+ ScrollViewProps,
197
+ style,
198
+ } = props as ScrollScreenProps
199
+
200
+ const ref = useRef<ScrollView>(null)
201
+
202
+ const { scrollEnabled, onContentSizeChange, onLayout } = useAutoPreset(props as AutoScreenProps)
203
+
204
+ // Add native behavior of pressing the active tab to scroll to the top of the content
205
+ // More info at: https://reactnavigation.org/docs/use-scroll-to-top/
206
+ useScrollToTop(ref)
207
+
208
+ return (
209
+ <KeyboardAwareScrollView
210
+ bottomOffset={keyboardBottomOffset}
211
+ {...{ keyboardShouldPersistTaps, scrollEnabled, ref }}
212
+ {...ScrollViewProps}
213
+ onLayout={(e) => {
214
+ onLayout(e)
215
+ ScrollViewProps?.onLayout?.(e)
216
+ }}
217
+ onContentSizeChange={(w: number, h: number) => {
218
+ onContentSizeChange(w, h)
219
+ ScrollViewProps?.onContentSizeChange?.(w, h)
220
+ }}
221
+ style={[$outerStyle, ScrollViewProps?.style, style]}
222
+ contentContainerStyle={[
223
+ $innerStyle,
224
+ ScrollViewProps?.contentContainerStyle,
225
+ contentContainerStyle,
226
+ ]}
227
+ >
228
+ {children}
229
+ </KeyboardAwareScrollView>
230
+ )
231
+ }
232
+
233
+ /**
234
+ * Represents a screen component that provides a consistent layout and behavior for different screen presets.
235
+ * The `Screen` component can be used with different presets such as "fixed", "scroll", or "auto".
236
+ * It handles safe area insets, status bar settings, keyboard avoiding behavior, and scrollability based on the preset.
237
+ * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/Screen/}
238
+ * @param {ScreenProps} props - The props for the `Screen` component.
239
+ * @returns {JSX.Element} The rendered `Screen` component.
240
+ */
241
+ export function Screen(props: ScreenProps) {
242
+ const {
243
+ theme: { colors },
244
+ themeContext,
245
+ } = useAppTheme()
246
+ const {
247
+ backgroundColor,
248
+ KeyboardAvoidingViewProps,
249
+ keyboardOffset = 0,
250
+ safeAreaEdges,
251
+ SystemBarsProps,
252
+ systemBarStyle,
253
+ } = props
254
+
255
+ const $containerInsets = useSafeAreaInsetsStyle(safeAreaEdges)
256
+
257
+ return (
258
+ <View
259
+ style={[
260
+ $containerStyle,
261
+ { backgroundColor: backgroundColor || colors.background },
262
+ $containerInsets,
263
+ ]}
264
+ >
265
+ <SystemBars
266
+ style={systemBarStyle || (themeContext === "dark" ? "light" : "dark")}
267
+ {...SystemBarsProps}
268
+ />
269
+
270
+ <KeyboardAvoidingView
271
+ behavior={isIos ? "padding" : "height"}
272
+ keyboardVerticalOffset={keyboardOffset}
273
+ {...KeyboardAvoidingViewProps}
274
+ style={[$styles.flex1, KeyboardAvoidingViewProps?.style]}
275
+ >
276
+ {isNonScrolling(props.preset) ? (
277
+ <ScreenWithoutScrolling {...props} />
278
+ ) : (
279
+ <ScreenWithScrolling {...props} />
280
+ )}
281
+ </KeyboardAvoidingView>
282
+ </View>
283
+ )
284
+ }
285
+
286
+ const $containerStyle: ViewStyle = {
287
+ flex: 1,
288
+ height: "100%",
289
+ width: "100%",
290
+ }
291
+
292
+ const $outerStyle: ViewStyle = {
293
+ flex: 1,
294
+ height: "100%",
295
+ width: "100%",
296
+ }
297
+
298
+ const $justifyFlexEnd: ViewStyle = {
299
+ justifyContent: "flex-end",
300
+ }
301
+
302
+ const $innerStyle: ViewStyle = {
303
+ justifyContent: "flex-start",
304
+ alignItems: "stretch",
305
+ }
@@ -0,0 +1,23 @@
1
+ import { NavigationContainer } from "@react-navigation/native"
2
+ import { render } from "@testing-library/react-native"
3
+
4
+ import { Text } from "./Text"
5
+ import { ThemeProvider } from "../theme/context"
6
+
7
+ /* This is an example component test using react-native-testing-library. For more
8
+ * information on how to write your own, see the documentation here:
9
+ * https://callstack.github.io/react-native-testing-library/ */
10
+ const testText = "Test string"
11
+
12
+ describe("Text", () => {
13
+ it("should render the component", () => {
14
+ const { getByText } = render(
15
+ <ThemeProvider>
16
+ <NavigationContainer>
17
+ <Text text={testText} />
18
+ </NavigationContainer>
19
+ </ThemeProvider>,
20
+ )
21
+ expect(getByText(testText)).toBeDefined()
22
+ })
23
+ })
@@ -0,0 +1,116 @@
1
+ import { ReactNode, forwardRef, ForwardedRef } from "react"
2
+ // eslint-disable-next-line no-restricted-imports
3
+ import { StyleProp, Text as RNText, TextProps as RNTextProps, TextStyle } from "react-native"
4
+ import { TOptions } from "i18next"
5
+
6
+ import { isRTL, TxKeyPath } from "@/i18n"
7
+ import { translate } from "@/i18n/translate"
8
+ import type { ThemedStyle, ThemedStyleArray } from "@/theme/types"
9
+ import { useAppTheme } from "@/theme/context"
10
+ import { typography } from "@/theme/typography"
11
+
12
+ type Sizes = keyof typeof $sizeStyles
13
+ type Weights = keyof typeof typography.primary
14
+ type Presets = "default" | "bold" | "heading" | "subheading" | "formLabel" | "formHelper"
15
+
16
+ export interface TextProps extends RNTextProps {
17
+ /**
18
+ * Text which is looked up via i18n.
19
+ */
20
+ tx?: TxKeyPath
21
+ /**
22
+ * The text to display if not using `tx` or nested components.
23
+ */
24
+ text?: string
25
+ /**
26
+ * Optional options to pass to i18n. Useful for interpolation
27
+ * as well as explicitly setting locale or translation fallbacks.
28
+ */
29
+ txOptions?: TOptions
30
+ /**
31
+ * An optional style override useful for padding & margin.
32
+ */
33
+ style?: StyleProp<TextStyle>
34
+ /**
35
+ * One of the different types of text presets.
36
+ */
37
+ preset?: Presets
38
+ /**
39
+ * Text weight modifier.
40
+ */
41
+ weight?: Weights
42
+ /**
43
+ * Text size modifier.
44
+ */
45
+ size?: Sizes
46
+ /**
47
+ * Children components.
48
+ */
49
+ children?: ReactNode
50
+ }
51
+
52
+ /**
53
+ * For your text displaying needs.
54
+ * This component is a HOC over the built-in React Native one.
55
+ * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/Text/}
56
+ * @param {TextProps} props - The props for the `Text` component.
57
+ * @returns {JSX.Element} The rendered `Text` component.
58
+ */
59
+ export const Text = forwardRef(function Text(props: TextProps, ref: ForwardedRef<RNText>) {
60
+ const { weight, size, tx, txOptions, text, children, style: $styleOverride, ...rest } = props
61
+ const { themed } = useAppTheme()
62
+
63
+ const i18nText = tx && translate(tx, txOptions)
64
+ const content = i18nText || text || children
65
+
66
+ const preset: Presets = props.preset ?? "default"
67
+ const $styles: StyleProp<TextStyle> = [
68
+ $rtlStyle,
69
+ themed($presets[preset]),
70
+ weight && $fontWeightStyles[weight],
71
+ size && $sizeStyles[size],
72
+ $styleOverride,
73
+ ]
74
+
75
+ return (
76
+ <RNText {...rest} style={$styles} ref={ref}>
77
+ {content}
78
+ </RNText>
79
+ )
80
+ })
81
+
82
+ const $sizeStyles = {
83
+ xxl: { fontSize: 36, lineHeight: 44 } satisfies TextStyle,
84
+ xl: { fontSize: 24, lineHeight: 34 } satisfies TextStyle,
85
+ lg: { fontSize: 20, lineHeight: 32 } satisfies TextStyle,
86
+ md: { fontSize: 18, lineHeight: 26 } satisfies TextStyle,
87
+ sm: { fontSize: 16, lineHeight: 24 } satisfies TextStyle,
88
+ xs: { fontSize: 14, lineHeight: 21 } satisfies TextStyle,
89
+ xxs: { fontSize: 12, lineHeight: 18 } satisfies TextStyle,
90
+ }
91
+
92
+ const $fontWeightStyles = Object.entries(typography.primary).reduce((acc, [weight, fontFamily]) => {
93
+ return { ...acc, [weight]: { fontFamily } }
94
+ }, {}) as Record<Weights, TextStyle>
95
+
96
+ const $baseStyle: ThemedStyle<TextStyle> = (theme) => ({
97
+ ...$sizeStyles.sm,
98
+ ...$fontWeightStyles.normal,
99
+ color: theme.colors.text,
100
+ })
101
+
102
+ const $presets: Record<Presets, ThemedStyleArray<TextStyle>> = {
103
+ default: [$baseStyle],
104
+ bold: [$baseStyle, { ...$fontWeightStyles.bold }],
105
+ heading: [
106
+ $baseStyle,
107
+ {
108
+ ...$sizeStyles.xxl,
109
+ ...$fontWeightStyles.bold,
110
+ },
111
+ ],
112
+ subheading: [$baseStyle, { ...$sizeStyles.lg, ...$fontWeightStyles.medium }],
113
+ formLabel: [$baseStyle, { ...$fontWeightStyles.medium }],
114
+ formHelper: [$baseStyle, { ...$sizeStyles.sm, ...$fontWeightStyles.normal }],
115
+ }
116
+ const $rtlStyle: TextStyle = isRTL ? { writingDirection: "rtl" } : {}