rn-smart-tour 1.0.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/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # react-native-app-tour
2
+
3
+ An enterprise-grade Digital Adoption Platform (DAP) package for React Native. Easily add product tours, guided walkthroughs, and onboarding overlays directly into your app without intrusive code changes.
4
+
5
+ ## Features
6
+ - **Auto-Start Engine**: Automatically triggers tours the moment specific features mount on the screen.
7
+ - **Seen State Caching**: Provide any storage adapter (`AsyncStorage`, `MMKV`) to ensure users only see tours once.
8
+ - **Zero Config Measurement**: Wraps your components and seamlessly uses Native `measureInWindow` API.
9
+ - **Smart Overlays**: Creates highlighted holes in backdrops over completely custom UIs.
10
+
11
+ ## Installation
12
+
13
+ ```sh
14
+ npm install rn-smart-tour
15
+ ```
16
+
17
+ ## Quick Start Guide
18
+
19
+ ### 1. Wrap your App with the Provider
20
+
21
+ Create your `tours` configuration and mount `<DapProvider>` at the root of your application (above your Navigators):
22
+
23
+ ```tsx
24
+ import React from 'react';
25
+ import { DapProvider } from 'rn-smart-tour';
26
+ import AsyncStorage from '@react-native-async-storage/async-storage'; // Optional, but recommended
27
+
28
+ const TOURS = {
29
+ 'onboarding-flow': {
30
+ id: 'onboarding-flow',
31
+ autoStart: true, // Will automatically start when the first target renders
32
+ steps: [
33
+ {
34
+ targetId: 'save-playlist-btn',
35
+ title: 'Save your work',
36
+ description: 'Tap this heart to save your favorite songs anytime.',
37
+ }
38
+ ]
39
+ }
40
+ };
41
+
42
+ // Map any storage library you prefer so it remembers if users have seen the tour!
43
+ const storageAdapter = {
44
+ getItem: async (key) => await AsyncStorage.getItem(key),
45
+ setItem: async (key, value) => { await AsyncStorage.setItem(key, value); }
46
+ };
47
+
48
+ export default function App() {
49
+ return (
50
+ <DapProvider tours={TOURS} storageAdapter={storageAdapter}>
51
+ <MainAppScreen />
52
+ </DapProvider>
53
+ );
54
+ }
55
+ ```
56
+
57
+ ### 2. Wrap the targets you want to highlight
58
+
59
+ Go to any deep-nested screen and wrap buttons or views with `<DapTarget name="targetId">`:
60
+
61
+ ```tsx
62
+ import { DapTarget } from 'rn-smart-tour';
63
+
64
+ const MainAppScreen = () => {
65
+ return (
66
+ <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
67
+ <DapTarget name="save-playlist-btn">
68
+ <TouchableOpacity style={{ backgroundColor: 'red', padding: 15 }}>
69
+ <Text>❤️ Add to Favorites</Text>
70
+ </TouchableOpacity>
71
+ </DapTarget>
72
+ </View>
73
+ );
74
+ };
75
+ ```
76
+
77
+ ### 3. Trigger tours Manually (Optional)
78
+
79
+ If a tour lacks `autoStart: true` or you want to trigger it from a "Help" menu, use the `useDap` hook:
80
+
81
+ ```tsx
82
+ import { useDap } from 'rn-smart-tour';
83
+
84
+ const HelpMenu = () => {
85
+ const { startTour } = useDap();
86
+
87
+ return (
88
+ <Button title="Need help?" onPress={() => startTour('onboarding-flow')} />
89
+ );
90
+ }
91
+ ```
92
+
93
+ ## Advanced Properties & Types
94
+
95
+ ### Tour Object
96
+ | Property | Type | Description |
97
+ |-----------|------|-------------|
98
+ | `id` | `string` | Unique identifier. Needed for cache tracking. |
99
+ | `autoStart` | `boolean` | If true, automatically renders when the first step's target mounts on the screen. |
100
+ | `steps` | `TourStep[]` | The sequence of highlighted elements and tooltips. |
101
+
102
+ ### TourStep Object
103
+ | Property | Type | Description |
104
+ |-----------|------|-------------|
105
+ | `targetId` | `string` | Must directly match the `name=""` prop passed to `<DapTarget>`. |
106
+ | `title` | `string` | Large text inside the tooltip. |
107
+ | `description` | `string` | Context explanation inside the tooltip. |
@@ -0,0 +1,2 @@
1
+ import { DapContextType } from './types';
2
+ export declare const DapContext: import("react").Context<DapContextType | null>;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DapContext = void 0;
4
+ const react_1 = require("react");
5
+ exports.DapContext = (0, react_1.createContext)(null);
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const DapOverlay: () => React.JSX.Element | null;
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DapOverlay = void 0;
37
+ const react_1 = __importStar(require("react"));
38
+ const react_native_1 = require("react-native");
39
+ const DapContext_1 = require("./DapContext");
40
+ const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } = react_native_1.Dimensions.get('window');
41
+ const DapOverlay = () => {
42
+ const context = (0, react_1.useContext)(DapContext_1.DapContext);
43
+ if (!context || !context.activeTour)
44
+ return null;
45
+ const { activeTour, currentStepIndex, targets, nextStep, stopTour } = context;
46
+ const currentStep = activeTour.steps[currentStepIndex];
47
+ if (!currentStep)
48
+ return null;
49
+ const targetId = currentStep.targetId;
50
+ const measurement = targets[targetId];
51
+ // If the target hasn't been measured yet, we can't show the overlay correctly.
52
+ if (!measurement) {
53
+ return (<react_native_1.Modal transparent visible animationType="fade">
54
+ <react_native_1.View style={styles.fullscreen}>
55
+ <react_native_1.Text style={{ color: 'white', marginTop: 100, textAlign: 'center' }}>
56
+ Waiting for target "{targetId}" to mount...
57
+ </react_native_1.Text>
58
+ </react_native_1.View>
59
+ </react_native_1.Modal>);
60
+ }
61
+ const { x, y, width, height } = measurement;
62
+ return (<react_native_1.Modal transparent visible animationType="fade">
63
+ <react_native_1.View style={styles.fullscreen}>
64
+ {/* Top backdrop */}
65
+ <react_native_1.View style={[styles.backdrop, { top: 0, left: 0, right: 0, height: Math.max(0, y) }]}/>
66
+ {/* Bottom backdrop */}
67
+ <react_native_1.View style={[styles.backdrop, { top: y + height, left: 0, right: 0, bottom: 0 }]}/>
68
+ {/* Left backdrop */}
69
+ <react_native_1.View style={[styles.backdrop, { top: y, left: 0, width: Math.max(0, x), height }]}/>
70
+ {/* Right backdrop */}
71
+ <react_native_1.View style={[styles.backdrop, { top: y, left: x + width, right: 0, height }]}/>
72
+
73
+ {/* The Tooltip Card */}
74
+ <react_native_1.View style={[styles.tooltipContainer, { top: y + height + 10, left: Math.max(10, x - 20) }]}>
75
+ <react_native_1.Text style={styles.title}>{currentStep.title}</react_native_1.Text>
76
+ <react_native_1.Text style={styles.description}>{currentStep.description}</react_native_1.Text>
77
+ <react_native_1.View style={styles.actions}>
78
+ <react_native_1.TouchableOpacity onPress={stopTour} style={styles.actionBtn}>
79
+ <react_native_1.Text style={styles.actionText}>Skip</react_native_1.Text>
80
+ </react_native_1.TouchableOpacity>
81
+ <react_native_1.TouchableOpacity onPress={nextStep} style={[styles.actionBtn, styles.primaryBtn]}>
82
+ <react_native_1.Text style={[styles.actionText, styles.primaryText]}>
83
+ {currentStepIndex === activeTour.steps.length - 1 ? 'Finish' : 'Next'}
84
+ </react_native_1.Text>
85
+ </react_native_1.TouchableOpacity>
86
+ </react_native_1.View>
87
+ </react_native_1.View>
88
+ </react_native_1.View>
89
+ </react_native_1.Modal>);
90
+ };
91
+ exports.DapOverlay = DapOverlay;
92
+ const styles = react_native_1.StyleSheet.create({
93
+ fullscreen: {
94
+ ...react_native_1.StyleSheet.absoluteFillObject,
95
+ },
96
+ backdrop: {
97
+ position: 'absolute',
98
+ backgroundColor: 'rgba(0, 0, 0, 0.6)',
99
+ },
100
+ tooltipContainer: {
101
+ position: 'absolute',
102
+ backgroundColor: 'white',
103
+ padding: 16,
104
+ borderRadius: 8,
105
+ width: 250,
106
+ shadowColor: '#000',
107
+ shadowOffset: { width: 0, height: 2 },
108
+ shadowOpacity: 0.25,
109
+ shadowRadius: 3.84,
110
+ elevation: 5,
111
+ },
112
+ title: {
113
+ fontSize: 16,
114
+ fontWeight: 'bold',
115
+ marginBottom: 8,
116
+ color: '#333',
117
+ },
118
+ description: {
119
+ fontSize: 14,
120
+ color: '#666',
121
+ marginBottom: 16,
122
+ },
123
+ actions: {
124
+ flexDirection: 'row',
125
+ justifyContent: 'flex-end',
126
+ marginTop: 10,
127
+ },
128
+ actionBtn: {
129
+ paddingHorizontal: 15,
130
+ paddingVertical: 8,
131
+ marginLeft: 10,
132
+ borderRadius: 4,
133
+ },
134
+ primaryBtn: {
135
+ backgroundColor: '#007AFF',
136
+ },
137
+ actionText: {
138
+ color: '#666',
139
+ fontWeight: '600',
140
+ },
141
+ primaryText: {
142
+ color: 'white',
143
+ fontWeight: '600',
144
+ },
145
+ });
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { Tour, StorageAdapter } from './types';
3
+ export interface DapProviderProps {
4
+ children: React.ReactNode;
5
+ tours: Record<string, Tour>;
6
+ storageAdapter?: StorageAdapter;
7
+ }
8
+ export declare const DapProvider: React.FC<DapProviderProps>;
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DapProvider = void 0;
37
+ const react_1 = __importStar(require("react"));
38
+ const DapContext_1 = require("./DapContext");
39
+ const DapOverlay_1 = require("./DapOverlay");
40
+ const STORAGE_KEY = '@rn-dap:seen_tours';
41
+ const DapProvider = ({ children, tours, storageAdapter }) => {
42
+ const [targets, setTargets] = (0, react_1.useState)({});
43
+ const [activeTourId, setActiveTourId] = (0, react_1.useState)(null);
44
+ const [currentStepIndex, setCurrentStepIndex] = (0, react_1.useState)(0);
45
+ const [seenTours, setSeenTours] = (0, react_1.useState)({});
46
+ const [isStorageLoaded, setIsStorageLoaded] = (0, react_1.useState)(!storageAdapter);
47
+ // Load seen tours on mount if a storage adapter is provided
48
+ (0, react_1.useEffect)(() => {
49
+ const loadStorage = async () => {
50
+ if (storageAdapter) {
51
+ try {
52
+ const stored = await storageAdapter.getItem(STORAGE_KEY);
53
+ if (stored) {
54
+ setSeenTours(JSON.parse(stored));
55
+ }
56
+ }
57
+ catch (e) {
58
+ console.error('[rn-dap] failed to load storage', e);
59
+ }
60
+ setIsStorageLoaded(true);
61
+ }
62
+ };
63
+ loadStorage();
64
+ }, [storageAdapter]);
65
+ const saveSeenTour = async (tourId) => {
66
+ const nextSeen = { ...seenTours, [tourId]: true };
67
+ setSeenTours(nextSeen);
68
+ if (storageAdapter) {
69
+ try {
70
+ await storageAdapter.setItem(STORAGE_KEY, JSON.stringify(nextSeen));
71
+ }
72
+ catch (e) {
73
+ console.error('[rn-dap] failed to save storage', e);
74
+ }
75
+ }
76
+ };
77
+ const registerTarget = (0, react_1.useCallback)((id, measurement) => {
78
+ setTargets(prev => ({ ...prev, [id]: measurement }));
79
+ }, []);
80
+ const unregisterTarget = (0, react_1.useCallback)((id) => {
81
+ setTargets(prev => {
82
+ const next = { ...prev };
83
+ delete next[id];
84
+ return next;
85
+ });
86
+ }, []);
87
+ const startTour = (0, react_1.useCallback)((tourId) => {
88
+ if (tours[tourId] && !seenTours[tourId]) {
89
+ setActiveTourId(tourId);
90
+ setCurrentStepIndex(0);
91
+ }
92
+ else if (!tours[tourId]) {
93
+ console.warn(`[rn-dap] Tour with id ${tourId} not found.`);
94
+ }
95
+ }, [tours, seenTours]);
96
+ const stopTour = (0, react_1.useCallback)((markAsSeen = true) => {
97
+ if (activeTourId && markAsSeen) {
98
+ saveSeenTour(activeTourId);
99
+ }
100
+ setActiveTourId(null);
101
+ setCurrentStepIndex(0);
102
+ }, [activeTourId, seenTours]);
103
+ const nextStep = (0, react_1.useCallback)(() => {
104
+ if (activeTourId && tours[activeTourId]) {
105
+ const tour = tours[activeTourId];
106
+ if (currentStepIndex < tour.steps.length - 1) {
107
+ setCurrentStepIndex(prev => prev + 1);
108
+ }
109
+ else {
110
+ // Finished the last step
111
+ stopTour(true);
112
+ }
113
+ }
114
+ }, [activeTourId, currentStepIndex, tours, stopTour]);
115
+ const prevStep = (0, react_1.useCallback)(() => {
116
+ if (currentStepIndex > 0) {
117
+ setCurrentStepIndex(prev => prev - 1);
118
+ }
119
+ }, [currentStepIndex]);
120
+ // Auto-Start Engine
121
+ (0, react_1.useEffect)(() => {
122
+ // Wait until storage is loaded, and ensure no tour is currently running
123
+ if (!isStorageLoaded || activeTourId)
124
+ return;
125
+ for (const tourId of Object.keys(tours)) {
126
+ const tour = tours[tourId];
127
+ if (tour.autoStart && !seenTours[tourId] && tour.steps.length > 0) {
128
+ const firstTargetId = tour.steps[0].targetId;
129
+ // If the first target of an unread, auto-starting tour is mounted
130
+ if (targets[firstTargetId]) {
131
+ startTour(tourId);
132
+ break; // Start only one auto-tour at a time
133
+ }
134
+ }
135
+ }
136
+ }, [targets, tours, seenTours, isStorageLoaded, activeTourId, startTour]);
137
+ const activeTour = activeTourId ? tours[activeTourId] : null;
138
+ return (<DapContext_1.DapContext.Provider value={{
139
+ registerTarget,
140
+ unregisterTarget,
141
+ startTour,
142
+ stopTour,
143
+ nextStep,
144
+ prevStep,
145
+ activeTour,
146
+ currentStepIndex,
147
+ targets,
148
+ seenTours
149
+ }}>
150
+ {children}
151
+ <DapOverlay_1.DapOverlay />
152
+ </DapContext_1.DapContext.Provider>);
153
+ };
154
+ exports.DapProvider = DapProvider;
@@ -0,0 +1,8 @@
1
+ import React, { ReactElement } from 'react';
2
+ import { ViewProps } from 'react-native';
3
+ interface DapTargetProps extends ViewProps {
4
+ name: string;
5
+ children: ReactElement;
6
+ }
7
+ export declare const DapTarget: React.FC<DapTargetProps>;
8
+ export {};
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DapTarget = void 0;
37
+ const react_1 = __importStar(require("react"));
38
+ const react_native_1 = require("react-native");
39
+ const DapContext_1 = require("./DapContext");
40
+ const DapTarget = ({ name, children, ...props }) => {
41
+ const viewRef = (0, react_1.useRef)(null);
42
+ const context = (0, react_1.useContext)(DapContext_1.DapContext);
43
+ const measureAndRegister = () => {
44
+ if (viewRef.current && context) {
45
+ setTimeout(() => {
46
+ viewRef.current?.measureInWindow((x, y, width, height) => {
47
+ if (width > 0 && height > 0) {
48
+ context.registerTarget(name, { x, y, width, height });
49
+ }
50
+ });
51
+ }, 100);
52
+ }
53
+ };
54
+ const handleLayout = (e) => {
55
+ measureAndRegister();
56
+ if (props.onLayout) {
57
+ props.onLayout(e);
58
+ }
59
+ };
60
+ (0, react_1.useEffect)(() => {
61
+ return () => {
62
+ context?.unregisterTarget(name);
63
+ };
64
+ }, [name, context]);
65
+ // collapsable={false} is vital for Android, otherwise it gets optimized away and measure fails
66
+ return (<react_native_1.View ref={viewRef} onLayout={handleLayout} collapsable={false} {...props}>
67
+ {children}
68
+ </react_native_1.View>);
69
+ };
70
+ exports.DapTarget = DapTarget;
@@ -0,0 +1,4 @@
1
+ export * from './DapProvider';
2
+ export * from './DapTarget';
3
+ export * from './useDap';
4
+ export * from './types';
package/dist/index.js ADDED
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./DapProvider"), exports);
18
+ __exportStar(require("./DapTarget"), exports);
19
+ __exportStar(require("./useDap"), exports);
20
+ __exportStar(require("./types"), exports);
@@ -0,0 +1,33 @@
1
+ export interface TargetMeasurement {
2
+ x: number;
3
+ y: number;
4
+ width: number;
5
+ height: number;
6
+ }
7
+ export interface TourStep {
8
+ targetId: string;
9
+ title: string;
10
+ description: string;
11
+ position?: 'top' | 'bottom' | 'left' | 'right';
12
+ }
13
+ export interface Tour {
14
+ id: string;
15
+ steps: TourStep[];
16
+ autoStart?: boolean;
17
+ }
18
+ export interface StorageAdapter {
19
+ getItem: (key: string) => Promise<string | null> | string | null;
20
+ setItem: (key: string, value: string) => Promise<void> | void;
21
+ }
22
+ export interface DapContextType {
23
+ registerTarget: (id: string, measurement: TargetMeasurement) => void;
24
+ unregisterTarget: (id: string) => void;
25
+ startTour: (tourId: string) => void;
26
+ nextStep: () => void;
27
+ prevStep: () => void;
28
+ stopTour: () => void;
29
+ activeTour: Tour | null;
30
+ currentStepIndex: number;
31
+ targets: Record<string, TargetMeasurement>;
32
+ seenTours: Record<string, boolean>;
33
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1 @@
1
+ export declare const useDap: () => import("./types").DapContextType;
package/dist/useDap.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useDap = void 0;
4
+ const react_1 = require("react");
5
+ const DapContext_1 = require("./DapContext");
6
+ const useDap = () => {
7
+ const context = (0, react_1.useContext)(DapContext_1.DapContext);
8
+ if (!context) {
9
+ throw new Error('useDap must be used within a DapProvider');
10
+ }
11
+ return context;
12
+ };
13
+ exports.useDap = useDap;
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "rn-smart-tour",
3
+ "version": "1.0.0",
4
+ "description": "Enterprise-grade Digital Adoption Platform (DAP) package for React Native. Provides guided walkthroughs, tooltips, and app tours.",
5
+ "author": "Vishwas Gaur",
6
+ "license": "MIT",
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "keywords": [
13
+ "react-native",
14
+ "tour",
15
+ "walkthrough",
16
+ "onboarding",
17
+ "dap",
18
+ "guide",
19
+ "product-tour"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsc"
23
+ },
24
+ "peerDependencies": {
25
+ "react": "*",
26
+ "react-native": "*"
27
+ },
28
+ "devDependencies": {
29
+ "@types/react": "^18.3.28",
30
+ "@types/react-native": "^0.72.8",
31
+ "react": "^19.2.4",
32
+ "react-native": "^0.84.1",
33
+ "typescript": "^5.9.3"
34
+ }
35
+ }