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,332 @@
1
+ import { ReactElement } from "react"
2
+ import {
3
+ StyleProp,
4
+ TextStyle,
5
+ TouchableOpacity,
6
+ TouchableOpacityProps,
7
+ View,
8
+ ViewStyle,
9
+ } from "react-native"
10
+
11
+ import { isRTL } from "@/i18n"
12
+ import { translate } from "@/i18n/translate"
13
+ import type { ThemedStyle } from "@/theme/types"
14
+ import { useAppTheme } from "@/theme/context"
15
+ import { $styles } from "@/theme/styles"
16
+ import { ExtendedEdge, useSafeAreaInsetsStyle } from "@/utils/useSafeAreaInsetsStyle"
17
+
18
+ import { IconTypes, PressableIcon } from "./Icon"
19
+ import { Text, TextProps } from "./Text"
20
+
21
+ export interface HeaderProps {
22
+ /**
23
+ * The layout of the title relative to the action components.
24
+ * - `center` will force the title to always be centered relative to the header. If the title or the action buttons are too long, the title will be cut off.
25
+ * - `flex` will attempt to center the title relative to the action buttons. If the action buttons are different widths, the title will be off-center relative to the header.
26
+ */
27
+ titleMode?: "center" | "flex"
28
+ /**
29
+ * Optional title style override.
30
+ */
31
+ titleStyle?: StyleProp<TextStyle>
32
+ /**
33
+ * Optional outer title container style override.
34
+ */
35
+ titleContainerStyle?: StyleProp<ViewStyle>
36
+ /**
37
+ * Optional inner header wrapper style override.
38
+ */
39
+ style?: StyleProp<ViewStyle>
40
+ /**
41
+ * Optional outer header container style override.
42
+ */
43
+ containerStyle?: StyleProp<ViewStyle>
44
+ /**
45
+ * Background color
46
+ */
47
+ backgroundColor?: string
48
+ /**
49
+ * Title text to display if not using `tx` or nested components.
50
+ */
51
+ title?: TextProps["text"]
52
+ /**
53
+ * Title text which is looked up via i18n.
54
+ */
55
+ titleTx?: TextProps["tx"]
56
+ /**
57
+ * Optional options to pass to i18n. Useful for interpolation
58
+ * as well as explicitly setting locale or translation fallbacks.
59
+ */
60
+ titleTxOptions?: TextProps["txOptions"]
61
+ /**
62
+ * Icon that should appear on the left.
63
+ * Can be used with `onLeftPress`.
64
+ */
65
+ leftIcon?: IconTypes
66
+ /**
67
+ * An optional tint color for the left icon
68
+ */
69
+ leftIconColor?: string
70
+ /**
71
+ * Left action text to display if not using `leftTx`.
72
+ * Can be used with `onLeftPress`. Overrides `leftIcon`.
73
+ */
74
+ leftText?: TextProps["text"]
75
+ /**
76
+ * Left action text text which is looked up via i18n.
77
+ * Can be used with `onLeftPress`. Overrides `leftIcon`.
78
+ */
79
+ leftTx?: TextProps["tx"]
80
+ /**
81
+ * Left action custom ReactElement if the built in action props don't suffice.
82
+ * Overrides `leftIcon`, `leftTx` and `leftText`.
83
+ */
84
+ LeftActionComponent?: ReactElement
85
+ /**
86
+ * Optional options to pass to i18n. Useful for interpolation
87
+ * as well as explicitly setting locale or translation fallbacks.
88
+ */
89
+ leftTxOptions?: TextProps["txOptions"]
90
+ /**
91
+ * What happens when you press the left icon or text action.
92
+ */
93
+ onLeftPress?: TouchableOpacityProps["onPress"]
94
+ /**
95
+ * Icon that should appear on the right.
96
+ * Can be used with `onRightPress`.
97
+ */
98
+ rightIcon?: IconTypes
99
+ /**
100
+ * An optional tint color for the right icon
101
+ */
102
+ rightIconColor?: string
103
+ /**
104
+ * Right action text to display if not using `rightTx`.
105
+ * Can be used with `onRightPress`. Overrides `rightIcon`.
106
+ */
107
+ rightText?: TextProps["text"]
108
+ /**
109
+ * Right action text text which is looked up via i18n.
110
+ * Can be used with `onRightPress`. Overrides `rightIcon`.
111
+ */
112
+ rightTx?: TextProps["tx"]
113
+ /**
114
+ * Right action custom ReactElement if the built in action props don't suffice.
115
+ * Overrides `rightIcon`, `rightTx` and `rightText`.
116
+ */
117
+ RightActionComponent?: ReactElement
118
+ /**
119
+ * Optional options to pass to i18n. Useful for interpolation
120
+ * as well as explicitly setting locale or translation fallbacks.
121
+ */
122
+ rightTxOptions?: TextProps["txOptions"]
123
+ /**
124
+ * What happens when you press the right icon or text action.
125
+ */
126
+ onRightPress?: TouchableOpacityProps["onPress"]
127
+ /**
128
+ * Override the default edges for the safe area.
129
+ */
130
+ safeAreaEdges?: ExtendedEdge[]
131
+ }
132
+
133
+ interface HeaderActionProps {
134
+ backgroundColor?: string
135
+ icon?: IconTypes
136
+ iconColor?: string
137
+ text?: TextProps["text"]
138
+ tx?: TextProps["tx"]
139
+ txOptions?: TextProps["txOptions"]
140
+ onPress?: TouchableOpacityProps["onPress"]
141
+ ActionComponent?: ReactElement
142
+ }
143
+
144
+ /**
145
+ * Header that appears on many screens. Will hold navigation buttons and screen title.
146
+ * The Header is meant to be used with the `screenOptions.header` option on navigators, routes, or screen components via `navigation.setOptions({ header })`.
147
+ * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/Header/}
148
+ * @param {HeaderProps} props - The props for the `Header` component.
149
+ * @returns {JSX.Element} The rendered `Header` component.
150
+ */
151
+ export function Header(props: HeaderProps) {
152
+ const {
153
+ theme: { colors },
154
+ themed,
155
+ } = useAppTheme()
156
+ const {
157
+ backgroundColor = colors.background,
158
+ LeftActionComponent,
159
+ leftIcon,
160
+ leftIconColor,
161
+ leftText,
162
+ leftTx,
163
+ leftTxOptions,
164
+ onLeftPress,
165
+ onRightPress,
166
+ RightActionComponent,
167
+ rightIcon,
168
+ rightIconColor,
169
+ rightText,
170
+ rightTx,
171
+ rightTxOptions,
172
+ safeAreaEdges = ["top"],
173
+ title,
174
+ titleMode = "center",
175
+ titleTx,
176
+ titleTxOptions,
177
+ titleContainerStyle: $titleContainerStyleOverride,
178
+ style: $styleOverride,
179
+ titleStyle: $titleStyleOverride,
180
+ containerStyle: $containerStyleOverride,
181
+ } = props
182
+
183
+ const $containerInsets = useSafeAreaInsetsStyle(safeAreaEdges)
184
+
185
+ const titleContent = titleTx ? translate(titleTx, titleTxOptions) : title
186
+
187
+ return (
188
+ <View style={[$container, $containerInsets, { backgroundColor }, $containerStyleOverride]}>
189
+ <View style={[$styles.row, $wrapper, $styleOverride]}>
190
+ <HeaderAction
191
+ tx={leftTx}
192
+ text={leftText}
193
+ icon={leftIcon}
194
+ iconColor={leftIconColor}
195
+ onPress={onLeftPress}
196
+ txOptions={leftTxOptions}
197
+ backgroundColor={backgroundColor}
198
+ ActionComponent={LeftActionComponent}
199
+ />
200
+
201
+ {!!titleContent && (
202
+ <View
203
+ style={[
204
+ $titleWrapperPointerEvents,
205
+ titleMode === "center" && themed($titleWrapperCenter),
206
+ titleMode === "flex" && $titleWrapperFlex,
207
+ $titleContainerStyleOverride,
208
+ ]}
209
+ >
210
+ <Text
211
+ weight="medium"
212
+ size="md"
213
+ text={titleContent}
214
+ style={[$title, $titleStyleOverride]}
215
+ />
216
+ </View>
217
+ )}
218
+
219
+ <HeaderAction
220
+ tx={rightTx}
221
+ text={rightText}
222
+ icon={rightIcon}
223
+ iconColor={rightIconColor}
224
+ onPress={onRightPress}
225
+ txOptions={rightTxOptions}
226
+ backgroundColor={backgroundColor}
227
+ ActionComponent={RightActionComponent}
228
+ />
229
+ </View>
230
+ </View>
231
+ )
232
+ }
233
+
234
+ /**
235
+ * @param {HeaderActionProps} props - The props for the `HeaderAction` component.
236
+ * @returns {JSX.Element} The rendered `HeaderAction` component.
237
+ */
238
+ function HeaderAction(props: HeaderActionProps) {
239
+ const { backgroundColor, icon, text, tx, txOptions, onPress, ActionComponent, iconColor } = props
240
+ const { themed } = useAppTheme()
241
+
242
+ const content = tx ? translate(tx, txOptions) : text
243
+
244
+ if (ActionComponent) return ActionComponent
245
+
246
+ if (content) {
247
+ return (
248
+ <TouchableOpacity
249
+ style={themed([$actionTextContainer, { backgroundColor }])}
250
+ onPress={onPress}
251
+ disabled={!onPress}
252
+ activeOpacity={0.8}
253
+ >
254
+ <Text weight="medium" size="md" text={content} style={themed($actionText)} />
255
+ </TouchableOpacity>
256
+ )
257
+ }
258
+
259
+ if (icon) {
260
+ return (
261
+ <PressableIcon
262
+ size={24}
263
+ icon={icon}
264
+ color={iconColor}
265
+ onPress={onPress}
266
+ containerStyle={themed([$actionIconContainer, { backgroundColor }])}
267
+ style={isRTL ? { transform: [{ rotate: "180deg" }] } : {}}
268
+ />
269
+ )
270
+ }
271
+
272
+ return <View style={[$actionFillerContainer, { backgroundColor }]} />
273
+ }
274
+
275
+ const $wrapper: ViewStyle = {
276
+ height: 56,
277
+ alignItems: "center",
278
+ justifyContent: "space-between",
279
+ }
280
+
281
+ const $container: ViewStyle = {
282
+ width: "100%",
283
+ }
284
+
285
+ const $title: TextStyle = {
286
+ textAlign: "center",
287
+ }
288
+
289
+ const $actionTextContainer: ThemedStyle<ViewStyle> = ({ spacing }) => ({
290
+ flexGrow: 0,
291
+ alignItems: "center",
292
+ justifyContent: "center",
293
+ height: "100%",
294
+ paddingHorizontal: spacing.md,
295
+ zIndex: 2,
296
+ })
297
+
298
+ const $actionText: ThemedStyle<TextStyle> = ({ colors }) => ({
299
+ color: colors.tint,
300
+ })
301
+
302
+ const $actionIconContainer: ThemedStyle<ViewStyle> = ({ spacing }) => ({
303
+ flexGrow: 0,
304
+ alignItems: "center",
305
+ justifyContent: "center",
306
+ height: "100%",
307
+ paddingHorizontal: spacing.md,
308
+ zIndex: 2,
309
+ })
310
+
311
+ const $actionFillerContainer: ViewStyle = {
312
+ width: 16,
313
+ }
314
+
315
+ const $titleWrapperPointerEvents: ViewStyle = {
316
+ pointerEvents: "none",
317
+ }
318
+
319
+ const $titleWrapperCenter: ThemedStyle<ViewStyle> = ({ spacing }) => ({
320
+ alignItems: "center",
321
+ justifyContent: "center",
322
+ height: "100%",
323
+ width: "100%",
324
+ position: "absolute",
325
+ paddingHorizontal: spacing.xxl,
326
+ zIndex: 1,
327
+ })
328
+
329
+ const $titleWrapperFlex: ViewStyle = {
330
+ justifyContent: "center",
331
+ flexGrow: 1,
332
+ }
@@ -0,0 +1,140 @@
1
+ import {
2
+ Image,
3
+ ImageStyle,
4
+ StyleProp,
5
+ TouchableOpacity,
6
+ TouchableOpacityProps,
7
+ View,
8
+ ViewProps,
9
+ ViewStyle,
10
+ } from "react-native"
11
+
12
+ import { useAppTheme } from "@/theme/context"
13
+
14
+ export type IconTypes = keyof typeof iconRegistry
15
+
16
+ type BaseIconProps = {
17
+ /**
18
+ * The name of the icon
19
+ */
20
+ icon: IconTypes
21
+
22
+ /**
23
+ * An optional tint color for the icon
24
+ */
25
+ color?: string
26
+
27
+ /**
28
+ * An optional size for the icon. If not provided, the icon will be sized to the icon's resolution.
29
+ */
30
+ size?: number
31
+
32
+ /**
33
+ * Style overrides for the icon image
34
+ */
35
+ style?: StyleProp<ImageStyle>
36
+
37
+ /**
38
+ * Style overrides for the icon container
39
+ */
40
+ containerStyle?: StyleProp<ViewStyle>
41
+ }
42
+
43
+ type PressableIconProps = Omit<TouchableOpacityProps, "style"> & BaseIconProps
44
+ type IconProps = Omit<ViewProps, "style"> & BaseIconProps
45
+
46
+ /**
47
+ * A component to render a registered icon.
48
+ * It is wrapped in a <TouchableOpacity />
49
+ * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/Icon/}
50
+ * @param {PressableIconProps} props - The props for the `PressableIcon` component.
51
+ * @returns {JSX.Element} The rendered `PressableIcon` component.
52
+ */
53
+ export function PressableIcon(props: PressableIconProps) {
54
+ const {
55
+ icon,
56
+ color,
57
+ size,
58
+ style: $imageStyleOverride,
59
+ containerStyle: $containerStyleOverride,
60
+ ...pressableProps
61
+ } = props
62
+
63
+ const { theme } = useAppTheme()
64
+
65
+ const $imageStyle: StyleProp<ImageStyle> = [
66
+ $imageStyleBase,
67
+ { tintColor: color ?? theme.colors.text },
68
+ size !== undefined && { width: size, height: size },
69
+ $imageStyleOverride,
70
+ ]
71
+
72
+ return (
73
+ <TouchableOpacity {...pressableProps} style={$containerStyleOverride}>
74
+ <Image style={$imageStyle} source={iconRegistry[icon]} />
75
+ </TouchableOpacity>
76
+ )
77
+ }
78
+
79
+ /**
80
+ * A component to render a registered icon.
81
+ * It is wrapped in a <View />, use `PressableIcon` if you want to react to input
82
+ * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/Icon/}
83
+ * @param {IconProps} props - The props for the `Icon` component.
84
+ * @returns {JSX.Element} The rendered `Icon` component.
85
+ */
86
+ export function Icon(props: IconProps) {
87
+ const {
88
+ icon,
89
+ color,
90
+ size,
91
+ style: $imageStyleOverride,
92
+ containerStyle: $containerStyleOverride,
93
+ ...viewProps
94
+ } = props
95
+
96
+ const { theme } = useAppTheme()
97
+
98
+ const $imageStyle: StyleProp<ImageStyle> = [
99
+ $imageStyleBase,
100
+ { tintColor: color ?? theme.colors.text },
101
+ size !== undefined && { width: size, height: size },
102
+ $imageStyleOverride,
103
+ ]
104
+
105
+ return (
106
+ <View {...viewProps} style={$containerStyleOverride}>
107
+ <Image style={$imageStyle} source={iconRegistry[icon]} />
108
+ </View>
109
+ )
110
+ }
111
+
112
+ export const iconRegistry = {
113
+ back: require("@assets/icons/back.png"),
114
+ bell: require("@assets/icons/bell.png"),
115
+ caretLeft: require("@assets/icons/caretLeft.png"),
116
+ caretRight: require("@assets/icons/caretRight.png"),
117
+ check: require("@assets/icons/check.png"),
118
+ clap: require("@assets/icons/demo/clap.png"), // @demo remove-current-line
119
+ community: require("@assets/icons/demo/community.png"), // @demo remove-current-line
120
+ components: require("@assets/icons/demo/components.png"), // @demo remove-current-line
121
+ debug: require("@assets/icons/demo/debug.png"), // @demo remove-current-line
122
+ github: require("@assets/icons/demo/github.png"), // @demo remove-current-line
123
+ heart: require("@assets/icons/demo/heart.png"), // @demo remove-current-line
124
+ hidden: require("@assets/icons/hidden.png"),
125
+ ladybug: require("@assets/icons/ladybug.png"),
126
+ lock: require("@assets/icons/lock.png"),
127
+ menu: require("@assets/icons/menu.png"),
128
+ more: require("@assets/icons/more.png"),
129
+ pin: require("@assets/icons/demo/pin.png"), // @demo remove-current-line
130
+ podcast: require("@assets/icons/demo/podcast.png"), // @demo remove-current-line
131
+ settings: require("@assets/icons/settings.png"),
132
+ slack: require("@assets/icons/demo/slack.png"), // @demo remove-current-line
133
+ view: require("@assets/icons/view.png"),
134
+ x: require("@assets/icons/x.png"),
135
+ google: require("@assets/icons/google.png"), // @demo remove-current-line
136
+ }
137
+
138
+ const $imageStyleBase: ImageStyle = {
139
+ resizeMode: "contain",
140
+ }
@@ -0,0 +1,243 @@
1
+ import { forwardRef, ReactElement, ComponentType } from "react"
2
+ import {
3
+ StyleProp,
4
+ TextStyle,
5
+ TouchableOpacity,
6
+ TouchableOpacityProps,
7
+ View,
8
+ ViewStyle,
9
+ } from "react-native"
10
+
11
+ import type { ThemedStyle } from "@/theme/types"
12
+ import { useAppTheme } from "@/theme/context"
13
+ import { $styles } from "@/theme/styles"
14
+
15
+ import { Icon, IconTypes } from "./Icon"
16
+ import { Text, TextProps } from "./Text"
17
+
18
+ export interface ListItemProps extends TouchableOpacityProps {
19
+ /**
20
+ * How tall the list item should be.
21
+ * Default: 56
22
+ */
23
+ height?: number
24
+ /**
25
+ * Whether to show the top separator.
26
+ * Default: false
27
+ */
28
+ topSeparator?: boolean
29
+ /**
30
+ * Whether to show the bottom separator.
31
+ * Default: false
32
+ */
33
+ bottomSeparator?: boolean
34
+ /**
35
+ * Text to display if not using `tx` or nested components.
36
+ */
37
+ text?: TextProps["text"]
38
+ /**
39
+ * Text which is looked up via i18n.
40
+ */
41
+ tx?: TextProps["tx"]
42
+ /**
43
+ * Children components.
44
+ */
45
+ children?: TextProps["children"]
46
+ /**
47
+ * Optional options to pass to i18n. Useful for interpolation
48
+ * as well as explicitly setting locale or translation fallbacks.
49
+ */
50
+ txOptions?: TextProps["txOptions"]
51
+ /**
52
+ * Optional text style override.
53
+ */
54
+ textStyle?: StyleProp<TextStyle>
55
+ /**
56
+ * Pass any additional props directly to the Text component.
57
+ */
58
+ TextProps?: TextProps
59
+ /**
60
+ * Optional View container style override.
61
+ */
62
+ containerStyle?: StyleProp<ViewStyle>
63
+ /**
64
+ * Optional TouchableOpacity style override.
65
+ */
66
+ style?: StyleProp<ViewStyle>
67
+ /**
68
+ * Icon that should appear on the left.
69
+ */
70
+ leftIcon?: IconTypes
71
+ /**
72
+ * An optional tint color for the left icon
73
+ */
74
+ leftIconColor?: string
75
+ /**
76
+ * Icon that should appear on the right.
77
+ */
78
+ rightIcon?: IconTypes
79
+ /**
80
+ * An optional tint color for the right icon
81
+ */
82
+ rightIconColor?: string
83
+ /**
84
+ * Right action custom ReactElement.
85
+ * Overrides `rightIcon`.
86
+ */
87
+ RightComponent?: ReactElement
88
+ /**
89
+ * Left action custom ReactElement.
90
+ * Overrides `leftIcon`.
91
+ */
92
+ LeftComponent?: ReactElement
93
+ }
94
+
95
+ interface ListItemActionProps {
96
+ icon?: IconTypes
97
+ iconColor?: string
98
+ Component?: ReactElement
99
+ size: number
100
+ side: "left" | "right"
101
+ }
102
+
103
+ /**
104
+ * A styled row component that can be used in FlatList, SectionList, or by itself.
105
+ * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/ListItem/}
106
+ * @param {ListItemProps} props - The props for the `ListItem` component.
107
+ * @returns {JSX.Element} The rendered `ListItem` component.
108
+ */
109
+ export const ListItem = forwardRef<View, ListItemProps>(function ListItem(
110
+ props: ListItemProps,
111
+ ref,
112
+ ) {
113
+ const {
114
+ bottomSeparator,
115
+ children,
116
+ height = 56,
117
+ LeftComponent,
118
+ leftIcon,
119
+ leftIconColor,
120
+ RightComponent,
121
+ rightIcon,
122
+ rightIconColor,
123
+ style,
124
+ text,
125
+ TextProps,
126
+ topSeparator,
127
+ tx,
128
+ txOptions,
129
+ textStyle: $textStyleOverride,
130
+ containerStyle: $containerStyleOverride,
131
+ ...TouchableOpacityProps
132
+ } = props
133
+ const { themed } = useAppTheme()
134
+
135
+ const isTouchable =
136
+ TouchableOpacityProps.onPress !== undefined ||
137
+ TouchableOpacityProps.onPressIn !== undefined ||
138
+ TouchableOpacityProps.onPressOut !== undefined ||
139
+ TouchableOpacityProps.onLongPress !== undefined
140
+
141
+ const $textStyles = [$textStyle, $textStyleOverride, TextProps?.style]
142
+
143
+ const $containerStyles = [
144
+ topSeparator && $separatorTop,
145
+ bottomSeparator && $separatorBottom,
146
+ $containerStyleOverride,
147
+ ]
148
+
149
+ const $touchableStyles = [$styles.row, $touchableStyle, { minHeight: height }, style]
150
+
151
+ const Wrapper: ComponentType<TouchableOpacityProps> = isTouchable ? TouchableOpacity : View
152
+
153
+ return (
154
+ <View ref={ref} style={themed($containerStyles)}>
155
+ <Wrapper {...TouchableOpacityProps} style={$touchableStyles}>
156
+ <ListItemAction
157
+ side="left"
158
+ size={height}
159
+ icon={leftIcon}
160
+ iconColor={leftIconColor}
161
+ Component={LeftComponent}
162
+ />
163
+
164
+ <Text {...TextProps} tx={tx} text={text} txOptions={txOptions} style={themed($textStyles)}>
165
+ {children}
166
+ </Text>
167
+
168
+ <ListItemAction
169
+ side="right"
170
+ size={height}
171
+ icon={rightIcon}
172
+ iconColor={rightIconColor}
173
+ Component={RightComponent}
174
+ />
175
+ </Wrapper>
176
+ </View>
177
+ )
178
+ })
179
+
180
+ /**
181
+ * @param {ListItemActionProps} props - The props for the `ListItemAction` component.
182
+ * @returns {JSX.Element | null} The rendered `ListItemAction` component.
183
+ */
184
+ function ListItemAction(props: ListItemActionProps) {
185
+ const { icon, Component, iconColor, size, side } = props
186
+ const { themed } = useAppTheme()
187
+
188
+ const $iconContainerStyles = [$iconContainer]
189
+
190
+ if (Component) return Component
191
+
192
+ if (icon !== undefined) {
193
+ return (
194
+ <Icon
195
+ size={24}
196
+ icon={icon}
197
+ color={iconColor}
198
+ containerStyle={themed([
199
+ $iconContainerStyles,
200
+ side === "left" && $iconContainerLeft,
201
+ side === "right" && $iconContainerRight,
202
+ { height: size },
203
+ ])}
204
+ />
205
+ )
206
+ }
207
+
208
+ return null
209
+ }
210
+
211
+ const $separatorTop: ThemedStyle<ViewStyle> = ({ colors }) => ({
212
+ borderTopWidth: 1,
213
+ borderTopColor: colors.separator,
214
+ })
215
+
216
+ const $separatorBottom: ThemedStyle<ViewStyle> = ({ colors }) => ({
217
+ borderBottomWidth: 1,
218
+ borderBottomColor: colors.separator,
219
+ })
220
+
221
+ const $textStyle: ThemedStyle<TextStyle> = ({ spacing }) => ({
222
+ paddingVertical: spacing.xs,
223
+ alignSelf: "center",
224
+ flexGrow: 1,
225
+ flexShrink: 1,
226
+ })
227
+
228
+ const $touchableStyle: ViewStyle = {
229
+ alignItems: "flex-start",
230
+ }
231
+
232
+ const $iconContainer: ViewStyle = {
233
+ justifyContent: "center",
234
+ alignItems: "center",
235
+ flexGrow: 0,
236
+ }
237
+ const $iconContainerLeft: ThemedStyle<ViewStyle> = ({ spacing }) => ({
238
+ marginEnd: spacing.md,
239
+ })
240
+
241
+ const $iconContainerRight: ThemedStyle<ViewStyle> = ({ spacing }) => ({
242
+ marginStart: spacing.md,
243
+ })