@umituz/react-native-splash 1.12.0 → 2.1.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@umituz/react-native-splash",
3
- "version": "1.12.0",
4
- "description": "Generic splash screen for React Native apps with animations, gradients, and customizable branding. SOLID, DRY, KISS principles applied.",
3
+ "version": "2.1.0",
4
+ "description": "Ultra minimal splash screen for React Native apps. Just icon, name, and tagline.",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
7
7
  "scripts": {
@@ -13,13 +13,7 @@
13
13
  "splash",
14
14
  "splash-screen",
15
15
  "loading",
16
- "animation",
17
- "gradient",
18
- "ddd",
19
- "domain-driven-design",
20
- "solid",
21
- "dry",
22
- "kiss"
16
+ "minimal"
23
17
  ],
24
18
  "author": "Ümit UZ <umit@umituz.com>",
25
19
  "license": "MIT",
@@ -37,7 +31,6 @@
37
31
  "@types/node": "^20.0.0",
38
32
  "@types/react": "~19.1.0",
39
33
  "@types/react-native": "^0.73.0",
40
- "expo-linear-gradient": "^14.0.0",
41
34
  "react": "^19.0.0",
42
35
  "react-native": "^0.76.0",
43
36
  "react-native-safe-area-context": "^5.0.0",
@@ -1,36 +1,28 @@
1
1
  /**
2
- * Splash Options - Minimal Configuration
2
+ * Splash Options - Ultra Minimal Configuration
3
3
  */
4
4
 
5
- import { ReactNode } from "react";
5
+ import type { ImageSourcePropType } from "react-native";
6
6
 
7
7
  export interface SplashOptions {
8
+ /** App icon/logo image source */
9
+ icon?: ImageSourcePropType;
10
+
8
11
  /** App name to display */
9
12
  appName?: string;
10
13
 
11
14
  /** Tagline or subtitle */
12
15
  tagline?: string;
13
16
 
14
- /** Background color */
17
+ /** Background color (default: #6366F1) */
15
18
  backgroundColor?: string;
16
19
 
17
- /** Custom gradient colors (overrides backgroundColor) */
18
- gradientColors?: readonly string[];
20
+ /** Gradient colors - if provided, overrides backgroundColor */
21
+ gradientColors?: readonly [string, string, ...string[]];
19
22
 
20
- /** Loading text */
21
- loadingText?: string;
23
+ /** Text color (default: #FFFFFF) */
24
+ textColor?: string;
22
25
 
23
26
  /** Show loading indicator (default: true) */
24
27
  showLoading?: boolean;
25
-
26
- /** Minimum display time in ms (default: 1500) */
27
- minimumDisplayTime?: number;
28
-
29
- /** Callback when splash is ready */
30
- onReady?: () => void | Promise<void>;
31
-
32
- /** Custom render functions */
33
- renderLogo?: () => ReactNode;
34
- renderContent?: () => ReactNode;
35
- renderFooter?: () => ReactNode;
36
28
  }
package/src/index.ts CHANGED
@@ -1,30 +1,31 @@
1
1
  /**
2
2
  * React Native Splash - Public API
3
3
  *
4
- * Generic splash screen for React Native apps with animations, gradients,
5
- * and customizable branding. Follows SOLID, DRY, KISS principles.
4
+ * Ultra minimal splash screen for React Native apps.
5
+ * Just displays icon, app name, and tagline.
6
+ * Parent component controls visibility and timing.
6
7
  *
7
8
  * Usage:
8
9
  * import { SplashScreen } from '@umituz/react-native-splash';
9
10
  *
10
- * <SplashScreen
11
- * appName="My App"
12
- * tagline="Your tagline here"
13
- * logo="Sparkles"
14
- * onReady={() => console.log('Ready')}
15
- * />
11
+ * // In your app:
12
+ * const [showSplash, setShowSplash] = useState(true);
13
+ *
14
+ * useEffect(() => {
15
+ * // Your initialization logic
16
+ * initializeApp().then(() => setShowSplash(false));
17
+ * }, []);
18
+ *
19
+ * if (showSplash) {
20
+ * return (
21
+ * <SplashScreen
22
+ * icon={require('./assets/icon.png')}
23
+ * appName="My App"
24
+ * tagline="Your tagline here"
25
+ * />
26
+ * );
27
+ * }
16
28
  */
17
29
 
18
- // =============================================================================
19
- // DOMAIN LAYER - Entities
20
- // =============================================================================
21
-
22
30
  export type { SplashOptions } from "./domain/entities/SplashOptions";
23
-
24
- // =============================================================================
25
- // PRESENTATION LAYER - Components
26
- // =============================================================================
27
-
28
31
  export { SplashScreen, type SplashScreenProps } from "./presentation/components/SplashScreen";
29
- export { useSplash } from "./presentation/hooks/useSplash";
30
-
@@ -1,123 +1,124 @@
1
1
  /**
2
2
  * Splash Screen Component
3
3
  *
4
- * ULTRA MINIMAL - No external dependencies
5
- * Only basic React Native + expo-linear-gradient + safe-area
4
+ * Ultra minimal splash screen - just displays icon, name, and tagline.
5
+ * Parent component controls visibility and timing.
6
6
  */
7
7
 
8
- import React, { useEffect, useRef, useCallback } from "react";
9
- import { View, Text, StyleSheet, ActivityIndicator } from "react-native";
8
+ import React from "react";
9
+ import { View, Text, Image, StyleSheet, ActivityIndicator } from "react-native";
10
10
  import { LinearGradient } from "expo-linear-gradient";
11
11
  import { useSafeAreaInsets } from "react-native-safe-area-context";
12
12
  import type { SplashOptions } from "../../domain/entities/SplashOptions";
13
13
 
14
14
  export interface SplashScreenProps extends SplashOptions {
15
+ /** Control visibility from parent */
15
16
  visible?: boolean;
16
- textColor?: string;
17
17
  }
18
18
 
19
19
  const DEFAULT_BG = "#6366F1";
20
20
  const DEFAULT_TEXT = "#FFFFFF";
21
21
 
22
22
  export const SplashScreen: React.FC<SplashScreenProps> = ({
23
+ icon,
23
24
  appName = "",
24
25
  tagline = "",
25
26
  backgroundColor = DEFAULT_BG,
26
27
  gradientColors,
27
- loadingText = "",
28
+ textColor = DEFAULT_TEXT,
28
29
  showLoading = true,
29
- minimumDisplayTime = 1500,
30
- onReady,
31
- renderLogo,
32
- renderContent,
33
- renderFooter,
34
30
  visible = true,
35
- textColor = DEFAULT_TEXT,
36
31
  }) => {
37
32
  const insets = useSafeAreaInsets();
38
- const timerRef = useRef<NodeJS.Timeout | null>(null);
39
- const onReadyRef = useRef(onReady);
40
- const hasCalledOnReady = useRef(false);
41
-
42
- // Keep onReady ref updated but don't trigger re-render
43
- useEffect(() => {
44
- onReadyRef.current = onReady;
45
- }, [onReady]);
46
-
47
- // Stable callback that uses ref
48
- const handleReady = useCallback(() => {
49
- if (hasCalledOnReady.current) return;
50
- hasCalledOnReady.current = true;
51
- onReadyRef.current?.();
52
- }, []);
53
-
54
- useEffect(() => {
55
- if (!visible) return;
56
-
57
- // Reset when becoming visible again
58
- hasCalledOnReady.current = false;
59
-
60
- timerRef.current = setTimeout(handleReady, minimumDisplayTime);
61
-
62
- return () => {
63
- if (timerRef.current) clearTimeout(timerRef.current);
64
- };
65
- }, [visible, minimumDisplayTime, handleReady]);
66
33
 
67
34
  if (!visible) return null;
68
35
 
69
- const hasGradient = gradientColors && gradientColors.length > 1;
70
- const colors: [string, string, ...string[]] = hasGradient
71
- ? (gradientColors as [string, string, ...string[]])
72
- : [backgroundColor, backgroundColor];
73
-
74
36
  const content = (
75
- <View style={[styles.inner, { paddingTop: insets.top, paddingBottom: insets.bottom }]}>
37
+ <View style={[styles.content, { paddingTop: insets.top, paddingBottom: insets.bottom }]}>
76
38
  <View style={styles.center}>
77
- {renderLogo ? renderLogo() : <View style={styles.logo} />}
78
-
79
- {renderContent ? (
80
- renderContent()
39
+ {icon ? (
40
+ <Image source={icon} style={styles.icon} resizeMode="contain" />
81
41
  ) : (
82
- <>
83
- {appName ? <Text style={[styles.title, { color: textColor }]}>{appName}</Text> : null}
84
- {tagline ? <Text style={[styles.subtitle, { color: textColor }]}>{tagline}</Text> : null}
85
- </>
42
+ <View style={styles.iconPlaceholder} />
86
43
  )}
44
+
45
+ {appName ? (
46
+ <Text style={[styles.title, { color: textColor }]}>{appName}</Text>
47
+ ) : null}
48
+
49
+ {tagline ? (
50
+ <Text style={[styles.subtitle, { color: textColor }]}>{tagline}</Text>
51
+ ) : null}
87
52
  </View>
88
53
 
89
- {showLoading && (
54
+ {showLoading ? (
90
55
  <View style={styles.loading}>
91
- <ActivityIndicator color={textColor} />
92
- {loadingText ? <Text style={[styles.loadingText, { color: textColor }]}>{loadingText}</Text> : null}
56
+ <ActivityIndicator color={textColor} size="small" />
93
57
  </View>
94
- )}
95
-
96
- {renderFooter?.()}
58
+ ) : null}
97
59
  </View>
98
60
  );
99
61
 
62
+ // Use gradient if colors provided, otherwise solid background
63
+ if (gradientColors && gradientColors.length >= 2) {
64
+ return (
65
+ <LinearGradient
66
+ colors={gradientColors as [string, string, ...string[]]}
67
+ style={styles.container}
68
+ start={{ x: 0, y: 0 }}
69
+ end={{ x: 0, y: 1 }}
70
+ >
71
+ {content}
72
+ </LinearGradient>
73
+ );
74
+ }
75
+
100
76
  return (
101
- <View style={styles.container}>
102
- {hasGradient ? (
103
- <LinearGradient colors={colors} start={{ x: 0, y: 0 }} end={{ x: 1, y: 1 }} style={styles.fill}>
104
- {content}
105
- </LinearGradient>
106
- ) : (
107
- <View style={[styles.fill, { backgroundColor }]}>{content}</View>
108
- )}
77
+ <View style={[styles.container, { backgroundColor }]}>
78
+ {content}
109
79
  </View>
110
80
  );
111
81
  };
112
82
 
113
83
  const styles = StyleSheet.create({
114
- container: { flex: 1 },
115
- fill: { flex: 1 },
116
- inner: { flex: 1, justifyContent: "space-between" },
117
- center: { flex: 1, alignItems: "center", justifyContent: "center", paddingHorizontal: 24 },
118
- logo: { width: 100, height: 100, borderRadius: 50, backgroundColor: "rgba(255,255,255,0.2)", marginBottom: 24 },
119
- title: { fontSize: 32, fontWeight: "700", textAlign: "center", marginBottom: 8 },
120
- subtitle: { fontSize: 16, textAlign: "center", opacity: 0.9 },
121
- loading: { alignItems: "center", paddingBottom: 48 },
122
- loadingText: { fontSize: 14, marginTop: 12, opacity: 0.8 },
84
+ container: {
85
+ flex: 1,
86
+ },
87
+ content: {
88
+ flex: 1,
89
+ justifyContent: "space-between",
90
+ },
91
+ center: {
92
+ flex: 1,
93
+ alignItems: "center",
94
+ justifyContent: "center",
95
+ paddingHorizontal: 24,
96
+ },
97
+ icon: {
98
+ width: 120,
99
+ height: 120,
100
+ marginBottom: 24,
101
+ },
102
+ iconPlaceholder: {
103
+ width: 100,
104
+ height: 100,
105
+ borderRadius: 50,
106
+ backgroundColor: "rgba(255,255,255,0.2)",
107
+ marginBottom: 24,
108
+ },
109
+ title: {
110
+ fontSize: 32,
111
+ fontWeight: "700",
112
+ textAlign: "center",
113
+ marginBottom: 8,
114
+ },
115
+ subtitle: {
116
+ fontSize: 16,
117
+ textAlign: "center",
118
+ opacity: 0.9,
119
+ },
120
+ loading: {
121
+ alignItems: "center",
122
+ paddingBottom: 48,
123
+ },
123
124
  });
@@ -1,70 +0,0 @@
1
- /**
2
- * Use Splash Hook
3
- * Single Responsibility: Manage splash screen state and timing
4
- */
5
-
6
- import { useEffect, useState, useRef } from "react";
7
-
8
- interface UseSplashOptions {
9
- minimumDisplayTime?: number;
10
- onReady?: () => void | Promise<void>;
11
- autoHide?: boolean;
12
- }
13
-
14
- export const useSplash = ({
15
- minimumDisplayTime = 1500,
16
- onReady,
17
- autoHide = true,
18
- }: UseSplashOptions = {}) => {
19
- const [isVisible, setIsVisible] = useState(true);
20
- const [isReady, setIsReady] = useState(false);
21
- const timerRef = useRef<NodeJS.Timeout | null>(null);
22
- const isReadyRef = useRef(false);
23
-
24
- const hide = () => {
25
- setIsVisible(false);
26
- };
27
-
28
- const show = () => {
29
- setIsVisible(true);
30
- };
31
-
32
- const markReady = async () => {
33
- if (isReadyRef.current) return;
34
-
35
- isReadyRef.current = true;
36
- setIsReady(true);
37
-
38
- if (onReady) {
39
- try {
40
- await onReady();
41
- } catch (error) {
42
- if (__DEV__) {
43
- console.error("Splash onReady error:", error);
44
- }
45
- }
46
- }
47
-
48
- if (autoHide) {
49
- timerRef.current = setTimeout(() => {
50
- hide();
51
- }, minimumDisplayTime);
52
- }
53
- };
54
-
55
- useEffect(() => {
56
- return () => {
57
- if (timerRef.current) {
58
- clearTimeout(timerRef.current);
59
- }
60
- };
61
- }, []);
62
-
63
- return {
64
- isVisible,
65
- isReady,
66
- hide,
67
- show,
68
- markReady,
69
- };
70
- };
@@ -1,47 +0,0 @@
1
- /**
2
- * Splash Gradient Utilities
3
- * Single Responsibility: Gradient color generation
4
- */
5
-
6
- /**
7
- * Adjust color brightness
8
- */
9
- export const adjustColorBrightness = (hex: string, percent: number): string => {
10
- const num = parseInt(hex.replace("#", ""), 16);
11
- const amt = Math.round(2.55 * percent);
12
- const R = (num >> 16) + amt;
13
- const G = ((num >> 8) & 0x00ff) + amt;
14
- const B = (num & 0x0000ff) + amt;
15
- return (
16
- "#" +
17
- (
18
- 0x1000000 +
19
- (R < 255 ? (R < 1 ? 0 : R) : 255) * 0x10000 +
20
- (G < 255 ? (G < 1 ? 0 : G) : 255) * 0x100 +
21
- (B < 255 ? (B < 1 ? 0 : B) : 255)
22
- )
23
- .toString(16)
24
- .slice(1)
25
- );
26
- };
27
-
28
- /**
29
- * Generate gradient colors from backgroundColor
30
- */
31
- export const generateGradientFromColor = (
32
- backgroundColor: string,
33
- isDark: boolean,
34
- ): readonly string[] => {
35
- return isDark
36
- ? ([
37
- backgroundColor,
38
- adjustColorBrightness(backgroundColor, -20),
39
- adjustColorBrightness(backgroundColor, -30),
40
- ] as const)
41
- : ([
42
- backgroundColor,
43
- adjustColorBrightness(backgroundColor, 10),
44
- adjustColorBrightness(backgroundColor, 20),
45
- ] as const);
46
- };
47
-
@@ -1,12 +0,0 @@
1
- declare module 'expo-linear-gradient' {
2
- import { View, ViewProps } from 'react-native';
3
-
4
- export interface LinearGradientProps extends ViewProps {
5
- colors: readonly string[];
6
- start?: { x: number; y: number };
7
- end?: { x: number; y: number };
8
- locations?: readonly number[];
9
- }
10
-
11
- export const LinearGradient: React.FC<LinearGradientProps>;
12
- }