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,292 @@
1
+ import { ComponentType, forwardRef, Ref, useImperativeHandle, useRef } from "react"
2
+ import {
3
+ ImageStyle,
4
+ StyleProp,
5
+ // eslint-disable-next-line no-restricted-imports
6
+ TextInput,
7
+ TextInputProps,
8
+ TextStyle,
9
+ TouchableOpacity,
10
+ View,
11
+ ViewStyle,
12
+ } from "react-native"
13
+
14
+ import { isRTL } from "@/i18n"
15
+ import { translate } from "@/i18n/translate"
16
+ import type { ThemedStyle, ThemedStyleArray } 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 TextFieldAccessoryProps {
23
+ style: StyleProp<ViewStyle | TextStyle | ImageStyle>
24
+ status: TextFieldProps["status"]
25
+ multiline: boolean
26
+ editable: boolean
27
+ }
28
+
29
+ export interface TextFieldProps extends Omit<TextInputProps, "ref"> {
30
+ /**
31
+ * A style modifier for different input states.
32
+ */
33
+ status?: "error" | "disabled"
34
+ /**
35
+ * The label text to display if not using `labelTx`.
36
+ */
37
+ label?: TextProps["text"]
38
+ /**
39
+ * Label text which is looked up via i18n.
40
+ */
41
+ labelTx?: TextProps["tx"]
42
+ /**
43
+ * Optional label options to pass to i18n. Useful for interpolation
44
+ * as well as explicitly setting locale or translation fallbacks.
45
+ */
46
+ labelTxOptions?: TextProps["txOptions"]
47
+ /**
48
+ * Pass any additional props directly to the label Text component.
49
+ */
50
+ LabelTextProps?: TextProps
51
+ /**
52
+ * The helper text to display if not using `helperTx`.
53
+ */
54
+ helper?: TextProps["text"]
55
+ /**
56
+ * Helper text which is looked up via i18n.
57
+ */
58
+ helperTx?: TextProps["tx"]
59
+ /**
60
+ * Optional helper options to pass to i18n. Useful for interpolation
61
+ * as well as explicitly setting locale or translation fallbacks.
62
+ */
63
+ helperTxOptions?: TextProps["txOptions"]
64
+ /**
65
+ * Pass any additional props directly to the helper Text component.
66
+ */
67
+ HelperTextProps?: TextProps
68
+ /**
69
+ * The placeholder text to display if not using `placeholderTx`.
70
+ */
71
+ placeholder?: TextProps["text"]
72
+ /**
73
+ * Placeholder text which is looked up via i18n.
74
+ */
75
+ placeholderTx?: TextProps["tx"]
76
+ /**
77
+ * Optional placeholder options to pass to i18n. Useful for interpolation
78
+ * as well as explicitly setting locale or translation fallbacks.
79
+ */
80
+ placeholderTxOptions?: TextProps["txOptions"]
81
+ /**
82
+ * Optional input style override.
83
+ */
84
+ style?: StyleProp<TextStyle>
85
+ /**
86
+ * Style overrides for the container
87
+ */
88
+ containerStyle?: StyleProp<ViewStyle>
89
+ /**
90
+ * Style overrides for the input wrapper
91
+ */
92
+ inputWrapperStyle?: StyleProp<ViewStyle>
93
+ /**
94
+ * An optional component to render on the right side of the input.
95
+ * Example: `RightAccessory={(props) => <Icon icon="ladybug" containerStyle={props.style} color={props.editable ? colors.textDim : colors.text} />}`
96
+ * Note: It is a good idea to memoize this.
97
+ */
98
+ RightAccessory?: ComponentType<TextFieldAccessoryProps>
99
+ /**
100
+ * An optional component to render on the left side of the input.
101
+ * Example: `LeftAccessory={(props) => <Icon icon="ladybug" containerStyle={props.style} color={props.editable ? colors.textDim : colors.text} />}`
102
+ * Note: It is a good idea to memoize this.
103
+ */
104
+ LeftAccessory?: ComponentType<TextFieldAccessoryProps>
105
+ }
106
+
107
+ /**
108
+ * A component that allows for the entering and editing of text.
109
+ * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/TextField/}
110
+ * @param {TextFieldProps} props - The props for the `TextField` component.
111
+ * @returns {JSX.Element} The rendered `TextField` component.
112
+ */
113
+ export const TextField = forwardRef(function TextField(props: TextFieldProps, ref: Ref<TextInput>) {
114
+ const {
115
+ labelTx,
116
+ label,
117
+ labelTxOptions,
118
+ placeholderTx,
119
+ placeholder,
120
+ placeholderTxOptions,
121
+ helper,
122
+ helperTx,
123
+ helperTxOptions,
124
+ status,
125
+ RightAccessory,
126
+ LeftAccessory,
127
+ HelperTextProps,
128
+ LabelTextProps,
129
+ style: $inputStyleOverride,
130
+ containerStyle: $containerStyleOverride,
131
+ inputWrapperStyle: $inputWrapperStyleOverride,
132
+ ...TextInputProps
133
+ } = props
134
+ const input = useRef<TextInput>(null)
135
+
136
+ const {
137
+ themed,
138
+ theme: { colors },
139
+ } = useAppTheme()
140
+
141
+ const disabled = TextInputProps.editable === false || status === "disabled"
142
+
143
+ const placeholderContent = placeholderTx
144
+ ? translate(placeholderTx, placeholderTxOptions)
145
+ : placeholder
146
+
147
+ const $containerStyles = [$containerStyleOverride]
148
+
149
+ const $labelStyles = [$labelStyle, LabelTextProps?.style]
150
+
151
+ const $inputWrapperStyles = [
152
+ $styles.row,
153
+ $inputWrapperStyle,
154
+ status === "error" && { borderColor: colors.error },
155
+ TextInputProps.multiline && { minHeight: 112 },
156
+ LeftAccessory && { paddingStart: 0 },
157
+ RightAccessory && { paddingEnd: 0 },
158
+ $inputWrapperStyleOverride,
159
+ ]
160
+
161
+ const $inputStyles: ThemedStyleArray<TextStyle> = [
162
+ $inputStyle,
163
+ disabled && { color: colors.textDim },
164
+ isRTL && { textAlign: "right" as TextStyle["textAlign"] },
165
+ TextInputProps.multiline && { height: "auto" },
166
+ $inputStyleOverride,
167
+ ]
168
+
169
+ const $helperStyles = [
170
+ $helperStyle,
171
+ status === "error" && { color: colors.error },
172
+ HelperTextProps?.style,
173
+ ]
174
+
175
+ /**
176
+ *
177
+ */
178
+ function focusInput() {
179
+ if (disabled) return
180
+
181
+ input.current?.focus()
182
+ }
183
+
184
+ useImperativeHandle(ref, () => input.current as TextInput)
185
+
186
+ return (
187
+ <TouchableOpacity
188
+ activeOpacity={1}
189
+ style={$containerStyles}
190
+ onPress={focusInput}
191
+ accessibilityState={{ disabled }}
192
+ >
193
+ {!!(label || labelTx) && (
194
+ <Text
195
+ preset="formLabel"
196
+ text={label}
197
+ tx={labelTx}
198
+ txOptions={labelTxOptions}
199
+ {...LabelTextProps}
200
+ style={themed($labelStyles)}
201
+ />
202
+ )}
203
+
204
+ <View style={themed($inputWrapperStyles)}>
205
+ {!!LeftAccessory && (
206
+ <LeftAccessory
207
+ style={themed($leftAccessoryStyle)}
208
+ status={status}
209
+ editable={!disabled}
210
+ multiline={TextInputProps.multiline ?? false}
211
+ />
212
+ )}
213
+
214
+ <TextInput
215
+ ref={input}
216
+ underlineColorAndroid={colors.transparent}
217
+ textAlignVertical="top"
218
+ placeholder={placeholderContent}
219
+ placeholderTextColor={colors.textDim}
220
+ {...TextInputProps}
221
+ editable={!disabled}
222
+ style={themed($inputStyles)}
223
+ />
224
+
225
+ {!!RightAccessory && (
226
+ <RightAccessory
227
+ style={themed($rightAccessoryStyle)}
228
+ status={status}
229
+ editable={!disabled}
230
+ multiline={TextInputProps.multiline ?? false}
231
+ />
232
+ )}
233
+ </View>
234
+
235
+ {!!(helper || helperTx) && (
236
+ <Text
237
+ preset="formHelper"
238
+ text={helper}
239
+ tx={helperTx}
240
+ txOptions={helperTxOptions}
241
+ {...HelperTextProps}
242
+ style={themed($helperStyles)}
243
+ />
244
+ )}
245
+ </TouchableOpacity>
246
+ )
247
+ })
248
+
249
+ const $labelStyle: ThemedStyle<TextStyle> = ({ spacing }) => ({
250
+ marginBottom: spacing.xs,
251
+ })
252
+
253
+ const $inputWrapperStyle: ThemedStyle<ViewStyle> = ({ colors }) => ({
254
+ alignItems: "flex-start",
255
+ borderWidth: 1,
256
+ borderRadius: 4,
257
+ backgroundColor: colors.palette.neutral200,
258
+ borderColor: colors.palette.neutral400,
259
+ overflow: "hidden",
260
+ })
261
+
262
+ const $inputStyle: ThemedStyle<TextStyle> = ({ colors, typography, spacing }) => ({
263
+ flex: 1,
264
+ alignSelf: "stretch",
265
+ fontFamily: typography.primary.normal,
266
+ color: colors.text,
267
+ fontSize: 16,
268
+ height: 24,
269
+ // https://github.com/facebook/react-native/issues/21720#issuecomment-532642093
270
+ paddingVertical: 0,
271
+ paddingHorizontal: 0,
272
+ marginVertical: spacing.xs,
273
+ marginHorizontal: spacing.sm,
274
+ })
275
+
276
+ const $helperStyle: ThemedStyle<TextStyle> = ({ spacing }) => ({
277
+ marginTop: spacing.xs,
278
+ })
279
+
280
+ const $rightAccessoryStyle: ThemedStyle<ViewStyle> = ({ spacing }) => ({
281
+ marginEnd: spacing.xs,
282
+ height: 40,
283
+ justifyContent: "center",
284
+ alignItems: "center",
285
+ })
286
+
287
+ const $leftAccessoryStyle: ThemedStyle<ViewStyle> = ({ spacing }) => ({
288
+ marginStart: spacing.xs,
289
+ height: 40,
290
+ justifyContent: "center",
291
+ alignItems: "center",
292
+ })
@@ -0,0 +1,123 @@
1
+ import { useEffect, useRef, useCallback } from "react"
2
+ import { Image, ImageStyle, Animated, StyleProp, View, ViewStyle } from "react-native"
3
+
4
+ import { useAppTheme } from "@/theme/context"
5
+ import { $styles } from "@/theme/styles"
6
+
7
+ import { iconRegistry, IconTypes } from "../Icon"
8
+ import { $inputOuterBase, BaseToggleInputProps, ToggleProps, Toggle } from "./Toggle"
9
+
10
+ export interface CheckboxToggleProps extends Omit<ToggleProps<CheckboxInputProps>, "ToggleInput"> {
11
+ /**
12
+ * Optional style prop that affects the Image component.
13
+ */
14
+ inputDetailStyle?: ImageStyle
15
+ /**
16
+ * Checkbox-only prop that changes the icon used for the "on" state.
17
+ */
18
+ icon?: IconTypes
19
+ }
20
+
21
+ interface CheckboxInputProps extends BaseToggleInputProps<CheckboxToggleProps> {
22
+ icon?: CheckboxToggleProps["icon"]
23
+ }
24
+ /**
25
+ * @param {CheckboxToggleProps} props - The props for the `Checkbox` component.
26
+ * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/Checkbox}
27
+ * @returns {JSX.Element} The rendered `Checkbox` component.
28
+ */
29
+ export function Checkbox(props: CheckboxToggleProps) {
30
+ const { icon, ...rest } = props
31
+ const checkboxInput = useCallback(
32
+ (toggleProps: CheckboxInputProps) => <CheckboxInput {...toggleProps} icon={icon} />,
33
+ [icon],
34
+ )
35
+ return <Toggle accessibilityRole="checkbox" {...rest} ToggleInput={checkboxInput} />
36
+ }
37
+
38
+ function CheckboxInput(props: CheckboxInputProps) {
39
+ const {
40
+ on,
41
+ status,
42
+ disabled,
43
+ icon = "check",
44
+ outerStyle: $outerStyleOverride,
45
+ innerStyle: $innerStyleOverride,
46
+ detailStyle: $detailStyleOverride,
47
+ } = props
48
+
49
+ const {
50
+ theme: { colors },
51
+ } = useAppTheme()
52
+
53
+ const opacity = useRef(new Animated.Value(0))
54
+
55
+ useEffect(() => {
56
+ Animated.timing(opacity.current, {
57
+ toValue: on ? 1 : 0,
58
+ duration: 300,
59
+ useNativeDriver: true,
60
+ }).start()
61
+ }, [on])
62
+
63
+ const offBackgroundColor = [
64
+ disabled && colors.palette.neutral400,
65
+ status === "error" && colors.errorBackground,
66
+ colors.palette.neutral200,
67
+ ].filter(Boolean)[0]
68
+
69
+ const outerBorderColor = [
70
+ disabled && colors.palette.neutral400,
71
+ status === "error" && colors.error,
72
+ !on && colors.palette.neutral800,
73
+ colors.palette.secondary500,
74
+ ].filter(Boolean)[0]
75
+
76
+ const onBackgroundColor = [
77
+ disabled && colors.transparent,
78
+ status === "error" && colors.errorBackground,
79
+ colors.palette.secondary500,
80
+ ].filter(Boolean)[0]
81
+
82
+ const iconTintColor = [
83
+ disabled && colors.palette.neutral600,
84
+ status === "error" && colors.error,
85
+ colors.palette.accent100,
86
+ ].filter(Boolean)[0]
87
+
88
+ return (
89
+ <View
90
+ style={[
91
+ $inputOuter,
92
+ { backgroundColor: offBackgroundColor, borderColor: outerBorderColor },
93
+ $outerStyleOverride,
94
+ ]}
95
+ >
96
+ <Animated.View
97
+ style={[
98
+ $styles.toggleInner,
99
+ { backgroundColor: onBackgroundColor },
100
+ $innerStyleOverride,
101
+ { opacity: opacity.current },
102
+ ]}
103
+ >
104
+ <Image
105
+ source={icon ? iconRegistry[icon] : iconRegistry.check}
106
+ style={[
107
+ $checkboxDetail,
108
+ !!iconTintColor && { tintColor: iconTintColor },
109
+ $detailStyleOverride as ImageStyle,
110
+ ]}
111
+ />
112
+ </Animated.View>
113
+ </View>
114
+ )
115
+ }
116
+
117
+ const $checkboxDetail: ImageStyle = {
118
+ width: 20,
119
+ height: 20,
120
+ resizeMode: "contain",
121
+ }
122
+
123
+ const $inputOuter: StyleProp<ViewStyle> = [$inputOuterBase, { borderRadius: 4 }]
@@ -0,0 +1,106 @@
1
+ import { useEffect, useRef } from "react"
2
+ import { StyleProp, View, ViewStyle, Animated } from "react-native"
3
+
4
+ import { useAppTheme } from "@/theme/context"
5
+ import { $styles } from "@/theme/styles"
6
+
7
+ import { $inputOuterBase, BaseToggleInputProps, ToggleProps, Toggle } from "./Toggle"
8
+
9
+ export interface RadioToggleProps extends Omit<ToggleProps<RadioInputProps>, "ToggleInput"> {
10
+ /**
11
+ * Optional style prop that affects the dot View.
12
+ */
13
+ inputDetailStyle?: ViewStyle
14
+ }
15
+
16
+ interface RadioInputProps extends BaseToggleInputProps<RadioToggleProps> {}
17
+
18
+ /**
19
+ * @param {RadioToggleProps} props - The props for the `Radio` component.
20
+ * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/Radio}
21
+ * @returns {JSX.Element} The rendered `Radio` component.
22
+ */
23
+ export function Radio(props: RadioToggleProps) {
24
+ return <Toggle accessibilityRole="radio" {...props} ToggleInput={RadioInput} />
25
+ }
26
+
27
+ function RadioInput(props: RadioInputProps) {
28
+ const {
29
+ on,
30
+ status,
31
+ disabled,
32
+ outerStyle: $outerStyleOverride,
33
+ innerStyle: $innerStyleOverride,
34
+ detailStyle: $detailStyleOverride,
35
+ } = props
36
+
37
+ const {
38
+ theme: { colors },
39
+ } = useAppTheme()
40
+
41
+ const opacity = useRef(new Animated.Value(0))
42
+
43
+ useEffect(() => {
44
+ Animated.timing(opacity.current, {
45
+ toValue: on ? 1 : 0,
46
+ duration: 300,
47
+ useNativeDriver: true,
48
+ }).start()
49
+ }, [on])
50
+
51
+ const offBackgroundColor = [
52
+ disabled && colors.palette.neutral400,
53
+ status === "error" && colors.errorBackground,
54
+ colors.palette.neutral200,
55
+ ].filter(Boolean)[0]
56
+
57
+ const outerBorderColor = [
58
+ disabled && colors.palette.neutral400,
59
+ status === "error" && colors.error,
60
+ !on && colors.palette.neutral800,
61
+ colors.palette.secondary500,
62
+ ].filter(Boolean)[0]
63
+
64
+ const onBackgroundColor = [
65
+ disabled && colors.transparent,
66
+ status === "error" && colors.errorBackground,
67
+ colors.palette.neutral100,
68
+ ].filter(Boolean)[0]
69
+
70
+ const dotBackgroundColor = [
71
+ disabled && colors.palette.neutral600,
72
+ status === "error" && colors.error,
73
+ colors.palette.secondary500,
74
+ ].filter(Boolean)[0]
75
+
76
+ return (
77
+ <View
78
+ style={[
79
+ $inputOuter,
80
+ { backgroundColor: offBackgroundColor, borderColor: outerBorderColor },
81
+ $outerStyleOverride,
82
+ ]}
83
+ >
84
+ <Animated.View
85
+ style={[
86
+ $styles.toggleInner,
87
+ { backgroundColor: onBackgroundColor },
88
+ $innerStyleOverride,
89
+ { opacity: opacity.current },
90
+ ]}
91
+ >
92
+ <View
93
+ style={[$radioDetail, { backgroundColor: dotBackgroundColor }, $detailStyleOverride]}
94
+ />
95
+ </Animated.View>
96
+ </View>
97
+ )
98
+ }
99
+
100
+ const $radioDetail: ViewStyle = {
101
+ width: 12,
102
+ height: 12,
103
+ borderRadius: 6,
104
+ }
105
+
106
+ const $inputOuter: StyleProp<ViewStyle> = [$inputOuterBase, { borderRadius: 12 }]