@umituz/react-native-splash 1.6.4 → 1.7.1
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 +0 -0
- package/README.md +0 -0
- package/lib/__tests__/mocks/expoLinearGradient.js +7 -0
- package/lib/__tests__/mocks/reactNative.js +16 -0
- package/lib/__tests__/setup.ts +57 -0
- package/lib/__tests__/utils/testUtils.tsx +86 -0
- package/lib/domain/entities/SplashOptions.ts +74 -0
- package/lib/index.ts +31 -0
- package/lib/presentation/components/SplashDecorations.tsx +56 -0
- package/lib/presentation/components/SplashErrorBoundary.tsx +63 -0
- package/lib/presentation/components/SplashLoading.tsx +74 -0
- package/lib/presentation/components/SplashLogo.tsx +80 -0
- package/lib/presentation/components/SplashScreen.tsx +175 -0
- package/lib/presentation/components/SplashTypography.tsx +72 -0
- package/lib/presentation/hooks/useSplash.ts +70 -0
- package/lib/presentation/utils/splashGradient.utils.ts +47 -0
- package/lib/types/expo-linear-gradient.d.ts +12 -0
- package/package.json +18 -5
- package/src/__tests__/SplashScreen.test.tsx +161 -0
- package/src/__tests__/accessibility/Accessibility.test.tsx +264 -0
- package/src/__tests__/basic/Basic.test.tsx +106 -0
- package/src/__tests__/basic/Simple.test.tsx +32 -0
- package/src/__tests__/edge-cases/EdgeCases.test.tsx +446 -0
- package/src/__tests__/integration/SplashScreen.integration.test.tsx +200 -0
- package/src/__tests__/mocks/expoLinearGradient.js +7 -0
- package/src/__tests__/mocks/reactNative.js +16 -0
- package/src/__tests__/performance/Performance.test.tsx +297 -0
- package/src/__tests__/setup.ts +57 -0
- package/src/__tests__/useSplash.test.tsx +123 -0
- package/src/__tests__/utils/testUtils.tsx +86 -0
- package/src/__tests__/visual/VisualRegression.test.tsx +338 -0
- package/src/domain/entities/SplashOptions.ts +7 -0
- package/src/index.ts +2 -0
- package/src/presentation/components/SplashDecorations.tsx +13 -5
- package/src/presentation/components/SplashErrorBoundary.tsx +63 -0
- package/src/presentation/components/SplashLoading.tsx +7 -5
- package/src/presentation/components/SplashLogo.tsx +4 -2
- package/src/presentation/components/SplashScreen.tsx +43 -26
- package/src/presentation/components/SplashTypography.tsx +6 -4
- package/src/presentation/hooks/useSplash.ts +70 -0
- package/src/presentation/utils/splashGradient.utils.ts +0 -0
- package/src/types/expo-linear-gradient.d.ts +12 -0
package/LICENSE
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Native Mocks
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const React = require('react');
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
View: ({ children, testID, style }) => React.createElement('View', { testID, style }, children),
|
|
9
|
+
Text: ({ children, testID, style }) => React.createElement('Text', { testID, style }, children),
|
|
10
|
+
StyleSheet: {
|
|
11
|
+
create: jest.fn((styles) => styles),
|
|
12
|
+
flatten: jest.fn((style) => style)
|
|
13
|
+
},
|
|
14
|
+
Dimensions: { get: jest.fn(() => ({ width: 375, height: 667 })) },
|
|
15
|
+
LinearGradient: ({ children, testID, style }) => React.createElement('LinearGradient', { testID, style }, children),
|
|
16
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple Test Setup
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Mock React Native before anything else
|
|
6
|
+
jest.mock('react-native', () => {
|
|
7
|
+
const React = require('react');
|
|
8
|
+
return {
|
|
9
|
+
View: ({ children, testID, style }) => React.createElement('View', { testID, style }, children),
|
|
10
|
+
Text: ({ children, testID, style }) => React.createElement('Text', { testID, style }, children),
|
|
11
|
+
StyleSheet: {
|
|
12
|
+
create: jest.fn((styles) => styles),
|
|
13
|
+
flatten: jest.fn((style) => style)
|
|
14
|
+
},
|
|
15
|
+
Dimensions: { get: jest.fn(() => ({ width: 375, height: 667 })) },
|
|
16
|
+
LinearGradient: ({ children, testID, style }) => React.createElement('LinearGradient', { testID, style }, children),
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// Mock expo-linear-gradient
|
|
21
|
+
jest.mock('expo-linear-gradient', () => {
|
|
22
|
+
const React = require('react');
|
|
23
|
+
return {
|
|
24
|
+
LinearGradient: ({ children, testID, style }) => React.createElement('LinearGradient', { testID, style }, children),
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Mock design system atoms
|
|
29
|
+
jest.mock('@umituz/react-native-design-system-atoms', () => {
|
|
30
|
+
const React = require('react');
|
|
31
|
+
return {
|
|
32
|
+
AtomicIcon: ({ name, testID }) => React.createElement('AtomicIcon', { testID: testID || `icon-${name}`, name }),
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Mock design system theme
|
|
37
|
+
jest.mock('@umituz/react-native-design-system-theme', () => ({
|
|
38
|
+
useAppDesignTokens: () => ({
|
|
39
|
+
colors: { primary: '#007AFF' },
|
|
40
|
+
spacing: { xl: 24, md: 16, xxxl: 48 },
|
|
41
|
+
}),
|
|
42
|
+
}));
|
|
43
|
+
|
|
44
|
+
// Mock localization
|
|
45
|
+
jest.mock('@umituz/react-native-localization', () => ({
|
|
46
|
+
useLocalization: () => ({
|
|
47
|
+
t: (key: string, fallback: string) => fallback || key,
|
|
48
|
+
}),
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
// Mock safe area context
|
|
52
|
+
jest.mock('react-native-safe-area-context', () => ({
|
|
53
|
+
useSafeAreaInsets: () => ({ top: 44, bottom: 34, left: 0, right: 0 }),
|
|
54
|
+
}));
|
|
55
|
+
|
|
56
|
+
// Global test utilities
|
|
57
|
+
global.__DEV__ = true;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Utilities and Mocks
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
import { render, RenderOptions } from '@testing-library/react-native';
|
|
7
|
+
import { View } from 'react-native';
|
|
8
|
+
|
|
9
|
+
// Custom render function with providers
|
|
10
|
+
const AllTheProviders = ({ children }: { children: React.ReactNode }) => {
|
|
11
|
+
return <View>{children}</View>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const customRender = (
|
|
15
|
+
ui: React.ReactElement,
|
|
16
|
+
options?: Omit<RenderOptions, 'wrapper'>
|
|
17
|
+
) => render(ui, { wrapper: AllTheProviders, ...options });
|
|
18
|
+
|
|
19
|
+
// Mock timers utilities
|
|
20
|
+
export const advanceTimersByTime = (ms: number) => {
|
|
21
|
+
jest.advanceTimersByTime(ms);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const runAllTimers = () => {
|
|
25
|
+
jest.runAllTimers();
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Mock data generators
|
|
29
|
+
export const createMockSplashProps = (overrides = {}) => ({
|
|
30
|
+
appName: 'Test App',
|
|
31
|
+
tagline: 'Test Tagline',
|
|
32
|
+
visible: true,
|
|
33
|
+
showLoading: true,
|
|
34
|
+
minimumDisplayTime: 1500,
|
|
35
|
+
...overrides,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export const createMockDesignTokens = (overrides = {}) => ({
|
|
39
|
+
colors: { primary: '#007AFF' },
|
|
40
|
+
spacing: { xl: 24, md: 16, xxxl: 48 },
|
|
41
|
+
...overrides,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Performance testing utilities
|
|
45
|
+
export const measureRenderTime = async (component: React.ReactElement) => {
|
|
46
|
+
const start = performance.now();
|
|
47
|
+
customRender(component);
|
|
48
|
+
const end = performance.now();
|
|
49
|
+
return end - start;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// Memory leak testing utilities
|
|
53
|
+
export const trackMemoryUsage = () => {
|
|
54
|
+
const initialMemory = (performance as any).memory?.usedJSHeapSize || 0;
|
|
55
|
+
return {
|
|
56
|
+
getMemoryIncrease: () => {
|
|
57
|
+
const currentMemory = (performance as any).memory?.usedJSHeapSize || 0;
|
|
58
|
+
return currentMemory - initialMemory;
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Accessibility testing utilities
|
|
64
|
+
export const checkAccessibility = (container: any) => {
|
|
65
|
+
const accessibilityElements = container.findAllByProps({
|
|
66
|
+
accessible: true,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
hasAccessibleElements: accessibilityElements.length > 0,
|
|
71
|
+
accessibleElementCount: accessibilityElements.length,
|
|
72
|
+
elements: accessibilityElements,
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Error boundary testing utilities
|
|
77
|
+
export const createErrorComponent = (errorMessage: string) => {
|
|
78
|
+
const ThrowError = () => {
|
|
79
|
+
throw new Error(errorMessage);
|
|
80
|
+
};
|
|
81
|
+
return ThrowError;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Re-export testing library
|
|
85
|
+
export * from '@testing-library/react-native';
|
|
86
|
+
export { customRender as render };
|
|
@@ -0,0 +1,74 @@
|
|
|
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 (will generate gradient automatically)
|
|
31
|
+
*/
|
|
32
|
+
backgroundColor?: string;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Custom gradient colors (overrides backgroundColor)
|
|
36
|
+
* If provided, backgroundColor is ignored
|
|
37
|
+
*/
|
|
38
|
+
gradientColors?: readonly string[];
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Loading text
|
|
42
|
+
*/
|
|
43
|
+
loadingText?: string;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Show loading indicator (default: true)
|
|
47
|
+
*/
|
|
48
|
+
showLoading?: boolean;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Minimum display time in milliseconds (default: 1500)
|
|
52
|
+
*/
|
|
53
|
+
minimumDisplayTime?: number;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Callback when splash is ready to hide
|
|
57
|
+
*/
|
|
58
|
+
onReady?: () => void | Promise<void>;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Custom render functions
|
|
62
|
+
*/
|
|
63
|
+
renderLogo?: () => ReactNode;
|
|
64
|
+
renderContent?: () => ReactNode;
|
|
65
|
+
renderFooter?: () => ReactNode;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Custom colors for dynamic theming
|
|
69
|
+
*/
|
|
70
|
+
textColor?: string;
|
|
71
|
+
iconColor?: string;
|
|
72
|
+
decorationColor?: string;
|
|
73
|
+
}
|
|
74
|
+
|
package/lib/index.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
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
|
+
export { SplashErrorBoundary } from "./presentation/components/SplashErrorBoundary";
|
|
30
|
+
export { useSplash } from "./presentation/hooks/useSplash";
|
|
31
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splash Decorations Component
|
|
3
|
+
* Single Responsibility: Render decorative background elements
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from "react";
|
|
7
|
+
import { View, StyleSheet } from "react-native";
|
|
8
|
+
|
|
9
|
+
export interface SplashDecorationsProps {
|
|
10
|
+
decorationColor?: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const SplashDecorations: React.FC<SplashDecorationsProps> = ({
|
|
14
|
+
decorationColor = "rgba(255, 255, 255, 0.05)",
|
|
15
|
+
}) => {
|
|
16
|
+
const styles = getStyles(decorationColor);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<>
|
|
20
|
+
<View style={styles.circle1} />
|
|
21
|
+
<View style={styles.circle2} />
|
|
22
|
+
<View style={styles.circle3} />
|
|
23
|
+
</>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const getStyles = (decorationColor: string) => StyleSheet.create({
|
|
28
|
+
circle1: {
|
|
29
|
+
position: "absolute",
|
|
30
|
+
width: 300,
|
|
31
|
+
height: 300,
|
|
32
|
+
borderRadius: 150,
|
|
33
|
+
backgroundColor: decorationColor,
|
|
34
|
+
top: -100,
|
|
35
|
+
right: -100,
|
|
36
|
+
},
|
|
37
|
+
circle2: {
|
|
38
|
+
position: "absolute",
|
|
39
|
+
width: 200,
|
|
40
|
+
height: 200,
|
|
41
|
+
borderRadius: 100,
|
|
42
|
+
backgroundColor: decorationColor.replace("0.05", "0.03"),
|
|
43
|
+
bottom: -50,
|
|
44
|
+
left: -50,
|
|
45
|
+
},
|
|
46
|
+
circle3: {
|
|
47
|
+
position: "absolute",
|
|
48
|
+
width: 150,
|
|
49
|
+
height: 150,
|
|
50
|
+
borderRadius: 75,
|
|
51
|
+
backgroundColor: decorationColor.replace("0.05", "0.04"),
|
|
52
|
+
top: "30%",
|
|
53
|
+
right: "10%",
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splash Error Boundary
|
|
3
|
+
* Single Responsibility: Handle splash screen errors gracefully
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React, { Component, ReactNode } from "react";
|
|
7
|
+
import { View, Text, StyleSheet } from "react-native";
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
fallback?: ReactNode;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface State {
|
|
15
|
+
hasError: boolean;
|
|
16
|
+
error?: Error;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class SplashErrorBoundary extends Component<Props, State> {
|
|
20
|
+
constructor(props: Props) {
|
|
21
|
+
super(props);
|
|
22
|
+
this.state = { hasError: false };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static getDerivedStateFromError(error: Error): State {
|
|
26
|
+
return { hasError: true, error };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
|
|
30
|
+
if (__DEV__) {
|
|
31
|
+
console.error("Splash Screen Error:", error, errorInfo);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
render() {
|
|
36
|
+
if (this.state.hasError) {
|
|
37
|
+
if (this.props.fallback) {
|
|
38
|
+
return this.props.fallback;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<View style={styles.container}>
|
|
43
|
+
<Text style={styles.text}>Something went wrong</Text>
|
|
44
|
+
</View>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return this.props.children;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const styles = StyleSheet.create({
|
|
53
|
+
container: {
|
|
54
|
+
flex: 1,
|
|
55
|
+
alignItems: "center",
|
|
56
|
+
justifyContent: "center",
|
|
57
|
+
backgroundColor: "#000000",
|
|
58
|
+
},
|
|
59
|
+
text: {
|
|
60
|
+
color: "#FFFFFF",
|
|
61
|
+
fontSize: 16,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splash Loading Component
|
|
3
|
+
* Single Responsibility: Render splash screen loading indicator
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from "react";
|
|
7
|
+
import { View, Text, StyleSheet } from "react-native";
|
|
8
|
+
import type { DesignTokens } from "@umituz/react-native-design-system-theme";
|
|
9
|
+
|
|
10
|
+
export interface SplashLoadingProps {
|
|
11
|
+
loadingText: string;
|
|
12
|
+
tokens: DesignTokens;
|
|
13
|
+
bottomInset: number;
|
|
14
|
+
textColor?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const SplashLoading: React.FC<SplashLoadingProps> = ({
|
|
18
|
+
loadingText,
|
|
19
|
+
tokens,
|
|
20
|
+
bottomInset,
|
|
21
|
+
textColor = "#FFFFFF",
|
|
22
|
+
}) => {
|
|
23
|
+
const styles = getStyles(tokens, bottomInset, textColor);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<View style={styles.container}>
|
|
27
|
+
<View style={styles.barContainer}>
|
|
28
|
+
<View style={styles.bar} />
|
|
29
|
+
</View>
|
|
30
|
+
<Text style={styles.text}>{loadingText}</Text>
|
|
31
|
+
</View>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const getStyles = (tokens: DesignTokens, bottomInset: number, textColor: string) => {
|
|
36
|
+
return StyleSheet.create({
|
|
37
|
+
container: {
|
|
38
|
+
alignItems: "center",
|
|
39
|
+
justifyContent: "center",
|
|
40
|
+
paddingBottom: tokens.spacing.xxxl + bottomInset,
|
|
41
|
+
zIndex: 1,
|
|
42
|
+
},
|
|
43
|
+
barContainer: {
|
|
44
|
+
width: 120,
|
|
45
|
+
height: 4,
|
|
46
|
+
backgroundColor: "rgba(255, 255, 255, 0.2)",
|
|
47
|
+
borderRadius: 2,
|
|
48
|
+
overflow: "hidden",
|
|
49
|
+
marginBottom: tokens.spacing.md,
|
|
50
|
+
},
|
|
51
|
+
bar: {
|
|
52
|
+
width: "60%",
|
|
53
|
+
height: "100%",
|
|
54
|
+
backgroundColor: textColor,
|
|
55
|
+
borderRadius: 2,
|
|
56
|
+
shadowColor: textColor,
|
|
57
|
+
shadowOffset: { width: 0, height: 0 },
|
|
58
|
+
shadowOpacity: 0.8,
|
|
59
|
+
shadowRadius: 4,
|
|
60
|
+
elevation: 4,
|
|
61
|
+
},
|
|
62
|
+
text: {
|
|
63
|
+
fontSize: 13,
|
|
64
|
+
color: textColor,
|
|
65
|
+
opacity: 0.9,
|
|
66
|
+
fontWeight: "500" as const,
|
|
67
|
+
letterSpacing: 0.8,
|
|
68
|
+
textShadowColor: "rgba(0, 0, 0, 0.15)",
|
|
69
|
+
textShadowOffset: { width: 0, height: 1 },
|
|
70
|
+
textShadowRadius: 2,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splash Logo Component
|
|
3
|
+
* Single Responsibility: Render splash screen logo
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from "react";
|
|
7
|
+
import { View, StyleSheet } from "react-native";
|
|
8
|
+
import { AtomicIcon } from "@umituz/react-native-design-system-atoms";
|
|
9
|
+
|
|
10
|
+
export interface SplashLogoProps {
|
|
11
|
+
logo?: string | React.ReactNode;
|
|
12
|
+
logoSize?: number;
|
|
13
|
+
glowSize?: number;
|
|
14
|
+
iconColor?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const SplashLogo: React.FC<SplashLogoProps> = ({
|
|
18
|
+
logo,
|
|
19
|
+
logoSize = 140,
|
|
20
|
+
glowSize = 160,
|
|
21
|
+
iconColor = "#FFFFFF",
|
|
22
|
+
}) => {
|
|
23
|
+
const styles = getStyles(logoSize, glowSize);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<View style={styles.container}>
|
|
27
|
+
<View style={styles.glow} />
|
|
28
|
+
<View style={styles.background}>
|
|
29
|
+
{typeof logo === "string" ? (
|
|
30
|
+
<AtomicIcon name={logo || "sparkles"} size="xxl" customColor={iconColor} />
|
|
31
|
+
) : logo ? (
|
|
32
|
+
logo
|
|
33
|
+
) : (
|
|
34
|
+
<AtomicIcon name="sparkles" size="xxl" customColor={iconColor} />
|
|
35
|
+
)}
|
|
36
|
+
</View>
|
|
37
|
+
</View>
|
|
38
|
+
);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const getStyles = (logoSize: number, glowSize: number) => {
|
|
42
|
+
const radius = logoSize / 2;
|
|
43
|
+
const glowRadius = glowSize / 2;
|
|
44
|
+
|
|
45
|
+
return StyleSheet.create({
|
|
46
|
+
container: {
|
|
47
|
+
alignItems: "center",
|
|
48
|
+
justifyContent: "center",
|
|
49
|
+
position: "relative",
|
|
50
|
+
},
|
|
51
|
+
glow: {
|
|
52
|
+
position: "absolute",
|
|
53
|
+
width: glowSize,
|
|
54
|
+
height: glowSize,
|
|
55
|
+
borderRadius: glowRadius,
|
|
56
|
+
backgroundColor: "rgba(255, 255, 255, 0.15)",
|
|
57
|
+
shadowColor: "#FFFFFF",
|
|
58
|
+
shadowOffset: { width: 0, height: 0 },
|
|
59
|
+
shadowOpacity: 0.5,
|
|
60
|
+
shadowRadius: 30,
|
|
61
|
+
elevation: 10,
|
|
62
|
+
},
|
|
63
|
+
background: {
|
|
64
|
+
width: logoSize,
|
|
65
|
+
height: logoSize,
|
|
66
|
+
borderRadius: radius,
|
|
67
|
+
backgroundColor: "rgba(255, 255, 255, 0.2)",
|
|
68
|
+
alignItems: "center",
|
|
69
|
+
justifyContent: "center",
|
|
70
|
+
borderWidth: 2,
|
|
71
|
+
borderColor: "rgba(255, 255, 255, 0.3)",
|
|
72
|
+
shadowColor: "#000",
|
|
73
|
+
shadowOffset: { width: 0, height: 4 },
|
|
74
|
+
shadowOpacity: 0.3,
|
|
75
|
+
shadowRadius: 8,
|
|
76
|
+
elevation: 8,
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
|