@robertlinde/react-tour-kit 0.0.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.
Files changed (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +838 -0
  3. package/dist/react-native-platform/components/index.d.ts +2 -0
  4. package/dist/react-native-platform/components/index.js +8 -0
  5. package/dist/react-native-platform/components/index.js.map +1 -0
  6. package/dist/react-native-platform/components/tour-overlay.d.ts +3 -0
  7. package/dist/react-native-platform/components/tour-overlay.js +83 -0
  8. package/dist/react-native-platform/components/tour-overlay.js.map +1 -0
  9. package/dist/react-native-platform/components/tour-tooltip.d.ts +3 -0
  10. package/dist/react-native-platform/components/tour-tooltip.js +138 -0
  11. package/dist/react-native-platform/components/tour-tooltip.js.map +1 -0
  12. package/dist/react-native-platform/hooks/index.d.ts +1 -0
  13. package/dist/react-native-platform/hooks/index.js +6 -0
  14. package/dist/react-native-platform/hooks/index.js.map +1 -0
  15. package/dist/react-native-platform/hooks/use-tour-target.d.ts +2 -0
  16. package/dist/react-native-platform/hooks/use-tour-target.js +16 -0
  17. package/dist/react-native-platform/hooks/use-tour-target.js.map +1 -0
  18. package/dist/react-native-platform/index.d.ts +7 -0
  19. package/dist/react-native-platform/index.js +16 -0
  20. package/dist/react-native-platform/index.js.map +1 -0
  21. package/dist/react-native-platform/platform-adapter.d.ts +2 -0
  22. package/dist/react-native-platform/platform-adapter.js +87 -0
  23. package/dist/react-native-platform/platform-adapter.js.map +1 -0
  24. package/dist/react-native-platform/target-registry.d.ts +10 -0
  25. package/dist/react-native-platform/target-registry.js +20 -0
  26. package/dist/react-native-platform/target-registry.js.map +1 -0
  27. package/dist/react-native-platform/tour-provider.d.ts +3 -0
  28. package/dist/react-native-platform/tour-provider.js +200 -0
  29. package/dist/react-native-platform/tour-provider.js.map +1 -0
  30. package/dist/react-native-platform/types/tour-provider.props.type.d.ts +10 -0
  31. package/dist/react-native-platform/types/tour-provider.props.type.js +3 -0
  32. package/dist/react-native-platform/types/tour-provider.props.type.js.map +1 -0
  33. package/dist/react-native.d.ts +8 -0
  34. package/dist/react-native.js +19 -0
  35. package/dist/react-native.js.map +1 -0
  36. package/dist/react-platform/components/index.d.ts +2 -0
  37. package/dist/react-platform/components/index.js +8 -0
  38. package/dist/react-platform/components/index.js.map +1 -0
  39. package/dist/react-platform/components/tour-overlay.d.ts +3 -0
  40. package/dist/react-platform/components/tour-overlay.js +31 -0
  41. package/dist/react-platform/components/tour-overlay.js.map +1 -0
  42. package/dist/react-platform/components/tour-tooltip.d.ts +2 -0
  43. package/dist/react-platform/components/tour-tooltip.js +126 -0
  44. package/dist/react-platform/components/tour-tooltip.js.map +1 -0
  45. package/dist/react-platform/index.d.ts +6 -0
  46. package/dist/react-platform/index.js +14 -0
  47. package/dist/react-platform/index.js.map +1 -0
  48. package/dist/react-platform/platform-adapter.d.ts +2 -0
  49. package/dist/react-platform/platform-adapter.js +95 -0
  50. package/dist/react-platform/platform-adapter.js.map +1 -0
  51. package/dist/react-platform/tour-provider.d.ts +3 -0
  52. package/dist/react-platform/tour-provider.js +207 -0
  53. package/dist/react-platform/tour-provider.js.map +1 -0
  54. package/dist/react-platform/types/tour-provider.props.type.d.ts +10 -0
  55. package/dist/react-platform/types/tour-provider.props.type.js +3 -0
  56. package/dist/react-platform/types/tour-provider.props.type.js.map +1 -0
  57. package/dist/react-platform/utils/find-visible-element.util.d.ts +1 -0
  58. package/dist/react-platform/utils/find-visible-element.util.js +14 -0
  59. package/dist/react-platform/utils/find-visible-element.util.js.map +1 -0
  60. package/dist/react-platform/utils/index.d.ts +1 -0
  61. package/dist/react-platform/utils/index.js +6 -0
  62. package/dist/react-platform/utils/index.js.map +1 -0
  63. package/dist/react.d.ts +8 -0
  64. package/dist/react.js +18 -0
  65. package/dist/react.js.map +1 -0
  66. package/dist/shared/context/index.d.ts +1 -0
  67. package/dist/shared/context/index.js +7 -0
  68. package/dist/shared/context/index.js.map +1 -0
  69. package/dist/shared/context/tour-context.d.ts +3 -0
  70. package/dist/shared/context/tour-context.js +17 -0
  71. package/dist/shared/context/tour-context.js.map +1 -0
  72. package/dist/shared/hooks/index.d.ts +1 -0
  73. package/dist/shared/hooks/index.js +6 -0
  74. package/dist/shared/hooks/index.js.map +1 -0
  75. package/dist/shared/hooks/use-tour.hook.d.ts +2 -0
  76. package/dist/shared/hooks/use-tour.hook.js +10 -0
  77. package/dist/shared/hooks/use-tour.hook.js.map +1 -0
  78. package/dist/shared/index.d.ts +5 -0
  79. package/dist/shared/index.js +14 -0
  80. package/dist/shared/index.js.map +1 -0
  81. package/dist/shared/types/index.d.ts +8 -0
  82. package/dist/shared/types/index.js +7 -0
  83. package/dist/shared/types/index.js.map +1 -0
  84. package/dist/shared/types/platform-adapter.type.d.ts +24 -0
  85. package/dist/shared/types/platform-adapter.type.js +3 -0
  86. package/dist/shared/types/platform-adapter.type.js.map +1 -0
  87. package/dist/shared/types/rect.type.d.ts +10 -0
  88. package/dist/shared/types/rect.type.js +3 -0
  89. package/dist/shared/types/rect.type.js.map +1 -0
  90. package/dist/shared/types/tour-context.type.d.ts +12 -0
  91. package/dist/shared/types/tour-context.type.js +3 -0
  92. package/dist/shared/types/tour-context.type.js.map +1 -0
  93. package/dist/shared/types/tour-overlay-props.type.d.ts +7 -0
  94. package/dist/shared/types/tour-overlay-props.type.js +3 -0
  95. package/dist/shared/types/tour-overlay-props.type.js.map +1 -0
  96. package/dist/shared/types/tour-step.type.d.ts +8 -0
  97. package/dist/shared/types/tour-step.type.js +3 -0
  98. package/dist/shared/types/tour-step.type.js.map +1 -0
  99. package/dist/shared/types/tour-theme.type.d.ts +9 -0
  100. package/dist/shared/types/tour-theme.type.js +21 -0
  101. package/dist/shared/types/tour-theme.type.js.map +1 -0
  102. package/dist/shared/types/tour-tooltip-props.type.d.ts +17 -0
  103. package/dist/shared/types/tour-tooltip-props.type.js +3 -0
  104. package/dist/shared/types/tour-tooltip-props.type.js.map +1 -0
  105. package/dist/shared/utils/calculate-tooltip-position.util.d.ts +14 -0
  106. package/dist/shared/utils/calculate-tooltip-position.util.js +56 -0
  107. package/dist/shared/utils/calculate-tooltip-position.util.js.map +1 -0
  108. package/dist/shared/utils/index.d.ts +1 -0
  109. package/dist/shared/utils/index.js +6 -0
  110. package/dist/shared/utils/index.js.map +1 -0
  111. package/package.json +88 -0
package/README.md ADDED
@@ -0,0 +1,838 @@
1
+ # react-tour-kit
2
+
3
+ Cross-platform guided tour library for React and React Native. Build interactive onboarding experiences with customizable tooltips, smart positioning, cross-page navigation, and async step actions. Fully themeable with TypeScript support.
4
+
5
+ ## Features
6
+
7
+ - **Cross-Platform**: Works with React (web) and React Native
8
+ - **Cross-Page Tours**: Navigate between pages/screens during a tour
9
+ - **Themeable**: Customize colors without building custom components
10
+ - **Fully Customizable**: Replace the default tooltip and overlay with your own components
11
+ - **Smart Positioning**: Automatic tooltip positioning with viewport boundary detection
12
+ - **Keyboard Navigation**: Arrow keys and Escape (web) or hardware back button (Android)
13
+ - **Async Step Actions**: Run async code before each step (e.g., navigate, switch tabs, open dialogs)
14
+ - **TypeScript First**: Full TypeScript support
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @robertlinde/react-tour-kit
20
+ ```
21
+
22
+ ## Live Demos
23
+
24
+ Try the demos locally:
25
+
26
+ ```bash
27
+ # Web demo (React + React Router)
28
+ cd demos/react
29
+ npm install
30
+ npm run dev
31
+
32
+ # React Native demo (Expo + React Navigation)
33
+ cd demos/react-native
34
+ npm install
35
+ npm run ios # or npm run android
36
+ ```
37
+
38
+ ## Platform Guide
39
+
40
+ | Platform | Import from | Target elements with |
41
+ | ---------------- | ----------------------------- | --------------------------------------------- |
42
+ | **React (Web)** | `react-tour-kit/react` | CSS selectors (e.g., `[data-tour="welcome"]`) |
43
+ | **React Native** | `react-tour-kit/react-native` | `useTourTarget` hook or refs |
44
+
45
+ ---
46
+
47
+ ## React (Web)
48
+
49
+ ### Quick Start
50
+
51
+ #### 1. Wrap your app with TourProvider
52
+
53
+ ```tsx
54
+ import {TourProvider} from 'react-tour-kit/react';
55
+
56
+ function App() {
57
+ return (
58
+ <TourProvider>
59
+ <YourApp />
60
+ </TourProvider>
61
+ );
62
+ }
63
+ ```
64
+
65
+ #### 2. Add data attributes to target elements
66
+
67
+ ```tsx
68
+ function Dashboard() {
69
+ return (
70
+ <div>
71
+ <header data-tour="welcome">
72
+ <h1>Dashboard</h1>
73
+ </header>
74
+
75
+ <nav data-tour="sidebar">{/* Navigation items */}</nav>
76
+
77
+ <button data-tour="settings">Settings</button>
78
+ </div>
79
+ );
80
+ }
81
+ ```
82
+
83
+ #### 3. Start a tour
84
+
85
+ ```tsx
86
+ import {useTour, type TourStep} from 'react-tour-kit/react';
87
+
88
+ const tourSteps: TourStep[] = [
89
+ {
90
+ target: '[data-tour="welcome"]', // CSS selector
91
+ title: 'Welcome!',
92
+ content: 'This is your dashboard. Let me show you around.',
93
+ placement: 'bottom',
94
+ },
95
+ {
96
+ target: '[data-tour="sidebar"]',
97
+ title: 'Navigation',
98
+ content: 'Use the sidebar to navigate between different sections.',
99
+ placement: 'right',
100
+ },
101
+ {
102
+ target: '[data-tour="settings"]',
103
+ title: 'Settings',
104
+ content: 'Click here to customize your preferences.',
105
+ placement: 'left',
106
+ },
107
+ ];
108
+
109
+ function WelcomeButton() {
110
+ const {startTour} = useTour();
111
+
112
+ return <button onClick={() => startTour(tourSteps, 'onboarding')}>Start Tour</button>;
113
+ }
114
+ ```
115
+
116
+ ### Keyboard Navigation (Web)
117
+
118
+ | Key | Action |
119
+ | --------------- | ------------- |
120
+ | `→` Arrow Right | Next step |
121
+ | `←` Arrow Left | Previous step |
122
+ | `Escape` | Close tour |
123
+
124
+ ---
125
+
126
+ ## React Native
127
+
128
+ ### Quick Start
129
+
130
+ #### 1. Wrap your app with TourProvider
131
+
132
+ ```tsx
133
+ import {TourProvider} from 'react-tour-kit/react-native';
134
+
135
+ function App() {
136
+ return (
137
+ <TourProvider>
138
+ <YourApp />
139
+ </TourProvider>
140
+ );
141
+ }
142
+ ```
143
+
144
+ #### 2. Register target elements with useTourTarget
145
+
146
+ ```tsx
147
+ import {View} from 'react-native';
148
+ import {useTourTarget} from 'react-tour-kit/react-native';
149
+
150
+ function MyComponent() {
151
+ const welcomeRef = useTourTarget<View>('welcome-button');
152
+ const settingsRef = useTourTarget<View>('settings-button');
153
+
154
+ return (
155
+ <View>
156
+ <TouchableOpacity ref={welcomeRef}>
157
+ <Text>Welcome</Text>
158
+ </TouchableOpacity>
159
+
160
+ <TouchableOpacity ref={settingsRef}>
161
+ <Text>Settings</Text>
162
+ </TouchableOpacity>
163
+ </View>
164
+ );
165
+ }
166
+ ```
167
+
168
+ #### 3. Start a tour
169
+
170
+ ```tsx
171
+ import {useTour, type TourStep} from 'react-tour-kit/react-native';
172
+
173
+ const tourSteps: TourStep[] = [
174
+ {
175
+ target: 'welcome-button', // String ID from useTourTarget
176
+ title: 'Welcome!',
177
+ content: 'This is your dashboard. Let me show you around.',
178
+ placement: 'bottom',
179
+ },
180
+ {
181
+ target: 'settings-button',
182
+ title: 'Settings',
183
+ content: 'Tap here to customize your preferences.',
184
+ placement: 'left',
185
+ },
186
+ ];
187
+
188
+ function StartTourButton() {
189
+ const {startTour} = useTour();
190
+
191
+ return (
192
+ <TouchableOpacity onPress={() => startTour(tourSteps, 'onboarding')}>
193
+ <Text>Start Tour</Text>
194
+ </TouchableOpacity>
195
+ );
196
+ }
197
+ ```
198
+
199
+ ### Using Refs Directly (React Native)
200
+
201
+ You can also pass refs directly instead of string IDs:
202
+
203
+ ```tsx
204
+ import {useRef} from 'react';
205
+ import {useTour, type TourStep} from 'react-tour-kit/react-native';
206
+
207
+ function MyComponent() {
208
+ const buttonRef = useRef(null);
209
+
210
+ const steps: TourStep[] = [
211
+ {
212
+ target: buttonRef, // Pass ref directly
213
+ title: 'Welcome!',
214
+ content: 'Tap here to get started.',
215
+ },
216
+ ];
217
+
218
+ return <TouchableOpacity ref={buttonRef}>...</TouchableOpacity>;
219
+ }
220
+ ```
221
+
222
+ ### Navigation (React Native)
223
+
224
+ | Action | Trigger |
225
+ | ------------- | ------------------------------------------------- |
226
+ | Next step | Tap "Next" button |
227
+ | Previous step | Tap "Back" button |
228
+ | Close tour | Tap close button, overlay, or Android back button |
229
+
230
+ ---
231
+
232
+ ## Cross-Page/Cross-Screen Tours
233
+
234
+ Tours can span multiple pages (web) or screens (React Native). The key is to:
235
+
236
+ 1. Wrap your **router/navigator** with `TourProvider`
237
+ 2. Use `onBeforeStep` to navigate before showing a step
238
+
239
+ ### Web (React Router)
240
+
241
+ ```tsx
242
+ import {BrowserRouter, useNavigate} from 'react-router-dom';
243
+ import {TourProvider, useTour, type TourStep} from 'react-tour-kit/react';
244
+
245
+ // TourProvider wraps the router
246
+ function App() {
247
+ return (
248
+ <TourProvider>
249
+ <BrowserRouter>
250
+ <Routes>
251
+ <Route path="/" element={<Home />} />
252
+ <Route path="/settings" element={<Settings />} />
253
+ </Routes>
254
+ </BrowserRouter>
255
+ </TourProvider>
256
+ );
257
+ }
258
+
259
+ // Define steps with navigation
260
+ function Home() {
261
+ const navigate = useNavigate();
262
+ const {startTour} = useTour();
263
+
264
+ const steps: TourStep[] = [
265
+ {
266
+ target: '[data-tour="welcome"]',
267
+ title: 'Welcome',
268
+ content: 'Let me show you around.',
269
+ placement: 'bottom',
270
+ },
271
+ {
272
+ target: '[data-tour="nav-settings"]',
273
+ title: 'Settings Link',
274
+ content: "Now let's visit the settings page.",
275
+ placement: 'bottom',
276
+ // Navigate before the NEXT step shows
277
+ onBeforeStep: async () => {
278
+ navigate('/settings');
279
+ await new Promise((r) => setTimeout(r, 100)); // Wait for navigation
280
+ },
281
+ },
282
+ {
283
+ target: '[data-tour="theme-toggle"]',
284
+ title: 'Theme Settings',
285
+ content: 'This element is on the Settings page!',
286
+ placement: 'right',
287
+ },
288
+ {
289
+ target: '[data-tour="welcome"]',
290
+ title: 'Back Home',
291
+ content: 'And we can navigate back.',
292
+ placement: 'bottom',
293
+ onBeforeStep: async () => {
294
+ navigate('/');
295
+ await new Promise((r) => setTimeout(r, 100));
296
+ },
297
+ },
298
+ ];
299
+
300
+ return <button onClick={() => startTour(steps, 'cross-page')}>Start Tour</button>;
301
+ }
302
+ ```
303
+
304
+ ### React Native (React Navigation)
305
+
306
+ ```tsx
307
+ import {NavigationContainer, useNavigation} from '@react-navigation/native';
308
+ import {createNativeStackNavigator} from '@react-navigation/native-stack';
309
+ import {TourProvider, useTour, useTourTarget, type TourStep} from 'react-tour-kit/react-native';
310
+
311
+ const Stack = createNativeStackNavigator();
312
+
313
+ // TourProvider wraps the navigator
314
+ function App() {
315
+ return (
316
+ <TourProvider>
317
+ <NavigationContainer>
318
+ <Stack.Navigator>
319
+ <Stack.Screen name="Home" component={HomeScreen} />
320
+ <Stack.Screen name="Settings" component={SettingsScreen} />
321
+ </Stack.Navigator>
322
+ </NavigationContainer>
323
+ </TourProvider>
324
+ );
325
+ }
326
+
327
+ // Define steps with navigation
328
+ function HomeScreen() {
329
+ const navigation = useNavigation();
330
+ const {startTour} = useTour();
331
+ const headerRef = useTourTarget<View>('header');
332
+
333
+ const steps: TourStep[] = [
334
+ {
335
+ target: 'header',
336
+ title: 'Welcome',
337
+ content: 'Let me show you around.',
338
+ placement: 'bottom',
339
+ },
340
+ {
341
+ target: 'settings-header',
342
+ title: 'Settings Screen',
343
+ content: 'This element is on the Settings screen!',
344
+ placement: 'bottom',
345
+ onBeforeStep: async () => {
346
+ navigation.navigate('Settings');
347
+ await new Promise((r) => setTimeout(r, 300)); // Wait for animation
348
+ },
349
+ },
350
+ {
351
+ target: 'header',
352
+ title: 'Back Home',
353
+ content: 'And we can navigate back.',
354
+ placement: 'bottom',
355
+ onBeforeStep: async () => {
356
+ navigation.navigate('Home');
357
+ await new Promise((r) => setTimeout(r, 300));
358
+ },
359
+ },
360
+ ];
361
+
362
+ return (
363
+ <View>
364
+ <View ref={headerRef}>{/* ... */}</View>
365
+ <Button onPress={() => startTour(steps, 'cross-screen')} title="Start Tour" />
366
+ </View>
367
+ );
368
+ }
369
+
370
+ function SettingsScreen() {
371
+ const headerRef = useTourTarget<View>('settings-header');
372
+
373
+ return <View ref={headerRef}>{/* ... */}</View>;
374
+ }
375
+ ```
376
+
377
+ ### Important Notes for Cross-Page Tours
378
+
379
+ 1. **TourProvider placement**: Must wrap your router/navigator so tour state persists across navigation
380
+ 2. **Target availability**: Targets must be mounted when their step is active. Use `onBeforeStep` to navigate first
381
+ 3. **Wait for navigation**: Add a small delay after navigation to ensure the new page/screen is rendered
382
+ 4. **Persistent elements**: Elements like navigation bars that exist on all pages don't need `onBeforeStep`
383
+
384
+ ---
385
+
386
+ ## API Reference
387
+
388
+ ### TourProvider
389
+
390
+ The provider component that enables tour functionality throughout your app.
391
+
392
+ ```tsx
393
+ import {TourProvider} from 'react-tour-kit/react';
394
+
395
+ <TourProvider
396
+ TooltipComponent={CustomTooltip} // Optional: custom tooltip component
397
+ OverlayComponent={CustomOverlay} // Optional: custom overlay component
398
+ theme={theme} // Optional: theme configuration
399
+ onTourEnd={(tourId) => {
400
+ // Optional: callback when tour ends
401
+ console.log(`Tour ${tourId} completed`);
402
+ }}
403
+ >
404
+ {children}
405
+ </TourProvider>;
406
+ ```
407
+
408
+ #### Props
409
+
410
+ | Prop | Type | Description |
411
+ | ------------------ | --------------------------------------------- | --------------------------------------------------- |
412
+ | `children` | `ReactNode` | Your application content |
413
+ | `theme` | `TourTheme` | Theme configuration for colors (see Theming below) |
414
+ | `TooltipComponent` | `ForwardRefExoticComponent<TourTooltipProps>` | Custom tooltip component (must use forwardRef) |
415
+ | `OverlayComponent` | `ComponentType<TourOverlayProps>` | Custom overlay component |
416
+ | `onTourEnd` | `(tourId: string \| null) => void` | Callback fired when tour ends (completed or closed) |
417
+
418
+ ### useTour Hook
419
+
420
+ Access the tour context from any component.
421
+
422
+ ```tsx
423
+ import {useTour} from 'react-tour-kit/react';
424
+
425
+ function MyComponent() {
426
+ const {
427
+ isActive, // boolean: is a tour currently running?
428
+ currentStep, // number: current step index (0-based)
429
+ steps, // TourStep[]: all steps in current tour
430
+ currentTourId, // string | null: ID of current tour
431
+ startTour, // (steps: TourStep[], tourId?: string) => void
432
+ endTour, // () => void
433
+ nextStep, // () => void
434
+ prevStep, // () => void
435
+ goToStep, // (step: number) => void
436
+ } = useTour();
437
+ }
438
+ ```
439
+
440
+ ### TourStep
441
+
442
+ Define the steps in your tour.
443
+
444
+ ```tsx
445
+ type TourStep = {
446
+ target: TourTarget; // Target element (see below)
447
+ title: string; // Step title
448
+ content: string; // Step description/content
449
+ placement?: 'top' | 'bottom' | 'left' | 'right'; // Tooltip position (default: 'bottom')
450
+ onBeforeStep?: () => void | Promise<void>; // Async action before showing step
451
+ };
452
+
453
+ // Target types differ by platform:
454
+ // Web: CSS selector string (e.g., '[data-tour="welcome"]', '#my-button')
455
+ // React Native: String ID (registered via useTourTarget) or RefObject
456
+ type TourTarget = string | RefObject<unknown>;
457
+ ```
458
+
459
+ ## Theming
460
+
461
+ Customize the look of the default tooltip and overlay without building custom components.
462
+
463
+ ### Theme Options
464
+
465
+ ```tsx
466
+ import {TourProvider, type TourTheme} from 'react-tour-kit/react';
467
+
468
+ const theme: TourTheme = {
469
+ primaryColor: '#10b981', // Buttons, step badge, highlight border (default: '#3b82f6')
470
+ tooltipBackground: '#ffffff', // Tooltip background color (default: '#ffffff')
471
+ titleColor: '#1f2937', // Title text color (default: '#1f2937')
472
+ contentColor: '#4b5563', // Body text color (default: '#4b5563')
473
+ overlayColor: 'rgba(0, 0, 0, 0.5)', // Semi-transparent overlay (default: 'rgba(0, 0, 0, 0.5)')
474
+ };
475
+
476
+ function App() {
477
+ return (
478
+ <TourProvider theme={theme}>
479
+ <YourApp />
480
+ </TourProvider>
481
+ );
482
+ }
483
+ ```
484
+
485
+ ### Theme Examples
486
+
487
+ **Dark theme:**
488
+
489
+ ```tsx
490
+ const darkTheme: TourTheme = {
491
+ primaryColor: '#8b5cf6',
492
+ tooltipBackground: '#1f2937',
493
+ titleColor: '#f9fafb',
494
+ contentColor: '#d1d5db',
495
+ overlayColor: 'rgba(0, 0, 0, 0.7)',
496
+ };
497
+ ```
498
+
499
+ **Brand colors:**
500
+
501
+ ```tsx
502
+ const brandTheme: TourTheme = {
503
+ primaryColor: '#your-brand-color',
504
+ };
505
+ // Other values use defaults
506
+ ```
507
+
508
+ ### React Native
509
+
510
+ Theming works the same way in React Native:
511
+
512
+ ```tsx
513
+ import {TourProvider, type TourTheme} from 'react-tour-kit/react-native';
514
+
515
+ const theme: TourTheme = {
516
+ primaryColor: '#10b981',
517
+ overlayColor: 'rgba(0, 0, 0, 0.7)',
518
+ };
519
+
520
+ function App() {
521
+ return (
522
+ <TourProvider theme={theme}>
523
+ <YourApp />
524
+ </TourProvider>
525
+ );
526
+ }
527
+ ```
528
+
529
+ ---
530
+
531
+ ## Advanced Usage
532
+
533
+ ### Async Step Actions
534
+
535
+ Run code before a step is shown. Useful for opening dialogs, switching tabs, navigating, etc.
536
+
537
+ ```tsx
538
+ const steps: TourStep[] = [
539
+ {
540
+ target: '[data-tour="settings-tab"]',
541
+ title: 'Settings Tab',
542
+ content: 'Click here to access settings.',
543
+ },
544
+ {
545
+ target: '[data-tour="notifications-panel"]',
546
+ title: 'Notifications',
547
+ content: 'Configure your notification preferences here.',
548
+ onBeforeStep: async () => {
549
+ // Open the settings tab before showing this step
550
+ document.querySelector('[data-tour="settings-tab"]')?.click();
551
+ // Wait for the panel to appear
552
+ await new Promise((resolve) => setTimeout(resolve, 300));
553
+ },
554
+ },
555
+ ];
556
+ ```
557
+
558
+ ### Custom Tooltip Component
559
+
560
+ Create your own tooltip with your design system.
561
+
562
+ **Web:**
563
+
564
+ ```tsx
565
+ import {forwardRef} from 'react';
566
+ import {TourProvider, type TourTooltipProps} from 'react-tour-kit/react';
567
+
568
+ const CustomTooltip = forwardRef<HTMLDivElement, TourTooltipProps>(
569
+ ({title, content, currentStep, totalSteps, position, isPositioned, onClose, onNext, onPrev}, ref) => (
570
+ <div
571
+ ref={ref}
572
+ className="custom-tooltip"
573
+ style={{
574
+ position: 'fixed',
575
+ top: position.top,
576
+ left: position.left,
577
+ opacity: isPositioned ? 1 : 0,
578
+ }}
579
+ >
580
+ <h3>{title}</h3>
581
+ <p>{content}</p>
582
+ <div className="tooltip-footer">
583
+ <span>
584
+ {currentStep + 1} of {totalSteps}
585
+ </span>
586
+ <button onClick={onPrev} disabled={currentStep === 0}>
587
+ Back
588
+ </button>
589
+ <button onClick={onNext}>{currentStep === totalSteps - 1 ? 'Finish' : 'Next'}</button>
590
+ <button onClick={onClose}>×</button>
591
+ </div>
592
+ </div>
593
+ ),
594
+ );
595
+
596
+ function App() {
597
+ return (
598
+ <TourProvider TooltipComponent={CustomTooltip}>
599
+ <YourApp />
600
+ </TourProvider>
601
+ );
602
+ }
603
+ ```
604
+
605
+ **React Native:**
606
+
607
+ ```tsx
608
+ import {forwardRef} from 'react';
609
+ import {View, Text, TouchableOpacity} from 'react-native';
610
+ import {TourProvider, type TourTooltipProps} from 'react-tour-kit/react-native';
611
+
612
+ const CustomTooltip = forwardRef<View, TourTooltipProps>(
613
+ ({title, content, position, isPositioned, onNext, onClose}, ref) => (
614
+ <View
615
+ ref={ref}
616
+ style={{
617
+ position: 'absolute',
618
+ top: position.top,
619
+ left: position.left,
620
+ opacity: isPositioned ? 1 : 0,
621
+ backgroundColor: '#fff',
622
+ padding: 16,
623
+ borderRadius: 8,
624
+ }}
625
+ >
626
+ <Text style={{fontWeight: 'bold'}}>{title}</Text>
627
+ <Text>{content}</Text>
628
+ <TouchableOpacity onPress={onNext}>
629
+ <Text>Next</Text>
630
+ </TouchableOpacity>
631
+ </View>
632
+ ),
633
+ );
634
+
635
+ function App() {
636
+ return (
637
+ <TourProvider TooltipComponent={CustomTooltip}>
638
+ <YourApp />
639
+ </TourProvider>
640
+ );
641
+ }
642
+ ```
643
+
644
+ ### Custom Overlay Component
645
+
646
+ Customize the backdrop overlay.
647
+
648
+ **Web:**
649
+
650
+ ```tsx
651
+ import {TourProvider, type TourOverlayProps} from 'react-tour-kit/react';
652
+
653
+ function CustomOverlay({highlightRect, onClose}: TourOverlayProps) {
654
+ return (
655
+ <div className="custom-overlay" onClick={onClose}>
656
+ <div
657
+ className="highlight-border"
658
+ style={{
659
+ position: 'absolute',
660
+ top: highlightRect.top - 4,
661
+ left: highlightRect.left - 4,
662
+ width: highlightRect.width + 8,
663
+ height: highlightRect.height + 8,
664
+ border: '2px solid #your-brand-color',
665
+ borderRadius: '8px',
666
+ }}
667
+ />
668
+ </div>
669
+ );
670
+ }
671
+
672
+ function App() {
673
+ return (
674
+ <TourProvider OverlayComponent={CustomOverlay}>
675
+ <YourApp />
676
+ </TourProvider>
677
+ );
678
+ }
679
+ ```
680
+
681
+ **React Native:**
682
+
683
+ ```tsx
684
+ import {View, TouchableWithoutFeedback, StyleSheet} from 'react-native';
685
+ import {TourProvider, type TourOverlayProps} from 'react-tour-kit/react-native';
686
+
687
+ function CustomOverlay({highlightRect, onClose}: TourOverlayProps) {
688
+ return (
689
+ <TouchableWithoutFeedback onPress={onClose}>
690
+ <View style={StyleSheet.absoluteFill}>
691
+ {/* Your custom overlay with cutout */}
692
+ <View
693
+ style={{
694
+ position: 'absolute',
695
+ top: highlightRect.top - 4,
696
+ left: highlightRect.left - 4,
697
+ width: highlightRect.width + 8,
698
+ height: highlightRect.height + 8,
699
+ borderWidth: 2,
700
+ borderColor: '#your-brand-color',
701
+ borderRadius: 8,
702
+ }}
703
+ />
704
+ </View>
705
+ </TouchableWithoutFeedback>
706
+ );
707
+ }
708
+
709
+ function App() {
710
+ return (
711
+ <TourProvider OverlayComponent={CustomOverlay}>
712
+ <YourApp />
713
+ </TourProvider>
714
+ );
715
+ }
716
+ ```
717
+
718
+ ### Persisting Tour Completion
719
+
720
+ Track which tours users have completed:
721
+
722
+ ```tsx
723
+ import {TourProvider} from 'react-tour-kit/react';
724
+
725
+ function App() {
726
+ const handleTourEnd = async (tourId: string | null) => {
727
+ if (tourId) {
728
+ // Save to your backend
729
+ await fetch('/api/users/me/completed-tours/' + tourId, {
730
+ method: 'POST',
731
+ });
732
+ }
733
+ };
734
+
735
+ return (
736
+ <TourProvider onTourEnd={handleTourEnd}>
737
+ <YourApp />
738
+ </TourProvider>
739
+ );
740
+ }
741
+ ```
742
+
743
+ ### Conditional Tour Start
744
+
745
+ Start tours based on user state:
746
+
747
+ ```tsx
748
+ function TourTrigger({tourId, steps, autoStart = true}) {
749
+ const {startTour} = useTour();
750
+ const {user} = useUser(); // Your auth hook
751
+
752
+ useEffect(() => {
753
+ if (autoStart && user && !user.completedTours?.[tourId]) {
754
+ // Auto-start if user hasn't completed this tour
755
+ setTimeout(() => startTour(steps, tourId), 500);
756
+ }
757
+ }, [user, tourId, autoStart]);
758
+
759
+ return <button onClick={() => startTour(steps, tourId)}>Start Tour</button>;
760
+ }
761
+ ```
762
+
763
+ ## Styling
764
+
765
+ The default components use inline styles for zero-dependency styling. You have three options for customization:
766
+
767
+ 1. **Theming**: Use the `theme` prop to customize colors (see [Theming](#theming) section)
768
+ 2. **Custom Components**: Provide your own `TooltipComponent` and `OverlayComponent` for full control
769
+ 3. **CSS Overrides** (Web only): Override styles via CSS selectors
770
+
771
+ ## Platform Support
772
+
773
+ **Web:**
774
+
775
+ - Chrome, Firefox, Safari, Edge (latest versions)
776
+
777
+ **React Native:**
778
+
779
+ - iOS 13+
780
+ - Android 5.0+ (API 21+)
781
+ - React Native 0.70+
782
+
783
+ Requires React 18+.
784
+
785
+ ## TypeScript
786
+
787
+ Full TypeScript support is included. Import types as needed:
788
+
789
+ ```tsx
790
+ import type {
791
+ TourStep,
792
+ TourContextType,
793
+ TourProviderProps,
794
+ TourTooltipProps,
795
+ TourOverlayProps,
796
+ TourTheme,
797
+ } from 'react-tour-kit/react';
798
+ ```
799
+
800
+ ## Utilities
801
+
802
+ The package exports utility functions for custom implementations:
803
+
804
+ ```tsx
805
+ import {
806
+ calculateTooltipPosition, // Calculate optimal tooltip position
807
+ findVisibleElement, // Find first visible element matching selector
808
+ } from 'react-tour-kit/react';
809
+ ```
810
+
811
+ ## Development
812
+
813
+ ```bash
814
+ # Install dependencies
815
+ npm install
816
+
817
+ # Build
818
+ npm run build
819
+
820
+ # Watch mode
821
+ npm run start:dev
822
+
823
+ # Lint
824
+ npm run lint
825
+
826
+ # Format
827
+ npm run format
828
+
829
+ # Run web demo
830
+ cd demos/react && npm install && npm run dev
831
+
832
+ # Run native demo
833
+ cd demos/react-native && npm install && npm run ios
834
+ ```
835
+
836
+ ## License
837
+
838
+ MIT