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.
- package/CONTRIBUTING.md +0 -0
- package/LICENSE +21 -0
- package/README.md +492 -0
- package/app/app.tsx +116 -0
- package/app/components/AlertTongle.tsx +105 -0
- package/app/components/AutoImage.tsx +89 -0
- package/app/components/Button.tsx +248 -0
- package/app/components/Card.tsx +314 -0
- package/app/components/EmptyState.tsx +248 -0
- package/app/components/Header.tsx +332 -0
- package/app/components/Icon.tsx +140 -0
- package/app/components/ListItem.tsx +243 -0
- package/app/components/ListView.tsx +42 -0
- package/app/components/Screen.tsx +305 -0
- package/app/components/Text.test.tsx +23 -0
- package/app/components/Text.tsx +116 -0
- package/app/components/TextField.tsx +292 -0
- package/app/components/Toggle/Checkbox.tsx +123 -0
- package/app/components/Toggle/Radio.tsx +106 -0
- package/app/components/Toggle/Switch.tsx +264 -0
- package/app/components/Toggle/Toggle.tsx +285 -0
- package/app/components/index copy.ts +15 -0
- package/app/components/index.ts +18 -0
- package/app/config/config.base.ts +26 -0
- package/app/config/config.dev.ts +10 -0
- package/app/config/config.prod.ts +10 -0
- package/app/config/index.ts +28 -0
- package/app/context/AuthContext.tsx +14 -0
- package/app/context/EpisodeContext.tsx +136 -0
- package/app/context/auth/AuthProvider.tsx +340 -0
- package/app/context/auth/hooks.ts +29 -0
- package/app/context/auth/index.ts +38 -0
- package/app/context/auth/reducer.ts +68 -0
- package/app/context/auth/services.ts +394 -0
- package/app/context/auth/types.ts +99 -0
- package/app/context/auth/validation.ts +45 -0
- package/app/devtools/ReactotronClient.ts +9 -0
- package/app/devtools/ReactotronClient.web.ts +12 -0
- package/app/devtools/ReactotronConfig.ts +139 -0
- package/app/i18n/ar.ts +126 -0
- package/app/i18n/demo-ar.ts +464 -0
- package/app/i18n/demo-en.ts +462 -0
- package/app/i18n/demo-es.ts +469 -0
- package/app/i18n/demo-fr.ts +471 -0
- package/app/i18n/demo-hi.ts +468 -0
- package/app/i18n/demo-ja.ts +464 -0
- package/app/i18n/demo-ko.ts +457 -0
- package/app/i18n/en.ts +146 -0
- package/app/i18n/es.ts +132 -0
- package/app/i18n/fr.ts +132 -0
- package/app/i18n/hi.ts +131 -0
- package/app/i18n/index.ts +86 -0
- package/app/i18n/ja.ts +130 -0
- package/app/i18n/ko.ts +129 -0
- package/app/i18n/translate.ts +33 -0
- package/app/lib/Parse/index.ts +2 -0
- package/app/lib/Parse/parse.ts +62 -0
- package/app/navigators/AppNavigator.tsx +145 -0
- package/app/navigators/DemoNavigator.tsx +137 -0
- package/app/navigators/navigationUtilities.ts +208 -0
- package/app/screens/ChooseAuthScreen.tsx +224 -0
- package/app/screens/DemoCommunityScreen.tsx +141 -0
- package/app/screens/DemoDebugScreen.tsx +192 -0
- package/app/screens/DemoPodcastListScreen.tsx +387 -0
- package/app/screens/DemoShowroomScreen/DemoDivider.tsx +66 -0
- package/app/screens/DemoShowroomScreen/DemoShowroomScreen.tsx +313 -0
- package/app/screens/DemoShowroomScreen/DemoUseCase.tsx +52 -0
- package/app/screens/DemoShowroomScreen/DrawerIconButton.tsx +120 -0
- package/app/screens/DemoShowroomScreen/SectionListWithKeyboardAwareScrollView.tsx +59 -0
- package/app/screens/DemoShowroomScreen/demos/DemoAutoImage.tsx +230 -0
- package/app/screens/DemoShowroomScreen/demos/DemoButton.tsx +234 -0
- package/app/screens/DemoShowroomScreen/demos/DemoCard.tsx +181 -0
- package/app/screens/DemoShowroomScreen/demos/DemoEmptyState.tsx +78 -0
- package/app/screens/DemoShowroomScreen/demos/DemoHeader.tsx +151 -0
- package/app/screens/DemoShowroomScreen/demos/DemoIcon.tsx +115 -0
- package/app/screens/DemoShowroomScreen/demos/DemoListItem.tsx +218 -0
- package/app/screens/DemoShowroomScreen/demos/DemoText.tsx +144 -0
- package/app/screens/DemoShowroomScreen/demos/DemoTextField.tsx +233 -0
- package/app/screens/DemoShowroomScreen/demos/DemoToggle.tsx +354 -0
- package/app/screens/DemoShowroomScreen/demos/index.ts +12 -0
- package/app/screens/ErrorScreen/ErrorBoundary.tsx +76 -0
- package/app/screens/ErrorScreen/ErrorDetails.tsx +98 -0
- package/app/screens/ForgetPasswordScreen.tsx +180 -0
- package/app/screens/LoginScreen.tsx +260 -0
- package/app/screens/RegisterScreen.tsx +395 -0
- package/app/screens/WelcomeScreen.tsx +114 -0
- package/app/services/api/apiProblem.test.ts +73 -0
- package/app/services/api/apiProblem.ts +74 -0
- package/app/services/api/index.ts +91 -0
- package/app/services/api/types.ts +50 -0
- package/app/theme/colors.ts +85 -0
- package/app/theme/colorsDark.ts +50 -0
- package/app/theme/context.tsx +145 -0
- package/app/theme/context.utils.ts +25 -0
- package/app/theme/spacing.ts +14 -0
- package/app/theme/spacingDark.ts +14 -0
- package/app/theme/styles.ts +24 -0
- package/app/theme/theme.ts +23 -0
- package/app/theme/timing.ts +6 -0
- package/app/theme/types.ts +64 -0
- package/app/theme/typography.ts +71 -0
- package/app/utils/crashReporting.ts +62 -0
- package/app/utils/delay.ts +6 -0
- package/app/utils/formatDate.ts +49 -0
- package/app/utils/gestureHandler.native.ts +3 -0
- package/app/utils/gestureHandler.ts +6 -0
- package/app/utils/hasValidStringProp.ts +11 -0
- package/app/utils/openLinkInBrowser.ts +8 -0
- package/app/utils/storage/index.ts +82 -0
- package/app/utils/storage/storage.test.ts +61 -0
- package/app/utils/useHeader.tsx +37 -0
- package/app/utils/useIsMounted.ts +18 -0
- package/app/utils/useSafeAreaInsetsStyle.ts +46 -0
- package/app.config.ts +39 -0
- package/app.json +67 -0
- package/assets/icons/back.png +0 -0
- package/assets/icons/back@2x.png +0 -0
- package/assets/icons/back@3x.png +0 -0
- package/assets/icons/bell.png +0 -0
- package/assets/icons/bell@2x.png +0 -0
- package/assets/icons/bell@3x.png +0 -0
- package/assets/icons/caretLeft.png +0 -0
- package/assets/icons/caretLeft@2x.png +0 -0
- package/assets/icons/caretLeft@3x.png +0 -0
- package/assets/icons/caretRight.png +0 -0
- package/assets/icons/caretRight@2x.png +0 -0
- package/assets/icons/caretRight@3x.png +0 -0
- package/assets/icons/check.png +0 -0
- package/assets/icons/check@2x.png +0 -0
- package/assets/icons/check@3x.png +0 -0
- package/assets/icons/demo/clap.png +0 -0
- package/assets/icons/demo/clap@2x.png +0 -0
- package/assets/icons/demo/clap@3x.png +0 -0
- package/assets/icons/demo/community.png +0 -0
- package/assets/icons/demo/community@2x.png +0 -0
- package/assets/icons/demo/community@3x.png +0 -0
- package/assets/icons/demo/components.png +0 -0
- package/assets/icons/demo/components@2x.png +0 -0
- package/assets/icons/demo/components@3x.png +0 -0
- package/assets/icons/demo/debug.png +0 -0
- package/assets/icons/demo/debug@2x.png +0 -0
- package/assets/icons/demo/debug@3x.png +0 -0
- package/assets/icons/demo/github.png +0 -0
- package/assets/icons/demo/github@2x.png +0 -0
- package/assets/icons/demo/github@3x.png +0 -0
- package/assets/icons/demo/heart.png +0 -0
- package/assets/icons/demo/heart@2x.png +0 -0
- package/assets/icons/demo/heart@3x.png +0 -0
- package/assets/icons/demo/pin.png +0 -0
- package/assets/icons/demo/pin@2x.png +0 -0
- package/assets/icons/demo/pin@3x.png +0 -0
- package/assets/icons/demo/podcast.png +0 -0
- package/assets/icons/demo/podcast@2x.png +0 -0
- package/assets/icons/demo/podcast@3x.png +0 -0
- package/assets/icons/demo/slack.png +0 -0
- package/assets/icons/demo/slack@2x.png +0 -0
- package/assets/icons/demo/slack@3x.png +0 -0
- package/assets/icons/google.png +0 -0
- package/assets/icons/hidden.png +0 -0
- package/assets/icons/hidden@2x.png +0 -0
- package/assets/icons/hidden@3x.png +0 -0
- package/assets/icons/ladybug.png +0 -0
- package/assets/icons/ladybug@2x.png +0 -0
- package/assets/icons/ladybug@3x.png +0 -0
- package/assets/icons/lock.png +0 -0
- package/assets/icons/lock@2x.png +0 -0
- package/assets/icons/lock@3x.png +0 -0
- package/assets/icons/menu.png +0 -0
- package/assets/icons/menu@2x.png +0 -0
- package/assets/icons/menu@3x.png +0 -0
- package/assets/icons/more.png +0 -0
- package/assets/icons/more@2x.png +0 -0
- package/assets/icons/more@3x.png +0 -0
- package/assets/icons/settings.png +0 -0
- package/assets/icons/settings@2x.png +0 -0
- package/assets/icons/settings@3x.png +0 -0
- package/assets/icons/view.png +0 -0
- package/assets/icons/view@2x.png +0 -0
- package/assets/icons/view@3x.png +0 -0
- package/assets/icons/x.png +0 -0
- package/assets/icons/x@2x.png +0 -0
- package/assets/icons/x@3x.png +0 -0
- package/assets/images/app-icon-all.png +0 -0
- package/assets/images/app-icon-android-adaptive-background.png +0 -0
- package/assets/images/app-icon-android-adaptive-foreground.png +0 -0
- package/assets/images/app-icon-android-legacy.png +0 -0
- package/assets/images/app-icon-ios.png +0 -0
- package/assets/images/app-icon-web-favicon.png +0 -0
- package/assets/images/demo/cr-logo.png +0 -0
- package/assets/images/demo/cr-logo@2x.png +0 -0
- package/assets/images/demo/cr-logo@3x.png +0 -0
- package/assets/images/demo/rnl-logo.png +0 -0
- package/assets/images/demo/rnl-logo@2x.png +0 -0
- package/assets/images/demo/rnl-logo@3x.png +0 -0
- package/assets/images/demo/rnn-logo.png +0 -0
- package/assets/images/demo/rnn-logo@2x.png +0 -0
- package/assets/images/demo/rnn-logo@3x.png +0 -0
- package/assets/images/demo/rnr-image-1.png +0 -0
- package/assets/images/demo/rnr-image-1@2x.png +0 -0
- package/assets/images/demo/rnr-image-1@3x.png +0 -0
- package/assets/images/demo/rnr-image-2.png +0 -0
- package/assets/images/demo/rnr-image-2@2x.png +0 -0
- package/assets/images/demo/rnr-image-2@3x.png +0 -0
- package/assets/images/demo/rnr-image-3.png +0 -0
- package/assets/images/demo/rnr-image-3@2x.png +0 -0
- package/assets/images/demo/rnr-image-3@3x.png +0 -0
- package/assets/images/demo/rnr-logo.png +0 -0
- package/assets/images/demo/rnr-logo@2x.png +0 -0
- package/assets/images/demo/rnr-logo@3x.png +0 -0
- package/assets/images/logo.png +0 -0
- package/assets/images/logo@2x.png +0 -0
- package/assets/images/logo@3x.png +0 -0
- package/assets/images/sad-face.png +0 -0
- package/assets/images/sad-face@2x.png +0 -0
- package/assets/images/sad-face@3x.png +0 -0
- package/assets/images/welcome-face.png +0 -0
- package/assets/images/welcome-face@2x.png +0 -0
- package/assets/images/welcome-face@3x.png +0 -0
- package/babel.config.js +7 -0
- package/bin/cli.js +196 -0
- package/ignite/templates/app-icon/android-adaptive-background.png +0 -0
- package/ignite/templates/app-icon/android-adaptive-foreground.png +0 -0
- package/ignite/templates/app-icon/android-legacy.png +0 -0
- package/ignite/templates/app-icon/ios-universal.png +0 -0
- package/ignite/templates/component/NAME.tsx.ejs +39 -0
- package/ignite/templates/navigator/NAMENavigator.tsx.ejs +18 -0
- package/ignite/templates/screen/NAMEScreen.tsx.ejs +29 -0
- package/ignite/templates/splash-screen/logo.png +0 -0
- package/index.tsx +9 -0
- package/jest.config.js +5 -0
- package/metro.config.js +31 -0
- package/package.json +166 -0
- package/plugins/withSplashScreen.ts +69 -0
- package/src/app/_layout.tsx +58 -0
- package/src/app/index.tsx +5 -0
- package/test/i18n.test.ts +75 -0
- package/test/mockFile.ts +6 -0
- package/test/setup.ts +58 -0
- package/test/test-tsconfig.json +8 -0
- package/tsconfig.json +52 -0
- 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
|
+
})
|