react-native-lumen 1.0.1 → 1.1.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.
Files changed (51) hide show
  1. package/README.md +763 -231
  2. package/lib/module/components/TourOverlay.js +43 -3
  3. package/lib/module/components/TourOverlay.js.map +1 -1
  4. package/lib/module/components/TourProvider.js +318 -61
  5. package/lib/module/components/TourProvider.js.map +1 -1
  6. package/lib/module/components/TourTooltip.js +113 -73
  7. package/lib/module/components/TourTooltip.js.map +1 -1
  8. package/lib/module/components/TourZone.js +186 -119
  9. package/lib/module/components/TourZone.js.map +1 -1
  10. package/lib/module/constants/defaults.js +43 -0
  11. package/lib/module/constants/defaults.js.map +1 -1
  12. package/lib/module/context/TourContext.js +5 -0
  13. package/lib/module/context/TourContext.js.map +1 -0
  14. package/lib/module/hooks/useTour.js +1 -1
  15. package/lib/module/hooks/useTour.js.map +1 -1
  16. package/lib/module/hooks/useTourScrollView.js +71 -0
  17. package/lib/module/hooks/useTourScrollView.js.map +1 -0
  18. package/lib/module/index.js +6 -0
  19. package/lib/module/index.js.map +1 -1
  20. package/lib/module/utils/storage.js +188 -0
  21. package/lib/module/utils/storage.js.map +1 -0
  22. package/lib/typescript/src/components/TourOverlay.d.ts.map +1 -1
  23. package/lib/typescript/src/components/TourProvider.d.ts +21 -4
  24. package/lib/typescript/src/components/TourProvider.d.ts.map +1 -1
  25. package/lib/typescript/src/components/TourTooltip.d.ts.map +1 -1
  26. package/lib/typescript/src/components/TourZone.d.ts +19 -1
  27. package/lib/typescript/src/components/TourZone.d.ts.map +1 -1
  28. package/lib/typescript/src/constants/defaults.d.ts +10 -0
  29. package/lib/typescript/src/constants/defaults.d.ts.map +1 -1
  30. package/lib/typescript/src/context/TourContext.d.ts +3 -0
  31. package/lib/typescript/src/context/TourContext.d.ts.map +1 -0
  32. package/lib/typescript/src/hooks/useTourScrollView.d.ts +65 -0
  33. package/lib/typescript/src/hooks/useTourScrollView.d.ts.map +1 -0
  34. package/lib/typescript/src/index.d.ts +4 -0
  35. package/lib/typescript/src/index.d.ts.map +1 -1
  36. package/lib/typescript/src/types/index.d.ts +296 -1
  37. package/lib/typescript/src/types/index.d.ts.map +1 -1
  38. package/lib/typescript/src/utils/storage.d.ts +51 -0
  39. package/lib/typescript/src/utils/storage.d.ts.map +1 -0
  40. package/package.json +173 -171
  41. package/src/components/TourOverlay.tsx +45 -2
  42. package/src/components/TourProvider.tsx +408 -56
  43. package/src/components/TourTooltip.tsx +144 -71
  44. package/src/components/TourZone.tsx +238 -140
  45. package/src/constants/defaults.ts +51 -0
  46. package/src/context/TourContext.ts +4 -0
  47. package/src/hooks/useTour.ts +1 -1
  48. package/src/hooks/useTourScrollView.ts +111 -0
  49. package/src/index.tsx +27 -0
  50. package/src/types/index.ts +306 -1
  51. package/src/utils/storage.ts +226 -0
@@ -0,0 +1,111 @@
1
+ import { useCallback, useMemo } from 'react';
2
+ import { useTour } from './useTour';
3
+
4
+ export interface TourScrollViewOptions {
5
+ /**
6
+ * If true, scrolling will be disabled while the tour is active.
7
+ * @default false
8
+ */
9
+ disableScrollDuringTour?: boolean;
10
+ }
11
+
12
+ export interface TourScrollViewResult {
13
+ /**
14
+ * Animated ref to attach to your ScrollView/Animated.ScrollView.
15
+ * This is the same ref as `scrollViewRef` from useTour().
16
+ */
17
+ scrollViewRef: React.RefObject<any>;
18
+ /**
19
+ * Whether the tour is currently active (a step is being shown).
20
+ */
21
+ isTourActive: boolean;
22
+ /**
23
+ * Whether scrolling should be enabled based on tour state.
24
+ * Only relevant if disableScrollDuringTour option is true.
25
+ */
26
+ scrollEnabled: boolean;
27
+ /**
28
+ * Helper function to scroll to a specific position.
29
+ * Wraps the scrollTo method with error handling.
30
+ */
31
+ scrollTo: (options: { x?: number; y?: number; animated?: boolean }) => void;
32
+ /**
33
+ * Props to spread onto your ScrollView for full tour integration.
34
+ * Includes ref and scrollEnabled (if disableScrollDuringTour is true).
35
+ */
36
+ scrollViewProps: {
37
+ ref: React.RefObject<any>;
38
+ scrollEnabled?: boolean;
39
+ };
40
+ }
41
+
42
+ /**
43
+ * Hook to simplify integrating custom scroll views with the tour system.
44
+ *
45
+ * @example
46
+ * // Basic usage with Animated.ScrollView
47
+ * const { scrollViewRef } = useTourScrollView();
48
+ * return <Animated.ScrollView ref={scrollViewRef}>...</Animated.ScrollView>;
49
+ *
50
+ * @example
51
+ * // With scroll disabled during tour
52
+ * const { scrollViewProps } = useTourScrollView({ disableScrollDuringTour: true });
53
+ * return <Animated.ScrollView {...scrollViewProps}>...</Animated.ScrollView>;
54
+ *
55
+ * @example
56
+ * // Custom scroll view wrapper (forwardRef pattern)
57
+ * const MyScrollView = forwardRef((props, ref) => {
58
+ * const { scrollViewRef } = useTourScrollView();
59
+ * useImperativeHandle(ref, () => ({
60
+ * getScrollRef: () => scrollViewRef.current,
61
+ * }));
62
+ * return <Animated.ScrollView ref={scrollViewRef} {...props} />;
63
+ * });
64
+ */
65
+ export function useTourScrollView(
66
+ options: TourScrollViewOptions = {}
67
+ ): TourScrollViewResult {
68
+ const { disableScrollDuringTour = false } = options;
69
+
70
+ // Get the tour context - use type assertion since we know the internal structure
71
+ const tour = useTour();
72
+ const { scrollViewRef, currentStep } = tour as any;
73
+
74
+ const isTourActive = currentStep !== null;
75
+ const scrollEnabled = disableScrollDuringTour ? !isTourActive : true;
76
+
77
+ const scrollTo = useCallback(
78
+ (opts: { x?: number; y?: number; animated?: boolean }) => {
79
+ try {
80
+ if (scrollViewRef?.current?.scrollTo) {
81
+ scrollViewRef.current.scrollTo({
82
+ x: opts.x ?? 0,
83
+ y: opts.y ?? 0,
84
+ animated: opts.animated !== false,
85
+ });
86
+ }
87
+ } catch {
88
+ // Silently ignore scroll errors
89
+ }
90
+ },
91
+ [scrollViewRef]
92
+ );
93
+
94
+ const scrollViewProps = useMemo(() => {
95
+ const props: { ref: React.RefObject<any>; scrollEnabled?: boolean } = {
96
+ ref: scrollViewRef,
97
+ };
98
+ if (disableScrollDuringTour) {
99
+ props.scrollEnabled = scrollEnabled;
100
+ }
101
+ return props;
102
+ }, [scrollViewRef, disableScrollDuringTour, scrollEnabled]);
103
+
104
+ return {
105
+ scrollViewRef,
106
+ isTourActive,
107
+ scrollEnabled,
108
+ scrollTo,
109
+ scrollViewProps,
110
+ };
111
+ }
package/src/index.tsx CHANGED
@@ -2,7 +2,34 @@ export * from './types';
2
2
  export * from './components/TourProvider';
3
3
  export * from './components/TourZone';
4
4
  export * from './hooks/useTour';
5
+ export { useTourScrollView } from './hooks/useTourScrollView';
6
+ export type {
7
+ TourScrollViewOptions,
8
+ TourScrollViewResult,
9
+ } from './hooks/useTourScrollView';
5
10
  export { TourOverlay } from './components/TourOverlay';
6
11
  export { TourTooltip } from './components/TourTooltip';
7
12
  export * from './constants/defaults';
8
13
  export * from './constants/animations';
14
+
15
+ // Storage utilities for advanced use cases
16
+ export {
17
+ detectStorage,
18
+ clearStorageCache,
19
+ type StorageType,
20
+ } from './utils/storage';
21
+
22
+ // Re-export specific types for convenience
23
+ export type {
24
+ ZoneStyle,
25
+ ZoneShape,
26
+ TourStep,
27
+ CardProps,
28
+ TourConfig,
29
+ TourLabels,
30
+ TooltipStyles,
31
+ TourPersistenceConfig,
32
+ TourContextType,
33
+ StorageAdapter,
34
+ StepsOrder,
35
+ } from './types';
@@ -1,5 +1,98 @@
1
1
  import type { WithSpringConfig, SharedValue } from 'react-native-reanimated';
2
2
  import React from 'react';
3
+ import type { ViewStyle, TextStyle } from 'react-native';
4
+
5
+ // ─── Zone Customization Types ───────────────────────────────────────────
6
+
7
+ /**
8
+ * Shape variants for the zone cutout.
9
+ */
10
+ export type ZoneShape = 'rounded-rect' | 'circle' | 'pill';
11
+
12
+ /**
13
+ * Customization options for the zone appearance.
14
+ * Can be set globally via TourConfig or per-step via TourStep/TourZone.
15
+ */
16
+ export interface ZoneStyle {
17
+ /**
18
+ * Uniform padding around the highlighted element.
19
+ * @default 0
20
+ */
21
+ padding?: number;
22
+ /**
23
+ * Top padding (overrides `padding` for top side).
24
+ */
25
+ paddingTop?: number;
26
+ /**
27
+ * Right padding (overrides `padding` for right side).
28
+ */
29
+ paddingRight?: number;
30
+ /**
31
+ * Bottom padding (overrides `padding` for bottom side).
32
+ */
33
+ paddingBottom?: number;
34
+ /**
35
+ * Left padding (overrides `padding` for left side).
36
+ */
37
+ paddingLeft?: number;
38
+ /**
39
+ * Border radius of the zone (for 'rounded-rect' shape).
40
+ * @default 10
41
+ */
42
+ borderRadius?: number;
43
+ /**
44
+ * Shape of the zone cutout.
45
+ * - 'rounded-rect': Standard rounded rectangle (default)
46
+ * - 'circle': Circular zone that encompasses the element
47
+ * - 'pill': Pill/capsule shape with fully rounded ends
48
+ * @default 'rounded-rect'
49
+ */
50
+ shape?: ZoneShape;
51
+ /**
52
+ * Width of the border around the zone.
53
+ * Set to 0 to disable.
54
+ * @default 0
55
+ */
56
+ borderWidth?: number;
57
+ /**
58
+ * Color of the border.
59
+ * @default 'transparent'
60
+ */
61
+ borderColor?: string;
62
+ /**
63
+ * Color of the outer glow effect. Applied only if `enableGlow` is true in `TourConfig`.
64
+ * @default '#FFFFFF'
65
+ */
66
+ glowColor?: string;
67
+ /**
68
+ * Blur radius for the glow effect. Applied only if `enableGlow` is true in `TourConfig`.
69
+ * @default 10
70
+ */
71
+ glowRadius?: number;
72
+ /**
73
+ * Spread radius for the glow effect. Applied only if `enableGlow` is true in `TourConfig`.
74
+ * @default 5
75
+ */
76
+ glowSpread?: number;
77
+ /**
78
+ * Horizontal offset for the glow effect.
79
+ * @default 0
80
+ */
81
+ glowOffsetX?: number;
82
+ /**
83
+ * Vertical offset for the glow effect.
84
+ * @default 0
85
+ */
86
+ glowOffsetY?: number;
87
+ /**
88
+ * Spring damping for zone animations (per-step override).
89
+ */
90
+ springDamping?: number;
91
+ /**
92
+ * Spring stiffness for zone animations (per-step override).
93
+ */
94
+ springStiffness?: number;
95
+ }
3
96
 
4
97
  export interface TourStep {
5
98
  /**
@@ -27,6 +120,36 @@ export interface TourStep {
27
120
  * If false, interactions are blocked (default behavior depends on global config).
28
121
  */
29
122
  clickable?: boolean;
123
+ /**
124
+ * If true, prevents interaction with the underlying app for this specific step.
125
+ * Overrides the global preventInteraction setting from TourConfig.
126
+ * @default undefined (uses global setting)
127
+ */
128
+ preventInteraction?: boolean;
129
+ /**
130
+ * If true, the skip button is hidden for this step (user must complete or press next).
131
+ * @default false
132
+ */
133
+ required?: boolean;
134
+ /**
135
+ * Controls whether the next/finish button is enabled.
136
+ * - `undefined`: No enforcement, next button always enabled (default).
137
+ * - `false`: Next button is disabled (grayed out, non-pressable).
138
+ * - `true`: Next button is enabled.
139
+ *
140
+ * Use this to gate progression until the user completes an action.
141
+ */
142
+ completed?: boolean;
143
+ /**
144
+ * Per-step zone style overrides.
145
+ * Merged with global zoneStyle from TourConfig.
146
+ */
147
+ zoneStyle?: ZoneStyle;
148
+ /**
149
+ * Custom render function for this step's tooltip/card.
150
+ * Overrides the global renderCard from TourConfig.
151
+ */
152
+ renderCustomCard?: (props: CardProps) => React.ReactNode;
30
153
  }
31
154
 
32
155
  export interface MeasureResult {
@@ -38,6 +161,13 @@ export interface MeasureResult {
38
161
 
39
162
  export type StepMap = Record<string, TourStep>;
40
163
 
164
+ /**
165
+ * Steps order can be either:
166
+ * - A flat array of step keys (single-screen tour): `['bio', 'prompt', 'poll']`
167
+ * - A screen-grouped object (multi-screen tour): `{ ProfileSelf: ['bio', 'prompt'], HomeSwipe: ['filters'] }`
168
+ */
169
+ export type StepsOrder = string[] | Record<string, string[]>;
170
+
41
171
  export interface TourLabels {
42
172
  next?: string;
43
173
  previous?: string;
@@ -45,6 +175,69 @@ export interface TourLabels {
45
175
  skip?: string;
46
176
  }
47
177
 
178
+ export interface TooltipStyles {
179
+ /**
180
+ * Background color of the tooltip
181
+ */
182
+ backgroundColor?: string;
183
+ /**
184
+ * Border radius of the tooltip (for shape customization)
185
+ */
186
+ borderRadius?: number;
187
+ /**
188
+ * Text color for the title
189
+ */
190
+ titleColor?: string;
191
+ /**
192
+ * Text color for the description
193
+ */
194
+ descriptionColor?: string;
195
+ /**
196
+ * Background color for the primary button
197
+ */
198
+ primaryButtonColor?: string;
199
+ /**
200
+ * Text color for the primary button
201
+ */
202
+ primaryButtonTextColor?: string;
203
+ /**
204
+ * Border radius for the primary button
205
+ */
206
+ primaryButtonBorderRadius?: number;
207
+ /**
208
+ * Text color for the skip button
209
+ */
210
+ skipButtonTextColor?: string;
211
+ /**
212
+ * Custom style for the tooltip container
213
+ */
214
+ containerStyle?: ViewStyle;
215
+ /**
216
+ * Custom style for the title text
217
+ */
218
+ titleStyle?: TextStyle;
219
+ /**
220
+ * Custom style for the description text
221
+ */
222
+ descriptionStyle?: TextStyle;
223
+ /**
224
+ * Custom style for the primary button
225
+ */
226
+ primaryButtonStyle?: ViewStyle;
227
+ /**
228
+ * Custom style for the primary button text
229
+ */
230
+ primaryButtonTextStyle?: TextStyle;
231
+ /**
232
+ * Custom style for the skip button
233
+ */
234
+ skipButtonStyle?: ViewStyle;
235
+ /**
236
+ * Custom style for the skip button text
237
+ */
238
+ skipButtonTextStyle?: TextStyle;
239
+ }
240
+
48
241
  export interface CardProps {
49
242
  step: TourStep;
50
243
  currentStepIndex: number;
@@ -55,11 +248,75 @@ export interface CardProps {
55
248
  isFirst: boolean;
56
249
  isLast: boolean;
57
250
  labels?: TourLabels;
251
+ /**
252
+ * Whether the step is required (skip button should be hidden).
253
+ */
254
+ required?: boolean;
255
+ /**
256
+ * Whether the step's completion condition is met.
257
+ * - `undefined`: No enforcement, next button always enabled.
258
+ * - `false`: Next button should be disabled.
259
+ * - `true`: Next button should be enabled.
260
+ */
261
+ completed?: boolean;
262
+ }
263
+
264
+ // ─── Persistence Types ───────────────────────────────────────────────────────
265
+
266
+ /**
267
+ * Storage adapter interface for tour persistence.
268
+ * Compatible with MMKV v4 and AsyncStorage APIs.
269
+ */
270
+ export interface StorageAdapter {
271
+ getItem: (key: string) => Promise<string | null> | string | null;
272
+ setItem: (key: string, value: string) => Promise<void> | void;
273
+ removeItem: (key: string) => Promise<void> | void;
274
+ }
275
+
276
+ /**
277
+ * Configuration for tour progress persistence.
278
+ */
279
+ export interface TourPersistenceConfig {
280
+ /**
281
+ * Enable persistence. When true, the library will auto-detect available storage
282
+ * (MMKV v4 or AsyncStorage) and save/restore tour progress.
283
+ * @default false
284
+ */
285
+ enabled: boolean;
286
+ /**
287
+ * Unique identifier for this tour. Used as the storage key.
288
+ * Required when persistence is enabled.
289
+ * @example 'onboarding-tour' or 'feature-tour-v2'
290
+ */
291
+ tourId: string;
292
+ /**
293
+ * Custom storage adapter. If not provided, the library will auto-detect
294
+ * MMKV v4 or AsyncStorage.
295
+ */
296
+ storage?: StorageAdapter;
297
+ /**
298
+ * If true, automatically resume the tour from the saved step when start() is called
299
+ * without a specific step key.
300
+ * @default true
301
+ */
302
+ autoResume?: boolean;
303
+ /**
304
+ * If true, clear saved progress when the tour is completed (reaches the last step).
305
+ * @default true
306
+ */
307
+ clearOnComplete?: boolean;
308
+ /**
309
+ * Maximum age (in milliseconds) for saved progress. Progress older than this
310
+ * will be ignored and cleared.
311
+ * @default undefined (no expiration)
312
+ * @example 7 * 24 * 60 * 60 * 1000 // 7 days
313
+ */
314
+ maxAge?: number;
58
315
  }
59
316
 
60
317
  export interface TourConfig {
61
318
  /**
62
- * Animation configuration for the spotlight movement.
319
+ * Animation configuration for the zone movement.
63
320
  */
64
321
  springConfig?: WithSpringConfig;
65
322
  /**
@@ -79,15 +336,36 @@ export interface TourConfig {
79
336
  * Backdrop opacity. Default 0.5
80
337
  */
81
338
  backdropOpacity?: number;
339
+ /**
340
+ * Custom styles for the tooltip appearance
341
+ */
342
+ tooltipStyles?: TooltipStyles;
343
+ /**
344
+ * Global zone style settings.
345
+ * Can be overridden per-step via TourStep.zoneStyle or TourZone props.
346
+ */
347
+ zoneStyle?: ZoneStyle;
348
+ /**
349
+ * Persistence configuration for saving/restoring tour progress.
350
+ * Supports MMKV v4 and AsyncStorage out of the box.
351
+ */
352
+ persistence?: TourPersistenceConfig;
353
+ /**
354
+ * Defines whether to apply a shadow/glow effect to the active tour zone highlight.
355
+ * @default false
356
+ */
357
+ enableGlow?: boolean;
82
358
  }
83
359
 
84
360
  export interface TourContextType {
85
361
  /**
86
362
  * Starts the tour at the first step or a specific step (by key).
363
+ * If persistence is enabled and autoResume is true, will resume from saved progress.
87
364
  */
88
365
  start: (stepKey?: string) => void;
89
366
  /**
90
367
  * Stops the tour and hides the overlay.
368
+ * Does NOT clear saved progress (use clearProgress for that).
91
369
  */
92
370
  stop: () => void;
93
371
  /**
@@ -124,9 +402,32 @@ export interface TourContextType {
124
402
  */
125
403
  config?: TourConfig;
126
404
  /**
405
+ * Animated ref to attach to your ScrollView for auto-scrolling.
406
+ * Use this ref directly on your ScrollView/Animated.ScrollView component.
407
+ * For custom scroll view components, use the useTourScrollView hook instead.
408
+ */
409
+ scrollViewRef: React.RefObject<any>;
410
+ /**
411
+ * @deprecated Use scrollViewRef directly instead.
127
412
  * Registers the main ScrollView ref for auto-scrolling
128
413
  */
129
414
  setScrollViewRef: (ref: any) => void;
415
+ /**
416
+ * Clears any saved tour progress from storage.
417
+ * Only available when persistence is enabled.
418
+ */
419
+ clearProgress: () => Promise<void>;
420
+ /**
421
+ * Whether there is saved progress available to resume.
422
+ * Only meaningful when persistence is enabled.
423
+ */
424
+ hasSavedProgress: boolean;
425
+ /**
426
+ * The full ordered list of step keys for this tour.
427
+ * Derived from stepsOrder prop or step registration order.
428
+ * Includes all steps across all screens (for multi-screen tours).
429
+ */
430
+ orderedStepKeys: string[];
130
431
  }
131
432
 
132
433
  export interface InternalTourContextType extends TourContextType {
@@ -136,7 +437,11 @@ export interface InternalTourContextType extends TourContextType {
136
437
  targetHeight: SharedValue<number>;
137
438
  targetRadius: SharedValue<number>;
138
439
  opacity: SharedValue<number>;
440
+ /** Border width for the zone glow ring */
441
+ zoneBorderWidth: SharedValue<number>;
139
442
  containerRef: React.RefObject<any>;
140
443
  scrollViewRef: React.RefObject<any>;
141
444
  setScrollViewRef: (ref: any) => void;
445
+ /** Resolved zone style for the current step */
446
+ currentZoneStyle: ZoneStyle | null;
142
447
  }