@umituz/react-native-design-system 2.5.42 → 2.6.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 +1 -1
- package/src/index.ts +4 -0
- package/src/molecules/index.ts +3 -0
- package/src/molecules/splash/components/SplashScreen.tsx +169 -0
- package/src/molecules/splash/components/index.ts +1 -0
- package/src/molecules/splash/constants/index.ts +9 -0
- package/src/molecules/splash/index.ts +10 -0
- package/src/molecules/splash/types/index.ts +90 -0
- package/src/theme/infrastructure/providers/DesignSystemProvider.tsx +13 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-design-system",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "Universal design system for React Native apps - Consolidated package with atoms, molecules, organisms, theme, typography, responsive and safe area utilities",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
package/src/index.ts
CHANGED
package/src/molecules/index.ts
CHANGED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splash Screen Component
|
|
3
|
+
* Pure prop-driven component, no context needed
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React, { useEffect, useState, useCallback } from "react";
|
|
7
|
+
import { View, Image, StyleSheet } from "react-native";
|
|
8
|
+
import { LinearGradient } from "expo-linear-gradient";
|
|
9
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
10
|
+
import { AtomicText } from "../../../atoms";
|
|
11
|
+
import type { SplashScreenProps } from "../types";
|
|
12
|
+
import { SPLASH_CONSTANTS } from "../constants";
|
|
13
|
+
|
|
14
|
+
declare const __DEV__: boolean;
|
|
15
|
+
|
|
16
|
+
export const SplashScreen: React.FC<SplashScreenProps> = ({
|
|
17
|
+
icon,
|
|
18
|
+
appName,
|
|
19
|
+
tagline,
|
|
20
|
+
colors,
|
|
21
|
+
gradientColors,
|
|
22
|
+
visible = true,
|
|
23
|
+
maxDuration,
|
|
24
|
+
onTimeout,
|
|
25
|
+
onReady,
|
|
26
|
+
style,
|
|
27
|
+
}: SplashScreenProps) => {
|
|
28
|
+
const insets = useSafeAreaInsets();
|
|
29
|
+
const [timedOut, setTimedOut] = useState(false);
|
|
30
|
+
|
|
31
|
+
const handleTimeout = useCallback(() => {
|
|
32
|
+
if (__DEV__) {
|
|
33
|
+
console.log(`[SplashScreen] Timeout reached: ${maxDuration}ms`);
|
|
34
|
+
}
|
|
35
|
+
setTimedOut(true);
|
|
36
|
+
onTimeout?.();
|
|
37
|
+
}, [maxDuration, onTimeout]);
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (__DEV__) {
|
|
41
|
+
console.log("[SplashScreen] Mounted", { appName, visible });
|
|
42
|
+
}
|
|
43
|
+
onReady?.();
|
|
44
|
+
}, [appName, visible, onReady]);
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (!maxDuration || !visible) return;
|
|
48
|
+
|
|
49
|
+
const timer = setTimeout(handleTimeout, maxDuration);
|
|
50
|
+
return () => clearTimeout(timer);
|
|
51
|
+
}, [maxDuration, visible, handleTimeout]);
|
|
52
|
+
|
|
53
|
+
if (!visible) {
|
|
54
|
+
if (__DEV__) {
|
|
55
|
+
console.log("[SplashScreen] Not visible, returning null");
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const iconPlaceholderColor = colors.iconPlaceholder ?? `${colors.text}30`;
|
|
61
|
+
|
|
62
|
+
const contentStyle = {
|
|
63
|
+
paddingTop: insets.top + SPLASH_CONSTANTS.CONTENT_PADDING,
|
|
64
|
+
paddingBottom: insets.bottom + SPLASH_CONSTANTS.CONTENT_PADDING,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const content = (
|
|
68
|
+
<View style={[styles.content, contentStyle]}>
|
|
69
|
+
<View style={styles.center}>
|
|
70
|
+
{icon ? (
|
|
71
|
+
<Image source={icon} style={styles.icon} resizeMode="contain" />
|
|
72
|
+
) : (
|
|
73
|
+
<View
|
|
74
|
+
style={[
|
|
75
|
+
styles.iconPlaceholder,
|
|
76
|
+
{ backgroundColor: iconPlaceholderColor },
|
|
77
|
+
]}
|
|
78
|
+
/>
|
|
79
|
+
)}
|
|
80
|
+
|
|
81
|
+
{appName ? (
|
|
82
|
+
<AtomicText
|
|
83
|
+
type="displaySmall"
|
|
84
|
+
style={[styles.title, { color: colors.text }]}
|
|
85
|
+
>
|
|
86
|
+
{appName}
|
|
87
|
+
</AtomicText>
|
|
88
|
+
) : null}
|
|
89
|
+
|
|
90
|
+
{tagline ? (
|
|
91
|
+
<AtomicText
|
|
92
|
+
type="bodyLarge"
|
|
93
|
+
style={[styles.tagline, { color: colors.text }]}
|
|
94
|
+
>
|
|
95
|
+
{tagline}
|
|
96
|
+
</AtomicText>
|
|
97
|
+
) : null}
|
|
98
|
+
|
|
99
|
+
{timedOut && __DEV__ ? (
|
|
100
|
+
<AtomicText
|
|
101
|
+
type="labelSmall"
|
|
102
|
+
style={[styles.timeoutText, { color: colors.text }]}
|
|
103
|
+
>
|
|
104
|
+
Initialization timeout
|
|
105
|
+
</AtomicText>
|
|
106
|
+
) : null}
|
|
107
|
+
</View>
|
|
108
|
+
</View>
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
if (gradientColors && gradientColors.length >= 2) {
|
|
112
|
+
return (
|
|
113
|
+
<LinearGradient
|
|
114
|
+
colors={gradientColors as [string, string, ...string[]]}
|
|
115
|
+
style={[styles.container, style]}
|
|
116
|
+
start={{ x: 0, y: 0 }}
|
|
117
|
+
end={{ x: 0, y: 1 }}
|
|
118
|
+
>
|
|
119
|
+
{content}
|
|
120
|
+
</LinearGradient>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<View style={[styles.container, { backgroundColor: colors.background }, style]}>
|
|
126
|
+
{content}
|
|
127
|
+
</View>
|
|
128
|
+
);
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const styles = StyleSheet.create({
|
|
132
|
+
container: {
|
|
133
|
+
flex: 1,
|
|
134
|
+
},
|
|
135
|
+
content: {
|
|
136
|
+
flex: 1,
|
|
137
|
+
justifyContent: "space-between",
|
|
138
|
+
},
|
|
139
|
+
center: {
|
|
140
|
+
flex: 1,
|
|
141
|
+
alignItems: "center",
|
|
142
|
+
justifyContent: "center",
|
|
143
|
+
paddingHorizontal: SPLASH_CONSTANTS.CONTENT_PADDING,
|
|
144
|
+
},
|
|
145
|
+
icon: {
|
|
146
|
+
width: SPLASH_CONSTANTS.ICON_SIZE,
|
|
147
|
+
height: SPLASH_CONSTANTS.ICON_SIZE,
|
|
148
|
+
marginBottom: SPLASH_CONSTANTS.CONTENT_PADDING,
|
|
149
|
+
},
|
|
150
|
+
iconPlaceholder: {
|
|
151
|
+
width: SPLASH_CONSTANTS.ICON_PLACEHOLDER_SIZE,
|
|
152
|
+
height: SPLASH_CONSTANTS.ICON_PLACEHOLDER_SIZE,
|
|
153
|
+
borderRadius: SPLASH_CONSTANTS.ICON_PLACEHOLDER_SIZE / 2,
|
|
154
|
+
marginBottom: SPLASH_CONSTANTS.CONTENT_PADDING,
|
|
155
|
+
},
|
|
156
|
+
title: {
|
|
157
|
+
textAlign: "center",
|
|
158
|
+
fontWeight: "800",
|
|
159
|
+
marginBottom: 8,
|
|
160
|
+
},
|
|
161
|
+
tagline: {
|
|
162
|
+
textAlign: "center",
|
|
163
|
+
opacity: 0.9,
|
|
164
|
+
},
|
|
165
|
+
timeoutText: {
|
|
166
|
+
textAlign: "center",
|
|
167
|
+
marginTop: 16,
|
|
168
|
+
},
|
|
169
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SplashScreen } from './SplashScreen';
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splash Screen Types
|
|
3
|
+
* All type definitions for the splash screen package
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ImageSourcePropType, StyleProp, ViewStyle } from "react-native";
|
|
7
|
+
import type { ReactNode } from "react";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Splash screen color configuration
|
|
11
|
+
* All colors should be provided by the main app via design tokens
|
|
12
|
+
*/
|
|
13
|
+
export interface SplashColors {
|
|
14
|
+
/** Background color when not using gradient */
|
|
15
|
+
background: string;
|
|
16
|
+
/** Text color for app name and tagline */
|
|
17
|
+
text: string;
|
|
18
|
+
/** Background color for icon placeholder circle */
|
|
19
|
+
iconPlaceholder?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Custom colors for SplashThemeProvider
|
|
24
|
+
*/
|
|
25
|
+
export interface SplashCustomColors {
|
|
26
|
+
/** Text color for app name and tagline */
|
|
27
|
+
textColor: string;
|
|
28
|
+
/** Background color when not using gradient */
|
|
29
|
+
backgroundColor?: string;
|
|
30
|
+
/** Background color for icon placeholder circle */
|
|
31
|
+
iconPlaceholderColor?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* SplashThemeProvider props
|
|
36
|
+
*/
|
|
37
|
+
export interface SplashThemeProviderProps {
|
|
38
|
+
/** Children components */
|
|
39
|
+
children: ReactNode;
|
|
40
|
+
/** Gradient colors for background */
|
|
41
|
+
gradientColors?: readonly [string, string, ...string[]];
|
|
42
|
+
/** Custom color configuration */
|
|
43
|
+
customColors?: SplashCustomColors;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Splash theme context value
|
|
48
|
+
*/
|
|
49
|
+
export interface SplashThemeContextValue {
|
|
50
|
+
/** Resolved colors for splash screen */
|
|
51
|
+
colors: SplashColors;
|
|
52
|
+
/** Gradient colors if provided */
|
|
53
|
+
gradientColors?: readonly [string, string, ...string[]];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Splash screen component props
|
|
58
|
+
* Can be used standalone with colors prop or with SplashThemeProvider
|
|
59
|
+
*/
|
|
60
|
+
export interface SplashScreenProps {
|
|
61
|
+
/** App name to display */
|
|
62
|
+
appName?: string;
|
|
63
|
+
|
|
64
|
+
/** Tagline or subtitle */
|
|
65
|
+
tagline?: string;
|
|
66
|
+
|
|
67
|
+
/** App icon/logo image source */
|
|
68
|
+
icon?: ImageSourcePropType;
|
|
69
|
+
|
|
70
|
+
/** Color configuration (required - must be provided by app) */
|
|
71
|
+
colors: SplashColors;
|
|
72
|
+
|
|
73
|
+
/** Optional gradient colors (overrides background color) */
|
|
74
|
+
gradientColors?: readonly [string, string, ...string[]];
|
|
75
|
+
|
|
76
|
+
/** Control visibility */
|
|
77
|
+
visible?: boolean;
|
|
78
|
+
|
|
79
|
+
/** Maximum duration before timeout callback */
|
|
80
|
+
maxDuration?: number;
|
|
81
|
+
|
|
82
|
+
/** Callback when max duration is reached */
|
|
83
|
+
onTimeout?: () => void;
|
|
84
|
+
|
|
85
|
+
/** Callback when splash is ready/mounted */
|
|
86
|
+
onReady?: () => void;
|
|
87
|
+
|
|
88
|
+
/** Additional container style */
|
|
89
|
+
style?: StyleProp<ViewStyle>;
|
|
90
|
+
}
|
|
@@ -3,6 +3,8 @@ import { ActivityIndicator, View, StyleSheet } from 'react-native';
|
|
|
3
3
|
import { useThemeStore } from '../stores/themeStore';
|
|
4
4
|
import { useDesignSystemTheme } from '../globalThemeStore';
|
|
5
5
|
import type { CustomThemeColors } from '../../core/CustomColors';
|
|
6
|
+
import { SplashScreen } from '../../../molecules/splash';
|
|
7
|
+
import type { SplashScreenProps } from '../../../molecules/splash/types';
|
|
6
8
|
|
|
7
9
|
declare const __DEV__: boolean;
|
|
8
10
|
|
|
@@ -11,9 +13,11 @@ interface DesignSystemProviderProps {
|
|
|
11
13
|
children: ReactNode;
|
|
12
14
|
/** Custom theme colors to override defaults */
|
|
13
15
|
customColors?: CustomThemeColors;
|
|
14
|
-
/** Show loading indicator while initializing (default:
|
|
16
|
+
/** Show loading indicator while initializing (default: true) */
|
|
15
17
|
showLoadingIndicator?: boolean;
|
|
16
|
-
/**
|
|
18
|
+
/** Splash screen configuration (used when showLoadingIndicator is true) */
|
|
19
|
+
splashConfig?: Pick<SplashScreenProps, 'appName' | 'tagline' | 'icon' | 'colors' | 'gradientColors'>;
|
|
20
|
+
/** Custom loading component (overrides splash screen) */
|
|
17
21
|
loadingComponent?: ReactNode;
|
|
18
22
|
/** Callback when initialization completes */
|
|
19
23
|
onInitialized?: () => void;
|
|
@@ -52,7 +56,8 @@ interface DesignSystemProviderProps {
|
|
|
52
56
|
export const DesignSystemProvider: React.FC<DesignSystemProviderProps> = ({
|
|
53
57
|
children,
|
|
54
58
|
customColors,
|
|
55
|
-
showLoadingIndicator =
|
|
59
|
+
showLoadingIndicator = true,
|
|
60
|
+
splashConfig,
|
|
56
61
|
loadingComponent,
|
|
57
62
|
onInitialized,
|
|
58
63
|
onError,
|
|
@@ -90,6 +95,11 @@ export const DesignSystemProvider: React.FC<DesignSystemProviderProps> = ({
|
|
|
90
95
|
return <>{loadingComponent}</>;
|
|
91
96
|
}
|
|
92
97
|
|
|
98
|
+
// Use SplashScreen if config provided, otherwise fallback to ActivityIndicator
|
|
99
|
+
if (splashConfig?.colors) {
|
|
100
|
+
return <SplashScreen {...splashConfig} />;
|
|
101
|
+
}
|
|
102
|
+
|
|
93
103
|
return (
|
|
94
104
|
<View style={styles.loadingContainer}>
|
|
95
105
|
<ActivityIndicator size="large" />
|