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,226 @@
1
+ /**
2
+ * Storage adapter for tour persistence.
3
+ * Auto-detects available storage (MMKV v4 or AsyncStorage) and provides a unified interface.
4
+ */
5
+
6
+ // ─── Types ───────────────────────────────────────────────────────────────────
7
+
8
+ export type StorageType = 'mmkv' | 'async-storage' | 'custom' | 'none';
9
+
10
+ export interface StorageAdapter {
11
+ getItem: (key: string) => Promise<string | null> | string | null;
12
+ setItem: (key: string, value: string) => Promise<void> | void;
13
+ removeItem: (key: string) => Promise<void> | void;
14
+ }
15
+
16
+ export interface TourStorageState {
17
+ tourId: string;
18
+ currentStepKey: string;
19
+ stepIndex: number;
20
+ timestamp: number;
21
+ }
22
+
23
+ // ─── Storage Detection ───────────────────────────────────────────────────────
24
+
25
+ let cachedStorageType: StorageType | null = null;
26
+ let cachedAdapter: StorageAdapter | null = null;
27
+
28
+ /**
29
+ * Attempts to detect and return the MMKV v4 default instance.
30
+ * Returns null if MMKV is not available.
31
+ */
32
+ function tryGetMMKV(): StorageAdapter | null {
33
+ try {
34
+ // Try to require react-native-mmkv (v4 uses different API)
35
+
36
+ const mmkvModule = require('react-native-mmkv');
37
+
38
+ // MMKV v4 exports createMMKV function
39
+ if (mmkvModule?.createMMKV) {
40
+ const createMMKV = mmkvModule.createMMKV;
41
+ // Create a dedicated instance for tour storage
42
+ const storage = createMMKV({ id: 'react-native-lumen-tour' });
43
+
44
+ if (
45
+ typeof storage.getString === 'function' &&
46
+ typeof storage.set === 'function' &&
47
+ typeof storage.remove === 'function'
48
+ ) {
49
+ return {
50
+ getItem: (key: string) => storage.getString(key) ?? null,
51
+ setItem: (key: string, value: string) => storage.set(key, value),
52
+ removeItem: (key: string) => storage.remove(key),
53
+ };
54
+ }
55
+ }
56
+
57
+ return null;
58
+ } catch {
59
+ return null;
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Attempts to detect and return AsyncStorage.
65
+ * Returns null if AsyncStorage is not available.
66
+ */
67
+ function tryGetAsyncStorage(): StorageAdapter | null {
68
+ try {
69
+ // Try to require @react-native-async-storage/async-storage
70
+
71
+ const asyncStorageModule = require('@react-native-async-storage/async-storage');
72
+ const AsyncStorage = asyncStorageModule?.default || asyncStorageModule;
73
+
74
+ if (
75
+ AsyncStorage &&
76
+ typeof AsyncStorage.getItem === 'function' &&
77
+ typeof AsyncStorage.setItem === 'function' &&
78
+ typeof AsyncStorage.removeItem === 'function'
79
+ ) {
80
+ return {
81
+ getItem: (key: string) => AsyncStorage.getItem(key),
82
+ setItem: (key: string, value: string) =>
83
+ AsyncStorage.setItem(key, value),
84
+ removeItem: (key: string) => AsyncStorage.removeItem(key),
85
+ };
86
+ }
87
+
88
+ return null;
89
+ } catch {
90
+ return null;
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Detects the available storage type and returns an adapter.
96
+ * Priority: MMKV v4 > AsyncStorage > none
97
+ */
98
+ export function detectStorage(): {
99
+ type: StorageType;
100
+ adapter: StorageAdapter | null;
101
+ } {
102
+ // Return cached result if available
103
+ if (cachedStorageType !== null) {
104
+ return { type: cachedStorageType, adapter: cachedAdapter };
105
+ }
106
+
107
+ // Try MMKV first (fastest)
108
+ const mmkvAdapter = tryGetMMKV();
109
+ if (mmkvAdapter) {
110
+ cachedStorageType = 'mmkv';
111
+ cachedAdapter = mmkvAdapter;
112
+ return { type: 'mmkv', adapter: mmkvAdapter };
113
+ }
114
+
115
+ // Try AsyncStorage
116
+ const asyncStorageAdapter = tryGetAsyncStorage();
117
+ if (asyncStorageAdapter) {
118
+ cachedStorageType = 'async-storage';
119
+ cachedAdapter = asyncStorageAdapter;
120
+ return { type: 'async-storage', adapter: asyncStorageAdapter };
121
+ }
122
+
123
+ // No storage available
124
+ cachedStorageType = 'none';
125
+ cachedAdapter = null;
126
+ return { type: 'none', adapter: null };
127
+ }
128
+
129
+ /**
130
+ * Clears the cached storage detection result.
131
+ * Useful for testing or when storage availability changes.
132
+ */
133
+ export function clearStorageCache(): void {
134
+ cachedStorageType = null;
135
+ cachedAdapter = null;
136
+ }
137
+
138
+ // ─── Storage Key Generation ──────────────────────────────────────────────────
139
+
140
+ const STORAGE_KEY_PREFIX = '@lumen_tour_';
141
+
142
+ /**
143
+ * Generates a storage key for a specific tour.
144
+ */
145
+ export function getTourStorageKey(tourId: string): string {
146
+ return `${STORAGE_KEY_PREFIX}${tourId}`;
147
+ }
148
+
149
+ // ─── Storage Operations ──────────────────────────────────────────────────────
150
+
151
+ /**
152
+ * Saves the current tour progress to storage.
153
+ */
154
+ export async function saveTourProgress(
155
+ adapter: StorageAdapter,
156
+ tourId: string,
157
+ currentStepKey: string,
158
+ stepIndex: number
159
+ ): Promise<void> {
160
+ const state: TourStorageState = {
161
+ tourId,
162
+ currentStepKey,
163
+ stepIndex,
164
+ timestamp: Date.now(),
165
+ };
166
+
167
+ const key = getTourStorageKey(tourId);
168
+ const value = JSON.stringify(state);
169
+
170
+ await adapter.setItem(key, value);
171
+ }
172
+
173
+ /**
174
+ * Loads the saved tour progress from storage.
175
+ * Returns null if no progress is saved or if the data is invalid.
176
+ */
177
+ export async function loadTourProgress(
178
+ adapter: StorageAdapter,
179
+ tourId: string
180
+ ): Promise<TourStorageState | null> {
181
+ try {
182
+ const key = getTourStorageKey(tourId);
183
+ const value = await adapter.getItem(key);
184
+
185
+ if (!value) {
186
+ return null;
187
+ }
188
+
189
+ const state: TourStorageState = JSON.parse(value);
190
+
191
+ // Validate the loaded state
192
+ if (
193
+ state.tourId !== tourId ||
194
+ typeof state.currentStepKey !== 'string' ||
195
+ typeof state.stepIndex !== 'number'
196
+ ) {
197
+ return null;
198
+ }
199
+
200
+ return state;
201
+ } catch {
202
+ return null;
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Clears the saved tour progress from storage.
208
+ */
209
+ export async function clearTourProgress(
210
+ adapter: StorageAdapter,
211
+ tourId: string
212
+ ): Promise<void> {
213
+ const key = getTourStorageKey(tourId);
214
+ await adapter.removeItem(key);
215
+ }
216
+
217
+ /**
218
+ * Checks if there is saved progress for a tour.
219
+ */
220
+ export async function hasTourProgress(
221
+ adapter: StorageAdapter,
222
+ tourId: string
223
+ ): Promise<boolean> {
224
+ const progress = await loadTourProgress(adapter, tourId);
225
+ return progress !== null;
226
+ }