@rubixscript/react-native-onboarding 1.0.1 → 1.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/LICENSE +21 -21
- package/README.md +383 -383
- package/dist/components/NavigationButtons.js +17 -17
- package/dist/components/Onboarding.js +16 -16
- package/dist/components/Pagination.js +30 -30
- package/dist/components/SimpleOnboardingScreen.d.ts +54 -0
- package/dist/components/SimpleOnboardingScreen.d.ts.map +1 -0
- package/dist/components/SimpleOnboardingScreen.js +184 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/presets/index.d.ts.map +1 -1
- package/dist/presets/index.js +24 -27
- package/dist/slides/FormSlide.js +37 -37
- package/dist/slides/IconSlide.js +24 -24
- package/dist/slides/ImageSlide.js +20 -20
- package/dist/slides/VideoSlide.js +20 -20
- package/dist/themes/index.d.ts.map +1 -1
- package/dist/themes/index.js +9 -7
- package/package.json +73 -66
- package/src/components/NavigationButtons.tsx +198 -198
- package/src/components/Onboarding.tsx +337 -337
- package/src/components/Pagination.tsx +337 -337
- package/src/components/SimpleOnboardingScreen.tsx +266 -0
- package/src/components/index.ts +7 -5
- package/src/index.ts +69 -65
- package/src/presets/index.ts +391 -394
- package/src/slides/FormSlide.tsx +314 -314
- package/src/slides/IconSlide.tsx +166 -166
- package/src/slides/ImageSlide.tsx +132 -132
- package/src/slides/VideoSlide.tsx +146 -146
- package/src/slides/index.tsx +37 -37
- package/src/themes/index.ts +576 -574
- package/src/types/index.ts +247 -247
|
@@ -1,146 +1,146 @@
|
|
|
1
|
-
import React, { useMemo, useState, useRef } from 'react';
|
|
2
|
-
import { View, Text, StyleSheet, Dimensions, Platform } from 'react-native';
|
|
3
|
-
import { Video, ResizeMode, AVPlaybackStatus } from 'expo-av';
|
|
4
|
-
import Animated, { FadeIn, FadeInDown } from 'react-native-reanimated';
|
|
5
|
-
import { LinearGradient } from 'expo-linear-gradient';
|
|
6
|
-
import { VideoSlideData, OnboardingTheme } from '../types';
|
|
7
|
-
|
|
8
|
-
interface VideoSlideProps {
|
|
9
|
-
data: VideoSlideData;
|
|
10
|
-
theme: OnboardingTheme;
|
|
11
|
-
darkMode?: boolean;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const { width: SCREEN_WIDTH } = Dimensions.get('window');
|
|
15
|
-
|
|
16
|
-
export const VideoSlide: React.FC<VideoSlideProps> = ({ data, theme, darkMode }) => {
|
|
17
|
-
const { videoSource, title, description, autoPlay = true, loop = true, muted = true, poster, gradientColors } = data;
|
|
18
|
-
const videoRef = useRef<Video>(null);
|
|
19
|
-
const [isReady, setIsReady] = useState(false);
|
|
20
|
-
|
|
21
|
-
const handleVideoLoad = (status: AVPlaybackStatus) => {
|
|
22
|
-
if (status.isLoaded) {
|
|
23
|
-
setIsReady(true);
|
|
24
|
-
if (autoPlay) {
|
|
25
|
-
videoRef.current?.playAsync();
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const containerStyle = useMemo(() => {
|
|
31
|
-
const styles: any = {
|
|
32
|
-
flex: 1,
|
|
33
|
-
justifyContent: 'center',
|
|
34
|
-
alignItems: 'center',
|
|
35
|
-
padding: theme.spacing.lg,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
if (data.backgroundColor) {
|
|
39
|
-
styles.backgroundColor = data.backgroundColor;
|
|
40
|
-
} else if (gradientColors && gradientColors.length > 0) {
|
|
41
|
-
// Will use LinearGradient
|
|
42
|
-
} else {
|
|
43
|
-
styles.backgroundColor = theme.colors.background;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return styles;
|
|
47
|
-
}, [data, theme]);
|
|
48
|
-
|
|
49
|
-
const videoContainerStyle = useMemo(() => ({
|
|
50
|
-
...styles.videoContainer,
|
|
51
|
-
marginBottom: theme.spacing.lg,
|
|
52
|
-
}), [theme]);
|
|
53
|
-
|
|
54
|
-
const videoStyle = {
|
|
55
|
-
width: SCREEN_WIDTH - theme.spacing.xl * 2,
|
|
56
|
-
height: (SCREEN_WIDTH - theme.spacing.xl * 2) * (9 / 16),
|
|
57
|
-
borderRadius: theme.borderRadius.lg,
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const titleStyle = useMemo(() => ({
|
|
61
|
-
...styles.title,
|
|
62
|
-
color: gradientColors?.length ? theme.colors.text.primary : theme.colors.text.primary,
|
|
63
|
-
}), [gradientColors, theme]);
|
|
64
|
-
|
|
65
|
-
const descriptionStyle = useMemo(() => ({
|
|
66
|
-
...styles.description,
|
|
67
|
-
color: gradientColors?.length ? theme.colors.text.secondary : theme.colors.text.secondary,
|
|
68
|
-
}), [gradientColors, theme]);
|
|
69
|
-
|
|
70
|
-
const videoSourceUri = typeof videoSource === 'string' ? { uri: videoSource } : videoSource;
|
|
71
|
-
|
|
72
|
-
const content = (
|
|
73
|
-
<>
|
|
74
|
-
{/* Video */}
|
|
75
|
-
<Animated.View entering={FadeIn.duration(400)} style={videoContainerStyle}>
|
|
76
|
-
<View style={videoStyle}>
|
|
77
|
-
<Video
|
|
78
|
-
ref={videoRef}
|
|
79
|
-
source={videoSourceUri}
|
|
80
|
-
style={StyleSheet.absoluteFillObject}
|
|
81
|
-
useNativeControls={false}
|
|
82
|
-
resizeMode={ResizeMode.CONTAIN}
|
|
83
|
-
shouldPlay={autoPlay}
|
|
84
|
-
isLooping={loop}
|
|
85
|
-
isMuted={muted}
|
|
86
|
-
onLoad={handleVideoLoad}
|
|
87
|
-
/>
|
|
88
|
-
{!isReady && poster && (
|
|
89
|
-
<Animated.Image
|
|
90
|
-
source={poster}
|
|
91
|
-
style={StyleSheet.absoluteFillObject}
|
|
92
|
-
resizeMode="cover"
|
|
93
|
-
/>
|
|
94
|
-
)}
|
|
95
|
-
</View>
|
|
96
|
-
</Animated.View>
|
|
97
|
-
|
|
98
|
-
{/* Title */}
|
|
99
|
-
{title && (
|
|
100
|
-
<Animated.Text entering={FadeInDown.delay(100).springify()} style={titleStyle}>
|
|
101
|
-
{title}
|
|
102
|
-
</Animated.Text>
|
|
103
|
-
)}
|
|
104
|
-
|
|
105
|
-
{/* Description */}
|
|
106
|
-
{description && (
|
|
107
|
-
<Animated.Text entering={FadeInDown.delay(200).springify()} style={descriptionStyle}>
|
|
108
|
-
{description}
|
|
109
|
-
</Animated.Text>
|
|
110
|
-
)}
|
|
111
|
-
</>
|
|
112
|
-
);
|
|
113
|
-
|
|
114
|
-
if (gradientColors && gradientColors.length > 0) {
|
|
115
|
-
return (
|
|
116
|
-
<LinearGradient colors={gradientColors as any} style={StyleSheet.absoluteFillObject}>
|
|
117
|
-
<View style={containerStyle}>{content}</View>
|
|
118
|
-
</LinearGradient>
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return <View style={containerStyle}>{content}</View>;
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
const styles = StyleSheet.create({
|
|
126
|
-
videoContainer: {
|
|
127
|
-
width: '100%',
|
|
128
|
-
alignItems: 'center',
|
|
129
|
-
overflow: 'hidden',
|
|
130
|
-
},
|
|
131
|
-
title: {
|
|
132
|
-
fontSize: 28,
|
|
133
|
-
fontWeight: '700',
|
|
134
|
-
textAlign: 'center',
|
|
135
|
-
marginBottom: 12,
|
|
136
|
-
paddingHorizontal: 20,
|
|
137
|
-
},
|
|
138
|
-
description: {
|
|
139
|
-
fontSize: 15,
|
|
140
|
-
textAlign: 'center',
|
|
141
|
-
paddingHorizontal: 32,
|
|
142
|
-
lineHeight: 22,
|
|
143
|
-
},
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
export default VideoSlide;
|
|
1
|
+
import React, { useMemo, useState, useRef } from 'react';
|
|
2
|
+
import { View, Text, StyleSheet, Dimensions, Platform } from 'react-native';
|
|
3
|
+
import { Video, ResizeMode, AVPlaybackStatus } from 'expo-av';
|
|
4
|
+
import Animated, { FadeIn, FadeInDown } from 'react-native-reanimated';
|
|
5
|
+
import { LinearGradient } from 'expo-linear-gradient';
|
|
6
|
+
import { VideoSlideData, OnboardingTheme } from '../types';
|
|
7
|
+
|
|
8
|
+
interface VideoSlideProps {
|
|
9
|
+
data: VideoSlideData;
|
|
10
|
+
theme: OnboardingTheme;
|
|
11
|
+
darkMode?: boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const { width: SCREEN_WIDTH } = Dimensions.get('window');
|
|
15
|
+
|
|
16
|
+
export const VideoSlide: React.FC<VideoSlideProps> = ({ data, theme, darkMode }) => {
|
|
17
|
+
const { videoSource, title, description, autoPlay = true, loop = true, muted = true, poster, gradientColors } = data;
|
|
18
|
+
const videoRef = useRef<Video>(null);
|
|
19
|
+
const [isReady, setIsReady] = useState(false);
|
|
20
|
+
|
|
21
|
+
const handleVideoLoad = (status: AVPlaybackStatus) => {
|
|
22
|
+
if (status.isLoaded) {
|
|
23
|
+
setIsReady(true);
|
|
24
|
+
if (autoPlay) {
|
|
25
|
+
videoRef.current?.playAsync();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const containerStyle = useMemo(() => {
|
|
31
|
+
const styles: any = {
|
|
32
|
+
flex: 1,
|
|
33
|
+
justifyContent: 'center',
|
|
34
|
+
alignItems: 'center',
|
|
35
|
+
padding: theme.spacing.lg,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
if (data.backgroundColor) {
|
|
39
|
+
styles.backgroundColor = data.backgroundColor;
|
|
40
|
+
} else if (gradientColors && gradientColors.length > 0) {
|
|
41
|
+
// Will use LinearGradient
|
|
42
|
+
} else {
|
|
43
|
+
styles.backgroundColor = theme.colors.background;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return styles;
|
|
47
|
+
}, [data, theme]);
|
|
48
|
+
|
|
49
|
+
const videoContainerStyle = useMemo(() => ({
|
|
50
|
+
...styles.videoContainer,
|
|
51
|
+
marginBottom: theme.spacing.lg,
|
|
52
|
+
}), [theme]);
|
|
53
|
+
|
|
54
|
+
const videoStyle = {
|
|
55
|
+
width: SCREEN_WIDTH - theme.spacing.xl * 2,
|
|
56
|
+
height: (SCREEN_WIDTH - theme.spacing.xl * 2) * (9 / 16),
|
|
57
|
+
borderRadius: theme.borderRadius.lg,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const titleStyle = useMemo(() => ({
|
|
61
|
+
...styles.title,
|
|
62
|
+
color: gradientColors?.length ? theme.colors.text.primary : theme.colors.text.primary,
|
|
63
|
+
}), [gradientColors, theme]);
|
|
64
|
+
|
|
65
|
+
const descriptionStyle = useMemo(() => ({
|
|
66
|
+
...styles.description,
|
|
67
|
+
color: gradientColors?.length ? theme.colors.text.secondary : theme.colors.text.secondary,
|
|
68
|
+
}), [gradientColors, theme]);
|
|
69
|
+
|
|
70
|
+
const videoSourceUri = typeof videoSource === 'string' ? { uri: videoSource } : videoSource;
|
|
71
|
+
|
|
72
|
+
const content = (
|
|
73
|
+
<>
|
|
74
|
+
{/* Video */}
|
|
75
|
+
<Animated.View entering={FadeIn.duration(400)} style={videoContainerStyle}>
|
|
76
|
+
<View style={videoStyle}>
|
|
77
|
+
<Video
|
|
78
|
+
ref={videoRef}
|
|
79
|
+
source={videoSourceUri}
|
|
80
|
+
style={StyleSheet.absoluteFillObject}
|
|
81
|
+
useNativeControls={false}
|
|
82
|
+
resizeMode={ResizeMode.CONTAIN}
|
|
83
|
+
shouldPlay={autoPlay}
|
|
84
|
+
isLooping={loop}
|
|
85
|
+
isMuted={muted}
|
|
86
|
+
onLoad={handleVideoLoad}
|
|
87
|
+
/>
|
|
88
|
+
{!isReady && poster && (
|
|
89
|
+
<Animated.Image
|
|
90
|
+
source={poster}
|
|
91
|
+
style={StyleSheet.absoluteFillObject}
|
|
92
|
+
resizeMode="cover"
|
|
93
|
+
/>
|
|
94
|
+
)}
|
|
95
|
+
</View>
|
|
96
|
+
</Animated.View>
|
|
97
|
+
|
|
98
|
+
{/* Title */}
|
|
99
|
+
{title && (
|
|
100
|
+
<Animated.Text entering={FadeInDown.delay(100).springify()} style={titleStyle}>
|
|
101
|
+
{title}
|
|
102
|
+
</Animated.Text>
|
|
103
|
+
)}
|
|
104
|
+
|
|
105
|
+
{/* Description */}
|
|
106
|
+
{description && (
|
|
107
|
+
<Animated.Text entering={FadeInDown.delay(200).springify()} style={descriptionStyle}>
|
|
108
|
+
{description}
|
|
109
|
+
</Animated.Text>
|
|
110
|
+
)}
|
|
111
|
+
</>
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
if (gradientColors && gradientColors.length > 0) {
|
|
115
|
+
return (
|
|
116
|
+
<LinearGradient colors={gradientColors as any} style={StyleSheet.absoluteFillObject}>
|
|
117
|
+
<View style={containerStyle}>{content}</View>
|
|
118
|
+
</LinearGradient>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return <View style={containerStyle}>{content}</View>;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const styles = StyleSheet.create({
|
|
126
|
+
videoContainer: {
|
|
127
|
+
width: '100%',
|
|
128
|
+
alignItems: 'center',
|
|
129
|
+
overflow: 'hidden',
|
|
130
|
+
},
|
|
131
|
+
title: {
|
|
132
|
+
fontSize: 28,
|
|
133
|
+
fontWeight: '700',
|
|
134
|
+
textAlign: 'center',
|
|
135
|
+
marginBottom: 12,
|
|
136
|
+
paddingHorizontal: 20,
|
|
137
|
+
},
|
|
138
|
+
description: {
|
|
139
|
+
fontSize: 15,
|
|
140
|
+
textAlign: 'center',
|
|
141
|
+
paddingHorizontal: 32,
|
|
142
|
+
lineHeight: 22,
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
export default VideoSlide;
|
package/src/slides/index.tsx
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
|
-
export { ImageSlide } from './ImageSlide';
|
|
2
|
-
export { IconSlide } from './IconSlide';
|
|
3
|
-
export { FormSlide } from './FormSlide';
|
|
4
|
-
export { VideoSlide } from './VideoSlide';
|
|
5
|
-
|
|
6
|
-
import { ImageSlide } from './ImageSlide';
|
|
7
|
-
import { IconSlide } from './IconSlide';
|
|
8
|
-
import { FormSlide } from './FormSlide';
|
|
9
|
-
import { VideoSlide } from './VideoSlide';
|
|
10
|
-
import { SlideData, OnboardingTheme } from '../types';
|
|
11
|
-
|
|
12
|
-
interface SlideRendererProps {
|
|
13
|
-
data: SlideData;
|
|
14
|
-
theme: OnboardingTheme;
|
|
15
|
-
darkMode?: boolean;
|
|
16
|
-
onSubmit?: (data: Record<string, any>) => void;
|
|
17
|
-
isSubmitting?: boolean;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const SlideRenderer: React.FC<SlideRendererProps> = ({ data, theme, darkMode, onSubmit, isSubmitting }) => {
|
|
21
|
-
switch (data.type) {
|
|
22
|
-
case 'image':
|
|
23
|
-
return <ImageSlide data={data} theme={theme} darkMode={darkMode} />;
|
|
24
|
-
case 'icon':
|
|
25
|
-
return <IconSlide data={data} theme={theme} darkMode={darkMode} />;
|
|
26
|
-
case 'form':
|
|
27
|
-
return <FormSlide data={data} theme={theme} onSubmit={onSubmit || (() => {})} darkMode={darkMode} isSubmitting={isSubmitting} />;
|
|
28
|
-
case 'video':
|
|
29
|
-
return <VideoSlide data={data} theme={theme} darkMode={darkMode} />;
|
|
30
|
-
case 'custom':
|
|
31
|
-
const CustomComponent = (data as any).component;
|
|
32
|
-
return <CustomComponent {...(data as any).props} theme={theme} darkMode={darkMode} />;
|
|
33
|
-
default:
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
|
|
1
|
+
export { ImageSlide } from './ImageSlide';
|
|
2
|
+
export { IconSlide } from './IconSlide';
|
|
3
|
+
export { FormSlide } from './FormSlide';
|
|
4
|
+
export { VideoSlide } from './VideoSlide';
|
|
5
|
+
|
|
6
|
+
import { ImageSlide } from './ImageSlide';
|
|
7
|
+
import { IconSlide } from './IconSlide';
|
|
8
|
+
import { FormSlide } from './FormSlide';
|
|
9
|
+
import { VideoSlide } from './VideoSlide';
|
|
10
|
+
import { SlideData, OnboardingTheme } from '../types';
|
|
11
|
+
|
|
12
|
+
interface SlideRendererProps {
|
|
13
|
+
data: SlideData;
|
|
14
|
+
theme: OnboardingTheme;
|
|
15
|
+
darkMode?: boolean;
|
|
16
|
+
onSubmit?: (data: Record<string, any>) => void;
|
|
17
|
+
isSubmitting?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const SlideRenderer: React.FC<SlideRendererProps> = ({ data, theme, darkMode, onSubmit, isSubmitting }) => {
|
|
21
|
+
switch (data.type) {
|
|
22
|
+
case 'image':
|
|
23
|
+
return <ImageSlide data={data} theme={theme} darkMode={darkMode} />;
|
|
24
|
+
case 'icon':
|
|
25
|
+
return <IconSlide data={data} theme={theme} darkMode={darkMode} />;
|
|
26
|
+
case 'form':
|
|
27
|
+
return <FormSlide data={data} theme={theme} onSubmit={onSubmit || (() => {})} darkMode={darkMode} isSubmitting={isSubmitting} />;
|
|
28
|
+
case 'video':
|
|
29
|
+
return <VideoSlide data={data} theme={theme} darkMode={darkMode} />;
|
|
30
|
+
case 'custom':
|
|
31
|
+
const CustomComponent = (data as any).component;
|
|
32
|
+
return <CustomComponent {...(data as any).props} theme={theme} darkMode={darkMode} />;
|
|
33
|
+
default:
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|