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,105 @@
1
+ import { Alert, StyleProp, TextStyle, View, ViewStyle } from "react-native"
2
+ import { useAppTheme } from "@/theme/context"
3
+ import type { ThemedStyle } from "@/theme/types"
4
+ import { Text } from "@/components/Text"
5
+ import React, { useEffect } from "react"
6
+ import { observer } from "mobx-react-lite"
7
+
8
+
9
+ export interface AlertTongleProps {
10
+ /**
11
+ * An optional style override useful for padding & margin.
12
+ */
13
+ style?: StyleProp<ViewStyle>
14
+ }
15
+
16
+ type AlertItem = {
17
+ title: string
18
+ message: string
19
+ buttons?: Array<{
20
+ text: string
21
+ onPress?: () => void
22
+ style?: 'default' | 'cancel' | 'destructive'
23
+ }>
24
+ }
25
+
26
+ // Static queue manager
27
+ class AlertQueueManager {
28
+ private static queue: AlertItem[] = []
29
+ private static isShowing = false
30
+ private static currentAlert: AlertItem | null = null
31
+
32
+ static enqueue(alert: AlertItem) {
33
+ if (this.isDuplicate(alert)) return
34
+
35
+ this.queue.push(alert)
36
+ this.showNext()
37
+ }
38
+
39
+ private static isDuplicate(alert: AlertItem): boolean {
40
+ if (this.isShowing && this.currentAlert?.title === alert.title && this.currentAlert?.message === alert.message) {
41
+ return true
42
+ }
43
+ if (this.queue.some(q => q.title === alert.title && q.message === alert.message)) {
44
+ return true
45
+ }
46
+ return false
47
+ }
48
+
49
+ private static showNext() {
50
+ if (this.isShowing || this.queue.length === 0) return
51
+
52
+ this.isShowing = true
53
+ const nextAlert = this.queue.shift()!
54
+ this.currentAlert = nextAlert
55
+
56
+ const { title, message, buttons = [{ text: "OK" }] } = nextAlert
57
+
58
+ Alert.alert(title, message, buttons.map(button => ({
59
+ ...button,
60
+ onPress: () => {
61
+ button.onPress?.()
62
+ this.isShowing = false
63
+ this.currentAlert = null
64
+ this.showNext()
65
+ },
66
+ })))
67
+ }
68
+ }
69
+
70
+ // Exportable function
71
+ export const showQueuedAlert = (alert: AlertItem) => {
72
+ AlertQueueManager.enqueue(alert)
73
+ }
74
+
75
+
76
+ // COMPONENT
77
+ export const AlertTongle = observer(function AlertTongle(props: AlertTongleProps) {
78
+ const { style } = props
79
+ const $styles = [$container, style]
80
+ const { themed } = useAppTheme()
81
+
82
+ useEffect(() => {
83
+ // Example trigger
84
+ showQueuedAlert({
85
+ title: "Initial Alert",
86
+ message: "This is triggered from AlertTongle component",
87
+ })
88
+ }, [])
89
+
90
+ return (
91
+ <View style={$styles}>
92
+ <Text style={themed($text)}>Hello</Text>
93
+ </View>
94
+ )
95
+ })
96
+
97
+ const $container: ViewStyle = {
98
+ justifyContent: "center",
99
+ }
100
+
101
+ const $text: ThemedStyle<TextStyle> = ({ colors, typography }) => ({
102
+ fontFamily: typography.primary.normal,
103
+ fontSize: 14,
104
+ color: colors.palette.primary500,
105
+ })
@@ -0,0 +1,89 @@
1
+ import { useLayoutEffect, useState } from "react"
2
+ import { Image, ImageProps, ImageURISource, Platform, PixelRatio } from "react-native"
3
+
4
+ export interface AutoImageProps extends ImageProps {
5
+ /**
6
+ * How wide should the image be?
7
+ */
8
+ maxWidth?: number
9
+ /**
10
+ * How tall should the image be?
11
+ */
12
+ maxHeight?: number
13
+ headers?: {
14
+ [key: string]: string
15
+ }
16
+ }
17
+
18
+ /**
19
+ * A hook that will return the scaled dimensions of an image based on the
20
+ * provided dimensions' aspect ratio. If no desired dimensions are provided,
21
+ * it will return the original dimensions of the remote image.
22
+ *
23
+ * How is this different from `resizeMode: 'contain'`? Firstly, you can
24
+ * specify only one side's size (not both). Secondly, the image will scale to fit
25
+ * the desired dimensions instead of just being contained within its image-container.
26
+ * @param {number} remoteUri - The URI of the remote image.
27
+ * @param {number} dimensions - The desired dimensions of the image. If not provided, the original dimensions will be returned.
28
+ * @returns {[number, number]} - The scaled dimensions of the image.
29
+ */
30
+ export function useAutoImage(
31
+ remoteUri: string,
32
+ headers?: {
33
+ [key: string]: string
34
+ },
35
+ dimensions?: [maxWidth?: number, maxHeight?: number],
36
+ ): [width: number, height: number] {
37
+ const [[remoteWidth, remoteHeight], setRemoteImageDimensions] = useState([0, 0])
38
+ const remoteAspectRatio = remoteWidth / remoteHeight
39
+ const [maxWidth, maxHeight] = dimensions ?? []
40
+
41
+ useLayoutEffect(() => {
42
+ if (!remoteUri) return
43
+
44
+ if (!headers) {
45
+ Image.getSize(remoteUri, (w, h) => setRemoteImageDimensions([w, h]))
46
+ } else {
47
+ Image.getSizeWithHeaders(remoteUri, headers, (w, h) => setRemoteImageDimensions([w, h]))
48
+ }
49
+ }, [remoteUri, headers])
50
+
51
+ if (Number.isNaN(remoteAspectRatio)) return [0, 0]
52
+
53
+ if (maxWidth && maxHeight) {
54
+ const aspectRatio = Math.min(maxWidth / remoteWidth, maxHeight / remoteHeight)
55
+ return [
56
+ PixelRatio.roundToNearestPixel(remoteWidth * aspectRatio),
57
+ PixelRatio.roundToNearestPixel(remoteHeight * aspectRatio),
58
+ ]
59
+ } else if (maxWidth) {
60
+ return [maxWidth, PixelRatio.roundToNearestPixel(maxWidth / remoteAspectRatio)]
61
+ } else if (maxHeight) {
62
+ return [PixelRatio.roundToNearestPixel(maxHeight * remoteAspectRatio), maxHeight]
63
+ } else {
64
+ return [remoteWidth, remoteHeight]
65
+ }
66
+ }
67
+
68
+ /**
69
+ * An Image component that automatically sizes a remote or data-uri image.
70
+ * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/AutoImage/}
71
+ * @param {AutoImageProps} props - The props for the `AutoImage` component.
72
+ * @returns {JSX.Element} The rendered `AutoImage` component.
73
+ */
74
+ export function AutoImage(props: AutoImageProps) {
75
+ const { maxWidth, maxHeight, ...ImageProps } = props
76
+ const source = props.source as ImageURISource
77
+ const headers = source?.headers
78
+
79
+ const [width, height] = useAutoImage(
80
+ Platform.select({
81
+ web: (source?.uri as string) ?? (source as string),
82
+ default: source?.uri as string,
83
+ }),
84
+ headers,
85
+ [maxWidth, maxHeight],
86
+ )
87
+
88
+ return <Image {...ImageProps} style={[{ width, height }, props.style]} />
89
+ }
@@ -0,0 +1,248 @@
1
+ import { ComponentType } from "react"
2
+ import {
3
+ Pressable,
4
+ PressableProps,
5
+ PressableStateCallbackType,
6
+ StyleProp,
7
+ TextStyle,
8
+ ViewStyle,
9
+ } from "react-native"
10
+
11
+ import { useAppTheme } from "@/theme/context"
12
+ import { $styles } from "@/theme/styles"
13
+ import type { ThemedStyle, ThemedStyleArray } from "@/theme/types"
14
+
15
+ import { Text, TextProps } from "./Text"
16
+
17
+ type Presets = "default" | "filled" | "reversed"
18
+
19
+ export interface ButtonAccessoryProps {
20
+ style: StyleProp<any>
21
+ pressableState: PressableStateCallbackType
22
+ disabled?: boolean
23
+ }
24
+
25
+ export interface ButtonProps extends PressableProps {
26
+ /**
27
+ * Text which is looked up via i18n.
28
+ */
29
+ tx?: TextProps["tx"]
30
+ /**
31
+ * The text to display if not using `tx` or nested components.
32
+ */
33
+ text?: TextProps["text"]
34
+ /**
35
+ * Optional options to pass to i18n. Useful for interpolation
36
+ * as well as explicitly setting locale or translation fallbacks.
37
+ */
38
+ txOptions?: TextProps["txOptions"]
39
+ /**
40
+ * An optional style override useful for padding & margin.
41
+ */
42
+ style?: StyleProp<ViewStyle>
43
+ /**
44
+ * An optional style override for the "pressed" state.
45
+ */
46
+ pressedStyle?: StyleProp<ViewStyle>
47
+ /**
48
+ * An optional style override for the button text.
49
+ */
50
+ textStyle?: StyleProp<TextStyle>
51
+ /**
52
+ * An optional style override for the button text when in the "pressed" state.
53
+ */
54
+ pressedTextStyle?: StyleProp<TextStyle>
55
+ /**
56
+ * An optional style override for the button text when in the "disabled" state.
57
+ */
58
+ disabledTextStyle?: StyleProp<TextStyle>
59
+ /**
60
+ * One of the different types of button presets.
61
+ */
62
+ preset?: Presets
63
+ /**
64
+ * An optional component to render on the right side of the text.
65
+ * Example: `RightAccessory={(props) => <View {...props} />}`
66
+ */
67
+ RightAccessory?: ComponentType<ButtonAccessoryProps>
68
+ /**
69
+ * An optional component to render on the left side of the text.
70
+ * Example: `LeftAccessory={(props) => <View {...props} />}`
71
+ */
72
+ LeftAccessory?: ComponentType<ButtonAccessoryProps>
73
+ /**
74
+ * Children components.
75
+ */
76
+ children?: React.ReactNode
77
+ /**
78
+ * disabled prop, accessed directly for declarative styling reasons.
79
+ * https://reactnative.dev/docs/pressable#disabled
80
+ */
81
+ disabled?: boolean
82
+ /**
83
+ * An optional style override for the disabled state
84
+ */
85
+ disabledStyle?: StyleProp<ViewStyle>
86
+ }
87
+
88
+ /**
89
+ * A component that allows users to take actions and make choices.
90
+ * Wraps the Text component with a Pressable component.
91
+ * @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/Button/}
92
+ * @param {ButtonProps} props - The props for the `Button` component.
93
+ * @returns {JSX.Element} The rendered `Button` component.
94
+ * @example
95
+ * <Button
96
+ * tx="common:ok"
97
+ * style={styles.button}
98
+ * textStyle={styles.buttonText}
99
+ * onPress={handleButtonPress}
100
+ * />
101
+ */
102
+ export function Button(props: ButtonProps) {
103
+ const {
104
+ tx,
105
+ text,
106
+ txOptions,
107
+ style: $viewStyleOverride,
108
+ pressedStyle: $pressedViewStyleOverride,
109
+ textStyle: $textStyleOverride,
110
+ pressedTextStyle: $pressedTextStyleOverride,
111
+ disabledTextStyle: $disabledTextStyleOverride,
112
+ children,
113
+ RightAccessory,
114
+ LeftAccessory,
115
+ disabled,
116
+ disabledStyle: $disabledViewStyleOverride,
117
+ ...rest
118
+ } = props
119
+
120
+ const { themed } = useAppTheme()
121
+
122
+ const preset: Presets = props.preset ?? "default"
123
+ /**
124
+ * @param {PressableStateCallbackType} root0 - The root object containing the pressed state.
125
+ * @param {boolean} root0.pressed - The pressed state.
126
+ * @returns {StyleProp<ViewStyle>} The view style based on the pressed state.
127
+ */
128
+ function $viewStyle({ pressed }: PressableStateCallbackType): StyleProp<ViewStyle> {
129
+ return [
130
+ themed($viewPresets[preset]),
131
+ $viewStyleOverride,
132
+ !!pressed && themed([$pressedViewPresets[preset], $pressedViewStyleOverride]),
133
+ !!disabled && $disabledViewStyleOverride,
134
+ ]
135
+ }
136
+ /**
137
+ * @param {PressableStateCallbackType} root0 - The root object containing the pressed state.
138
+ * @param {boolean} root0.pressed - The pressed state.
139
+ * @returns {StyleProp<TextStyle>} The text style based on the pressed state.
140
+ */
141
+ function $textStyle({ pressed }: PressableStateCallbackType): StyleProp<TextStyle> {
142
+ return [
143
+ themed($textPresets[preset]),
144
+ $textStyleOverride,
145
+ !!pressed && themed([$pressedTextPresets[preset], $pressedTextStyleOverride]),
146
+ !!disabled && $disabledTextStyleOverride,
147
+ ]
148
+ }
149
+
150
+ return (
151
+ <Pressable
152
+ style={$viewStyle}
153
+ accessibilityRole="button"
154
+ accessibilityState={{ disabled: !!disabled }}
155
+ {...rest}
156
+ disabled={disabled}
157
+ >
158
+ {(state) => (
159
+ <>
160
+ {!!LeftAccessory && (
161
+ <LeftAccessory style={$leftAccessoryStyle} pressableState={state} disabled={disabled} />
162
+ )}
163
+
164
+ <Text tx={tx} text={text} txOptions={txOptions} style={$textStyle(state)}>
165
+ {children}
166
+ </Text>
167
+
168
+ {!!RightAccessory && (
169
+ <RightAccessory
170
+ style={$rightAccessoryStyle}
171
+ pressableState={state}
172
+ disabled={disabled}
173
+ />
174
+ )}
175
+ </>
176
+ )}
177
+ </Pressable>
178
+ )
179
+ }
180
+
181
+ const $baseViewStyle: ThemedStyle<ViewStyle> = ({ spacing }) => ({
182
+ minHeight: 56,
183
+ borderRadius: 4,
184
+ justifyContent: "center",
185
+ alignItems: "center",
186
+ paddingVertical: spacing.sm,
187
+ paddingHorizontal: spacing.sm,
188
+ overflow: "hidden",
189
+ })
190
+
191
+ const $baseTextStyle: ThemedStyle<TextStyle> = ({ typography }) => ({
192
+ fontSize: 16,
193
+ lineHeight: 20,
194
+ fontFamily: typography.primary.medium,
195
+ textAlign: "center",
196
+ flexShrink: 1,
197
+ flexGrow: 0,
198
+ zIndex: 2,
199
+ })
200
+
201
+ const $rightAccessoryStyle: ThemedStyle<ViewStyle> = ({ spacing }) => ({
202
+ marginStart: spacing.xs,
203
+ zIndex: 1,
204
+ })
205
+ const $leftAccessoryStyle: ThemedStyle<ViewStyle> = ({ spacing }) => ({
206
+ marginEnd: spacing.xs,
207
+ zIndex: 1,
208
+ })
209
+
210
+ const $viewPresets: Record<Presets, ThemedStyleArray<ViewStyle>> = {
211
+ default: [
212
+ $styles.row,
213
+ $baseViewStyle,
214
+ ({ colors }) => ({
215
+ borderWidth: 1,
216
+ borderColor: colors.palette.neutral400,
217
+ backgroundColor: colors.palette.neutral100,
218
+ }),
219
+ ],
220
+ filled: [
221
+ $styles.row,
222
+ $baseViewStyle,
223
+ ({ colors }) => ({ backgroundColor: colors.palette.neutral300 }),
224
+ ],
225
+ reversed: [
226
+ $styles.row,
227
+ $baseViewStyle,
228
+ ({ colors }) => ({ backgroundColor: colors.palette.neutral800 }),
229
+ ],
230
+ }
231
+
232
+ const $textPresets: Record<Presets, ThemedStyleArray<TextStyle>> = {
233
+ default: [$baseTextStyle],
234
+ filled: [$baseTextStyle],
235
+ reversed: [$baseTextStyle, ({ colors }) => ({ color: colors.palette.neutral100 })],
236
+ }
237
+
238
+ const $pressedViewPresets: Record<Presets, ThemedStyle<ViewStyle>> = {
239
+ default: ({ colors }) => ({ backgroundColor: colors.palette.neutral200 }),
240
+ filled: ({ colors }) => ({ backgroundColor: colors.palette.neutral400 }),
241
+ reversed: ({ colors }) => ({ backgroundColor: colors.palette.neutral700 }),
242
+ }
243
+
244
+ const $pressedTextPresets: Record<Presets, ThemedStyle<TextStyle>> = {
245
+ default: () => ({ opacity: 0.9 }),
246
+ filled: () => ({ opacity: 0.9 }),
247
+ reversed: () => ({ opacity: 0.9 }),
248
+ }