@umituz/react-native-splash 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/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ümit UZ
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # @umituz/react-native-splash
2
+
3
+ Generic splash screen for React Native apps with animations, gradients, and customizable branding. Follows SOLID, DRY, KISS principles - fully reusable across hundreds of apps.
4
+
5
+ ## Features
6
+
7
+ - ✅ **Generic & Reusable**: Works with any app, fully customizable via props
8
+ - ✅ **Animations**: Smooth fade, scale, and slide animations
9
+ - ✅ **Gradient Backgrounds**: Support for gradient or solid colors
10
+ - ✅ **Customizable Branding**: Logo, app name, tagline, footer
11
+ - ✅ **Loading Indicators**: Progress bar and loading text
12
+ - ✅ **SOLID Principles**: Clean architecture, easy to extend
13
+ - ✅ **DRY**: No code duplication, generic components
14
+ - ✅ **KISS**: Simple API, easy to understand and use
15
+ - ✅ **Type-Safe**: Full TypeScript support
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @umituz/react-native-splash
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ### Basic Example
26
+
27
+ ```typescript
28
+ import { SplashScreen } from '@umituz/react-native-splash';
29
+
30
+ <SplashScreen
31
+ appName="My App"
32
+ tagline="Your tagline here"
33
+ logo="Sparkles"
34
+ onReady={() => {
35
+ // Navigate to main app
36
+ }}
37
+ />
38
+ ```
39
+
40
+ ### Advanced Example
41
+
42
+ ```typescript
43
+ <SplashScreen
44
+ appName="My App"
45
+ tagline="Your tagline here"
46
+ logo="Sparkles"
47
+ backgroundColor="#3B82F6"
48
+ gradientColors={['#3B82F6', '#8B5CF6']}
49
+ loadingText="Loading..."
50
+ showLoading={true}
51
+ showProgressBar={true}
52
+ footerText="Powered by"
53
+ versionText="v1.0.0"
54
+ animationDuration={2000}
55
+ minimumDisplayTime={1500}
56
+ onReady={handleReady}
57
+ />
58
+ ```
59
+
60
+ ### Custom Render Functions
61
+
62
+ ```typescript
63
+ <SplashScreen
64
+ appName="My App"
65
+ renderLogo={() => <CustomLogo />}
66
+ renderContent={() => <CustomContent />}
67
+ renderFooter={() => <CustomFooter />}
68
+ onReady={handleReady}
69
+ />
70
+ ```
71
+
72
+ ## API Reference
73
+
74
+ ### `SplashOptions`
75
+
76
+ ```typescript
77
+ interface SplashOptions {
78
+ appName?: string;
79
+ tagline?: string;
80
+ logo?: ReactNode | string;
81
+ backgroundColor?: string;
82
+ gradientColors?: string[];
83
+ loadingText?: string;
84
+ showLoading?: boolean;
85
+ showProgressBar?: boolean;
86
+ footerText?: string;
87
+ versionText?: string;
88
+ animationDuration?: number;
89
+ minimumDisplayTime?: number;
90
+ onReady?: () => void | Promise<void>;
91
+ renderLogo?: () => ReactNode;
92
+ renderContent?: () => ReactNode;
93
+ renderFooter?: () => ReactNode;
94
+ }
95
+ ```
96
+
97
+ ## Architecture
98
+
99
+ - **Domain Layer**: Entities and interfaces (business logic)
100
+ - **Presentation Layer**: Components (UI)
101
+
102
+ No app-specific code, fully generic and reusable.
103
+
104
+ ## License
105
+
106
+ MIT
107
+
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@umituz/react-native-splash",
3
+ "version": "1.0.0",
4
+ "description": "Generic splash screen for React Native apps with animations, gradients, and customizable branding. SOLID, DRY, KISS principles applied.",
5
+ "main": "./src/index.ts",
6
+ "types": "./src/index.ts",
7
+ "scripts": {
8
+ "typecheck": "tsc --noEmit",
9
+ "lint": "tsc --noEmit",
10
+ "version:patch": "npm version patch -m 'chore: release v%s'",
11
+ "version:minor": "npm version minor -m 'chore: release v%s'",
12
+ "version:major": "npm version major -m 'chore: release v%s'"
13
+ },
14
+ "keywords": [
15
+ "react-native",
16
+ "splash",
17
+ "splash-screen",
18
+ "loading",
19
+ "animation",
20
+ "gradient",
21
+ "ddd",
22
+ "domain-driven-design",
23
+ "solid",
24
+ "dry",
25
+ "kiss"
26
+ ],
27
+ "author": "Ümit UZ <umit@umituz.com>",
28
+ "license": "MIT",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/umituz/react-native-splash"
32
+ },
33
+ "peerDependencies": {
34
+ "@umituz/react-native-theme": "latest",
35
+ "@umituz/react-native-localization": "latest",
36
+ "@umituz/react-native-design-system": "latest",
37
+ "react": ">=18.2.0",
38
+ "react-native": ">=0.74.0",
39
+ "react-native-safe-area-context": "^5.0.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/react": "^18.2.45",
43
+ "@types/react-native": "^0.73.0",
44
+ "@umituz/react-native-theme": "latest",
45
+ "@umituz/react-native-localization": "latest",
46
+ "@umituz/react-native-design-system": "latest",
47
+ "react": "^18.2.0",
48
+ "react-native": "^0.74.0",
49
+ "react-native-safe-area-context": "^5.6.0",
50
+ "typescript": "^5.3.3"
51
+ },
52
+ "publishConfig": {
53
+ "access": "public"
54
+ },
55
+ "files": [
56
+ "src",
57
+ "README.md",
58
+ "LICENSE"
59
+ ]
60
+ }
61
+
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Splash Options
3
+ *
4
+ * Configuration options for splash screen
5
+ */
6
+
7
+ import { ReactNode } from "react";
8
+
9
+ /**
10
+ * Splash Options
11
+ * Customize the splash screen experience
12
+ */
13
+ export interface SplashOptions {
14
+ /**
15
+ * App name to display
16
+ */
17
+ appName?: string;
18
+
19
+ /**
20
+ * Tagline or subtitle
21
+ */
22
+ tagline?: string;
23
+
24
+ /**
25
+ * Logo/icon component or name
26
+ */
27
+ logo?: ReactNode | string;
28
+
29
+ /**
30
+ * Background color or gradient colors
31
+ */
32
+ backgroundColor?: string;
33
+ gradientColors?: string[];
34
+
35
+ /**
36
+ * Loading text
37
+ */
38
+ loadingText?: string;
39
+
40
+ /**
41
+ * Show loading indicator (default: true)
42
+ */
43
+ showLoading?: boolean;
44
+
45
+ /**
46
+ * Show progress bar (default: true)
47
+ */
48
+ showProgressBar?: boolean;
49
+
50
+ /**
51
+ * Footer text (e.g., "Powered by...")
52
+ */
53
+ footerText?: string;
54
+
55
+ /**
56
+ * Version text
57
+ */
58
+ versionText?: string;
59
+
60
+ /**
61
+ * Animation duration in milliseconds (default: 2000)
62
+ */
63
+ animationDuration?: number;
64
+
65
+ /**
66
+ * Minimum display time in milliseconds (default: 1500)
67
+ */
68
+ minimumDisplayTime?: number;
69
+
70
+ /**
71
+ * Callback when splash is ready to hide
72
+ */
73
+ onReady?: () => void | Promise<void>;
74
+
75
+ /**
76
+ * Custom render functions
77
+ */
78
+ renderLogo?: () => ReactNode;
79
+ renderContent?: () => ReactNode;
80
+ renderFooter?: () => ReactNode;
81
+ }
82
+
package/src/index.ts ADDED
@@ -0,0 +1,29 @@
1
+ /**
2
+ * React Native Splash - Public API
3
+ *
4
+ * Generic splash screen for React Native apps with animations, gradients,
5
+ * and customizable branding. Follows SOLID, DRY, KISS principles.
6
+ *
7
+ * Usage:
8
+ * import { SplashScreen } from '@umituz/react-native-splash';
9
+ *
10
+ * <SplashScreen
11
+ * appName="My App"
12
+ * tagline="Your tagline here"
13
+ * logo="Sparkles"
14
+ * onReady={() => console.log('Ready')}
15
+ * />
16
+ */
17
+
18
+ // =============================================================================
19
+ // DOMAIN LAYER - Entities
20
+ // =============================================================================
21
+
22
+ export type { SplashOptions } from "./domain/entities/SplashOptions";
23
+
24
+ // =============================================================================
25
+ // PRESENTATION LAYER - Components
26
+ // =============================================================================
27
+
28
+ export { SplashScreen, type SplashScreenProps } from "./presentation/components/SplashScreen";
29
+
@@ -0,0 +1,322 @@
1
+ /**
2
+ * Splash Screen Component
3
+ *
4
+ * Generic splash screen with animations, gradients, and customizable branding
5
+ */
6
+
7
+ import React, { useEffect, useRef, useMemo } from "react";
8
+ import { View, StyleSheet, Animated } from "react-native";
9
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
10
+ import { useAppDesignTokens } from "@umituz/react-native-theme";
11
+ import { useLocalization } from "@umituz/react-native-localization";
12
+ import { useResponsive, AtomicIcon, AtomicText, STATIC_TOKENS, withAlpha } from "@umituz/react-native-design-system";
13
+ import type { SplashOptions } from "../../domain/entities/SplashOptions";
14
+
15
+ export interface SplashScreenProps extends SplashOptions {
16
+ /**
17
+ * Whether splash is visible
18
+ */
19
+ visible?: boolean;
20
+ }
21
+
22
+ /**
23
+ * Splash Screen Component
24
+ */
25
+ export const SplashScreen: React.FC<SplashScreenProps> = ({
26
+ appName,
27
+ tagline,
28
+ logo,
29
+ backgroundColor,
30
+ gradientColors,
31
+ loadingText,
32
+ showLoading = true,
33
+ showProgressBar = true,
34
+ footerText,
35
+ versionText,
36
+ animationDuration = 2000,
37
+ minimumDisplayTime = 1500,
38
+ onReady,
39
+ renderLogo,
40
+ renderContent,
41
+ renderFooter,
42
+ visible = true,
43
+ }) => {
44
+ const tokens = useAppDesignTokens();
45
+ const responsive = useResponsive();
46
+ const insets = useSafeAreaInsets();
47
+ const { t } = useLocalization();
48
+ const styles = useMemo(
49
+ () => getStyles(tokens, responsive, insets, backgroundColor, gradientColors),
50
+ [tokens, responsive, insets, backgroundColor, gradientColors],
51
+ );
52
+
53
+ // Animation values
54
+ const fadeAnim = useRef(new Animated.Value(0)).current;
55
+ const scaleAnim = useRef(new Animated.Value(0.8)).current;
56
+ const slideAnim = useRef(new Animated.Value(50)).current;
57
+
58
+ /**
59
+ * Initialize animations
60
+ */
61
+ useEffect(() => {
62
+ if (!visible) return;
63
+
64
+ // Start entrance animations
65
+ Animated.parallel([
66
+ Animated.timing(fadeAnim, {
67
+ toValue: 1,
68
+ duration: 1000,
69
+ useNativeDriver: true,
70
+ }),
71
+ Animated.spring(scaleAnim, {
72
+ toValue: 1,
73
+ tension: 100,
74
+ friction: 8,
75
+ useNativeDriver: true,
76
+ }),
77
+ Animated.timing(slideAnim, {
78
+ toValue: 0,
79
+ duration: 800,
80
+ useNativeDriver: true,
81
+ }),
82
+ ]).start();
83
+
84
+ // Call onReady after minimum display time
85
+ const timer = setTimeout(() => {
86
+ if (onReady) {
87
+ onReady();
88
+ }
89
+ }, Math.max(minimumDisplayTime, animationDuration));
90
+
91
+ return () => clearTimeout(timer);
92
+ }, [visible, fadeAnim, scaleAnim, slideAnim, minimumDisplayTime, animationDuration, onReady]);
93
+
94
+ if (!visible) return null;
95
+
96
+ const displayAppName = appName || t("branding.appName", "App Name");
97
+ const displayTagline = tagline || t("branding.tagline", "Your tagline here");
98
+ const displayLoadingText = loadingText || t("general.loading", "Loading...");
99
+ const displayFooterText = footerText || t("branding.poweredBy", "Powered by");
100
+ const displayVersionText = versionText;
101
+
102
+ return (
103
+ <View style={styles.container}>
104
+ {/* Background Gradient Effect */}
105
+ {gradientColors && gradientColors.length > 0 ? (
106
+ <View style={[styles.backgroundGradient, { backgroundColor: gradientColors[0] }]} />
107
+ ) : (
108
+ <View style={[styles.backgroundGradient, { backgroundColor: backgroundColor || tokens.colors.primary }]} />
109
+ )}
110
+
111
+ {/* Main Content */}
112
+ <Animated.View
113
+ style={[
114
+ styles.content,
115
+ {
116
+ opacity: fadeAnim,
117
+ transform: [{ scale: scaleAnim }],
118
+ },
119
+ ]}
120
+ >
121
+ {renderLogo ? (
122
+ renderLogo()
123
+ ) : (
124
+ <View style={styles.logoContainer}>
125
+ <Animated.View
126
+ style={[
127
+ styles.logoBackground,
128
+ {
129
+ transform: [{ scale: scaleAnim }],
130
+ },
131
+ ]}
132
+ >
133
+ {typeof logo === "string" ? (
134
+ <AtomicIcon name={logo || "Sparkles"} size="xl" color="primary" />
135
+ ) : logo ? (
136
+ logo
137
+ ) : (
138
+ <AtomicIcon name="Sparkles" size="xl" color="primary" />
139
+ )}
140
+ </Animated.View>
141
+ </View>
142
+ )}
143
+
144
+ {renderContent ? (
145
+ renderContent()
146
+ ) : (
147
+ <Animated.View
148
+ style={[
149
+ styles.textContainer,
150
+ {
151
+ opacity: fadeAnim,
152
+ transform: [{ translateY: slideAnim }],
153
+ },
154
+ ]}
155
+ >
156
+ <AtomicText style={styles.appName}>{displayAppName}</AtomicText>
157
+ <AtomicText style={styles.tagline}>{displayTagline}</AtomicText>
158
+ </Animated.View>
159
+ )}
160
+ </Animated.View>
161
+
162
+ {/* Loading Indicator */}
163
+ {showLoading && (
164
+ <Animated.View
165
+ style={[
166
+ styles.loadingContainer,
167
+ {
168
+ opacity: fadeAnim,
169
+ },
170
+ ]}
171
+ >
172
+ {showProgressBar && (
173
+ <View style={styles.loadingBar}>
174
+ <Animated.View
175
+ style={[
176
+ styles.loadingProgress,
177
+ {
178
+ transform: [{ scaleX: scaleAnim }],
179
+ },
180
+ ]}
181
+ />
182
+ </View>
183
+ )}
184
+ <AtomicText style={styles.loadingText}>{displayLoadingText}</AtomicText>
185
+ </Animated.View>
186
+ )}
187
+
188
+ {/* Footer */}
189
+ {renderFooter ? (
190
+ renderFooter()
191
+ ) : (
192
+ <Animated.View
193
+ style={[
194
+ styles.footer,
195
+ {
196
+ opacity: fadeAnim,
197
+ },
198
+ ]}
199
+ >
200
+ {displayFooterText && (
201
+ <AtomicText style={styles.footerText}>{displayFooterText}</AtomicText>
202
+ )}
203
+ {displayVersionText && (
204
+ <AtomicText style={styles.versionText}>{displayVersionText}</AtomicText>
205
+ )}
206
+ </Animated.View>
207
+ )}
208
+ </View>
209
+ );
210
+ };
211
+
212
+ const getStyles = (
213
+ tokens: ReturnType<typeof useAppDesignTokens>,
214
+ responsive: ReturnType<typeof useResponsive>,
215
+ insets: { top: number; bottom: number },
216
+ backgroundColor?: string,
217
+ gradientColors?: string[],
218
+ ) =>
219
+ StyleSheet.create({
220
+ container: {
221
+ flex: 1,
222
+ backgroundColor: backgroundColor || tokens.colors.primary,
223
+ paddingHorizontal: responsive.horizontalPadding,
224
+ paddingTop: insets.top,
225
+ paddingBottom: insets.bottom,
226
+ },
227
+ backgroundGradient: {
228
+ position: "absolute",
229
+ top: 0,
230
+ left: 0,
231
+ right: 0,
232
+ bottom: 0,
233
+ opacity: 0.9,
234
+ },
235
+ content: {
236
+ flex: 3,
237
+ alignItems: "center",
238
+ justifyContent: "center",
239
+ paddingHorizontal: tokens.spacing.lg,
240
+ },
241
+ logoContainer: {
242
+ marginBottom: tokens.spacing.xxl * 2,
243
+ alignItems: "center",
244
+ justifyContent: "center",
245
+ },
246
+ logoBackground: {
247
+ width: responsive.logoSize,
248
+ height: responsive.logoSize,
249
+ borderRadius: STATIC_TOKENS.borders.radius.full,
250
+ backgroundColor: tokens.colors.surface,
251
+ alignItems: "center",
252
+ justifyContent: "center",
253
+ padding: STATIC_TOKENS.spacing.md,
254
+ },
255
+ textContainer: {
256
+ alignItems: "center",
257
+ marginBottom: tokens.spacing.xxl * 2,
258
+ },
259
+ appName: {
260
+ ...STATIC_TOKENS.typography.headingLarge,
261
+ color: tokens.colors.textInverse,
262
+ textAlign: "center",
263
+ marginBottom: tokens.spacing.md,
264
+ fontSize: responsive.getFontSize(STATIC_TOKENS.typography.headingLarge.fontSize ?? 32),
265
+ fontWeight: STATIC_TOKENS.typography.bold,
266
+ },
267
+ tagline: {
268
+ ...STATIC_TOKENS.typography.bodyLarge,
269
+ color: tokens.colors.textInverse,
270
+ textAlign: "center",
271
+ opacity: 0.9,
272
+ maxWidth: responsive.maxContentWidth,
273
+ fontSize: responsive.getFontSize(STATIC_TOKENS.typography.bodyLarge.fontSize ?? 18),
274
+ },
275
+ loadingContainer: {
276
+ flex: 1,
277
+ alignItems: "center",
278
+ justifyContent: "center",
279
+ width: responsive.maxContentWidth,
280
+ alignSelf: "center",
281
+ },
282
+ loadingBar: {
283
+ width: "100%",
284
+ height: 4,
285
+ backgroundColor: withAlpha(tokens.colors.textInverse, 0.3),
286
+ borderRadius: STATIC_TOKENS.borders.radius.xs,
287
+ marginBottom: tokens.spacing.md,
288
+ overflow: "hidden",
289
+ },
290
+ loadingProgress: {
291
+ width: "100%",
292
+ height: "100%",
293
+ backgroundColor: tokens.colors.textInverse,
294
+ borderRadius: STATIC_TOKENS.borders.radius.xs,
295
+ },
296
+ loadingText: {
297
+ ...STATIC_TOKENS.typography.bodyMedium,
298
+ color: tokens.colors.textInverse,
299
+ opacity: 0.8,
300
+ fontSize: responsive.getFontSize(STATIC_TOKENS.typography.bodyMedium.fontSize ?? 16),
301
+ },
302
+ footer: {
303
+ flex: 0.5,
304
+ alignItems: "center",
305
+ justifyContent: "flex-start",
306
+ paddingBottom: tokens.spacing.md,
307
+ },
308
+ footerText: {
309
+ ...STATIC_TOKENS.typography.caption,
310
+ color: tokens.colors.textInverse,
311
+ opacity: 0.7,
312
+ marginBottom: tokens.spacing.xs,
313
+ fontSize: responsive.getFontSize(STATIC_TOKENS.typography.caption.fontSize ?? 12),
314
+ },
315
+ versionText: {
316
+ ...STATIC_TOKENS.typography.caption,
317
+ color: tokens.colors.textInverse,
318
+ opacity: 0.5,
319
+ fontSize: responsive.getFontSize(STATIC_TOKENS.typography.caption.fontSize ?? 12),
320
+ },
321
+ });
322
+