@umituz/react-native-onboarding 3.6.21 → 3.6.22

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.21",
3
+ "version": "3.6.22",
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, TouchableOpacity, StyleSheet } from "react-native";
3
- import { AtomicIcon, AtomicText } from "@umituz/react-native-design-system";
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, QuestionOption } from "../../../domain/entities/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(renderOption)}
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 type="labelSmall" style={[styles.hint, { color: colors.subTextColor }]}>
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
+ });