@umituz/react-native-onboarding 3.6.21 → 3.6.23
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": "3.6.
|
|
3
|
+
"version": "3.6.23",
|
|
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",
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multiple Choice Question Component
|
|
3
|
+
* Single Responsibility: Render multiple choice question with options
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
import React from "react";
|
|
2
|
-
import { View,
|
|
3
|
-
import {
|
|
7
|
+
import { View, StyleSheet } from "react-native";
|
|
8
|
+
import { AtomicText } from "@umituz/react-native-design-system";
|
|
4
9
|
import { useOnboardingProvider } from "../../providers/OnboardingProvider";
|
|
5
10
|
import { ensureArray } from "../../../infrastructure/utils/arrayUtils";
|
|
6
|
-
import type { OnboardingQuestion
|
|
11
|
+
import type { OnboardingQuestion } from "../../../domain/entities/OnboardingQuestion";
|
|
12
|
+
import { QuestionOptionItem } from "./QuestionOptionItem";
|
|
7
13
|
|
|
8
14
|
export interface MultipleChoiceQuestionProps {
|
|
9
15
|
question: OnboardingQuestion;
|
|
@@ -32,64 +38,23 @@ export const MultipleChoiceQuestion = ({
|
|
|
32
38
|
}
|
|
33
39
|
onChange(newValue);
|
|
34
40
|
};
|
|
35
|
-
const renderOption = (option: QuestionOption) => {
|
|
36
|
-
const isSelected = safeValue.includes(option.id);
|
|
37
|
-
const isEmoji = option.iconType === 'emoji';
|
|
38
|
-
|
|
39
|
-
return (
|
|
40
|
-
<TouchableOpacity
|
|
41
|
-
key={option.id}
|
|
42
|
-
style={[
|
|
43
|
-
styles.option,
|
|
44
|
-
{
|
|
45
|
-
backgroundColor: isSelected ? colors.iconBg : colors.featureItemBg,
|
|
46
|
-
borderColor: isSelected ? colors.iconColor : colors.headerButtonBorder,
|
|
47
|
-
borderWidth: isSelected ? 2 : 1,
|
|
48
|
-
}
|
|
49
|
-
]}
|
|
50
|
-
onPress={() => handleToggle(option.id)}
|
|
51
|
-
activeOpacity={0.8}
|
|
52
|
-
>
|
|
53
|
-
{option.icon && (
|
|
54
|
-
<View style={[
|
|
55
|
-
styles.optionIcon,
|
|
56
|
-
{ backgroundColor: isSelected ? colors.iconColor : colors.featureItemBg }
|
|
57
|
-
]}>
|
|
58
|
-
{isEmoji ? (
|
|
59
|
-
<AtomicText style={{ fontSize: 24 }}>{option.icon}</AtomicText>
|
|
60
|
-
) : (
|
|
61
|
-
<AtomicIcon
|
|
62
|
-
name={option.icon as any}
|
|
63
|
-
customSize={20}
|
|
64
|
-
customColor={isSelected ? colors.buttonTextColor : colors.subTextColor}
|
|
65
|
-
/>
|
|
66
|
-
)}
|
|
67
|
-
</View>
|
|
68
|
-
)}
|
|
69
|
-
<AtomicText type="bodyLarge" style={[styles.optionLabel, { color: isSelected ? colors.textColor : colors.subTextColor, fontWeight: isSelected ? '700' : '500' }]}>
|
|
70
|
-
{option.label}
|
|
71
|
-
</AtomicText>
|
|
72
|
-
<View style={[
|
|
73
|
-
styles.checkbox,
|
|
74
|
-
{
|
|
75
|
-
borderColor: isSelected ? colors.iconColor : colors.headerButtonBorder,
|
|
76
|
-
backgroundColor: isSelected ? colors.iconColor : 'transparent',
|
|
77
|
-
borderWidth: isSelected ? 0 : 2,
|
|
78
|
-
}
|
|
79
|
-
]}>
|
|
80
|
-
{isSelected && (
|
|
81
|
-
<AtomicIcon name="checkmark" customSize={16} customColor={colors.buttonTextColor} />
|
|
82
|
-
)}
|
|
83
|
-
</View>
|
|
84
|
-
</TouchableOpacity>
|
|
85
|
-
);
|
|
86
|
-
};
|
|
87
41
|
|
|
88
42
|
return (
|
|
89
43
|
<View style={styles.container}>
|
|
90
|
-
{question.options?.map(
|
|
44
|
+
{question.options?.map((option) => (
|
|
45
|
+
<QuestionOptionItem
|
|
46
|
+
key={option.id}
|
|
47
|
+
option={option}
|
|
48
|
+
isSelected={safeValue.includes(option.id)}
|
|
49
|
+
onPress={() => handleToggle(option.id)}
|
|
50
|
+
colors={colors}
|
|
51
|
+
/>
|
|
52
|
+
))}
|
|
91
53
|
{question.validation?.maxSelections && (
|
|
92
|
-
<AtomicText
|
|
54
|
+
<AtomicText
|
|
55
|
+
type="labelSmall"
|
|
56
|
+
style={[styles.hint, { color: colors.subTextColor }]}
|
|
57
|
+
>
|
|
93
58
|
Select up to {question.validation.maxSelections} options
|
|
94
59
|
</AtomicText>
|
|
95
60
|
)}
|
|
@@ -102,36 +67,8 @@ const styles = StyleSheet.create({
|
|
|
102
67
|
width: "100%",
|
|
103
68
|
gap: 12,
|
|
104
69
|
},
|
|
105
|
-
option: {
|
|
106
|
-
flexDirection: "row",
|
|
107
|
-
alignItems: "center",
|
|
108
|
-
borderRadius: 20,
|
|
109
|
-
padding: 16,
|
|
110
|
-
marginBottom: 8,
|
|
111
|
-
},
|
|
112
|
-
optionIcon: {
|
|
113
|
-
width: 40,
|
|
114
|
-
height: 40,
|
|
115
|
-
borderRadius: 20,
|
|
116
|
-
alignItems: 'center',
|
|
117
|
-
justifyContent: 'center',
|
|
118
|
-
marginRight: 16,
|
|
119
|
-
},
|
|
120
|
-
optionLabel: {
|
|
121
|
-
flex: 1,
|
|
122
|
-
fontSize: 16,
|
|
123
|
-
},
|
|
124
|
-
checkbox: {
|
|
125
|
-
width: 24,
|
|
126
|
-
height: 24,
|
|
127
|
-
borderRadius: 8,
|
|
128
|
-
alignItems: "center",
|
|
129
|
-
justifyContent: "center",
|
|
130
|
-
},
|
|
131
70
|
hint: {
|
|
132
71
|
textAlign: "center",
|
|
133
72
|
marginTop: 8,
|
|
134
73
|
},
|
|
135
74
|
});
|
|
136
|
-
|
|
137
|
-
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Question Option Item Component
|
|
3
|
+
* Single Responsibility: Render a single selectable option
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import React from "react";
|
|
7
|
+
import { View, TouchableOpacity, StyleSheet } from "react-native";
|
|
8
|
+
import { AtomicIcon, AtomicText } from "@umituz/react-native-design-system";
|
|
9
|
+
import type { QuestionOption } from "../../../domain/entities/OnboardingQuestion";
|
|
10
|
+
import type { OnboardingColors } from "../../types/OnboardingTheme";
|
|
11
|
+
|
|
12
|
+
export interface QuestionOptionItemProps {
|
|
13
|
+
option: QuestionOption;
|
|
14
|
+
isSelected: boolean;
|
|
15
|
+
onPress: () => void;
|
|
16
|
+
colors: OnboardingColors;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const QuestionOptionItem = ({
|
|
20
|
+
option,
|
|
21
|
+
isSelected,
|
|
22
|
+
onPress,
|
|
23
|
+
colors,
|
|
24
|
+
}: QuestionOptionItemProps) => {
|
|
25
|
+
const isEmoji = option.iconType === 'emoji';
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<TouchableOpacity
|
|
29
|
+
style={[
|
|
30
|
+
styles.option,
|
|
31
|
+
{
|
|
32
|
+
backgroundColor: isSelected ? colors.iconBg : colors.featureItemBg,
|
|
33
|
+
borderColor: isSelected ? colors.iconColor : colors.headerButtonBorder,
|
|
34
|
+
borderWidth: isSelected ? 2 : 1,
|
|
35
|
+
}
|
|
36
|
+
]}
|
|
37
|
+
onPress={onPress}
|
|
38
|
+
activeOpacity={0.8}
|
|
39
|
+
>
|
|
40
|
+
{option.icon && (
|
|
41
|
+
<View style={[
|
|
42
|
+
styles.optionIcon,
|
|
43
|
+
{ backgroundColor: isSelected ? colors.iconColor : colors.featureItemBg }
|
|
44
|
+
]}>
|
|
45
|
+
{isEmoji ? (
|
|
46
|
+
<AtomicText style={{ fontSize: 24 }}>{option.icon}</AtomicText>
|
|
47
|
+
) : (
|
|
48
|
+
<AtomicIcon
|
|
49
|
+
name={option.icon as any}
|
|
50
|
+
customSize={20}
|
|
51
|
+
customColor={isSelected ? colors.buttonTextColor : colors.subTextColor}
|
|
52
|
+
/>
|
|
53
|
+
)}
|
|
54
|
+
</View>
|
|
55
|
+
)}
|
|
56
|
+
<AtomicText
|
|
57
|
+
type="bodyLarge"
|
|
58
|
+
style={[
|
|
59
|
+
styles.optionLabel,
|
|
60
|
+
{
|
|
61
|
+
color: isSelected ? colors.textColor : colors.subTextColor,
|
|
62
|
+
fontWeight: isSelected ? '700' : '500'
|
|
63
|
+
}
|
|
64
|
+
]}
|
|
65
|
+
>
|
|
66
|
+
{option.label}
|
|
67
|
+
</AtomicText>
|
|
68
|
+
<View style={[
|
|
69
|
+
styles.checkbox,
|
|
70
|
+
{
|
|
71
|
+
borderColor: isSelected ? colors.iconColor : colors.headerButtonBorder,
|
|
72
|
+
backgroundColor: isSelected ? colors.iconColor : 'transparent',
|
|
73
|
+
borderWidth: isSelected ? 0 : 2,
|
|
74
|
+
}
|
|
75
|
+
]}>
|
|
76
|
+
{isSelected && (
|
|
77
|
+
<AtomicIcon
|
|
78
|
+
name="checkmark"
|
|
79
|
+
customSize={16}
|
|
80
|
+
customColor={colors.buttonTextColor}
|
|
81
|
+
/>
|
|
82
|
+
)}
|
|
83
|
+
</View>
|
|
84
|
+
</TouchableOpacity>
|
|
85
|
+
);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const styles = StyleSheet.create({
|
|
89
|
+
option: {
|
|
90
|
+
flexDirection: "row",
|
|
91
|
+
alignItems: "center",
|
|
92
|
+
borderRadius: 20,
|
|
93
|
+
padding: 16,
|
|
94
|
+
marginBottom: 8,
|
|
95
|
+
},
|
|
96
|
+
optionIcon: {
|
|
97
|
+
width: 40,
|
|
98
|
+
height: 40,
|
|
99
|
+
borderRadius: 20,
|
|
100
|
+
alignItems: 'center',
|
|
101
|
+
justifyContent: 'center',
|
|
102
|
+
marginRight: 16,
|
|
103
|
+
},
|
|
104
|
+
optionLabel: {
|
|
105
|
+
flex: 1,
|
|
106
|
+
fontSize: 16,
|
|
107
|
+
},
|
|
108
|
+
checkbox: {
|
|
109
|
+
width: 24,
|
|
110
|
+
height: 24,
|
|
111
|
+
borderRadius: 8,
|
|
112
|
+
alignItems: "center",
|
|
113
|
+
justifyContent: "center",
|
|
114
|
+
},
|
|
115
|
+
});
|