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,314 @@
|
|
|
1
|
+
import { ComponentType, Fragment, ReactElement } from "react"
|
|
2
|
+
import {
|
|
3
|
+
StyleProp,
|
|
4
|
+
TextStyle,
|
|
5
|
+
TouchableOpacity,
|
|
6
|
+
TouchableOpacityProps,
|
|
7
|
+
View,
|
|
8
|
+
ViewProps,
|
|
9
|
+
ViewStyle,
|
|
10
|
+
} from "react-native"
|
|
11
|
+
|
|
12
|
+
import type { ThemedStyle, ThemedStyleArray } from "@/theme/types"
|
|
13
|
+
import { useAppTheme } from "@/theme/context"
|
|
14
|
+
import { $styles } from "@/theme/styles"
|
|
15
|
+
|
|
16
|
+
import { Text, TextProps } from "./Text"
|
|
17
|
+
|
|
18
|
+
type Presets = "default" | "reversed"
|
|
19
|
+
|
|
20
|
+
interface CardProps extends TouchableOpacityProps {
|
|
21
|
+
/**
|
|
22
|
+
* One of the different types of text presets.
|
|
23
|
+
*/
|
|
24
|
+
preset?: Presets
|
|
25
|
+
/**
|
|
26
|
+
* How the content should be aligned vertically. This is especially (but not exclusively) useful
|
|
27
|
+
* when the card is a fixed height but the content is dynamic.
|
|
28
|
+
*
|
|
29
|
+
* `top` (default) - aligns all content to the top.
|
|
30
|
+
* `center` - aligns all content to the center.
|
|
31
|
+
* `space-between` - spreads out the content evenly.
|
|
32
|
+
* `force-footer-bottom` - aligns all content to the top, but forces the footer to the bottom.
|
|
33
|
+
*/
|
|
34
|
+
verticalAlignment?: "top" | "center" | "space-between" | "force-footer-bottom"
|
|
35
|
+
/**
|
|
36
|
+
* Custom component added to the left of the card body.
|
|
37
|
+
*/
|
|
38
|
+
LeftComponent?: ReactElement
|
|
39
|
+
/**
|
|
40
|
+
* Custom component added to the right of the card body.
|
|
41
|
+
*/
|
|
42
|
+
RightComponent?: ReactElement
|
|
43
|
+
/**
|
|
44
|
+
* The heading text to display if not using `headingTx`.
|
|
45
|
+
*/
|
|
46
|
+
heading?: TextProps["text"]
|
|
47
|
+
/**
|
|
48
|
+
* Heading text which is looked up via i18n.
|
|
49
|
+
*/
|
|
50
|
+
headingTx?: TextProps["tx"]
|
|
51
|
+
/**
|
|
52
|
+
* Optional heading options to pass to i18n. Useful for interpolation
|
|
53
|
+
* as well as explicitly setting locale or translation fallbacks.
|
|
54
|
+
*/
|
|
55
|
+
headingTxOptions?: TextProps["txOptions"]
|
|
56
|
+
/**
|
|
57
|
+
* Style overrides for heading text.
|
|
58
|
+
*/
|
|
59
|
+
headingStyle?: StyleProp<TextStyle>
|
|
60
|
+
/**
|
|
61
|
+
* Pass any additional props directly to the heading Text component.
|
|
62
|
+
*/
|
|
63
|
+
HeadingTextProps?: TextProps
|
|
64
|
+
/**
|
|
65
|
+
* Custom heading component.
|
|
66
|
+
* Overrides all other `heading*` props.
|
|
67
|
+
*/
|
|
68
|
+
HeadingComponent?: ReactElement
|
|
69
|
+
/**
|
|
70
|
+
* The content text to display if not using `contentTx`.
|
|
71
|
+
*/
|
|
72
|
+
content?: TextProps["text"]
|
|
73
|
+
/**
|
|
74
|
+
* Content text which is looked up via i18n.
|
|
75
|
+
*/
|
|
76
|
+
contentTx?: TextProps["tx"]
|
|
77
|
+
/**
|
|
78
|
+
* Optional content options to pass to i18n. Useful for interpolation
|
|
79
|
+
* as well as explicitly setting locale or translation fallbacks.
|
|
80
|
+
*/
|
|
81
|
+
contentTxOptions?: TextProps["txOptions"]
|
|
82
|
+
/**
|
|
83
|
+
* Style overrides for content text.
|
|
84
|
+
*/
|
|
85
|
+
contentStyle?: StyleProp<TextStyle>
|
|
86
|
+
/**
|
|
87
|
+
* Pass any additional props directly to the content Text component.
|
|
88
|
+
*/
|
|
89
|
+
ContentTextProps?: TextProps
|
|
90
|
+
/**
|
|
91
|
+
* Custom content component.
|
|
92
|
+
* Overrides all other `content*` props.
|
|
93
|
+
*/
|
|
94
|
+
ContentComponent?: ReactElement
|
|
95
|
+
/**
|
|
96
|
+
* The footer text to display if not using `footerTx`.
|
|
97
|
+
*/
|
|
98
|
+
footer?: TextProps["text"]
|
|
99
|
+
/**
|
|
100
|
+
* Footer text which is looked up via i18n.
|
|
101
|
+
*/
|
|
102
|
+
footerTx?: TextProps["tx"]
|
|
103
|
+
/**
|
|
104
|
+
* Optional footer options to pass to i18n. Useful for interpolation
|
|
105
|
+
* as well as explicitly setting locale or translation fallbacks.
|
|
106
|
+
*/
|
|
107
|
+
footerTxOptions?: TextProps["txOptions"]
|
|
108
|
+
/**
|
|
109
|
+
* Style overrides for footer text.
|
|
110
|
+
*/
|
|
111
|
+
footerStyle?: StyleProp<TextStyle>
|
|
112
|
+
/**
|
|
113
|
+
* Pass any additional props directly to the footer Text component.
|
|
114
|
+
*/
|
|
115
|
+
FooterTextProps?: TextProps
|
|
116
|
+
/**
|
|
117
|
+
* Custom footer component.
|
|
118
|
+
* Overrides all other `footer*` props.
|
|
119
|
+
*/
|
|
120
|
+
FooterComponent?: ReactElement
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Cards are useful for displaying related information in a contained way.
|
|
125
|
+
* If a ListItem displays content horizontally, a Card can be used to display content vertically.
|
|
126
|
+
* @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/Card/}
|
|
127
|
+
* @param {CardProps} props - The props for the `Card` component.
|
|
128
|
+
* @returns {JSX.Element} The rendered `Card` component.
|
|
129
|
+
*/
|
|
130
|
+
export function Card(props: CardProps) {
|
|
131
|
+
const {
|
|
132
|
+
content,
|
|
133
|
+
contentTx,
|
|
134
|
+
contentTxOptions,
|
|
135
|
+
footer,
|
|
136
|
+
footerTx,
|
|
137
|
+
footerTxOptions,
|
|
138
|
+
heading,
|
|
139
|
+
headingTx,
|
|
140
|
+
headingTxOptions,
|
|
141
|
+
ContentComponent,
|
|
142
|
+
HeadingComponent,
|
|
143
|
+
FooterComponent,
|
|
144
|
+
LeftComponent,
|
|
145
|
+
RightComponent,
|
|
146
|
+
verticalAlignment = "top",
|
|
147
|
+
style: $containerStyleOverride,
|
|
148
|
+
contentStyle: $contentStyleOverride,
|
|
149
|
+
headingStyle: $headingStyleOverride,
|
|
150
|
+
footerStyle: $footerStyleOverride,
|
|
151
|
+
ContentTextProps,
|
|
152
|
+
HeadingTextProps,
|
|
153
|
+
FooterTextProps,
|
|
154
|
+
...WrapperProps
|
|
155
|
+
} = props
|
|
156
|
+
|
|
157
|
+
const {
|
|
158
|
+
themed,
|
|
159
|
+
theme: { spacing },
|
|
160
|
+
} = useAppTheme()
|
|
161
|
+
|
|
162
|
+
const preset: Presets = props.preset ?? "default"
|
|
163
|
+
const isPressable = !!WrapperProps.onPress
|
|
164
|
+
const isHeadingPresent = !!(HeadingComponent || heading || headingTx)
|
|
165
|
+
const isContentPresent = !!(ContentComponent || content || contentTx)
|
|
166
|
+
const isFooterPresent = !!(FooterComponent || footer || footerTx)
|
|
167
|
+
|
|
168
|
+
const Wrapper = (isPressable ? TouchableOpacity : View) as ComponentType<
|
|
169
|
+
TouchableOpacityProps | ViewProps
|
|
170
|
+
>
|
|
171
|
+
const HeaderContentWrapper = verticalAlignment === "force-footer-bottom" ? View : Fragment
|
|
172
|
+
|
|
173
|
+
const $containerStyle: StyleProp<ViewStyle> = [
|
|
174
|
+
themed($containerPresets[preset]),
|
|
175
|
+
$containerStyleOverride,
|
|
176
|
+
]
|
|
177
|
+
const $headingStyle = [
|
|
178
|
+
themed($headingPresets[preset]),
|
|
179
|
+
(isFooterPresent || isContentPresent) && { marginBottom: spacing.xxxs },
|
|
180
|
+
$headingStyleOverride,
|
|
181
|
+
HeadingTextProps?.style,
|
|
182
|
+
]
|
|
183
|
+
const $contentStyle = [
|
|
184
|
+
themed($contentPresets[preset]),
|
|
185
|
+
isHeadingPresent && { marginTop: spacing.xxxs },
|
|
186
|
+
isFooterPresent && { marginBottom: spacing.xxxs },
|
|
187
|
+
$contentStyleOverride,
|
|
188
|
+
ContentTextProps?.style,
|
|
189
|
+
]
|
|
190
|
+
const $footerStyle = [
|
|
191
|
+
themed($footerPresets[preset]),
|
|
192
|
+
(isHeadingPresent || isContentPresent) && { marginTop: spacing.xxxs },
|
|
193
|
+
$footerStyleOverride,
|
|
194
|
+
FooterTextProps?.style,
|
|
195
|
+
]
|
|
196
|
+
const $alignmentWrapperStyle = [
|
|
197
|
+
$alignmentWrapper,
|
|
198
|
+
{ justifyContent: $alignmentWrapperFlexOptions[verticalAlignment] },
|
|
199
|
+
LeftComponent && { marginStart: spacing.md },
|
|
200
|
+
RightComponent && { marginEnd: spacing.md },
|
|
201
|
+
]
|
|
202
|
+
|
|
203
|
+
return (
|
|
204
|
+
<Wrapper
|
|
205
|
+
style={$containerStyle}
|
|
206
|
+
activeOpacity={0.8}
|
|
207
|
+
accessibilityRole={isPressable ? "button" : undefined}
|
|
208
|
+
{...WrapperProps}
|
|
209
|
+
>
|
|
210
|
+
{LeftComponent}
|
|
211
|
+
|
|
212
|
+
<View style={$alignmentWrapperStyle}>
|
|
213
|
+
<HeaderContentWrapper>
|
|
214
|
+
{HeadingComponent ||
|
|
215
|
+
(isHeadingPresent && (
|
|
216
|
+
<Text
|
|
217
|
+
weight="bold"
|
|
218
|
+
text={heading}
|
|
219
|
+
tx={headingTx}
|
|
220
|
+
txOptions={headingTxOptions}
|
|
221
|
+
{...HeadingTextProps}
|
|
222
|
+
style={$headingStyle}
|
|
223
|
+
/>
|
|
224
|
+
))}
|
|
225
|
+
|
|
226
|
+
{ContentComponent ||
|
|
227
|
+
(isContentPresent && (
|
|
228
|
+
<Text
|
|
229
|
+
weight="normal"
|
|
230
|
+
text={content}
|
|
231
|
+
tx={contentTx}
|
|
232
|
+
txOptions={contentTxOptions}
|
|
233
|
+
{...ContentTextProps}
|
|
234
|
+
style={$contentStyle}
|
|
235
|
+
/>
|
|
236
|
+
))}
|
|
237
|
+
</HeaderContentWrapper>
|
|
238
|
+
|
|
239
|
+
{FooterComponent ||
|
|
240
|
+
(isFooterPresent && (
|
|
241
|
+
<Text
|
|
242
|
+
weight="normal"
|
|
243
|
+
size="xs"
|
|
244
|
+
text={footer}
|
|
245
|
+
tx={footerTx}
|
|
246
|
+
txOptions={footerTxOptions}
|
|
247
|
+
{...FooterTextProps}
|
|
248
|
+
style={$footerStyle}
|
|
249
|
+
/>
|
|
250
|
+
))}
|
|
251
|
+
</View>
|
|
252
|
+
|
|
253
|
+
{RightComponent}
|
|
254
|
+
</Wrapper>
|
|
255
|
+
)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const $containerBase: ThemedStyle<ViewStyle> = (theme) => ({
|
|
259
|
+
borderRadius: theme.spacing.md,
|
|
260
|
+
padding: theme.spacing.xs,
|
|
261
|
+
borderWidth: 1,
|
|
262
|
+
shadowColor: theme.colors.palette.neutral800,
|
|
263
|
+
shadowOffset: { width: 0, height: 12 },
|
|
264
|
+
shadowOpacity: 0.08,
|
|
265
|
+
shadowRadius: 12.81,
|
|
266
|
+
elevation: 16,
|
|
267
|
+
minHeight: 96,
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
const $alignmentWrapper: ViewStyle = {
|
|
271
|
+
flex: 1,
|
|
272
|
+
alignSelf: "stretch",
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const $alignmentWrapperFlexOptions = {
|
|
276
|
+
"top": "flex-start",
|
|
277
|
+
"center": "center",
|
|
278
|
+
"space-between": "space-between",
|
|
279
|
+
"force-footer-bottom": "space-between",
|
|
280
|
+
} as const
|
|
281
|
+
|
|
282
|
+
const $containerPresets: Record<Presets, ThemedStyleArray<ViewStyle>> = {
|
|
283
|
+
default: [
|
|
284
|
+
$styles.row,
|
|
285
|
+
$containerBase,
|
|
286
|
+
(theme) => ({
|
|
287
|
+
backgroundColor: theme.colors.palette.neutral100,
|
|
288
|
+
borderColor: theme.colors.palette.neutral300,
|
|
289
|
+
}),
|
|
290
|
+
],
|
|
291
|
+
reversed: [
|
|
292
|
+
$styles.row,
|
|
293
|
+
$containerBase,
|
|
294
|
+
(theme) => ({
|
|
295
|
+
backgroundColor: theme.colors.palette.neutral800,
|
|
296
|
+
borderColor: theme.colors.palette.neutral500,
|
|
297
|
+
}),
|
|
298
|
+
],
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const $headingPresets: Record<Presets, ThemedStyleArray<TextStyle>> = {
|
|
302
|
+
default: [],
|
|
303
|
+
reversed: [(theme) => ({ color: theme.colors.palette.neutral100 })],
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const $contentPresets: Record<Presets, ThemedStyleArray<TextStyle>> = {
|
|
307
|
+
default: [],
|
|
308
|
+
reversed: [(theme) => ({ color: theme.colors.palette.neutral100 })],
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const $footerPresets: Record<Presets, ThemedStyleArray<TextStyle>> = {
|
|
312
|
+
default: [],
|
|
313
|
+
reversed: [(theme) => ({ color: theme.colors.palette.neutral100 })],
|
|
314
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { Image, ImageProps, ImageStyle, StyleProp, TextStyle, View, ViewStyle } from "react-native"
|
|
2
|
+
|
|
3
|
+
import { translate } from "@/i18n/translate"
|
|
4
|
+
import type { ThemedStyle } from "@/theme/types"
|
|
5
|
+
import { useAppTheme } from "@/theme/context"
|
|
6
|
+
|
|
7
|
+
import { Button, ButtonProps } from "./Button"
|
|
8
|
+
import { Text, TextProps } from "./Text"
|
|
9
|
+
|
|
10
|
+
const sadFace = require("@assets/images/sad-face.png")
|
|
11
|
+
|
|
12
|
+
interface EmptyStateProps {
|
|
13
|
+
/**
|
|
14
|
+
* An optional prop that specifies the text/image set to use for the empty state.
|
|
15
|
+
*/
|
|
16
|
+
preset?: "generic"
|
|
17
|
+
/**
|
|
18
|
+
* Style override for the container.
|
|
19
|
+
*/
|
|
20
|
+
style?: StyleProp<ViewStyle>
|
|
21
|
+
/**
|
|
22
|
+
* An Image source to be displayed above the heading.
|
|
23
|
+
*/
|
|
24
|
+
imageSource?: ImageProps["source"]
|
|
25
|
+
/**
|
|
26
|
+
* Style overrides for image.
|
|
27
|
+
*/
|
|
28
|
+
imageStyle?: StyleProp<ImageStyle>
|
|
29
|
+
/**
|
|
30
|
+
* Pass any additional props directly to the Image component.
|
|
31
|
+
*/
|
|
32
|
+
ImageProps?: Omit<ImageProps, "source">
|
|
33
|
+
/**
|
|
34
|
+
* The heading text to display if not using `headingTx`.
|
|
35
|
+
*/
|
|
36
|
+
heading?: TextProps["text"]
|
|
37
|
+
/**
|
|
38
|
+
* Heading text which is looked up via i18n.
|
|
39
|
+
*/
|
|
40
|
+
headingTx?: TextProps["tx"]
|
|
41
|
+
/**
|
|
42
|
+
* Optional heading options to pass to i18n. Useful for interpolation
|
|
43
|
+
* as well as explicitly setting locale or translation fallbacks.
|
|
44
|
+
*/
|
|
45
|
+
headingTxOptions?: TextProps["txOptions"]
|
|
46
|
+
/**
|
|
47
|
+
* Style overrides for heading text.
|
|
48
|
+
*/
|
|
49
|
+
headingStyle?: StyleProp<TextStyle>
|
|
50
|
+
/**
|
|
51
|
+
* Pass any additional props directly to the heading Text component.
|
|
52
|
+
*/
|
|
53
|
+
HeadingTextProps?: TextProps
|
|
54
|
+
/**
|
|
55
|
+
* The content text to display if not using `contentTx`.
|
|
56
|
+
*/
|
|
57
|
+
content?: TextProps["text"]
|
|
58
|
+
/**
|
|
59
|
+
* Content text which is looked up via i18n.
|
|
60
|
+
*/
|
|
61
|
+
contentTx?: TextProps["tx"]
|
|
62
|
+
/**
|
|
63
|
+
* Optional content options to pass to i18n. Useful for interpolation
|
|
64
|
+
* as well as explicitly setting locale or translation fallbacks.
|
|
65
|
+
*/
|
|
66
|
+
contentTxOptions?: TextProps["txOptions"]
|
|
67
|
+
/**
|
|
68
|
+
* Style overrides for content text.
|
|
69
|
+
*/
|
|
70
|
+
contentStyle?: StyleProp<TextStyle>
|
|
71
|
+
/**
|
|
72
|
+
* Pass any additional props directly to the content Text component.
|
|
73
|
+
*/
|
|
74
|
+
ContentTextProps?: TextProps
|
|
75
|
+
/**
|
|
76
|
+
* The button text to display if not using `buttonTx`.
|
|
77
|
+
*/
|
|
78
|
+
button?: TextProps["text"]
|
|
79
|
+
/**
|
|
80
|
+
* Button text which is looked up via i18n.
|
|
81
|
+
*/
|
|
82
|
+
buttonTx?: TextProps["tx"]
|
|
83
|
+
/**
|
|
84
|
+
* Optional button options to pass to i18n. Useful for interpolation
|
|
85
|
+
* as well as explicitly setting locale or translation fallbacks.
|
|
86
|
+
*/
|
|
87
|
+
buttonTxOptions?: TextProps["txOptions"]
|
|
88
|
+
/**
|
|
89
|
+
* Style overrides for button.
|
|
90
|
+
*/
|
|
91
|
+
buttonStyle?: ButtonProps["style"]
|
|
92
|
+
/**
|
|
93
|
+
* Style overrides for button text.
|
|
94
|
+
*/
|
|
95
|
+
buttonTextStyle?: ButtonProps["textStyle"]
|
|
96
|
+
/**
|
|
97
|
+
* Called when the button is pressed.
|
|
98
|
+
*/
|
|
99
|
+
buttonOnPress?: ButtonProps["onPress"]
|
|
100
|
+
/**
|
|
101
|
+
* Pass any additional props directly to the Button component.
|
|
102
|
+
*/
|
|
103
|
+
ButtonProps?: ButtonProps
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
interface EmptyStatePresetItem {
|
|
107
|
+
imageSource: ImageProps["source"]
|
|
108
|
+
heading: TextProps["text"]
|
|
109
|
+
content: TextProps["text"]
|
|
110
|
+
button: TextProps["text"]
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* A component to use when there is no data to display. It can be utilized to direct the user what to do next.
|
|
115
|
+
* @see [Documentation and Examples]{@link https://docs.infinite.red/ignite-cli/boilerplate/app/components/EmptyState/}
|
|
116
|
+
* @param {EmptyStateProps} props - The props for the `EmptyState` component.
|
|
117
|
+
* @returns {JSX.Element} The rendered `EmptyState` component.
|
|
118
|
+
*/
|
|
119
|
+
export function EmptyState(props: EmptyStateProps) {
|
|
120
|
+
const {
|
|
121
|
+
theme,
|
|
122
|
+
themed,
|
|
123
|
+
theme: { spacing },
|
|
124
|
+
} = useAppTheme()
|
|
125
|
+
|
|
126
|
+
const EmptyStatePresets = {
|
|
127
|
+
generic: {
|
|
128
|
+
imageSource: sadFace,
|
|
129
|
+
heading: translate("emptyStateComponent:generic.heading"),
|
|
130
|
+
content: translate("emptyStateComponent:generic.content"),
|
|
131
|
+
button: translate("emptyStateComponent:generic.button"),
|
|
132
|
+
} as EmptyStatePresetItem,
|
|
133
|
+
} as const
|
|
134
|
+
|
|
135
|
+
const preset = EmptyStatePresets[props.preset ?? "generic"]
|
|
136
|
+
|
|
137
|
+
const {
|
|
138
|
+
button = preset.button,
|
|
139
|
+
buttonTx,
|
|
140
|
+
buttonOnPress,
|
|
141
|
+
buttonTxOptions,
|
|
142
|
+
content = preset.content,
|
|
143
|
+
contentTx,
|
|
144
|
+
contentTxOptions,
|
|
145
|
+
heading = preset.heading,
|
|
146
|
+
headingTx,
|
|
147
|
+
headingTxOptions,
|
|
148
|
+
imageSource = preset.imageSource,
|
|
149
|
+
style: $containerStyleOverride,
|
|
150
|
+
buttonStyle: $buttonStyleOverride,
|
|
151
|
+
buttonTextStyle: $buttonTextStyleOverride,
|
|
152
|
+
contentStyle: $contentStyleOverride,
|
|
153
|
+
headingStyle: $headingStyleOverride,
|
|
154
|
+
imageStyle: $imageStyleOverride,
|
|
155
|
+
ButtonProps,
|
|
156
|
+
ContentTextProps,
|
|
157
|
+
HeadingTextProps,
|
|
158
|
+
ImageProps,
|
|
159
|
+
} = props
|
|
160
|
+
|
|
161
|
+
const isImagePresent = !!imageSource
|
|
162
|
+
const isHeadingPresent = !!(heading || headingTx)
|
|
163
|
+
const isContentPresent = !!(content || contentTx)
|
|
164
|
+
const isButtonPresent = !!(button || buttonTx)
|
|
165
|
+
|
|
166
|
+
const $containerStyles = [$containerStyleOverride]
|
|
167
|
+
const $imageStyles = [
|
|
168
|
+
$image,
|
|
169
|
+
(isHeadingPresent || isContentPresent || isButtonPresent) && { marginBottom: spacing.xxxs },
|
|
170
|
+
$imageStyleOverride,
|
|
171
|
+
ImageProps?.style,
|
|
172
|
+
]
|
|
173
|
+
const $headingStyles = [
|
|
174
|
+
themed($heading),
|
|
175
|
+
isImagePresent && { marginTop: spacing.xxxs },
|
|
176
|
+
(isContentPresent || isButtonPresent) && { marginBottom: spacing.xxxs },
|
|
177
|
+
$headingStyleOverride,
|
|
178
|
+
HeadingTextProps?.style,
|
|
179
|
+
]
|
|
180
|
+
const $contentStyles = [
|
|
181
|
+
themed($content),
|
|
182
|
+
(isImagePresent || isHeadingPresent) && { marginTop: spacing.xxxs },
|
|
183
|
+
isButtonPresent && { marginBottom: spacing.xxxs },
|
|
184
|
+
$contentStyleOverride,
|
|
185
|
+
ContentTextProps?.style,
|
|
186
|
+
]
|
|
187
|
+
const $buttonStyles = [
|
|
188
|
+
(isImagePresent || isHeadingPresent || isContentPresent) && { marginTop: spacing.xl },
|
|
189
|
+
$buttonStyleOverride,
|
|
190
|
+
ButtonProps?.style,
|
|
191
|
+
]
|
|
192
|
+
|
|
193
|
+
return (
|
|
194
|
+
<View style={$containerStyles}>
|
|
195
|
+
{isImagePresent && (
|
|
196
|
+
<Image
|
|
197
|
+
source={imageSource}
|
|
198
|
+
{...ImageProps}
|
|
199
|
+
style={$imageStyles}
|
|
200
|
+
tintColor={theme.colors.palette.neutral900}
|
|
201
|
+
/>
|
|
202
|
+
)}
|
|
203
|
+
|
|
204
|
+
{isHeadingPresent && (
|
|
205
|
+
<Text
|
|
206
|
+
preset="subheading"
|
|
207
|
+
text={heading}
|
|
208
|
+
tx={headingTx}
|
|
209
|
+
txOptions={headingTxOptions}
|
|
210
|
+
{...HeadingTextProps}
|
|
211
|
+
style={$headingStyles}
|
|
212
|
+
/>
|
|
213
|
+
)}
|
|
214
|
+
|
|
215
|
+
{isContentPresent && (
|
|
216
|
+
<Text
|
|
217
|
+
text={content}
|
|
218
|
+
tx={contentTx}
|
|
219
|
+
txOptions={contentTxOptions}
|
|
220
|
+
{...ContentTextProps}
|
|
221
|
+
style={$contentStyles}
|
|
222
|
+
/>
|
|
223
|
+
)}
|
|
224
|
+
|
|
225
|
+
{isButtonPresent && (
|
|
226
|
+
<Button
|
|
227
|
+
onPress={buttonOnPress}
|
|
228
|
+
text={button}
|
|
229
|
+
tx={buttonTx}
|
|
230
|
+
txOptions={buttonTxOptions}
|
|
231
|
+
textStyle={$buttonTextStyleOverride}
|
|
232
|
+
{...ButtonProps}
|
|
233
|
+
style={$buttonStyles}
|
|
234
|
+
/>
|
|
235
|
+
)}
|
|
236
|
+
</View>
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const $image: ImageStyle = { alignSelf: "center" }
|
|
241
|
+
const $heading: ThemedStyle<TextStyle> = ({ spacing }) => ({
|
|
242
|
+
textAlign: "center",
|
|
243
|
+
paddingHorizontal: spacing.lg,
|
|
244
|
+
})
|
|
245
|
+
const $content: ThemedStyle<TextStyle> = ({ spacing }) => ({
|
|
246
|
+
textAlign: "center",
|
|
247
|
+
paddingHorizontal: spacing.lg,
|
|
248
|
+
})
|