@umituz/react-native-onboarding 2.7.2 → 2.8.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-onboarding",
3
- "version": "2.7.2",
3
+ "version": "2.8.0",
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",
@@ -31,7 +31,6 @@
31
31
  "url": "https://github.com/umituz/react-native-onboarding"
32
32
  },
33
33
  "peerDependencies": {
34
- "@react-native-community/slider": "^4.5.0",
35
34
  "@umituz/react-native-storage": "latest",
36
35
  "@umituz/react-native-localization": "latest",
37
36
  "@umituz/react-native-design-system-theme": "latest",
@@ -11,7 +11,6 @@ export type QuestionType =
11
11
  | "single_choice" // Radio buttons - single selection
12
12
  | "multiple_choice" // Checkboxes - multiple selections
13
13
  | "text_input" // Text input field
14
- | "slider" // Slider for numeric values
15
14
  | "rating" // Star rating or numeric rating
16
15
  | "date" // Date picker
17
16
  | "image_picker"; // Image selection from gallery
@@ -27,15 +26,9 @@ export interface QuestionOption {
27
26
 
28
27
  /**
29
28
  * Display label for the option
30
- * Can be either a string or an i18n key
31
29
  */
32
30
  label: string;
33
31
 
34
- /**
35
- * i18n key for label (optional, if provided, label will be used as fallback)
36
- */
37
- labelKey?: string;
38
-
39
32
  /**
40
33
  * Optional icon (emoji or Lucide icon name)
41
34
  */
@@ -62,12 +55,12 @@ export interface QuestionValidation {
62
55
  required?: boolean;
63
56
 
64
57
  /**
65
- * Minimum value (for slider/rating)
58
+ * Minimum value (for rating)
66
59
  */
67
60
  min?: number;
68
61
 
69
62
  /**
70
- * Maximum value (for slider/rating)
63
+ * Maximum value (for rating)
71
64
  */
72
65
  max?: number;
73
66
 
@@ -62,15 +62,9 @@ export interface OnboardingSlide {
62
62
 
63
63
  /**
64
64
  * Optional features list to display
65
- * Can be either strings or i18n keys
66
65
  */
67
66
  features?: string[];
68
67
 
69
- /**
70
- * Optional i18n keys for features (optional, if provided, features will be used as fallback)
71
- */
72
- featuresKeys?: string[];
73
-
74
68
  /**
75
69
  * Optional question for personalization
76
70
  * Only used when type is "question"
package/src/index.ts CHANGED
@@ -80,8 +80,6 @@ export { MultipleChoiceQuestion } from "./presentation/components/questions/Mult
80
80
  export type { MultipleChoiceQuestionProps } from "./presentation/components/questions/MultipleChoiceQuestion";
81
81
  export { TextInputQuestion } from "./presentation/components/questions/TextInputQuestion";
82
82
  export type { TextInputQuestionProps } from "./presentation/components/questions/TextInputQuestion";
83
- export { SliderQuestion } from "./presentation/components/questions/SliderQuestion";
84
- export type { SliderQuestionProps } from "./presentation/components/questions/SliderQuestion";
85
83
  export { RatingQuestion } from "./presentation/components/questions/RatingQuestion";
86
84
  export type { RatingQuestionProps } from "./presentation/components/questions/RatingQuestion";
87
85
 
@@ -37,7 +37,6 @@ export class OnboardingValidationService {
37
37
  return this.validateMultipleChoice(answer, validation);
38
38
  case "text_input":
39
39
  return this.validateTextInput(answer, validation);
40
- case "slider":
41
40
  case "rating":
42
41
  return this.validateNumeric(answer, validation);
43
42
  default:
@@ -102,7 +101,7 @@ export class OnboardingValidationService {
102
101
  }
103
102
 
104
103
  /**
105
- * Validate numeric answer (slider/rating)
104
+ * Validate numeric answer (rating)
106
105
  */
107
106
  private static validateNumeric(
108
107
  answer: any,
@@ -36,7 +36,11 @@ export const OnboardingHeader: React.FC<OnboardingHeaderProps> = ({
36
36
  const skipText = skipButtonText || t("onboarding.skip", "Skip");
37
37
 
38
38
  const handleBackPress = () => {
39
- if (!isFirstSlide) {
39
+ /* eslint-disable-next-line no-console */
40
+ if (__DEV__) {
41
+ console.log("[OnboardingHeader] Back pressed, isFirstSlide:", isFirstSlide);
42
+ }
43
+ if (!isFirstSlide && onBack) {
40
44
  onBack();
41
45
  }
42
46
  };
@@ -52,6 +56,7 @@ export const OnboardingHeader: React.FC<OnboardingHeaderProps> = ({
52
56
  isFirstSlide && styles.headerButtonDisabled,
53
57
  ]}
54
58
  activeOpacity={0.7}
59
+ hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
55
60
  >
56
61
  <ArrowLeft
57
62
  size={20}
@@ -51,17 +51,6 @@ export interface OnboardingScreenContentProps {
51
51
  renderSlide?: (slide: OnboardingSlide) => React.ReactNode;
52
52
  onUpgrade?: () => void;
53
53
  showPaywallOnComplete?: boolean;
54
- SliderComponent?: React.ComponentType<{
55
- style?: any;
56
- minimumValue: number;
57
- maximumValue: number;
58
- value: number;
59
- onValueChange: (value: number) => void;
60
- minimumTrackTintColor?: string;
61
- maximumTrackTintColor?: string;
62
- thumbTintColor?: string;
63
- step?: number;
64
- }>;
65
54
  }
66
55
 
67
56
  export const OnboardingScreenContent: React.FC<OnboardingScreenContentProps> = ({
@@ -91,7 +80,6 @@ export const OnboardingScreenContent: React.FC<OnboardingScreenContentProps> = (
91
80
  renderSlide,
92
81
  onUpgrade,
93
82
  showPaywallOnComplete,
94
- SliderComponent,
95
83
  }) => {
96
84
  const { themeMode } = useTheme();
97
85
 
@@ -132,7 +120,6 @@ export const OnboardingScreenContent: React.FC<OnboardingScreenContentProps> = (
132
120
  value={currentAnswer}
133
121
  onChange={onAnswerChange}
134
122
  useGradient={useGradient}
135
- SliderComponent={SliderComponent}
136
123
  />
137
124
  ) : (
138
125
  <OnboardingSlideComponent slide={currentSlide} useGradient={useGradient} />
@@ -4,36 +4,22 @@
4
4
  */
5
5
 
6
6
  import React from "react";
7
- import { View, Text } from "react-native";
8
7
  import type { OnboardingQuestion } from "../../domain/entities/OnboardingQuestion";
9
8
  import { SingleChoiceQuestion } from "./questions/SingleChoiceQuestion";
10
9
  import { MultipleChoiceQuestion } from "./questions/MultipleChoiceQuestion";
11
10
  import { TextInputQuestion } from "./questions/TextInputQuestion";
12
- import { SliderQuestion } from "./questions/SliderQuestion";
13
11
  import { RatingQuestion } from "./questions/RatingQuestion";
14
12
 
15
13
  export interface QuestionRendererProps {
16
14
  question: OnboardingQuestion;
17
15
  value: any;
18
16
  onChange: (value: any) => void;
19
- SliderComponent?: React.ComponentType<{
20
- style?: any;
21
- minimumValue: number;
22
- maximumValue: number;
23
- value: number;
24
- onValueChange: (value: number) => void;
25
- minimumTrackTintColor?: string;
26
- maximumTrackTintColor?: string;
27
- thumbTintColor?: string;
28
- step?: number;
29
- }>;
30
17
  }
31
18
 
32
19
  export const QuestionRenderer: React.FC<QuestionRendererProps> = ({
33
20
  question,
34
21
  value,
35
22
  onChange,
36
- SliderComponent,
37
23
  }) => {
38
24
  switch (question.type) {
39
25
  case "single_choice":
@@ -60,29 +46,6 @@ export const QuestionRenderer: React.FC<QuestionRendererProps> = ({
60
46
  onChange={onChange}
61
47
  />
62
48
  );
63
- case "slider":
64
- if (!SliderComponent) {
65
- return (
66
- <View style={{ padding: 20, alignItems: "center" }}>
67
- <Text style={{ color: "#FFFFFF", textAlign: "center" }}>
68
- Slider component is not available. Please provide SliderComponent prop
69
- to OnboardingScreen.
70
- </Text>
71
- <Text style={{ color: "#FFFFFF", textAlign: "center", marginTop: 8, fontSize: 12 }}>
72
- Example: SliderComponent={"Slider"} where {"Slider"} is imported from
73
- "@react-native-community/slider"
74
- </Text>
75
- </View>
76
- );
77
- }
78
- return (
79
- <SliderQuestion
80
- question={question}
81
- value={value}
82
- onChange={onChange}
83
- SliderComponent={SliderComponent}
84
- />
85
- );
86
49
  case "rating":
87
50
  return (
88
51
  <RatingQuestion
@@ -15,17 +15,6 @@ 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
- }>;
29
18
  }
30
19
 
31
20
  export const QuestionSlide: React.FC<QuestionSlideProps> = ({
@@ -33,7 +22,6 @@ export const QuestionSlide: React.FC<QuestionSlideProps> = ({
33
22
  value,
34
23
  onChange,
35
24
  useGradient = false,
36
- SliderComponent,
37
25
  }) => {
38
26
  const tokens = useAppDesignTokens();
39
27
  const styles = useMemo(() => getStyles(tokens, useGradient), [tokens, useGradient]);
@@ -52,7 +40,6 @@ export const QuestionSlide: React.FC<QuestionSlideProps> = ({
52
40
  question={question}
53
41
  value={value}
54
42
  onChange={onChange}
55
- SliderComponent={SliderComponent}
56
43
  />
57
44
  </View>
58
45
 
@@ -58,7 +58,7 @@ export const SingleChoiceQuestion: React.FC<SingleChoiceQuestionProps> = ({
58
58
 
59
59
  return (
60
60
  <View style={styles.container}>
61
- {question.options?.map((option) => renderOption(option))}
61
+ {question.options?.map(renderOption)}
62
62
  </View>
63
63
  );
64
64
  };
@@ -51,23 +51,6 @@ export interface OnboardingScreenProps extends OnboardingOptions {
51
51
  * When true, shows premium paywall before completing onboarding
52
52
  */
53
53
  showPaywallOnComplete?: boolean;
54
-
55
- /**
56
- * Slider component for slider questions
57
- * Required if using slider question type
58
- * Import from @react-native-community/slider
59
- */
60
- SliderComponent?: React.ComponentType<{
61
- style?: any;
62
- minimumValue: number;
63
- maximumValue: number;
64
- value: number;
65
- onValueChange: (value: number) => void;
66
- minimumTrackTintColor?: string;
67
- maximumTrackTintColor?: string;
68
- thumbTintColor?: string;
69
- step?: number;
70
- }>;
71
54
  }
72
55
 
73
56
  export const OnboardingScreen: React.FC<OnboardingScreenProps> = ({
@@ -90,7 +73,6 @@ export const OnboardingScreen: React.FC<OnboardingScreenProps> = ({
90
73
  onUpgrade,
91
74
  showPaywallOnComplete = false,
92
75
  useGradient: globalUseGradient = false,
93
- SliderComponent,
94
76
  }) => {
95
77
  const {
96
78
  filteredSlides,
@@ -142,7 +124,6 @@ export const OnboardingScreen: React.FC<OnboardingScreenProps> = ({
142
124
  renderSlide={renderSlide}
143
125
  onUpgrade={onUpgrade}
144
126
  showPaywallOnComplete={showPaywallOnComplete}
145
- SliderComponent={SliderComponent}
146
127
  />
147
128
  );
148
129
  };
@@ -1,137 +0,0 @@
1
- /**
2
- * Slider Question Component
3
- * Single Responsibility: Display slider for numeric value selection
4
- */
5
-
6
- import React, { useMemo } from "react";
7
- import { View, Text, StyleSheet } from "react-native";
8
- import type { OnboardingQuestion } from "../../../domain/entities/OnboardingQuestion";
9
-
10
- export interface SliderQuestionProps {
11
- question: OnboardingQuestion;
12
- value: number | undefined;
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
- }>;
25
- }
26
-
27
- const getSliderConfig = (question: OnboardingQuestion) => {
28
- const { validation } = question;
29
- const min = validation?.min ?? 0;
30
- const max = validation?.max ?? 100;
31
- return { min, max };
32
- };
33
-
34
- export const SliderQuestion: React.FC<SliderQuestionProps> = ({
35
- question,
36
- value,
37
- onChange,
38
- SliderComponent,
39
- }) => {
40
- const { min, max } = useMemo(() => getSliderConfig(question), [question]);
41
- const currentValue = value ?? question.defaultValue ?? min;
42
-
43
- // Error boundary for SliderComponent
44
- try {
45
- return (
46
- <View style={styles.container}>
47
- <View style={styles.valueContainer}>
48
- <Text style={styles.valueText}>{currentValue}</Text>
49
- </View>
50
- {SliderComponent ? (
51
- <SliderComponent
52
- style={styles.slider}
53
- minimumValue={min}
54
- maximumValue={max}
55
- value={currentValue}
56
- onValueChange={onChange}
57
- minimumTrackTintColor="#FFFFFF"
58
- maximumTrackTintColor="rgba(255, 255, 255, 0.3)"
59
- thumbTintColor="#FFFFFF"
60
- step={1}
61
- />
62
- ) : (
63
- <View style={styles.errorContainer}>
64
- <Text style={styles.errorText}>
65
- Slider component is not available. Please provide SliderComponent prop.
66
- </Text>
67
- </View>
68
- )}
69
- <View style={styles.labels}>
70
- <Text style={styles.label}>{min}</Text>
71
- <Text style={styles.label}>{max}</Text>
72
- </View>
73
- </View>
74
- );
75
- } catch (error) {
76
- /* eslint-disable-next-line no-console */
77
- if (__DEV__) {
78
- console.error("SliderQuestion render error:", error);
79
- }
80
- return (
81
- <View style={styles.container}>
82
- <View style={styles.valueContainer}>
83
- <Text style={styles.valueText}>{currentValue}</Text>
84
- </View>
85
- <View style={styles.errorContainer}>
86
- <Text style={styles.errorText}>
87
- Unable to render slider. Please check SliderComponent installation.
88
- </Text>
89
- </View>
90
- <View style={styles.labels}>
91
- <Text style={styles.label}>{min}</Text>
92
- <Text style={styles.label}>{max}</Text>
93
- </View>
94
- </View>
95
- );
96
- }
97
- };
98
-
99
- const styles = StyleSheet.create({
100
- container: {
101
- width: "100%",
102
- paddingHorizontal: 8,
103
- },
104
- valueContainer: {
105
- alignItems: "center",
106
- marginBottom: 16,
107
- },
108
- valueText: {
109
- fontSize: 48,
110
- fontWeight: "bold",
111
- color: "#FFFFFF",
112
- },
113
- slider: {
114
- width: "100%",
115
- height: 40,
116
- },
117
- labels: {
118
- flexDirection: "row",
119
- justifyContent: "space-between",
120
- marginTop: 8,
121
- },
122
- label: {
123
- fontSize: 14,
124
- color: "rgba(255, 255, 255, 0.7)",
125
- fontWeight: "500",
126
- },
127
- errorContainer: {
128
- padding: 20,
129
- alignItems: "center",
130
- marginVertical: 16,
131
- },
132
- errorText: {
133
- color: "#FFFFFF",
134
- textAlign: "center",
135
- fontSize: 14,
136
- },
137
- });