@umituz/react-native-onboarding 3.3.11 → 3.5.1

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.3.11",
3
+ "version": "3.5.1",
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,10 +31,9 @@
31
31
  "url": "https://github.com/umituz/react-native-onboarding"
32
32
  },
33
33
  "peerDependencies": {
34
- "@umituz/react-native-icons": "latest",
35
34
  "@umituz/react-native-storage": "latest",
36
35
  "@umituz/react-native-localization": "latest",
37
- "@umituz/react-native-design-system": "latest",
36
+ "@umituz/react-native-design-system": "^2.1.0",
38
37
  "@expo/vector-icons": ">=14.0.0",
39
38
  "expo-image": ">=2.0.0",
40
39
  "expo-linear-gradient": ">=13.0.0",
@@ -42,13 +41,12 @@
42
41
  "react": ">=18.2.0",
43
42
  "react-native": ">=0.74.0",
44
43
  "react-native-safe-area-context": ">=4.0.0",
45
- "zustand": ">=5.0.0"
44
+ "zustand": "^4.5.0 || ^5.0.0"
46
45
  },
47
46
  "devDependencies": {
48
- "@umituz/react-native-icons": "latest",
49
47
  "@umituz/react-native-storage": "latest",
50
48
  "@umituz/react-native-localization": "latest",
51
- "@umituz/react-native-design-system": "latest",
49
+ "@umituz/react-native-design-system": "^2.1.0",
52
50
  "@expo/vector-icons": "^14.0.0",
53
51
  "expo-image": "~2.0.0",
54
52
  "expo-linear-gradient": "^15.0.7",
@@ -68,4 +66,4 @@
68
66
  "README.md",
69
67
  "LICENSE"
70
68
  ]
71
- }
69
+ }
package/src/index.ts CHANGED
@@ -68,6 +68,7 @@ export {
68
68
  export { OnboardingScreen, type OnboardingScreenProps } from "./presentation/screens/OnboardingScreen";
69
69
  export { OnboardingHeader, type OnboardingHeaderProps } from "./presentation/components/OnboardingHeader";
70
70
  export { OnboardingFooter, type OnboardingFooterProps } from "./presentation/components/OnboardingFooter";
71
+ export { OnboardingThemeProvider, type OnboardingThemeProviderProps, useOnboardingTheme } from "./presentation/providers/OnboardingThemeProvider";
71
72
 
72
73
  // Export OnboardingSlide component
73
74
  // Note: TypeScript doesn't allow exporting both a type and a value with the same name
@@ -5,7 +5,7 @@
5
5
  * Uses @umituz/react-native-storage for persistence
6
6
  */
7
7
 
8
- import { create } from "zustand";
8
+ import { create, StoreApi } from "zustand";
9
9
  import type { OnboardingStoreState } from "./OnboardingStoreState";
10
10
  import { initialOnboardingState } from "./OnboardingStoreState";
11
11
  import { createOnboardingStoreActions } from "./OnboardingStoreActions";
@@ -27,8 +27,8 @@ interface OnboardingStore extends OnboardingStoreState {
27
27
  setUserData: (data: any) => Promise<void>;
28
28
  }
29
29
 
30
- export const useOnboardingStore = create<OnboardingStore>((set, get) => {
31
- const actions = createOnboardingStoreActions(set as any, get);
30
+ export const useOnboardingStore = create<OnboardingStore>((set: StoreApi<OnboardingStore>['setState'], get: StoreApi<OnboardingStore>['getState']) => {
31
+ const actions = createOnboardingStoreActions(set, get);
32
32
 
33
33
  return {
34
34
  ...initialOnboardingState,
@@ -54,7 +54,7 @@ export const useOnboardingStore = create<OnboardingStore>((set, get) => {
54
54
  */
55
55
  export const useOnboarding = () => {
56
56
  const store = useOnboardingStore();
57
- const setState = store.setState as any;
57
+ const setState = store.setState;
58
58
  const getState = () => store;
59
59
  const actions = createOnboardingStoreActions(setState, getState);
60
60
  const selectors = createOnboardingStoreSelectors(getState);
@@ -14,10 +14,10 @@ import { OnboardingSlide as OnboardingSlideComponent } from "./OnboardingSlide";
14
14
  import { QuestionSlide } from "./QuestionSlide";
15
15
  import { OnboardingFooter } from "./OnboardingFooter";
16
16
  import { BackgroundVideo } from "./BackgroundVideo";
17
+ import { useOnboardingTheme } from "../providers/OnboardingThemeProvider";
17
18
 
18
19
  export interface OnboardingScreenContentProps {
19
20
  containerStyle?: any;
20
- useGradient: boolean;
21
21
  currentSlide: OnboardingSlide | undefined;
22
22
  isFirstSlide: boolean;
23
23
  isLastSlide: boolean;
@@ -58,7 +58,6 @@ export interface OnboardingScreenContentProps {
58
58
 
59
59
  export const OnboardingScreenContent = ({
60
60
  containerStyle,
61
- useGradient,
62
61
  currentSlide,
63
62
  isFirstSlide,
64
63
  isLastSlide,
@@ -86,6 +85,7 @@ export const OnboardingScreenContent = ({
86
85
  variant = "default",
87
86
  }: OnboardingScreenContentProps) => {
88
87
  const { themeMode } = useTheme();
88
+ const { useGradient } = useOnboardingTheme();
89
89
 
90
90
  const hasMedia = !!currentSlide?.backgroundImage || !!currentSlide?.backgroundVideo;
91
91
  const overlayOpacity = currentSlide?.overlayOpacity ?? 0.5;
@@ -157,7 +157,6 @@ export const OnboardingScreenContent = ({
157
157
  showBackButton={showBackButton}
158
158
  showSkipButton={showSkipButton}
159
159
  skipButtonText={skipButtonText}
160
- useGradient={effectivelyUseGradient}
161
160
  />
162
161
  )}
163
162
  {currentSlide &&
@@ -168,13 +167,11 @@ export const OnboardingScreenContent = ({
168
167
  slide={currentSlide}
169
168
  value={currentAnswer}
170
169
  onChange={onAnswerChange}
171
- useGradient={effectivelyUseGradient}
172
170
  variant={variant}
173
171
  />
174
172
  ) : (
175
173
  <OnboardingSlideComponent
176
174
  slide={currentSlide}
177
- useGradient={effectivelyUseGradient}
178
175
  variant={variant}
179
176
  />
180
177
  ))}
@@ -199,7 +196,6 @@ export const OnboardingScreenContent = ({
199
196
  nextButtonText={nextButtonText}
200
197
  getStartedButtonText={getStartedButtonText}
201
198
  disabled={!isAnswerValid}
202
- useGradient={effectivelyUseGradient}
203
199
  />
204
200
  )}
205
201
  </View>
@@ -118,7 +118,6 @@ export const OnboardingScreen = ({
118
118
  <OnboardingThemeProvider useGradient={useGradient}>
119
119
  <OnboardingScreenContent
120
120
  containerStyle={[styles.container, containerStyle]}
121
- useGradient={useGradient}
122
121
  currentSlide={currentSlide}
123
122
  isFirstSlide={isFirstSlide}
124
123
  isLastSlide={isLastSlide}
package/README.md DELETED
@@ -1,387 +0,0 @@
1
- # @umituz/react-native-onboarding
2
-
3
- Advanced onboarding flow for React Native apps with **personalization questions**, gradient backgrounds, animations, and customizable slides. Built with SOLID, DRY, KISS principles.
4
-
5
- ## ✨ Features
6
-
7
- - 🎨 **Beautiful gradient backgrounds** with smooth transitions
8
- - ❓ **Personalization questions** - Get to know your users
9
- - 📝 **Multiple question types** - Single choice, multiple choice, text input, slider, rating
10
- - ✅ **Built-in validation** - Required fields, min/max values, custom validators
11
- - 🔄 **Conditional slides** - Skip slides based on previous answers
12
- - 💾 **Persistent storage** - Save user answers and onboarding state
13
- - 🎯 **Type-safe** - Full TypeScript support
14
- - 🎭 **Customizable** - Custom header, footer, and slide components
15
- - 📱 **Universal** - Works on iOS, Android, and Web
16
- - 🚀 **Production-ready** - Used in hundreds of apps
17
-
18
- ## 📦 Installation
19
-
20
- ```bash
21
- npm install @umituz/react-native-onboarding
22
- ```
23
-
24
- ### Peer Dependencies
25
-
26
- ```bash
27
- npm install \
28
- @umituz/react-native-storage \
29
- @umituz/react-native-localization \
30
- @umituz/react-native-design-system-theme \
31
- @umituz/react-native-design-system \
32
- @umituz/react-native-design-system-atoms \
33
- @react-native-community/slider \
34
- expo-linear-gradient \
35
- react-native-safe-area-context \
36
- zustand
37
- ```
38
-
39
- ## 🚀 Quick Start
40
-
41
- ### Basic Onboarding (Info Slides Only)
42
-
43
- ```tsx
44
- import { OnboardingScreen } from '@umituz/react-native-onboarding';
45
-
46
- const slides = [
47
- {
48
- id: '1',
49
- title: 'Welcome to Our App',
50
- description: 'Discover amazing features',
51
- icon: '👋',
52
- gradient: ['#667eea', '#764ba2'],
53
- },
54
- {
55
- id: '2',
56
- title: 'Stay Organized',
57
- description: 'Keep track of everything',
58
- icon: '📋',
59
- gradient: ['#f093fb', '#f5576c'],
60
- },
61
- ];
62
-
63
- <OnboardingScreen
64
- slides={slides}
65
- onComplete={() => console.log('Onboarding completed')}
66
- />
67
- ```
68
-
69
- ### Advanced Onboarding (With Personalization Questions)
70
-
71
- ```tsx
72
- import { OnboardingScreen, OnboardingSlide } from '@umituz/react-native-onboarding';
73
-
74
- const slides: OnboardingSlide[] = [
75
- // Welcome slide
76
- {
77
- id: '1',
78
- type: 'welcome',
79
- title: 'Welcome to FishWise',
80
- description: 'Your personal aquarium assistant',
81
- icon: '🐠',
82
- gradient: ['#667eea', '#764ba2'],
83
- },
84
-
85
- // Question: Experience level
86
- {
87
- id: '2',
88
- type: 'question',
89
- title: 'What\'s your experience level?',
90
- description: 'Help us personalize your experience',
91
- icon: '🎯',
92
- gradient: ['#f093fb', '#f5576c'],
93
- question: {
94
- id: 'experience_level',
95
- type: 'single_choice',
96
- question: 'Select your experience level',
97
- storageKey: '@user_experience_level',
98
- validation: { required: true },
99
- options: [
100
- { id: 'beginner', label: 'Beginner', icon: '🌱' },
101
- { id: 'intermediate', label: 'Intermediate', icon: '🌿' },
102
- { id: 'expert', label: 'Expert', icon: '🌳' },
103
- ],
104
- },
105
- },
106
-
107
- // Question: Tank size
108
- {
109
- id: '3',
110
- type: 'question',
111
- title: 'What\'s your tank size?',
112
- description: 'This helps us recommend suitable fish',
113
- icon: '📏',
114
- gradient: ['#4facfe', '#00f2fe'],
115
- question: {
116
- id: 'tank_size',
117
- type: 'slider',
118
- question: 'Select your tank size (gallons)',
119
- storageKey: '@user_tank_size',
120
- validation: { required: true, min: 10, max: 500 },
121
- defaultValue: 50,
122
- },
123
- },
124
-
125
- // Question: Interests
126
- {
127
- id: '4',
128
- type: 'question',
129
- title: 'What interests you most?',
130
- description: 'Select all that apply',
131
- icon: '❤️',
132
- gradient: ['#fa709a', '#fee140'],
133
- question: {
134
- id: 'interests',
135
- type: 'multiple_choice',
136
- question: 'Choose your interests',
137
- storageKey: '@user_interests',
138
- validation: { required: true, minSelections: 1, maxSelections: 3 },
139
- options: [
140
- { id: 'freshwater', label: 'Freshwater Fish', icon: '🐟' },
141
- { id: 'saltwater', label: 'Saltwater Fish', icon: '🐠' },
142
- { id: 'plants', label: 'Aquatic Plants', icon: '🌿' },
143
- { id: 'equipment', label: 'Equipment & Tech', icon: '⚙️' },
144
- ],
145
- },
146
- },
147
-
148
- // Completion slide
149
- {
150
- id: '5',
151
- type: 'completion',
152
- title: 'You\'re All Set!',
153
- description: 'Let\'s start your aquarium journey',
154
- icon: '🎉',
155
- gradient: ['#30cfd0', '#330867'],
156
- },
157
- ];
158
-
159
- import Slider from '@react-native-community/slider';
160
-
161
- <OnboardingScreen
162
- slides={slides}
163
- SliderComponent={Slider}
164
- onComplete={async () => {
165
- const userData = onboardingStore.getUserData();
166
- console.log('User answers:', userData.answers);
167
- // Save to backend, navigate to home, etc.
168
- }}
169
- />
170
- ```
171
-
172
- ## 📖 API Reference
173
-
174
- ### OnboardingScreen Props
175
-
176
- | Prop | Type | Default | Description |
177
- |------|------|---------|-------------|
178
- | `slides` | `OnboardingSlide[]` | Required | Array of slides to display |
179
- | `onComplete` | `() => void \| Promise<void>` | - | Callback when onboarding is completed |
180
- | `onSkip` | `() => void \| Promise<void>` | - | Callback when onboarding is skipped |
181
- | `skipButtonText` | `string` | "Skip" | Custom skip button text |
182
- | `nextButtonText` | `string` | "Next" | Custom next button text |
183
- | `getStartedButtonText` | `string` | "Get Started" | Custom get started button text |
184
- | `showSkipButton` | `boolean` | `true` | Show skip button |
185
- | `showBackButton` | `boolean` | `true` | Show back button |
186
- | `showProgressBar` | `boolean` | `true` | Show progress bar |
187
- | `showDots` | `boolean` | `true` | Show dots indicator |
188
- | `showProgressText` | `boolean` | `true` | Show progress text (1 of 5) |
189
- | `storageKey` | `string` | - | Custom storage key for completion state |
190
- | `autoComplete` | `boolean` | `false` | Auto-complete on last slide |
191
- | `SliderComponent` | `React.ComponentType` | - | **Required if using slider questions.** Import from `@react-native-community/slider` |
192
-
193
- ### OnboardingSlide Interface
194
-
195
- ```typescript
196
- interface OnboardingSlide {
197
- id: string;
198
- type?: 'info' | 'question' | 'welcome' | 'completion';
199
- title: string;
200
- description: string;
201
- icon: string; // Emoji or Lucide icon name
202
- gradient: string[]; // [startColor, endColor] or [color1, color2, color3]
203
- image?: string;
204
- features?: string[];
205
- question?: OnboardingQuestion;
206
- skipIf?: (answers: Record<string, any>) => boolean;
207
- }
208
- ```
209
-
210
- ### Question Types
211
-
212
- #### Single Choice
213
-
214
- ```typescript
215
- {
216
- type: 'single_choice',
217
- question: 'What is your goal?',
218
- options: [
219
- { id: 'weight_loss', label: 'Weight Loss', icon: '🏃' },
220
- { id: 'muscle_gain', label: 'Muscle Gain', icon: '💪' },
221
- ],
222
- }
223
- ```
224
-
225
- #### Multiple Choice
226
-
227
- ```typescript
228
- {
229
- type: 'multiple_choice',
230
- question: 'Select your interests',
231
- validation: { minSelections: 1, maxSelections: 3 },
232
- options: [
233
- { id: 'yoga', label: 'Yoga', icon: '🧘' },
234
- { id: 'running', label: 'Running', icon: '🏃' },
235
- { id: 'swimming', label: 'Swimming', icon: '🏊' },
236
- ],
237
- }
238
- ```
239
-
240
- #### Text Input
241
-
242
- ```typescript
243
- {
244
- type: 'text_input',
245
- question: 'What is your name?',
246
- placeholder: 'Enter your name',
247
- validation: { required: true, minLength: 2, maxLength: 50 },
248
- }
249
- ```
250
-
251
- #### Slider
252
-
253
- **⚠️ Important:** When using slider questions, you must provide the `SliderComponent` prop to `OnboardingScreen`:
254
-
255
- ```tsx
256
- import Slider from '@react-native-community/slider';
257
-
258
- <OnboardingScreen
259
- slides={slides}
260
- SliderComponent={Slider}
261
- onComplete={handleComplete}
262
- />
263
- ```
264
-
265
- ```typescript
266
- {
267
- type: 'slider',
268
- question: 'What is your age?',
269
- validation: { min: 18, max: 100 },
270
- defaultValue: 25,
271
- }
272
- ```
273
-
274
- **Note:** Make sure `@react-native-community/slider` is installed and properly linked (run `pod install` for iOS).
275
-
276
- #### Rating
277
-
278
- ```typescript
279
- {
280
- type: 'rating',
281
- question: 'Rate your experience',
282
- validation: { max: 5 },
283
- }
284
- ```
285
-
286
- ## 🎨 Customization
287
-
288
- ### Custom Header
289
-
290
- ```tsx
291
- <OnboardingScreen
292
- slides={slides}
293
- renderHeader={({ isFirstSlide, onBack, onSkip }) => (
294
- <View>
295
- {!isFirstSlide && <Button onPress={onBack}>Back</Button>}
296
- <Button onPress={onSkip}>Skip</Button>
297
- </View>
298
- )}
299
- />
300
- ```
301
-
302
- ### Custom Footer
303
-
304
- ```tsx
305
- <OnboardingScreen
306
- slides={slides}
307
- renderFooter={({ currentIndex, totalSlides, isLastSlide, onNext }) => (
308
- <View>
309
- <Text>{currentIndex + 1} / {totalSlides}</Text>
310
- <Button onPress={onNext}>
311
- {isLastSlide ? 'Get Started' : 'Next'}
312
- </Button>
313
- </View>
314
- )}
315
- />
316
- ```
317
-
318
- ### Conditional Slides
319
-
320
- ```tsx
321
- {
322
- id: '3',
323
- title: 'Advanced Features',
324
- description: 'Only for experienced users',
325
- icon: '⚡',
326
- gradient: ['#667eea', '#764ba2'],
327
- skipIf: (answers) => answers.experience_level === 'beginner',
328
- }
329
- ```
330
-
331
- ## 💾 Accessing User Data
332
-
333
- ```tsx
334
- import { useOnboarding } from '@umituz/react-native-onboarding';
335
-
336
- const { userData, getAnswer } = useOnboarding();
337
-
338
- // Get specific answer
339
- const experienceLevel = getAnswer('experience_level');
340
-
341
- // Get all answers
342
- const allAnswers = userData.answers;
343
-
344
- // Check if onboarding was completed
345
- const isComplete = userData.completedAt !== undefined;
346
-
347
- // Check if onboarding was skipped
348
- const wasSkipped = userData.skipped === true;
349
- ```
350
-
351
- ## 🔄 Resetting Onboarding
352
-
353
- ```tsx
354
- import { useOnboarding } from '@umituz/react-native-onboarding';
355
-
356
- const { reset } = useOnboarding();
357
-
358
- // Reset onboarding (useful for testing or settings)
359
- await reset();
360
- ```
361
-
362
- ## 📱 Platform Support
363
-
364
- - ✅ iOS
365
- - ✅ Android
366
- - ✅ Web
367
-
368
- ## 🏗️ Architecture
369
-
370
- Built with Domain-Driven Design (DDD):
371
-
372
- - **Domain Layer**: Entities and interfaces (business logic)
373
- - **Infrastructure Layer**: Storage and hooks (state management)
374
- - **Presentation Layer**: Components and screens (UI)
375
-
376
- ## 📄 License
377
-
378
- MIT
379
-
380
- ## 🤝 Contributing
381
-
382
- Contributions are welcome! Please open an issue or PR.
383
-
384
- ## 📧 Support
385
-
386
- For issues and questions, please open an issue on GitHub.
387
-