@umituz/react-native-onboarding 2.6.7 → 2.6.8
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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@umituz/react-native-onboarding",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.8",
|
|
4
4
|
"description": "Advanced onboarding flow for React Native apps with personalization questions, theme-aware colors, animations, and customizable slides. SOLID, DRY, KISS principles applied.",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -15,12 +15,24 @@ export interface QuestionRendererProps {
|
|
|
15
15
|
question: OnboardingQuestion;
|
|
16
16
|
value: any;
|
|
17
17
|
onChange: (value: any) => void;
|
|
18
|
+
SliderComponent?: React.ComponentType<{
|
|
19
|
+
style?: any;
|
|
20
|
+
minimumValue: number;
|
|
21
|
+
maximumValue: number;
|
|
22
|
+
value: number;
|
|
23
|
+
onValueChange: (value: number) => void;
|
|
24
|
+
minimumTrackTintColor?: string;
|
|
25
|
+
maximumTrackTintColor?: string;
|
|
26
|
+
thumbTintColor?: string;
|
|
27
|
+
step?: number;
|
|
28
|
+
}>;
|
|
18
29
|
}
|
|
19
30
|
|
|
20
31
|
export const QuestionRenderer: React.FC<QuestionRendererProps> = ({
|
|
21
32
|
question,
|
|
22
33
|
value,
|
|
23
34
|
onChange,
|
|
35
|
+
SliderComponent,
|
|
24
36
|
}) => {
|
|
25
37
|
switch (question.type) {
|
|
26
38
|
case "single_choice":
|
|
@@ -48,11 +60,15 @@ export const QuestionRenderer: React.FC<QuestionRendererProps> = ({
|
|
|
48
60
|
/>
|
|
49
61
|
);
|
|
50
62
|
case "slider":
|
|
63
|
+
if (!SliderComponent) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
51
66
|
return (
|
|
52
67
|
<SliderQuestion
|
|
53
68
|
question={question}
|
|
54
69
|
value={value}
|
|
55
70
|
onChange={onChange}
|
|
71
|
+
SliderComponent={SliderComponent}
|
|
56
72
|
/>
|
|
57
73
|
);
|
|
58
74
|
case "rating":
|
|
@@ -67,4 +83,3 @@ export const QuestionRenderer: React.FC<QuestionRendererProps> = ({
|
|
|
67
83
|
return null;
|
|
68
84
|
}
|
|
69
85
|
};
|
|
70
|
-
|
|
@@ -15,6 +15,17 @@ export interface QuestionSlideProps {
|
|
|
15
15
|
value: any;
|
|
16
16
|
onChange: (value: any) => void;
|
|
17
17
|
useGradient?: boolean;
|
|
18
|
+
SliderComponent?: React.ComponentType<{
|
|
19
|
+
style?: any;
|
|
20
|
+
minimumValue: number;
|
|
21
|
+
maximumValue: number;
|
|
22
|
+
value: number;
|
|
23
|
+
onValueChange: (value: number) => void;
|
|
24
|
+
minimumTrackTintColor?: string;
|
|
25
|
+
maximumTrackTintColor?: string;
|
|
26
|
+
thumbTintColor?: string;
|
|
27
|
+
step?: number;
|
|
28
|
+
}>;
|
|
18
29
|
}
|
|
19
30
|
|
|
20
31
|
export const QuestionSlide: React.FC<QuestionSlideProps> = ({
|
|
@@ -22,6 +33,7 @@ export const QuestionSlide: React.FC<QuestionSlideProps> = ({
|
|
|
22
33
|
value,
|
|
23
34
|
onChange,
|
|
24
35
|
useGradient = false,
|
|
36
|
+
SliderComponent,
|
|
25
37
|
}) => {
|
|
26
38
|
const tokens = useAppDesignTokens();
|
|
27
39
|
const styles = useMemo(() => getStyles(tokens, useGradient), [tokens, useGradient]);
|
|
@@ -36,7 +48,12 @@ export const QuestionSlide: React.FC<QuestionSlideProps> = ({
|
|
|
36
48
|
<QuestionSlideHeader slide={slide} useGradient={useGradient} />
|
|
37
49
|
|
|
38
50
|
<View style={styles.questionContainer}>
|
|
39
|
-
<QuestionRenderer
|
|
51
|
+
<QuestionRenderer
|
|
52
|
+
question={question}
|
|
53
|
+
value={value}
|
|
54
|
+
onChange={onChange}
|
|
55
|
+
SliderComponent={SliderComponent}
|
|
56
|
+
/>
|
|
40
57
|
</View>
|
|
41
58
|
|
|
42
59
|
{question.validation?.required && !value && (
|
|
@@ -4,22 +4,24 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import React, { useMemo } from "react";
|
|
7
|
-
import { View, Text,
|
|
7
|
+
import { View, Text, StyleSheet } from "react-native";
|
|
8
8
|
import type { OnboardingQuestion } from "../../../domain/entities/OnboardingQuestion";
|
|
9
9
|
|
|
10
|
-
// Lazy import slider to handle peer dependency gracefully
|
|
11
|
-
let SliderComponent: any = null;
|
|
12
|
-
try {
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
14
|
-
SliderComponent = require("@react-native-community/slider").default;
|
|
15
|
-
} catch {
|
|
16
|
-
// Slider not available - will show fallback
|
|
17
|
-
}
|
|
18
|
-
|
|
19
10
|
export interface SliderQuestionProps {
|
|
20
11
|
question: OnboardingQuestion;
|
|
21
12
|
value: number | undefined;
|
|
22
13
|
onChange: (value: number) => void;
|
|
14
|
+
SliderComponent: React.ComponentType<{
|
|
15
|
+
style?: any;
|
|
16
|
+
minimumValue: number;
|
|
17
|
+
maximumValue: number;
|
|
18
|
+
value: number;
|
|
19
|
+
onValueChange: (value: number) => void;
|
|
20
|
+
minimumTrackTintColor?: string;
|
|
21
|
+
maximumTrackTintColor?: string;
|
|
22
|
+
thumbTintColor?: string;
|
|
23
|
+
step?: number;
|
|
24
|
+
}>;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
const getSliderConfig = (question: OnboardingQuestion) => {
|
|
@@ -29,87 +31,35 @@ const getSliderConfig = (question: OnboardingQuestion) => {
|
|
|
29
31
|
return { min, max };
|
|
30
32
|
};
|
|
31
33
|
|
|
32
|
-
const SliderFallback: React.FC<{
|
|
33
|
-
min: number;
|
|
34
|
-
max: number;
|
|
35
|
-
value: number;
|
|
36
|
-
onChange: (value: number) => void;
|
|
37
|
-
}> = ({ min, max, value, onChange }) => {
|
|
38
|
-
const handleIncrement = () => {
|
|
39
|
-
if (value < max) {
|
|
40
|
-
onChange(value + 1);
|
|
41
|
-
}
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
const handleDecrement = () => {
|
|
45
|
-
if (value > min) {
|
|
46
|
-
onChange(value - 1);
|
|
47
|
-
}
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
return (
|
|
51
|
-
<View style={styles.fallbackContainer}>
|
|
52
|
-
<View style={styles.fallbackControls}>
|
|
53
|
-
<TouchableOpacity
|
|
54
|
-
style={styles.fallbackButton}
|
|
55
|
-
onPress={handleDecrement}
|
|
56
|
-
activeOpacity={0.7}
|
|
57
|
-
>
|
|
58
|
-
<Text style={styles.fallbackButtonText}>−</Text>
|
|
59
|
-
</TouchableOpacity>
|
|
60
|
-
<Text style={styles.fallbackValue}>{value}</Text>
|
|
61
|
-
<TouchableOpacity
|
|
62
|
-
style={styles.fallbackButton}
|
|
63
|
-
onPress={handleIncrement}
|
|
64
|
-
activeOpacity={0.7}
|
|
65
|
-
>
|
|
66
|
-
<Text style={styles.fallbackButtonText}>+</Text>
|
|
67
|
-
</TouchableOpacity>
|
|
68
|
-
</View>
|
|
69
|
-
<View style={styles.fallbackLabels}>
|
|
70
|
-
<Text style={styles.label}>{min}</Text>
|
|
71
|
-
<Text style={styles.label}>{max}</Text>
|
|
72
|
-
</View>
|
|
73
|
-
</View>
|
|
74
|
-
);
|
|
75
|
-
};
|
|
76
|
-
|
|
77
34
|
export const SliderQuestion: React.FC<SliderQuestionProps> = ({
|
|
78
35
|
question,
|
|
79
36
|
value,
|
|
80
37
|
onChange,
|
|
38
|
+
SliderComponent,
|
|
81
39
|
}) => {
|
|
82
40
|
const { min, max } = useMemo(() => getSliderConfig(question), [question]);
|
|
83
41
|
const currentValue = value ?? min;
|
|
84
42
|
|
|
85
|
-
const sliderProps = {
|
|
86
|
-
style: styles.slider,
|
|
87
|
-
minimumValue: min,
|
|
88
|
-
maximumValue: max,
|
|
89
|
-
value: currentValue,
|
|
90
|
-
onValueChange: onChange,
|
|
91
|
-
minimumTrackTintColor: "#FFFFFF",
|
|
92
|
-
maximumTrackTintColor: "rgba(255, 255, 255, 0.3)",
|
|
93
|
-
thumbTintColor: "#FFFFFF",
|
|
94
|
-
step: 1,
|
|
95
|
-
};
|
|
96
|
-
|
|
97
43
|
return (
|
|
98
44
|
<View style={styles.container}>
|
|
99
45
|
<View style={styles.valueContainer}>
|
|
100
46
|
<Text style={styles.valueText}>{currentValue}</Text>
|
|
101
47
|
</View>
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
48
|
+
<SliderComponent
|
|
49
|
+
style={styles.slider}
|
|
50
|
+
minimumValue={min}
|
|
51
|
+
maximumValue={max}
|
|
52
|
+
value={currentValue}
|
|
53
|
+
onValueChange={onChange}
|
|
54
|
+
minimumTrackTintColor="#FFFFFF"
|
|
55
|
+
maximumTrackTintColor="rgba(255, 255, 255, 0.3)"
|
|
56
|
+
thumbTintColor="#FFFFFF"
|
|
57
|
+
step={1}
|
|
58
|
+
/>
|
|
59
|
+
<View style={styles.labels}>
|
|
60
|
+
<Text style={styles.label}>{min}</Text>
|
|
61
|
+
<Text style={styles.label}>{max}</Text>
|
|
62
|
+
</View>
|
|
113
63
|
</View>
|
|
114
64
|
);
|
|
115
65
|
};
|
|
@@ -142,39 +92,4 @@ const styles = StyleSheet.create({
|
|
|
142
92
|
color: "rgba(255, 255, 255, 0.7)",
|
|
143
93
|
fontWeight: "500",
|
|
144
94
|
},
|
|
145
|
-
fallbackContainer: {
|
|
146
|
-
width: "100%",
|
|
147
|
-
},
|
|
148
|
-
fallbackControls: {
|
|
149
|
-
flexDirection: "row",
|
|
150
|
-
alignItems: "center",
|
|
151
|
-
justifyContent: "center",
|
|
152
|
-
gap: 24,
|
|
153
|
-
},
|
|
154
|
-
fallbackButton: {
|
|
155
|
-
width: 60,
|
|
156
|
-
height: 60,
|
|
157
|
-
backgroundColor: "rgba(255, 255, 255, 0.2)",
|
|
158
|
-
borderRadius: 30,
|
|
159
|
-
alignItems: "center",
|
|
160
|
-
justifyContent: "center",
|
|
161
|
-
},
|
|
162
|
-
fallbackButtonText: {
|
|
163
|
-
fontSize: 48,
|
|
164
|
-
fontWeight: "bold",
|
|
165
|
-
color: "#FFFFFF",
|
|
166
|
-
lineHeight: 60,
|
|
167
|
-
},
|
|
168
|
-
fallbackValue: {
|
|
169
|
-
fontSize: 36,
|
|
170
|
-
fontWeight: "bold",
|
|
171
|
-
color: "#FFFFFF",
|
|
172
|
-
minWidth: 80,
|
|
173
|
-
textAlign: "center",
|
|
174
|
-
},
|
|
175
|
-
fallbackLabels: {
|
|
176
|
-
flexDirection: "row",
|
|
177
|
-
justifyContent: "space-between",
|
|
178
|
-
marginTop: 16,
|
|
179
|
-
},
|
|
180
95
|
});
|
|
@@ -62,6 +62,23 @@ export interface OnboardingScreenProps extends OnboardingOptions {
|
|
|
62
62
|
* When true, shows premium paywall before completing onboarding
|
|
63
63
|
*/
|
|
64
64
|
showPaywallOnComplete?: boolean;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Slider component for slider questions
|
|
68
|
+
* Required if using slider question type
|
|
69
|
+
* Import from @react-native-community/slider
|
|
70
|
+
*/
|
|
71
|
+
SliderComponent?: React.ComponentType<{
|
|
72
|
+
style?: any;
|
|
73
|
+
minimumValue: number;
|
|
74
|
+
maximumValue: number;
|
|
75
|
+
value: number;
|
|
76
|
+
onValueChange: (value: number) => void;
|
|
77
|
+
minimumTrackTintColor?: string;
|
|
78
|
+
maximumTrackTintColor?: string;
|
|
79
|
+
thumbTintColor?: string;
|
|
80
|
+
step?: number;
|
|
81
|
+
}>;
|
|
65
82
|
}
|
|
66
83
|
|
|
67
84
|
/**
|
|
@@ -89,6 +106,7 @@ export const OnboardingScreen: React.FC<OnboardingScreenProps> = ({
|
|
|
89
106
|
onUpgrade,
|
|
90
107
|
showPaywallOnComplete = false,
|
|
91
108
|
useGradient: globalUseGradient = false,
|
|
109
|
+
SliderComponent,
|
|
92
110
|
}) => {
|
|
93
111
|
const insets = useSafeAreaInsets();
|
|
94
112
|
const tokens = useAppDesignTokens();
|
|
@@ -231,6 +249,7 @@ export const OnboardingScreen: React.FC<OnboardingScreenProps> = ({
|
|
|
231
249
|
value={currentAnswer}
|
|
232
250
|
onChange={setCurrentAnswer}
|
|
233
251
|
useGradient={useGradient}
|
|
252
|
+
SliderComponent={SliderComponent}
|
|
234
253
|
/>
|
|
235
254
|
) : (
|
|
236
255
|
<OnboardingSlideComponent slide={currentSlide} useGradient={useGradient} />
|