onboard-engine 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/LICENSE +21 -0
- package/README.md +227 -0
- package/dist/index.css +2 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.mts +64 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Robin Fors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="logo.png" alt="Onboard Engine Logo" width="200" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# Onboard Engine
|
|
6
|
+
|
|
7
|
+
**A modern, lightweight, and customizable onboarding library for React and Next.js applications.**
|
|
8
|
+
|
|
9
|
+
`onboard-engine` provides a seamless way to guide users through your application using an animated focus overlay, tooltips, and persistent state management. Built with smooth CSS transitions and **Cookies** for state persistence.
|
|
10
|
+
|
|
11
|
+

|
|
12
|
+

|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
|
|
16
|
+
- **Smart Focus Overlay:** Dim the background and highlight the target element.
|
|
17
|
+
- **Deeply Customizable:** Custom renderers for buttons and styling options for the overlay.
|
|
18
|
+
- **State Persistence:** Remembers the user's progress across page reloads using cookies.
|
|
19
|
+
- **Automatic Navigation:** Seamlessly transitions between steps on different pages.
|
|
20
|
+
- **Interactive:** Supports click automation and draggable tooltips.
|
|
21
|
+
- **SSR Compatible:** Built with Server-Side Rendering (Next.js) in mind.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install onboard-engine
|
|
27
|
+
# or
|
|
28
|
+
yarn add onboard-engine
|
|
29
|
+
# or
|
|
30
|
+
pnpm add onboard-engine
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Getting Started
|
|
34
|
+
|
|
35
|
+
### 1. Import Styles
|
|
36
|
+
|
|
37
|
+
Import the necessary CSS in your global stylesheet or root component (e.g., `_app.tsx` or `layout.tsx`).
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import 'onboard-engine/dist/index.css';
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 2. Define Configuration
|
|
44
|
+
|
|
45
|
+
Create your onboarding configuration object. This defines the steps, metadata, and optional styling.
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { OnboardingConfig } from 'onboard-engine';
|
|
49
|
+
|
|
50
|
+
const onboardingConfig: OnboardingConfig = {
|
|
51
|
+
metadata: {
|
|
52
|
+
name: 'user-onboarding',
|
|
53
|
+
draggable: true, // Allow users to drag the tooltip
|
|
54
|
+
inOrder: true, // Default true. If false, steps can be activated out of order based on URL match.
|
|
55
|
+
},
|
|
56
|
+
steps: [
|
|
57
|
+
{
|
|
58
|
+
title: 'Welcome!',
|
|
59
|
+
description: 'Let us show you around the dashboard.',
|
|
60
|
+
attribute: 'welcome-header',
|
|
61
|
+
urlMatch: '/',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
title: 'Create Project',
|
|
65
|
+
description: 'Click here to start a new project.',
|
|
66
|
+
attribute: 'create-btn',
|
|
67
|
+
navigate: '/dashboard', // Navigate to this page when clicking next
|
|
68
|
+
urlMatch: '/home', // This step is active when on /home
|
|
69
|
+
subSteps: [
|
|
70
|
+
{
|
|
71
|
+
title: 'Project Name',
|
|
72
|
+
description: 'Enter a unique name for your project.',
|
|
73
|
+
attribute: 'project-name-input',
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
onOnboardingComplete: () => {
|
|
79
|
+
console.log('Onboarding finished!');
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 3. Wrap Your Application
|
|
85
|
+
|
|
86
|
+
Wrap your application (or the part you want to onboard) with the `OnboardingProvider`.
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
import { OnboardingProvider } from 'onboard-engine';
|
|
90
|
+
|
|
91
|
+
export default function App({ children }) {
|
|
92
|
+
return (
|
|
93
|
+
<OnboardingProvider config={onboardingConfig}>
|
|
94
|
+
{children}
|
|
95
|
+
</OnboardingProvider>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 4. Tag Your Elements
|
|
101
|
+
|
|
102
|
+
Add the `data-onboarding-id` attribute to the elements you want to highlight. This must match the `attribute` defined in your config steps.
|
|
103
|
+
|
|
104
|
+
```tsx
|
|
105
|
+
<h1 data-onboarding-id="welcome-header">Welcome to My App</h1>
|
|
106
|
+
<button data-onboarding-id="create-btn">Create Project</button>
|
|
107
|
+
<input data-onboarding-id="project-name-input" type="text" />
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Advanced Configuration
|
|
111
|
+
|
|
112
|
+
### Custom Styling
|
|
113
|
+
|
|
114
|
+
You can customize the appearance of the overlay and tooltip through the `style` property in the config. This accepts standard React CSS properties for each element.
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
const config: OnboardingConfig = {
|
|
118
|
+
// ...
|
|
119
|
+
style: {
|
|
120
|
+
// The mask overlaying the page
|
|
121
|
+
background: { backgroundColor: 'rgba(0, 0, 0, 0.85)' },
|
|
122
|
+
|
|
123
|
+
// The main tooltip container
|
|
124
|
+
container: {
|
|
125
|
+
borderRadius: '16px',
|
|
126
|
+
boxShadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1)'
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
// Buttons
|
|
130
|
+
next: { backgroundColor: '#4F46E5', color: 'white' },
|
|
131
|
+
prev: { color: '#6B7280' },
|
|
132
|
+
finish: { backgroundColor: '#10B981' },
|
|
133
|
+
start: { backgroundColor: '#4F46E5' }, // Used for the "Next" button on the first step
|
|
134
|
+
|
|
135
|
+
// Layout
|
|
136
|
+
padding: 10, // Add 10px padding around the highlighted element
|
|
137
|
+
},
|
|
138
|
+
// ...
|
|
139
|
+
};
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## API Reference
|
|
143
|
+
|
|
144
|
+
### `OnboardingConfig`
|
|
145
|
+
|
|
146
|
+
| Property | Type | Description |
|
|
147
|
+
| :--- | :--- | :--- |
|
|
148
|
+
| `metadata` | `OnboardingMetadata` | General settings for the onboarding instance. |
|
|
149
|
+
| `steps` | `OnboardingStep[]` | Array of steps defining the flow. |
|
|
150
|
+
| `style` | `OnboardingStyle` | Optional. Visual styling configuration. |
|
|
151
|
+
| `onOnboardingComplete` | `() => void` | Optional. Callback fired when onboarding finishes. |
|
|
152
|
+
|
|
153
|
+
### `OnboardingMetadata`
|
|
154
|
+
|
|
155
|
+
| Property | Type | Default | Description |
|
|
156
|
+
| :--- | :--- | :--- | :--- |
|
|
157
|
+
| `name` | `string` | **Required** | Unique name for the onboarding flow. |
|
|
158
|
+
| `nextRouter` | `boolean` | `false` | Enable if using Next.js router. |
|
|
159
|
+
| `draggable` | `boolean` | `false` | Allow the tooltip to be dragged. |
|
|
160
|
+
| `inOrder` | `boolean` | `true` | If `true`, strict step order is enforced. If `false`, matching `urlMatch` activates the step. |
|
|
161
|
+
|
|
162
|
+
### `OnboardingStep`
|
|
163
|
+
|
|
164
|
+
| Property | Type | Description |
|
|
165
|
+
| :--- | :--- | :--- |
|
|
166
|
+
| `title` | `string` | Title displayed in the tooltip. |
|
|
167
|
+
| `description` | `string` | Description text in the tooltip. |
|
|
168
|
+
| `attribute` | `string` | The `data-onboarding-id` value to target. |
|
|
169
|
+
| `urlMatch` | `string` \| `RegExp` | **Required**. Checks if current URL matches to active this step. Supports `*` wildcards in strings (e.g., `"/user/*"`). <br/>**Note:** `RegExp` objects cannot be passed from Server Components in Next.js. Use string wildcards or define config in a Client Component. |
|
|
170
|
+
| `navigate` | `string` | URL to navigate to when this step is completed (next button clicked). |
|
|
171
|
+
| `click` | `boolean` | If `true`, clicks the element when the step activates. |
|
|
172
|
+
| `subSteps` | `OnboardingSubStep[]` | Nested steps for complex workflows. |
|
|
173
|
+
|
|
174
|
+
### `OnboardingStyle`
|
|
175
|
+
|
|
176
|
+
All properties (except `padding`) accept `React.CSSProperties` objects.
|
|
177
|
+
|
|
178
|
+
| Property | Type | Description |
|
|
179
|
+
| :--- | :--- | :--- |
|
|
180
|
+
| `background` | `CSSProperties` | Styles for the overlay mask. |
|
|
181
|
+
| `container` | `CSSProperties` | Styles for the tooltip box. |
|
|
182
|
+
| `next` | `CSSProperties` | Styles for the "Next" button. |
|
|
183
|
+
| `prev` | `CSSProperties` | Styles for the "Prev" button. |
|
|
184
|
+
| `finish` | `CSSProperties` | Styles for the "Finish" button. |
|
|
185
|
+
| `start` | `CSSProperties` | Styles for the "Start" button (Step 1 "Next" button). |
|
|
186
|
+
| `padding` | `number` | Padding (in px) around the highlighted element. |
|
|
187
|
+
|
|
188
|
+
## Hooks
|
|
189
|
+
|
|
190
|
+
### `useOnboarding()`
|
|
191
|
+
|
|
192
|
+
Access the onboarding state and controls from any component within the provider.
|
|
193
|
+
|
|
194
|
+
```tsx
|
|
195
|
+
import { useOnboarding } from 'onboard-engine';
|
|
196
|
+
|
|
197
|
+
const MyComponent = () => {
|
|
198
|
+
const {
|
|
199
|
+
// Actions
|
|
200
|
+
nextStep, // Go to the next step
|
|
201
|
+
prevStep, // Go to the previous step
|
|
202
|
+
finish, // End the onboarding flow
|
|
203
|
+
goToStep, // Jump to a specific step (index, subStepIndex?)
|
|
204
|
+
|
|
205
|
+
// State
|
|
206
|
+
state, // The full internal state object
|
|
207
|
+
currentStep,// The current OnboardingStep or OnboardingSubStep object
|
|
208
|
+
isFirstStep,// Boolean: true if on the first step
|
|
209
|
+
isLastStep, // Boolean: true if on the last step
|
|
210
|
+
|
|
211
|
+
// Configuration
|
|
212
|
+
config // The full configuration object
|
|
213
|
+
} = useOnboarding();
|
|
214
|
+
|
|
215
|
+
return (
|
|
216
|
+
<button onClick={nextStep}>Next</button>
|
|
217
|
+
);
|
|
218
|
+
};
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Contributing
|
|
222
|
+
|
|
223
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
224
|
+
|
|
225
|
+
## License
|
|
226
|
+
|
|
227
|
+
ISC © [Forsrobin](https://github.com/Forsrobin)
|
package/dist/index.css
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
.onboard-overlay-mask{position:absolute;background-color:#000000b3;pointer-events:auto;transition:all .3s cubic-bezier(.25,.1,.25,1)}.onboard-tooltip{position:absolute;width:300px;background-color:#fff;border-radius:12px;box-shadow:0 25px 50px -12px #00000040;pointer-events:auto;padding:20px;border:1px solid #f3f4f6;z-index:10000;transition:top .3s cubic-bezier(.25,.1,.25,1),left .3s cubic-bezier(.25,.1,.25,1)}.onboard-button-primary{background-color:#000;color:#fff;padding:8px 16px;border-radius:8px;font-weight:600;font-size:14px;transition:all .2s;display:flex;align-items:center;gap:4px}.onboard-button-primary:hover{background-color:#1f2937}.onboard-button-primary:active{transform:scale(.95)}.onboard-button-ghost{color:#4b5563;font-weight:500;font-size:14px;transition:color .2s;display:flex;align-items:center;gap:4px}.onboard-button-ghost:hover{color:#111827}.onboard-button-ghost:disabled{color:#d1d5db;cursor:not-allowed}
|
|
2
|
+
/*# sourceMappingURL=index.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/styles.css"],"sourcesContent":[".onboard-overlay-mask {\n position: absolute;\n background-color: rgba(0, 0, 0, 0.7);\n pointer-events: auto;\n transition: all 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);\n}\n\n.onboard-tooltip {\n position: absolute;\n width: 300px;\n background-color: white;\n border-radius: 12px;\n box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);\n pointer-events: auto;\n padding: 20px;\n border: 1px solid #f3f4f6;\n z-index: 10000;\n transition: top 0.3s cubic-bezier(0.25, 0.1, 0.25, 1), left 0.3s cubic-bezier(0.25, 0.1, 0.25, 1);\n}\n\n.onboard-button-primary {\n background-color: black;\n color: white;\n padding: 8px 16px;\n border-radius: 8px;\n font-weight: 600;\n font-size: 14px;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.onboard-button-primary:hover {\n background-color: #1f2937;\n}\n\n.onboard-button-primary:active {\n transform: scale(0.95);\n}\n\n.onboard-button-ghost {\n color: #4b5563;\n font-weight: 500;\n font-size: 14px;\n transition: color 0.2s;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.onboard-button-ghost:hover {\n color: #111827;\n}\n\n.onboard-button-ghost:disabled {\n color: #d1d5db;\n cursor: not-allowed;\n}\n"],"mappings":"AAAA,CAAC,qBACC,SAAU,SACV,iBAAkB,UAClB,eAAgB,KAChB,WAAY,IAAI,IAAK,aAAa,GAAI,CAAE,EAAG,CAAE,GAAI,CAAE,EACrD,CAEA,CAAC,gBACC,SAAU,SACV,MAAO,MACP,iBAAkB,KAVpB,cAWiB,KACf,WAAY,EAAE,KAAK,KAAK,MAAM,UAC9B,eAAgB,KAblB,QAcW,KACT,OAAQ,IAAI,MAAM,QAClB,QAAS,MACT,WAAY,IAAI,IAAK,aAAa,GAAI,CAAE,EAAG,CAAE,GAAI,CAAE,EAAE,CAAE,KAAK,IAAK,aAAa,GAAI,CAAE,EAAG,CAAE,GAAI,CAAE,EACjG,CAEA,CAAC,uBACC,iBAAkB,KAClB,MAAO,KAtBT,QAuBW,IAAI,KAvBf,cAwBiB,IACf,YAAa,IACb,UAAW,KACX,WAAY,IAAI,IAChB,QAAS,KACT,YAAa,OACb,IAAK,GACP,CAEA,CAbC,sBAasB,OACrB,iBAAkB,OACpB,CAEA,CAjBC,sBAiBsB,QACrB,UAAW,MAAM,IACnB,CAEA,CAAC,qBACC,MAAO,QACP,YAAa,IACb,UAAW,KACX,WAAY,MAAM,IAClB,QAAS,KACT,YAAa,OACb,IAAK,GACP,CAEA,CAVC,oBAUoB,OACnB,MAAO,OACT,CAEA,CAdC,oBAcoB,UACnB,MAAO,QACP,OAAQ,WACV","names":[]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface OnboardingSubStep {
|
|
4
|
+
title: string;
|
|
5
|
+
description: string;
|
|
6
|
+
attribute: string;
|
|
7
|
+
navigate?: string;
|
|
8
|
+
click?: boolean;
|
|
9
|
+
}
|
|
10
|
+
interface OnboardingStep {
|
|
11
|
+
title: string;
|
|
12
|
+
description: string;
|
|
13
|
+
attribute: string;
|
|
14
|
+
urlMatch: string | RegExp;
|
|
15
|
+
navigate?: string;
|
|
16
|
+
subSteps?: OnboardingSubStep[];
|
|
17
|
+
click?: boolean;
|
|
18
|
+
}
|
|
19
|
+
interface OnboardingMetadata {
|
|
20
|
+
name: string;
|
|
21
|
+
nextRouter?: boolean;
|
|
22
|
+
draggable?: boolean;
|
|
23
|
+
inOrder?: boolean;
|
|
24
|
+
}
|
|
25
|
+
interface OnboardingStyle {
|
|
26
|
+
padding?: number;
|
|
27
|
+
background?: React.CSSProperties;
|
|
28
|
+
container?: React.CSSProperties;
|
|
29
|
+
next?: React.CSSProperties;
|
|
30
|
+
prev?: React.CSSProperties;
|
|
31
|
+
start?: React.CSSProperties;
|
|
32
|
+
finish?: React.CSSProperties;
|
|
33
|
+
}
|
|
34
|
+
interface OnboardingConfig {
|
|
35
|
+
metadata: OnboardingMetadata;
|
|
36
|
+
steps: OnboardingStep[];
|
|
37
|
+
style?: OnboardingStyle;
|
|
38
|
+
onOnboardingComplete?: () => void;
|
|
39
|
+
}
|
|
40
|
+
interface OnboardingState {
|
|
41
|
+
currentStepIndex: number;
|
|
42
|
+
currentSubStepIndex: number | null;
|
|
43
|
+
isActive: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface OnboardingContextType {
|
|
47
|
+
config: OnboardingConfig;
|
|
48
|
+
state: OnboardingState;
|
|
49
|
+
nextStep: () => void;
|
|
50
|
+
prevStep: () => void;
|
|
51
|
+
finish: () => void;
|
|
52
|
+
goToStep: (stepIndex: number, subStepIndex?: number | null) => void;
|
|
53
|
+
currentStep: OnboardingStep | OnboardingSubStep | null;
|
|
54
|
+
isFirstStep: boolean;
|
|
55
|
+
isLastStep: boolean;
|
|
56
|
+
}
|
|
57
|
+
declare const OnboardingProvider: React.FC<{
|
|
58
|
+
config: OnboardingConfig;
|
|
59
|
+
ssr?: boolean;
|
|
60
|
+
children: React.ReactNode;
|
|
61
|
+
}>;
|
|
62
|
+
declare const useOnboarding: () => OnboardingContextType;
|
|
63
|
+
|
|
64
|
+
export { type OnboardingConfig, type OnboardingMetadata, OnboardingProvider, type OnboardingState, type OnboardingStep, type OnboardingStyle, type OnboardingSubStep, useOnboarding };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
interface OnboardingSubStep {
|
|
4
|
+
title: string;
|
|
5
|
+
description: string;
|
|
6
|
+
attribute: string;
|
|
7
|
+
navigate?: string;
|
|
8
|
+
click?: boolean;
|
|
9
|
+
}
|
|
10
|
+
interface OnboardingStep {
|
|
11
|
+
title: string;
|
|
12
|
+
description: string;
|
|
13
|
+
attribute: string;
|
|
14
|
+
urlMatch: string | RegExp;
|
|
15
|
+
navigate?: string;
|
|
16
|
+
subSteps?: OnboardingSubStep[];
|
|
17
|
+
click?: boolean;
|
|
18
|
+
}
|
|
19
|
+
interface OnboardingMetadata {
|
|
20
|
+
name: string;
|
|
21
|
+
nextRouter?: boolean;
|
|
22
|
+
draggable?: boolean;
|
|
23
|
+
inOrder?: boolean;
|
|
24
|
+
}
|
|
25
|
+
interface OnboardingStyle {
|
|
26
|
+
padding?: number;
|
|
27
|
+
background?: React.CSSProperties;
|
|
28
|
+
container?: React.CSSProperties;
|
|
29
|
+
next?: React.CSSProperties;
|
|
30
|
+
prev?: React.CSSProperties;
|
|
31
|
+
start?: React.CSSProperties;
|
|
32
|
+
finish?: React.CSSProperties;
|
|
33
|
+
}
|
|
34
|
+
interface OnboardingConfig {
|
|
35
|
+
metadata: OnboardingMetadata;
|
|
36
|
+
steps: OnboardingStep[];
|
|
37
|
+
style?: OnboardingStyle;
|
|
38
|
+
onOnboardingComplete?: () => void;
|
|
39
|
+
}
|
|
40
|
+
interface OnboardingState {
|
|
41
|
+
currentStepIndex: number;
|
|
42
|
+
currentSubStepIndex: number | null;
|
|
43
|
+
isActive: boolean;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface OnboardingContextType {
|
|
47
|
+
config: OnboardingConfig;
|
|
48
|
+
state: OnboardingState;
|
|
49
|
+
nextStep: () => void;
|
|
50
|
+
prevStep: () => void;
|
|
51
|
+
finish: () => void;
|
|
52
|
+
goToStep: (stepIndex: number, subStepIndex?: number | null) => void;
|
|
53
|
+
currentStep: OnboardingStep | OnboardingSubStep | null;
|
|
54
|
+
isFirstStep: boolean;
|
|
55
|
+
isLastStep: boolean;
|
|
56
|
+
}
|
|
57
|
+
declare const OnboardingProvider: React.FC<{
|
|
58
|
+
config: OnboardingConfig;
|
|
59
|
+
ssr?: boolean;
|
|
60
|
+
children: React.ReactNode;
|
|
61
|
+
}>;
|
|
62
|
+
declare const useOnboarding: () => OnboardingContextType;
|
|
63
|
+
|
|
64
|
+
export { type OnboardingConfig, type OnboardingMetadata, OnboardingProvider, type OnboardingState, type OnboardingStep, type OnboardingStyle, type OnboardingSubStep, useOnboarding };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";"use client";var Q=Object.create;var W=Object.defineProperty;var V=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var tt=Object.getPrototypeOf,et=Object.prototype.hasOwnProperty;var nt=(e,s)=>{for(var f in s)W(e,f,{get:s[f],enumerable:!0})},F=(e,s,f,y)=>{if(s&&typeof s=="object"||typeof s=="function")for(let m of Z(s))!et.call(e,m)&&m!==f&&W(e,m,{get:()=>s[m],enumerable:!(y=V(s,m))||y.enumerable});return e};var T=(e,s,f)=>(f=e!=null?Q(tt(e)):{},F(s||!e||!e.__esModule?W(f,"default",{value:e,enumerable:!0}):f,e)),ot=e=>F(W({},"__esModule",{value:!0}),e);var it={};nt(it,{OnboardingProvider:()=>rt,useOnboarding:()=>$});module.exports=ot(it);var l=T(require("react")),B=T(require("js-cookie"));var b=require("react"),X=require("react-dom");var a=require("react/jsx-runtime"),j=()=>{let{config:e,currentStep:s,nextStep:f,prevStep:y,finish:m,isFirstStep:n,isLastStep:p}=$(),[d,v]=(0,b.useState)(null),[H,D]=(0,b.useState)({top:0,left:0}),[C,A]=(0,b.useState)({x:0,y:0}),E=(0,b.useRef)(!1),R=(0,b.useRef)({x:0,y:0}),w=(0,b.useRef)(null);(0,b.useEffect)(()=>{A({x:0,y:0})},[s]);let N=r=>{e.metadata.draggable&&(r.stopPropagation(),r.preventDefault(),E.current=!0,R.current={x:r.clientX-C.x,y:r.clientY-C.y},w.current&&(w.current.style.transition="none",w.current.style.cursor="grabbing"),window.addEventListener("pointermove",I),window.addEventListener("pointerup",t))},I=(0,b.useCallback)(r=>{if(!E.current)return;let g=r.clientX-R.current.x,S=r.clientY-R.current.y;A({x:g,y:S})},[]),t=(0,b.useCallback)(()=>{E.current=!1,w.current&&(w.current.style.transition="top 0.3s cubic-bezier(0.25, 0.1, 0.25, 1), left 0.3s cubic-bezier(0.25, 0.1, 0.25, 1)",w.current.style.cursor=e.metadata.draggable?"grab":"auto"),window.removeEventListener("pointermove",I),window.removeEventListener("pointerup",t)},[e.metadata.draggable,I]);(0,b.useEffect)(()=>()=>{window.removeEventListener("pointermove",I),window.removeEventListener("pointerup",t)},[I,t]);let c=(0,b.useCallback)(r=>{let z=r.top,x=window.innerHeight-r.bottom,U=r.left,G=window.innerWidth-r.right,P=0,L=0;return x>232?(P=r.bottom+12,L=Math.max(20,Math.min(window.innerWidth-300-20,r.left+r.width/2-300/2))):z>232?(P=r.top-200-12,L=Math.max(20,Math.min(window.innerWidth-300-20,r.left+r.width/2-300/2))):G>332?(P=Math.max(20,Math.min(window.innerHeight-200-20,r.top+r.height/2-200/2)),L=r.right+12):U>332?(P=Math.max(20,Math.min(window.innerHeight-200-20,r.top+r.height/2-200/2)),L=r.left-300-12):(P=window.innerHeight/2-200/2,L=window.innerWidth/2-300/2),{top:P+window.scrollY,left:L+window.scrollX}},[]),i=(0,b.useCallback)(()=>{if(!s)return;let r=document.querySelector(`[data-onboarding-id="${s.attribute}"]`);if(r){let g=r.getBoundingClientRect(),S=e.style?.padding||0,k={top:g.top-S,bottom:g.bottom+S,left:g.left-S,right:g.right+S,width:g.width+S*2,height:g.height+S*2},M={top:k.top+window.scrollY,left:k.left+window.scrollX,width:k.width,height:k.height},z=c(k);v(x=>x&&x.top===M.top&&x.left===M.left&&x.width===M.width&&x.height===M.height?x:M),D(x=>x.top===z.top&&x.left===z.left?x:z)}else v(null)},[s,c,e.style]);if((0,b.useEffect)(()=>{i(),window.addEventListener("resize",i),window.addEventListener("scroll",i);let r=new MutationObserver(i);r.observe(document.body,{childList:!0,subtree:!0,attributes:!0});let g=null;if(typeof ResizeObserver<"u"){g=new ResizeObserver(i),g.observe(document.body);let S=s?.attribute?document.querySelector(`[data-onboarding-id="${s.attribute}"]`):null;S&&g.observe(S)}return()=>{window.removeEventListener("resize",i),window.removeEventListener("scroll",i),r.disconnect(),g&&g.disconnect()}},[i,s?.attribute]),!s||!d)return null;let u={...e.style?.background,transition:"all 0.3s cubic-bezier(0.25, 0.1, 0.25, 1)"},o=r=>{r.stopPropagation()},h=()=>(0,a.jsx)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:(0,a.jsx)("path",{d:"M15 18l-6-6 6-6"})}),J=()=>(0,a.jsx)("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:(0,a.jsx)("path",{d:"M9 18l6-6-6-6"})}),_=()=>(0,a.jsxs)("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[(0,a.jsx)("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),(0,a.jsx)("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]}),K=(0,a.jsxs)("div",{className:"fixed inset-0 z-[999999] pointer-events-none",children:[(0,a.jsx)("div",{style:{height:d.top,...u},className:"onboard-overlay-mask top-0 left-0 w-full pointer-events-auto",onPointerDown:o,onMouseDown:o,onClick:o}),(0,a.jsx)("div",{style:{top:d.top+d.height,height:`calc(100vh - ${d.top+d.height}px)`,...u},className:"onboard-overlay-mask left-0 w-full pointer-events-auto",onPointerDown:o,onMouseDown:o,onClick:o}),(0,a.jsx)("div",{style:{top:d.top,height:d.height,width:d.left,...u},className:"onboard-overlay-mask left-0 pointer-events-auto",onPointerDown:o,onMouseDown:o,onClick:o}),(0,a.jsx)("div",{style:{top:d.top,height:d.height,left:d.left+d.width,width:`calc(100% - ${d.left+d.width}px)`,...u},className:"onboard-overlay-mask pointer-events-auto",onPointerDown:o,onMouseDown:o,onClick:o}),(0,a.jsxs)("div",{ref:w,className:"onboard-tooltip pointer-events-auto",onPointerDown:N,style:{zIndex:1e6,...e.style?.container,top:H.top+C.y,left:H.left+C.x,transition:"top 0.3s cubic-bezier(0.25, 0.1, 0.25, 1), left 0.3s cubic-bezier(0.25, 0.1, 0.25, 1)",cursor:e.metadata.draggable?"grab":"auto",touchAction:"none"},onMouseDown:o,onClick:o,children:[(0,a.jsxs)("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:"8px"},children:[(0,a.jsx)("h3",{style:{margin:0,fontWeight:"bold",color:"#111827",fontSize:"18px",lineHeight:1.2},children:s.title}),(0,a.jsx)("button",{onClick:r=>{r.stopPropagation(),m()},style:{background:"none",border:"none",cursor:"pointer",padding:"4px",color:"#9ca3af"},children:(0,a.jsx)(_,{})})]}),(0,a.jsx)("p",{style:{margin:0,color:"#4b5563",fontSize:"14px",marginBottom:"24px",lineHeight:1.5},children:s.description}),(0,a.jsxs)("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between"},children:[(0,a.jsxs)("button",{onClick:r=>{r.stopPropagation(),y()},disabled:n,className:"onboard-button-ghost",style:{background:"none",border:"none",cursor:n?"not-allowed":"pointer",...e.style?.prev},children:[(0,a.jsx)(h,{}),"Prev"]}),p?(0,a.jsx)("button",{onClick:r=>{r.stopPropagation(),m()},className:"onboard-button-primary",style:{border:"none",cursor:"pointer",...e.style?.finish},children:"Finish"}):(0,a.jsxs)("button",{onClick:r=>{r.stopPropagation(),f()},className:"onboard-button-primary",style:{border:"none",cursor:"pointer",...n?e.style?.start:{},...n?{}:e.style?.next},children:[n&&e.style?.start?"Start":"Next",!(n&&e.style?.start)&&(0,a.jsx)(J,{})]})]})]})]});return typeof document<"u"?(0,X.createPortal)(K,document.body):null};var O=require("react/jsx-runtime"),q=(0,l.createContext)(void 0),Y="onboarding_state",rt=({config:e,ssr:s=!1,children:f})=>{let[y,m]=(0,l.useState)(!s),[n,p]=(0,l.useState)({currentStepIndex:0,currentSubStepIndex:null,isActive:!0}),d=l.default.useRef(e);(0,l.useEffect)(()=>{d.current=e},[e]);let v=(0,l.useCallback)(t=>{t&&(d.current.metadata.nextRouter,window.location.href=t)},[]);(0,l.useEffect)(()=>{s&&m(!0)},[s]);let H=(t,c)=>{if(t.urlMatch instanceof RegExp)return t.urlMatch.test(c);if(typeof t.urlMatch=="string"&&t.urlMatch.includes("*")){let i=t.urlMatch.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp(`^${i}$`).test(c)}return c===t.urlMatch};(0,l.useEffect)(()=>{let t=d.current,c=window.location.pathname,i=-1;t.metadata.inOrder===!1&&(i=t.steps.findIndex(o=>H(o,c)));let u=B.default.get(Y);if(u)try{let o=JSON.parse(u);if(t.metadata.inOrder===!1)i!==-1?o.currentStepIndex===i?p(o):p(h=>({...h,currentStepIndex:i,currentSubStepIndex:null,isActive:!0})):p(h=>({...o,isActive:!1}));else if(p(o),t.metadata.inOrder!==!1){let h=t.steps[o.currentStepIndex];h&&o.isActive&&typeof h.urlMatch=="string"&&window.location.pathname!==h.urlMatch&&v(h.urlMatch)}}catch(o){console.error("Failed to parse onboarding state from cookie",o),i!==-1&&p(h=>({...h,currentStepIndex:i,currentSubStepIndex:null,isActive:!0}))}else if(i!==-1)p(o=>({...o,currentStepIndex:i,currentSubStepIndex:null,isActive:!0}));else if(t.metadata.inOrder===!1)p(o=>({...o,isActive:!1}));else{let o=t.steps[0];o&&typeof o.urlMatch=="string"&&window.location.pathname!==o.urlMatch&&v(o.urlMatch)}},[v]),(0,l.useEffect)(()=>{y&&B.default.set(Y,JSON.stringify(n),{expires:365})},[n,y]);let D=(0,l.useMemo)(()=>{let t=e.steps[n.currentStepIndex];return t?n.currentSubStepIndex!==null&&t.subSteps&&t.subSteps[n.currentSubStepIndex]||t:null},[e.steps,n.currentStepIndex,n.currentSubStepIndex]),C=n.currentStepIndex===0&&n.currentSubStepIndex===null,A=(0,l.useMemo)(()=>{let t=e.steps.length,c=n.currentStepIndex===t-1,i=e.steps[n.currentStepIndex],u=i?.subSteps&&i.subSteps.length>0;return c?u?n.currentSubStepIndex===i.subSteps.length-1:!0:!1},[e.steps,n.currentStepIndex,n.currentSubStepIndex]),E=(0,l.useCallback)(()=>{let t=d.current,c=t.steps[n.currentStepIndex],i=n.currentSubStepIndex!==null&&c.subSteps?c.subSteps[n.currentSubStepIndex]:c;if(i.click){let u=document.querySelector(`[data-onboarding-id="${i.attribute}"]`);u&&u.click()}if(c.subSteps&&(n.currentSubStepIndex===null||n.currentSubStepIndex<c.subSteps.length-1)){let u=n.currentSubStepIndex===null?0:n.currentSubStepIndex+1,o=c.subSteps[u];p(h=>({...h,currentSubStepIndex:u})),o.navigate&&v(o.navigate);return}if(n.currentStepIndex<t.steps.length-1){let u=n.currentStepIndex+1,o=t.steps[u];p({currentStepIndex:u,currentSubStepIndex:null,isActive:!0}),o.navigate&&v(o.navigate)}else p(u=>({...u,isActive:!1})),t.onOnboardingComplete&&t.onOnboardingComplete()},[n.currentStepIndex,n.currentSubStepIndex,v]),R=(0,l.useCallback)(()=>{let t=d.current,c=t.steps[n.currentStepIndex];if(n.currentSubStepIndex!==null&&n.currentSubStepIndex>0){p(i=>({...i,currentSubStepIndex:i.currentSubStepIndex-1}));return}if(n.currentSubStepIndex===0){p(i=>({...i,currentSubStepIndex:null}));return}if(n.currentStepIndex>0){let i=n.currentStepIndex-1,u=t.steps[i],o=u.subSteps?u.subSteps.length-1:null;p({currentStepIndex:i,currentSubStepIndex:o,isActive:!0})}},[n.currentStepIndex,n.currentSubStepIndex]),w=(0,l.useCallback)(()=>{p(t=>({...t,isActive:!1})),d.current.onOnboardingComplete&&d.current.onOnboardingComplete()},[]),N=(0,l.useCallback)((t,c=null)=>{p({currentStepIndex:t,currentSubStepIndex:c,isActive:!0})},[]),I={config:e,state:n,nextStep:E,prevStep:R,finish:w,goToStep:N,currentStep:D,isFirstStep:C,isLastStep:A};return y?(0,O.jsxs)(q.Provider,{value:I,children:[f,n.isActive&&(0,O.jsx)(j,{})]}):(0,O.jsx)(O.Fragment,{children:f})},$=()=>{let e=(0,l.useContext)(q);if(e===void 0)throw new Error("useOnboarding must be used within an OnboardingProvider");return e};0&&(module.exports={OnboardingProvider,useOnboarding});
|
|
3
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/components/OnboardingProvider.tsx","../src/components/OnboardingOverlay.tsx"],"sourcesContent":["\"use client\";\n\nimport './styles.css';\nexport * from './components/OnboardingProvider';\nexport * from './types';\n","\"use client\";\n\nimport React, { createContext, useContext, useEffect, useState, useCallback, useMemo } from 'react';\nimport Cookies from 'js-cookie';\nimport { OnboardingConfig, OnboardingState, OnboardingStep, OnboardingSubStep } from '../types';\nimport { OnboardingOverlay } from './OnboardingOverlay';\n\ninterface OnboardingContextType {\n config: OnboardingConfig;\n state: OnboardingState;\n nextStep: () => void;\n prevStep: () => void;\n finish: () => void;\n goToStep: (stepIndex: number, subStepIndex?: number | null) => void;\n currentStep: OnboardingStep | OnboardingSubStep | null;\n isFirstStep: boolean;\n isLastStep: boolean;\n}\n\nconst OnboardingContext = createContext<OnboardingContextType | undefined>(undefined);\n\nconst COOKIE_NAME = 'onboarding_state';\n\nexport const OnboardingProvider: React.FC<{\n config: OnboardingConfig;\n ssr?: boolean;\n children: React.ReactNode;\n}> = ({ config, ssr = false, children }) => {\n const [isMounted, setIsMounted] = useState(!ssr);\n const [state, setState] = useState<OnboardingState>({\n currentStepIndex: 0,\n currentSubStepIndex: null,\n isActive: true,\n });\n\n // Stabilize config to prevent infinite loops if the user passes a new object on every render\n const configRef = React.useRef(config);\n useEffect(() => {\n configRef.current = config;\n }, [config]);\n\n const handleNavigation = useCallback((link?: string) => {\n if (!link) return;\n \n if (configRef.current.metadata.nextRouter) {\n window.location.href = link;\n } else {\n window.location.href = link;\n }\n }, []);\n\n useEffect(() => {\n if (ssr) {\n setIsMounted(true);\n }\n }, [ssr]);\n\n const isMatch = (step: OnboardingStep, path: string) => {\n if (step.urlMatch instanceof RegExp) return step.urlMatch.test(path);\n \n if (typeof step.urlMatch === 'string' && step.urlMatch.includes('*')) {\n // Escape regex special characters but keep '*' as '.*'\n const pattern = step.urlMatch\n .replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&') // Escape regex chars\n .replace(/\\*/g, '.*'); // Convert * to .*\n return new RegExp(`^${pattern}$`).test(path);\n }\n\n return path === step.urlMatch;\n };\n\n useEffect(() => {\n const currentConfig = configRef.current;\n const currentPath = window.location.pathname;\n let matchedStepIndex = -1;\n \n // Check if inOrder is explicitly false to find matching step from URL\n if ((currentConfig.metadata.inOrder as boolean | undefined) === false) {\n matchedStepIndex = currentConfig.steps.findIndex(step => isMatch(step, currentPath));\n }\n\n const savedState = Cookies.get(COOKIE_NAME);\n if (savedState) {\n try {\n const parsed: OnboardingState = JSON.parse(savedState);\n \n // If inOrder is false\n if ((currentConfig.metadata.inOrder as boolean | undefined) === false) {\n if (matchedStepIndex !== -1) {\n // We found a matching step for this URL\n if (parsed.currentStepIndex === matchedStepIndex) {\n // If it matches the saved step, restore state (keep substeps)\n setState(parsed);\n } else {\n // Different step, switch to it\n setState(prev => ({\n ...prev,\n currentStepIndex: matchedStepIndex,\n currentSubStepIndex: null,\n isActive: true\n }));\n }\n } else {\n // inOrder is false, and NO step matches this URL.\n // We should hide the onboarding, essentially \"pausing\" it until we return to a valid page.\n setState(prev => ({ ...parsed, isActive: false }));\n }\n } else {\n // Standard behavior (inOrder: true OR no match found) - restore saved state\n setState(parsed);\n\n // Only enforce navigation if inOrder is true (or default)\n if ((currentConfig.metadata.inOrder as boolean | undefined) !== false) {\n const step = currentConfig.steps[parsed.currentStepIndex];\n if (step && parsed.isActive) {\n // Always enforce location based on the main step's urlMatch\n if (typeof step.urlMatch === 'string' && window.location.pathname !== step.urlMatch) {\n handleNavigation(step.urlMatch);\n }\n }\n }\n }\n } catch (e) {\n console.error('Failed to parse onboarding state from cookie', e);\n // Fallback if cookie fails but we have a match\n if (matchedStepIndex !== -1) {\n setState(prev => ({\n ...prev,\n currentStepIndex: matchedStepIndex,\n currentSubStepIndex: null,\n isActive: true\n }));\n }\n }\n } else if (matchedStepIndex !== -1) {\n // No cookie, but we have a URL match\n setState(prev => ({\n ...prev,\n currentStepIndex: matchedStepIndex,\n currentSubStepIndex: null,\n isActive: true\n }));\n } else if ((currentConfig.metadata.inOrder as boolean | undefined) === false) {\n // No cookie, no match, and inOrder is false.\n // We are on a page that doesn't trigger any onboarding step.\n setState(prev => ({ ...prev, isActive: false }));\n } else {\n // No cookie, no match, inOrder is true (default).\n // Enforce navigation for the default first step if needed.\n const step = currentConfig.steps[0];\n if (step && typeof step.urlMatch === 'string' && window.location.pathname !== step.urlMatch) {\n handleNavigation(step.urlMatch);\n }\n }\n }, [handleNavigation]); // Removed config.steps dependency\n\n useEffect(() => {\n if (isMounted) {\n Cookies.set(COOKIE_NAME, JSON.stringify(state), { expires: 365 });\n }\n }, [state, isMounted]);\n\n const currentStep = useMemo(() => {\n const step = config.steps[state.currentStepIndex];\n if (!step) return null;\n if (state.currentSubStepIndex !== null && step.subSteps) {\n return step.subSteps[state.currentSubStepIndex] || step;\n }\n return step;\n }, [config.steps, state.currentStepIndex, state.currentSubStepIndex]);\n\n const isFirstStep = state.currentStepIndex === 0 && state.currentSubStepIndex === null;\n const isLastStep = useMemo(() => {\n const totalSteps = config.steps.length;\n const isLastMainStep = state.currentStepIndex === totalSteps - 1;\n const step = config.steps[state.currentStepIndex];\n const hasSubSteps = step?.subSteps && step.subSteps.length > 0;\n \n if (isLastMainStep) {\n if (hasSubSteps) {\n return state.currentSubStepIndex === (step.subSteps!.length - 1);\n }\n return true;\n }\n return false;\n }, [config.steps, state.currentStepIndex, state.currentSubStepIndex]);\n\n const nextStep = useCallback(() => {\n const currentConfig = configRef.current;\n const step = currentConfig.steps[state.currentStepIndex];\n const currentActiveStep = state.currentSubStepIndex !== null && step.subSteps \n ? step.subSteps[state.currentSubStepIndex] \n : step;\n\n // Perform click if requested for the current step before moving to the next\n if (currentActiveStep.click) {\n const element = document.querySelector(`[data-onboarding-id=\"${currentActiveStep.attribute}\"]`) as HTMLElement;\n if (element) {\n element.click();\n }\n }\n \n // Check for subSteps\n if (step.subSteps && (state.currentSubStepIndex === null || state.currentSubStepIndex < step.subSteps.length - 1)) {\n const nextSubIndex = state.currentSubStepIndex === null ? 0 : state.currentSubStepIndex + 1;\n const nextSubStep = step.subSteps[nextSubIndex];\n setState(prev => ({ ...prev, currentSubStepIndex: nextSubIndex }));\n \n if (nextSubStep.navigate) handleNavigation(nextSubStep.navigate);\n return;\n }\n\n // Move to next main step\n if (state.currentStepIndex < currentConfig.steps.length - 1) {\n const nextIndex = state.currentStepIndex + 1;\n const nextStepObj = currentConfig.steps[nextIndex];\n setState({\n currentStepIndex: nextIndex,\n currentSubStepIndex: null,\n isActive: true,\n });\n \n if (nextStepObj.navigate) handleNavigation(nextStepObj.navigate);\n } else {\n setState(prev => ({ ...prev, isActive: false }));\n if (currentConfig.onOnboardingComplete) {\n currentConfig.onOnboardingComplete();\n }\n }\n }, [state.currentStepIndex, state.currentSubStepIndex, handleNavigation]);\n\n const prevStep = useCallback(() => {\n const currentConfig = configRef.current;\n const step = currentConfig.steps[state.currentStepIndex];\n\n if (state.currentSubStepIndex !== null && state.currentSubStepIndex > 0) {\n setState(prev => ({ ...prev, currentSubStepIndex: prev.currentSubStepIndex! - 1 }));\n return;\n }\n\n if (state.currentSubStepIndex === 0) {\n setState(prev => ({ ...prev, currentSubStepIndex: null }));\n return;\n }\n\n if (state.currentStepIndex > 0) {\n const prevIndex = state.currentStepIndex - 1;\n const prevStepObj = currentConfig.steps[prevIndex];\n const prevSubStepIndex = prevStepObj.subSteps ? prevStepObj.subSteps.length - 1 : null;\n \n setState({\n currentStepIndex: prevIndex,\n currentSubStepIndex: prevSubStepIndex,\n isActive: true,\n });\n }\n }, [state.currentStepIndex, state.currentSubStepIndex]);\n\n const finish = useCallback(() => {\n setState(prev => ({ ...prev, isActive: false }));\n if (configRef.current.onOnboardingComplete) {\n configRef.current.onOnboardingComplete();\n }\n }, []);\n\n const goToStep = useCallback((stepIndex: number, subStepIndex: number | null = null) => {\n setState({\n currentStepIndex: stepIndex,\n currentSubStepIndex: subStepIndex,\n isActive: true,\n });\n }, []);\n\n const value = {\n config,\n state,\n nextStep,\n prevStep,\n finish,\n goToStep,\n currentStep,\n isFirstStep,\n isLastStep,\n };\n\n if (!isMounted) return <>{children}</>;\n\n return (\n <OnboardingContext.Provider value={value}>\n {children}\n {state.isActive && <OnboardingOverlay />}\n </OnboardingContext.Provider>\n );\n};\n\nexport const useOnboarding = () => {\n const context = useContext(OnboardingContext);\n if (context === undefined) {\n throw new Error('useOnboarding must be used within an OnboardingProvider');\n }\n return context;\n};","\"use client\";\n\nimport React, { useState, useEffect, useCallback, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useOnboarding } from './OnboardingProvider';\n\nexport const OnboardingOverlay: React.FC = () => {\n const { config, currentStep, nextStep, prevStep, finish, isFirstStep, isLastStep } = useOnboarding();\n const [coords, setCoords] = useState<{ top: number; left: number; width: number; height: number } | null>(null);\n const [position, setPosition] = useState<{ top: number; left: number }>({ top: 0, left: 0 });\n const [dragOffset, setDragOffset] = useState<{ x: number; y: number }>({ x: 0, y: 0 });\n const isDragging = useRef(false);\n const dragStart = useRef<{ x: number; y: number }>({ x: 0, y: 0 });\n const tooltipRef = useRef<HTMLDivElement>(null);\n\n // Reset drag offset when step changes\n useEffect(() => {\n setDragOffset({ x: 0, y: 0 });\n }, [currentStep]);\n\n const handlePointerDown = (e: React.PointerEvent) => {\n if (!config.metadata.draggable) return;\n e.stopPropagation(); // Prevent click-through\n e.preventDefault(); // Prevent text selection\n isDragging.current = true;\n dragStart.current = { x: e.clientX - dragOffset.x, y: e.clientY - dragOffset.y };\n \n // Disable transition during drag for responsiveness\n if (tooltipRef.current) {\n tooltipRef.current.style.transition = 'none';\n tooltipRef.current.style.cursor = 'grabbing';\n }\n\n window.addEventListener('pointermove', handlePointerMove);\n window.addEventListener('pointerup', handlePointerUp);\n };\n\n const handlePointerMove = useCallback((e: PointerEvent) => {\n if (!isDragging.current) return;\n \n const newX = e.clientX - dragStart.current.x;\n const newY = e.clientY - dragStart.current.y;\n \n setDragOffset({ x: newX, y: newY });\n }, []);\n\n const handlePointerUp = useCallback(() => {\n isDragging.current = false;\n \n // Re-enable transition\n if (tooltipRef.current) {\n tooltipRef.current.style.transition = 'top 0.3s cubic-bezier(0.25, 0.1, 0.25, 1), left 0.3s cubic-bezier(0.25, 0.1, 0.25, 1)';\n tooltipRef.current.style.cursor = config.metadata.draggable ? 'grab' : 'auto';\n }\n\n window.removeEventListener('pointermove', handlePointerMove);\n window.removeEventListener('pointerup', handlePointerUp);\n }, [config.metadata.draggable, handlePointerMove]);\n\n // Clean up listeners on unmount\n useEffect(() => {\n return () => {\n window.removeEventListener('pointermove', handlePointerMove);\n window.removeEventListener('pointerup', handlePointerUp);\n };\n }, [handlePointerMove, handlePointerUp]);\n\n const calculateBestPosition = useCallback((rect: { top: number; bottom: number; left: number; right: number; width: number; height: number }) => {\n const tooltipWidth = 300;\n const tooltipHeight = 200;\n const gap = 12;\n const padding = 20;\n\n const spaceAbove = rect.top;\n const spaceBelow = window.innerHeight - rect.bottom;\n const spaceLeft = rect.left;\n const spaceRight = window.innerWidth - rect.right;\n\n let top = 0;\n let left = 0;\n\n if (spaceBelow > tooltipHeight + gap + padding) {\n top = rect.bottom + gap;\n left = Math.max(padding, Math.min(window.innerWidth - tooltipWidth - padding, rect.left + rect.width / 2 - tooltipWidth / 2));\n } else if (spaceAbove > tooltipHeight + gap + padding) {\n top = rect.top - tooltipHeight - gap;\n left = Math.max(padding, Math.min(window.innerWidth - tooltipWidth - padding, rect.left + rect.width / 2 - tooltipWidth / 2));\n } else if (spaceRight > tooltipWidth + gap + padding) {\n top = Math.max(padding, Math.min(window.innerHeight - tooltipHeight - padding, rect.top + rect.height / 2 - tooltipHeight / 2));\n left = rect.right + gap;\n } else if (spaceLeft > tooltipWidth + gap + padding) {\n top = Math.max(padding, Math.min(window.innerHeight - tooltipHeight - padding, rect.top + rect.height / 2 - tooltipHeight / 2));\n left = rect.left - tooltipWidth - gap;\n } else {\n top = window.innerHeight / 2 - tooltipHeight / 2;\n left = window.innerWidth / 2 - tooltipWidth / 2;\n }\n\n return { top: top + window.scrollY, left: left + window.scrollX };\n }, []);\n\n const updateCoords = useCallback(() => {\n if (!currentStep) return;\n\n const element = document.querySelector(`[data-onboarding-id=\"${currentStep.attribute}\"]`) as HTMLElement;\n if (element) {\n const rect = element.getBoundingClientRect();\n const padding = config.style?.padding || 0;\n \n const paddedRect = {\n top: rect.top - padding,\n bottom: rect.bottom + padding,\n left: rect.left - padding,\n right: rect.right + padding,\n width: rect.width + (padding * 2),\n height: rect.height + (padding * 2),\n };\n\n const newCoords = {\n top: paddedRect.top + window.scrollY,\n left: paddedRect.left + window.scrollX,\n width: paddedRect.width,\n height: paddedRect.height,\n };\n\n const newPosition = calculateBestPosition(paddedRect);\n\n // Prevent infinite loops by only updating if values actually changed\n setCoords(prev => {\n if (prev && \n prev.top === newCoords.top && \n prev.left === newCoords.left && \n prev.width === newCoords.width && \n prev.height === newCoords.height) {\n return prev;\n }\n return newCoords;\n });\n\n setPosition(prev => {\n if (prev.top === newPosition.top && prev.left === newPosition.left) {\n return prev;\n }\n return newPosition;\n });\n } else {\n setCoords(null);\n }\n }, [currentStep, calculateBestPosition, config.style]);\n\n useEffect(() => {\n updateCoords();\n window.addEventListener('resize', updateCoords);\n window.addEventListener('scroll', updateCoords);\n\n const observer = new MutationObserver(updateCoords);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true });\n\n let resizeObserver: ResizeObserver | null = null;\n if (typeof ResizeObserver !== 'undefined') {\n resizeObserver = new ResizeObserver(updateCoords);\n resizeObserver.observe(document.body);\n \n const element = currentStep?.attribute \n ? document.querySelector(`[data-onboarding-id=\"${currentStep.attribute}\"]`) \n : null;\n if (element) {\n resizeObserver.observe(element);\n }\n }\n\n return () => {\n window.removeEventListener('resize', updateCoords);\n window.removeEventListener('scroll', updateCoords);\n observer.disconnect();\n if (resizeObserver) resizeObserver.disconnect();\n };\n }, [updateCoords, currentStep?.attribute]);\n\n if (!currentStep || !coords) return null;\n\n const maskStyle = {\n ...config.style?.background,\n transition: 'all 0.3s cubic-bezier(0.25, 0.1, 0.25, 1)',\n };\n\n const stopPropagation = (e: React.PointerEvent | React.MouseEvent) => {\n e.stopPropagation();\n };\n\n const ChevronLeftIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M15 18l-6-6 6-6\" />\n </svg>\n );\n\n const ChevronRightIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M9 18l6-6-6-6\" />\n </svg>\n );\n\n const XIcon = () => (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n\n const overlayContent = (\n <div className=\"fixed inset-0 z-[999999] pointer-events-none\">\n {/* Top Mask */}\n <div\n style={{ height: coords.top, ...maskStyle }}\n className=\"onboard-overlay-mask top-0 left-0 w-full pointer-events-auto\"\n onPointerDown={stopPropagation}\n onMouseDown={stopPropagation}\n onClick={stopPropagation}\n />\n {/* Bottom Mask */}\n <div\n style={{ top: coords.top + coords.height, height: `calc(100vh - ${coords.top + coords.height}px)`, ...maskStyle }}\n className=\"onboard-overlay-mask left-0 w-full pointer-events-auto\"\n onPointerDown={stopPropagation}\n onMouseDown={stopPropagation}\n onClick={stopPropagation}\n />\n {/* Left Mask */}\n <div\n style={{ top: coords.top, height: coords.height, width: coords.left, ...maskStyle }}\n className=\"onboard-overlay-mask left-0 pointer-events-auto\"\n onPointerDown={stopPropagation}\n onMouseDown={stopPropagation}\n onClick={stopPropagation}\n />\n {/* Right Mask */}\n <div\n style={{ \n top: coords.top, \n height: coords.height, \n left: coords.left + coords.width, \n width: `calc(100% - ${coords.left + coords.width}px)`, \n ...maskStyle \n }}\n className=\"onboard-overlay-mask pointer-events-auto\"\n onPointerDown={stopPropagation}\n onMouseDown={stopPropagation}\n onClick={stopPropagation}\n />\n\n {/* Tooltip */}\n <div\n ref={tooltipRef}\n className=\"onboard-tooltip pointer-events-auto\"\n onPointerDown={handlePointerDown}\n style={{ \n zIndex: 1000000, \n ...config.style?.container,\n top: position.top + dragOffset.y,\n left: position.left + dragOffset.x,\n transition: 'top 0.3s cubic-bezier(0.25, 0.1, 0.25, 1), left 0.3s cubic-bezier(0.25, 0.1, 0.25, 1)',\n cursor: config.metadata.draggable ? 'grab' : 'auto',\n touchAction: 'none' // Prevent scrolling on touch devices while dragging\n }}\n onMouseDown={stopPropagation}\n onClick={stopPropagation}\n >\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: '8px' }}>\n <h3 style={{ margin: 0, fontWeight: 'bold', color: '#111827', fontSize: '18px', lineHeight: 1.2 }}>{currentStep.title}</h3>\n <button \n onClick={(e) => { e.stopPropagation(); finish(); }}\n style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '4px', color: '#9ca3af' }}\n >\n <XIcon />\n </button>\n </div>\n <p style={{ margin: 0, color: '#4b5563', fontSize: '14px', marginBottom: '24px', lineHeight: 1.5 }}>\n {currentStep.description}\n </p>\n \n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n <button\n onClick={(e) => { e.stopPropagation(); prevStep(); }}\n disabled={isFirstStep}\n className=\"onboard-button-ghost\"\n style={{ \n background: 'none', \n border: 'none', \n cursor: isFirstStep ? 'not-allowed' : 'pointer',\n ...config.style?.prev \n }}\n >\n <ChevronLeftIcon />\n Prev\n </button>\n \n {isLastStep ? (\n <button\n onClick={(e) => { e.stopPropagation(); finish(); }}\n className=\"onboard-button-primary\"\n style={{ border: 'none', cursor: 'pointer', ...config.style?.finish }}\n >\n Finish\n </button>\n ) : (\n <button\n onClick={(e) => { e.stopPropagation(); nextStep(); }}\n className=\"onboard-button-primary\"\n style={{ \n border: 'none', \n cursor: 'pointer',\n ...(isFirstStep ? config.style?.start : {}),\n ...(!isFirstStep ? config.style?.next : {})\n }}\n >\n {isFirstStep && config.style?.start ? 'Start' : 'Next'}\n {!(isFirstStep && config.style?.start) && <ChevronRightIcon />}\n </button>\n )}\n </div>\n </div>\n </div>\n );\n\n return typeof document !== 'undefined' \n ? createPortal(overlayContent, document.body) \n : null;\n};\n"],"mappings":"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","names":["index_exports","__export","OnboardingProvider","useOnboarding","__toCommonJS","import_react","import_js_cookie","import_react","import_react_dom","import_jsx_runtime","OnboardingOverlay","config","currentStep","nextStep","prevStep","finish","isFirstStep","isLastStep","useOnboarding","coords","setCoords","position","setPosition","dragOffset","setDragOffset","isDragging","dragStart","tooltipRef","handlePointerDown","e","handlePointerMove","handlePointerUp","newX","newY","calculateBestPosition","rect","spaceAbove","spaceBelow","spaceLeft","spaceRight","top","left","updateCoords","element","padding","paddedRect","newCoords","newPosition","prev","observer","resizeObserver","maskStyle","stopPropagation","ChevronLeftIcon","ChevronRightIcon","XIcon","overlayContent","import_jsx_runtime","OnboardingContext","COOKIE_NAME","OnboardingProvider","config","ssr","children","isMounted","setIsMounted","state","setState","configRef","React","handleNavigation","link","isMatch","step","path","pattern","currentConfig","currentPath","matchedStepIndex","savedState","Cookies","parsed","prev","e","currentStep","isFirstStep","isLastStep","totalSteps","isLastMainStep","hasSubSteps","nextStep","currentActiveStep","element","nextSubIndex","nextSubStep","nextIndex","nextStepObj","prevStep","prevIndex","prevStepObj","prevSubStepIndex","finish","goToStep","stepIndex","subStepIndex","value","OnboardingOverlay","useOnboarding","context"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";import et,{createContext as nt,useContext as ot,useEffect as W,useState as j,useCallback as L,useMemo as Y}from"react";import q from"js-cookie";import{useState as $,useEffect as B,useCallback as A,useRef as F}from"react";import{createPortal as tt}from"react-dom";import{jsx as l,jsxs as m}from"react/jsx-runtime";var T=()=>{let{config:i,currentStep:p,nextStep:E,prevStep:C,finish:R,isFirstStep:e,isLastStep:u}=X(),[s,h]=$(null),[z,D]=$({top:0,left:0}),[v,H]=$({x:0,y:0}),k=F(!1),M=F({x:0,y:0}),S=F(null);B(()=>{H({x:0,y:0})},[p]);let N=o=>{i.metadata.draggable&&(o.stopPropagation(),o.preventDefault(),k.current=!0,M.current={x:o.clientX-v.x,y:o.clientY-v.y},S.current&&(S.current.style.transition="none",S.current.style.cursor="grabbing"),window.addEventListener("pointermove",x),window.addEventListener("pointerup",t))},x=A(o=>{if(!k.current)return;let c=o.clientX-M.current.x,g=o.clientY-M.current.y;H({x:c,y:g})},[]),t=A(()=>{k.current=!1,S.current&&(S.current.style.transition="top 0.3s cubic-bezier(0.25, 0.1, 0.25, 1), left 0.3s cubic-bezier(0.25, 0.1, 0.25, 1)",S.current.style.cursor=i.metadata.draggable?"grab":"auto"),window.removeEventListener("pointermove",x),window.removeEventListener("pointerup",t)},[i.metadata.draggable,x]);B(()=>()=>{window.removeEventListener("pointermove",x),window.removeEventListener("pointerup",t)},[x,t]);let d=A(o=>{let P=o.top,f=window.innerHeight-o.bottom,V=o.left,Z=window.innerWidth-o.right,I=0,O=0;return f>232?(I=o.bottom+12,O=Math.max(20,Math.min(window.innerWidth-300-20,o.left+o.width/2-300/2))):P>232?(I=o.top-200-12,O=Math.max(20,Math.min(window.innerWidth-300-20,o.left+o.width/2-300/2))):Z>332?(I=Math.max(20,Math.min(window.innerHeight-200-20,o.top+o.height/2-200/2)),O=o.right+12):V>332?(I=Math.max(20,Math.min(window.innerHeight-200-20,o.top+o.height/2-200/2)),O=o.left-300-12):(I=window.innerHeight/2-200/2,O=window.innerWidth/2-300/2),{top:I+window.scrollY,left:O+window.scrollX}},[]),r=A(()=>{if(!p)return;let o=document.querySelector(`[data-onboarding-id="${p.attribute}"]`);if(o){let c=o.getBoundingClientRect(),g=i.style?.padding||0,w={top:c.top-g,bottom:c.bottom+g,left:c.left-g,right:c.right+g,width:c.width+g*2,height:c.height+g*2},y={top:w.top+window.scrollY,left:w.left+window.scrollX,width:w.width,height:w.height},P=d(w);h(f=>f&&f.top===y.top&&f.left===y.left&&f.width===y.width&&f.height===y.height?f:y),D(f=>f.top===P.top&&f.left===P.left?f:P)}else h(null)},[p,d,i.style]);if(B(()=>{r(),window.addEventListener("resize",r),window.addEventListener("scroll",r);let o=new MutationObserver(r);o.observe(document.body,{childList:!0,subtree:!0,attributes:!0});let c=null;if(typeof ResizeObserver<"u"){c=new ResizeObserver(r),c.observe(document.body);let g=p?.attribute?document.querySelector(`[data-onboarding-id="${p.attribute}"]`):null;g&&c.observe(g)}return()=>{window.removeEventListener("resize",r),window.removeEventListener("scroll",r),o.disconnect(),c&&c.disconnect()}},[r,p?.attribute]),!p||!s)return null;let a={...i.style?.background,transition:"all 0.3s cubic-bezier(0.25, 0.1, 0.25, 1)"},n=o=>{o.stopPropagation()},b=()=>l("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:l("path",{d:"M15 18l-6-6 6-6"})}),U=()=>l("svg",{width:"16",height:"16",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:l("path",{d:"M9 18l6-6-6-6"})}),G=()=>m("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:[l("line",{x1:"18",y1:"6",x2:"6",y2:"18"}),l("line",{x1:"6",y1:"6",x2:"18",y2:"18"})]}),Q=m("div",{className:"fixed inset-0 z-[999999] pointer-events-none",children:[l("div",{style:{height:s.top,...a},className:"onboard-overlay-mask top-0 left-0 w-full pointer-events-auto",onPointerDown:n,onMouseDown:n,onClick:n}),l("div",{style:{top:s.top+s.height,height:`calc(100vh - ${s.top+s.height}px)`,...a},className:"onboard-overlay-mask left-0 w-full pointer-events-auto",onPointerDown:n,onMouseDown:n,onClick:n}),l("div",{style:{top:s.top,height:s.height,width:s.left,...a},className:"onboard-overlay-mask left-0 pointer-events-auto",onPointerDown:n,onMouseDown:n,onClick:n}),l("div",{style:{top:s.top,height:s.height,left:s.left+s.width,width:`calc(100% - ${s.left+s.width}px)`,...a},className:"onboard-overlay-mask pointer-events-auto",onPointerDown:n,onMouseDown:n,onClick:n}),m("div",{ref:S,className:"onboard-tooltip pointer-events-auto",onPointerDown:N,style:{zIndex:1e6,...i.style?.container,top:z.top+v.y,left:z.left+v.x,transition:"top 0.3s cubic-bezier(0.25, 0.1, 0.25, 1), left 0.3s cubic-bezier(0.25, 0.1, 0.25, 1)",cursor:i.metadata.draggable?"grab":"auto",touchAction:"none"},onMouseDown:n,onClick:n,children:[m("div",{style:{display:"flex",justifyContent:"space-between",alignItems:"flex-start",marginBottom:"8px"},children:[l("h3",{style:{margin:0,fontWeight:"bold",color:"#111827",fontSize:"18px",lineHeight:1.2},children:p.title}),l("button",{onClick:o=>{o.stopPropagation(),R()},style:{background:"none",border:"none",cursor:"pointer",padding:"4px",color:"#9ca3af"},children:l(G,{})})]}),l("p",{style:{margin:0,color:"#4b5563",fontSize:"14px",marginBottom:"24px",lineHeight:1.5},children:p.description}),m("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between"},children:[m("button",{onClick:o=>{o.stopPropagation(),C()},disabled:e,className:"onboard-button-ghost",style:{background:"none",border:"none",cursor:e?"not-allowed":"pointer",...i.style?.prev},children:[l(b,{}),"Prev"]}),u?l("button",{onClick:o=>{o.stopPropagation(),R()},className:"onboard-button-primary",style:{border:"none",cursor:"pointer",...i.style?.finish},children:"Finish"}):m("button",{onClick:o=>{o.stopPropagation(),E()},className:"onboard-button-primary",style:{border:"none",cursor:"pointer",...e?i.style?.start:{},...e?{}:i.style?.next},children:[e&&i.style?.start?"Start":"Next",!(e&&i.style?.start)&&l(U,{})]})]})]})]});return typeof document<"u"?tt(Q,document.body):null};import{Fragment as rt,jsx as _,jsxs as it}from"react/jsx-runtime";var K=nt(void 0),J="onboarding_state",St=({config:i,ssr:p=!1,children:E})=>{let[C,R]=j(!p),[e,u]=j({currentStepIndex:0,currentSubStepIndex:null,isActive:!0}),s=et.useRef(i);W(()=>{s.current=i},[i]);let h=L(t=>{t&&(s.current.metadata.nextRouter,window.location.href=t)},[]);W(()=>{p&&R(!0)},[p]);let z=(t,d)=>{if(t.urlMatch instanceof RegExp)return t.urlMatch.test(d);if(typeof t.urlMatch=="string"&&t.urlMatch.includes("*")){let r=t.urlMatch.replace(/[.+?^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*");return new RegExp(`^${r}$`).test(d)}return d===t.urlMatch};W(()=>{let t=s.current,d=window.location.pathname,r=-1;t.metadata.inOrder===!1&&(r=t.steps.findIndex(n=>z(n,d)));let a=q.get(J);if(a)try{let n=JSON.parse(a);if(t.metadata.inOrder===!1)r!==-1?n.currentStepIndex===r?u(n):u(b=>({...b,currentStepIndex:r,currentSubStepIndex:null,isActive:!0})):u(b=>({...n,isActive:!1}));else if(u(n),t.metadata.inOrder!==!1){let b=t.steps[n.currentStepIndex];b&&n.isActive&&typeof b.urlMatch=="string"&&window.location.pathname!==b.urlMatch&&h(b.urlMatch)}}catch(n){console.error("Failed to parse onboarding state from cookie",n),r!==-1&&u(b=>({...b,currentStepIndex:r,currentSubStepIndex:null,isActive:!0}))}else if(r!==-1)u(n=>({...n,currentStepIndex:r,currentSubStepIndex:null,isActive:!0}));else if(t.metadata.inOrder===!1)u(n=>({...n,isActive:!1}));else{let n=t.steps[0];n&&typeof n.urlMatch=="string"&&window.location.pathname!==n.urlMatch&&h(n.urlMatch)}},[h]),W(()=>{C&&q.set(J,JSON.stringify(e),{expires:365})},[e,C]);let D=Y(()=>{let t=i.steps[e.currentStepIndex];return t?e.currentSubStepIndex!==null&&t.subSteps&&t.subSteps[e.currentSubStepIndex]||t:null},[i.steps,e.currentStepIndex,e.currentSubStepIndex]),v=e.currentStepIndex===0&&e.currentSubStepIndex===null,H=Y(()=>{let t=i.steps.length,d=e.currentStepIndex===t-1,r=i.steps[e.currentStepIndex],a=r?.subSteps&&r.subSteps.length>0;return d?a?e.currentSubStepIndex===r.subSteps.length-1:!0:!1},[i.steps,e.currentStepIndex,e.currentSubStepIndex]),k=L(()=>{let t=s.current,d=t.steps[e.currentStepIndex],r=e.currentSubStepIndex!==null&&d.subSteps?d.subSteps[e.currentSubStepIndex]:d;if(r.click){let a=document.querySelector(`[data-onboarding-id="${r.attribute}"]`);a&&a.click()}if(d.subSteps&&(e.currentSubStepIndex===null||e.currentSubStepIndex<d.subSteps.length-1)){let a=e.currentSubStepIndex===null?0:e.currentSubStepIndex+1,n=d.subSteps[a];u(b=>({...b,currentSubStepIndex:a})),n.navigate&&h(n.navigate);return}if(e.currentStepIndex<t.steps.length-1){let a=e.currentStepIndex+1,n=t.steps[a];u({currentStepIndex:a,currentSubStepIndex:null,isActive:!0}),n.navigate&&h(n.navigate)}else u(a=>({...a,isActive:!1})),t.onOnboardingComplete&&t.onOnboardingComplete()},[e.currentStepIndex,e.currentSubStepIndex,h]),M=L(()=>{let t=s.current,d=t.steps[e.currentStepIndex];if(e.currentSubStepIndex!==null&&e.currentSubStepIndex>0){u(r=>({...r,currentSubStepIndex:r.currentSubStepIndex-1}));return}if(e.currentSubStepIndex===0){u(r=>({...r,currentSubStepIndex:null}));return}if(e.currentStepIndex>0){let r=e.currentStepIndex-1,a=t.steps[r],n=a.subSteps?a.subSteps.length-1:null;u({currentStepIndex:r,currentSubStepIndex:n,isActive:!0})}},[e.currentStepIndex,e.currentSubStepIndex]),S=L(()=>{u(t=>({...t,isActive:!1})),s.current.onOnboardingComplete&&s.current.onOnboardingComplete()},[]),N=L((t,d=null)=>{u({currentStepIndex:t,currentSubStepIndex:d,isActive:!0})},[]),x={config:i,state:e,nextStep:k,prevStep:M,finish:S,goToStep:N,currentStep:D,isFirstStep:v,isLastStep:H};return C?it(K.Provider,{value:x,children:[E,e.isActive&&_(T,{})]}):_(rt,{children:E})},X=()=>{let i=ot(K);if(i===void 0)throw new Error("useOnboarding must be used within an OnboardingProvider");return i};export{St as OnboardingProvider,X as useOnboarding};
|
|
3
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/OnboardingProvider.tsx","../src/components/OnboardingOverlay.tsx"],"sourcesContent":["\"use client\";\n\nimport React, { createContext, useContext, useEffect, useState, useCallback, useMemo } from 'react';\nimport Cookies from 'js-cookie';\nimport { OnboardingConfig, OnboardingState, OnboardingStep, OnboardingSubStep } from '../types';\nimport { OnboardingOverlay } from './OnboardingOverlay';\n\ninterface OnboardingContextType {\n config: OnboardingConfig;\n state: OnboardingState;\n nextStep: () => void;\n prevStep: () => void;\n finish: () => void;\n goToStep: (stepIndex: number, subStepIndex?: number | null) => void;\n currentStep: OnboardingStep | OnboardingSubStep | null;\n isFirstStep: boolean;\n isLastStep: boolean;\n}\n\nconst OnboardingContext = createContext<OnboardingContextType | undefined>(undefined);\n\nconst COOKIE_NAME = 'onboarding_state';\n\nexport const OnboardingProvider: React.FC<{\n config: OnboardingConfig;\n ssr?: boolean;\n children: React.ReactNode;\n}> = ({ config, ssr = false, children }) => {\n const [isMounted, setIsMounted] = useState(!ssr);\n const [state, setState] = useState<OnboardingState>({\n currentStepIndex: 0,\n currentSubStepIndex: null,\n isActive: true,\n });\n\n // Stabilize config to prevent infinite loops if the user passes a new object on every render\n const configRef = React.useRef(config);\n useEffect(() => {\n configRef.current = config;\n }, [config]);\n\n const handleNavigation = useCallback((link?: string) => {\n if (!link) return;\n \n if (configRef.current.metadata.nextRouter) {\n window.location.href = link;\n } else {\n window.location.href = link;\n }\n }, []);\n\n useEffect(() => {\n if (ssr) {\n setIsMounted(true);\n }\n }, [ssr]);\n\n const isMatch = (step: OnboardingStep, path: string) => {\n if (step.urlMatch instanceof RegExp) return step.urlMatch.test(path);\n \n if (typeof step.urlMatch === 'string' && step.urlMatch.includes('*')) {\n // Escape regex special characters but keep '*' as '.*'\n const pattern = step.urlMatch\n .replace(/[.+?^${}()|[\\]\\\\]/g, '\\\\$&') // Escape regex chars\n .replace(/\\*/g, '.*'); // Convert * to .*\n return new RegExp(`^${pattern}$`).test(path);\n }\n\n return path === step.urlMatch;\n };\n\n useEffect(() => {\n const currentConfig = configRef.current;\n const currentPath = window.location.pathname;\n let matchedStepIndex = -1;\n \n // Check if inOrder is explicitly false to find matching step from URL\n if ((currentConfig.metadata.inOrder as boolean | undefined) === false) {\n matchedStepIndex = currentConfig.steps.findIndex(step => isMatch(step, currentPath));\n }\n\n const savedState = Cookies.get(COOKIE_NAME);\n if (savedState) {\n try {\n const parsed: OnboardingState = JSON.parse(savedState);\n \n // If inOrder is false\n if ((currentConfig.metadata.inOrder as boolean | undefined) === false) {\n if (matchedStepIndex !== -1) {\n // We found a matching step for this URL\n if (parsed.currentStepIndex === matchedStepIndex) {\n // If it matches the saved step, restore state (keep substeps)\n setState(parsed);\n } else {\n // Different step, switch to it\n setState(prev => ({\n ...prev,\n currentStepIndex: matchedStepIndex,\n currentSubStepIndex: null,\n isActive: true\n }));\n }\n } else {\n // inOrder is false, and NO step matches this URL.\n // We should hide the onboarding, essentially \"pausing\" it until we return to a valid page.\n setState(prev => ({ ...parsed, isActive: false }));\n }\n } else {\n // Standard behavior (inOrder: true OR no match found) - restore saved state\n setState(parsed);\n\n // Only enforce navigation if inOrder is true (or default)\n if ((currentConfig.metadata.inOrder as boolean | undefined) !== false) {\n const step = currentConfig.steps[parsed.currentStepIndex];\n if (step && parsed.isActive) {\n // Always enforce location based on the main step's urlMatch\n if (typeof step.urlMatch === 'string' && window.location.pathname !== step.urlMatch) {\n handleNavigation(step.urlMatch);\n }\n }\n }\n }\n } catch (e) {\n console.error('Failed to parse onboarding state from cookie', e);\n // Fallback if cookie fails but we have a match\n if (matchedStepIndex !== -1) {\n setState(prev => ({\n ...prev,\n currentStepIndex: matchedStepIndex,\n currentSubStepIndex: null,\n isActive: true\n }));\n }\n }\n } else if (matchedStepIndex !== -1) {\n // No cookie, but we have a URL match\n setState(prev => ({\n ...prev,\n currentStepIndex: matchedStepIndex,\n currentSubStepIndex: null,\n isActive: true\n }));\n } else if ((currentConfig.metadata.inOrder as boolean | undefined) === false) {\n // No cookie, no match, and inOrder is false.\n // We are on a page that doesn't trigger any onboarding step.\n setState(prev => ({ ...prev, isActive: false }));\n } else {\n // No cookie, no match, inOrder is true (default).\n // Enforce navigation for the default first step if needed.\n const step = currentConfig.steps[0];\n if (step && typeof step.urlMatch === 'string' && window.location.pathname !== step.urlMatch) {\n handleNavigation(step.urlMatch);\n }\n }\n }, [handleNavigation]); // Removed config.steps dependency\n\n useEffect(() => {\n if (isMounted) {\n Cookies.set(COOKIE_NAME, JSON.stringify(state), { expires: 365 });\n }\n }, [state, isMounted]);\n\n const currentStep = useMemo(() => {\n const step = config.steps[state.currentStepIndex];\n if (!step) return null;\n if (state.currentSubStepIndex !== null && step.subSteps) {\n return step.subSteps[state.currentSubStepIndex] || step;\n }\n return step;\n }, [config.steps, state.currentStepIndex, state.currentSubStepIndex]);\n\n const isFirstStep = state.currentStepIndex === 0 && state.currentSubStepIndex === null;\n const isLastStep = useMemo(() => {\n const totalSteps = config.steps.length;\n const isLastMainStep = state.currentStepIndex === totalSteps - 1;\n const step = config.steps[state.currentStepIndex];\n const hasSubSteps = step?.subSteps && step.subSteps.length > 0;\n \n if (isLastMainStep) {\n if (hasSubSteps) {\n return state.currentSubStepIndex === (step.subSteps!.length - 1);\n }\n return true;\n }\n return false;\n }, [config.steps, state.currentStepIndex, state.currentSubStepIndex]);\n\n const nextStep = useCallback(() => {\n const currentConfig = configRef.current;\n const step = currentConfig.steps[state.currentStepIndex];\n const currentActiveStep = state.currentSubStepIndex !== null && step.subSteps \n ? step.subSteps[state.currentSubStepIndex] \n : step;\n\n // Perform click if requested for the current step before moving to the next\n if (currentActiveStep.click) {\n const element = document.querySelector(`[data-onboarding-id=\"${currentActiveStep.attribute}\"]`) as HTMLElement;\n if (element) {\n element.click();\n }\n }\n \n // Check for subSteps\n if (step.subSteps && (state.currentSubStepIndex === null || state.currentSubStepIndex < step.subSteps.length - 1)) {\n const nextSubIndex = state.currentSubStepIndex === null ? 0 : state.currentSubStepIndex + 1;\n const nextSubStep = step.subSteps[nextSubIndex];\n setState(prev => ({ ...prev, currentSubStepIndex: nextSubIndex }));\n \n if (nextSubStep.navigate) handleNavigation(nextSubStep.navigate);\n return;\n }\n\n // Move to next main step\n if (state.currentStepIndex < currentConfig.steps.length - 1) {\n const nextIndex = state.currentStepIndex + 1;\n const nextStepObj = currentConfig.steps[nextIndex];\n setState({\n currentStepIndex: nextIndex,\n currentSubStepIndex: null,\n isActive: true,\n });\n \n if (nextStepObj.navigate) handleNavigation(nextStepObj.navigate);\n } else {\n setState(prev => ({ ...prev, isActive: false }));\n if (currentConfig.onOnboardingComplete) {\n currentConfig.onOnboardingComplete();\n }\n }\n }, [state.currentStepIndex, state.currentSubStepIndex, handleNavigation]);\n\n const prevStep = useCallback(() => {\n const currentConfig = configRef.current;\n const step = currentConfig.steps[state.currentStepIndex];\n\n if (state.currentSubStepIndex !== null && state.currentSubStepIndex > 0) {\n setState(prev => ({ ...prev, currentSubStepIndex: prev.currentSubStepIndex! - 1 }));\n return;\n }\n\n if (state.currentSubStepIndex === 0) {\n setState(prev => ({ ...prev, currentSubStepIndex: null }));\n return;\n }\n\n if (state.currentStepIndex > 0) {\n const prevIndex = state.currentStepIndex - 1;\n const prevStepObj = currentConfig.steps[prevIndex];\n const prevSubStepIndex = prevStepObj.subSteps ? prevStepObj.subSteps.length - 1 : null;\n \n setState({\n currentStepIndex: prevIndex,\n currentSubStepIndex: prevSubStepIndex,\n isActive: true,\n });\n }\n }, [state.currentStepIndex, state.currentSubStepIndex]);\n\n const finish = useCallback(() => {\n setState(prev => ({ ...prev, isActive: false }));\n if (configRef.current.onOnboardingComplete) {\n configRef.current.onOnboardingComplete();\n }\n }, []);\n\n const goToStep = useCallback((stepIndex: number, subStepIndex: number | null = null) => {\n setState({\n currentStepIndex: stepIndex,\n currentSubStepIndex: subStepIndex,\n isActive: true,\n });\n }, []);\n\n const value = {\n config,\n state,\n nextStep,\n prevStep,\n finish,\n goToStep,\n currentStep,\n isFirstStep,\n isLastStep,\n };\n\n if (!isMounted) return <>{children}</>;\n\n return (\n <OnboardingContext.Provider value={value}>\n {children}\n {state.isActive && <OnboardingOverlay />}\n </OnboardingContext.Provider>\n );\n};\n\nexport const useOnboarding = () => {\n const context = useContext(OnboardingContext);\n if (context === undefined) {\n throw new Error('useOnboarding must be used within an OnboardingProvider');\n }\n return context;\n};","\"use client\";\n\nimport React, { useState, useEffect, useCallback, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { useOnboarding } from './OnboardingProvider';\n\nexport const OnboardingOverlay: React.FC = () => {\n const { config, currentStep, nextStep, prevStep, finish, isFirstStep, isLastStep } = useOnboarding();\n const [coords, setCoords] = useState<{ top: number; left: number; width: number; height: number } | null>(null);\n const [position, setPosition] = useState<{ top: number; left: number }>({ top: 0, left: 0 });\n const [dragOffset, setDragOffset] = useState<{ x: number; y: number }>({ x: 0, y: 0 });\n const isDragging = useRef(false);\n const dragStart = useRef<{ x: number; y: number }>({ x: 0, y: 0 });\n const tooltipRef = useRef<HTMLDivElement>(null);\n\n // Reset drag offset when step changes\n useEffect(() => {\n setDragOffset({ x: 0, y: 0 });\n }, [currentStep]);\n\n const handlePointerDown = (e: React.PointerEvent) => {\n if (!config.metadata.draggable) return;\n e.stopPropagation(); // Prevent click-through\n e.preventDefault(); // Prevent text selection\n isDragging.current = true;\n dragStart.current = { x: e.clientX - dragOffset.x, y: e.clientY - dragOffset.y };\n \n // Disable transition during drag for responsiveness\n if (tooltipRef.current) {\n tooltipRef.current.style.transition = 'none';\n tooltipRef.current.style.cursor = 'grabbing';\n }\n\n window.addEventListener('pointermove', handlePointerMove);\n window.addEventListener('pointerup', handlePointerUp);\n };\n\n const handlePointerMove = useCallback((e: PointerEvent) => {\n if (!isDragging.current) return;\n \n const newX = e.clientX - dragStart.current.x;\n const newY = e.clientY - dragStart.current.y;\n \n setDragOffset({ x: newX, y: newY });\n }, []);\n\n const handlePointerUp = useCallback(() => {\n isDragging.current = false;\n \n // Re-enable transition\n if (tooltipRef.current) {\n tooltipRef.current.style.transition = 'top 0.3s cubic-bezier(0.25, 0.1, 0.25, 1), left 0.3s cubic-bezier(0.25, 0.1, 0.25, 1)';\n tooltipRef.current.style.cursor = config.metadata.draggable ? 'grab' : 'auto';\n }\n\n window.removeEventListener('pointermove', handlePointerMove);\n window.removeEventListener('pointerup', handlePointerUp);\n }, [config.metadata.draggable, handlePointerMove]);\n\n // Clean up listeners on unmount\n useEffect(() => {\n return () => {\n window.removeEventListener('pointermove', handlePointerMove);\n window.removeEventListener('pointerup', handlePointerUp);\n };\n }, [handlePointerMove, handlePointerUp]);\n\n const calculateBestPosition = useCallback((rect: { top: number; bottom: number; left: number; right: number; width: number; height: number }) => {\n const tooltipWidth = 300;\n const tooltipHeight = 200;\n const gap = 12;\n const padding = 20;\n\n const spaceAbove = rect.top;\n const spaceBelow = window.innerHeight - rect.bottom;\n const spaceLeft = rect.left;\n const spaceRight = window.innerWidth - rect.right;\n\n let top = 0;\n let left = 0;\n\n if (spaceBelow > tooltipHeight + gap + padding) {\n top = rect.bottom + gap;\n left = Math.max(padding, Math.min(window.innerWidth - tooltipWidth - padding, rect.left + rect.width / 2 - tooltipWidth / 2));\n } else if (spaceAbove > tooltipHeight + gap + padding) {\n top = rect.top - tooltipHeight - gap;\n left = Math.max(padding, Math.min(window.innerWidth - tooltipWidth - padding, rect.left + rect.width / 2 - tooltipWidth / 2));\n } else if (spaceRight > tooltipWidth + gap + padding) {\n top = Math.max(padding, Math.min(window.innerHeight - tooltipHeight - padding, rect.top + rect.height / 2 - tooltipHeight / 2));\n left = rect.right + gap;\n } else if (spaceLeft > tooltipWidth + gap + padding) {\n top = Math.max(padding, Math.min(window.innerHeight - tooltipHeight - padding, rect.top + rect.height / 2 - tooltipHeight / 2));\n left = rect.left - tooltipWidth - gap;\n } else {\n top = window.innerHeight / 2 - tooltipHeight / 2;\n left = window.innerWidth / 2 - tooltipWidth / 2;\n }\n\n return { top: top + window.scrollY, left: left + window.scrollX };\n }, []);\n\n const updateCoords = useCallback(() => {\n if (!currentStep) return;\n\n const element = document.querySelector(`[data-onboarding-id=\"${currentStep.attribute}\"]`) as HTMLElement;\n if (element) {\n const rect = element.getBoundingClientRect();\n const padding = config.style?.padding || 0;\n \n const paddedRect = {\n top: rect.top - padding,\n bottom: rect.bottom + padding,\n left: rect.left - padding,\n right: rect.right + padding,\n width: rect.width + (padding * 2),\n height: rect.height + (padding * 2),\n };\n\n const newCoords = {\n top: paddedRect.top + window.scrollY,\n left: paddedRect.left + window.scrollX,\n width: paddedRect.width,\n height: paddedRect.height,\n };\n\n const newPosition = calculateBestPosition(paddedRect);\n\n // Prevent infinite loops by only updating if values actually changed\n setCoords(prev => {\n if (prev && \n prev.top === newCoords.top && \n prev.left === newCoords.left && \n prev.width === newCoords.width && \n prev.height === newCoords.height) {\n return prev;\n }\n return newCoords;\n });\n\n setPosition(prev => {\n if (prev.top === newPosition.top && prev.left === newPosition.left) {\n return prev;\n }\n return newPosition;\n });\n } else {\n setCoords(null);\n }\n }, [currentStep, calculateBestPosition, config.style]);\n\n useEffect(() => {\n updateCoords();\n window.addEventListener('resize', updateCoords);\n window.addEventListener('scroll', updateCoords);\n\n const observer = new MutationObserver(updateCoords);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true });\n\n let resizeObserver: ResizeObserver | null = null;\n if (typeof ResizeObserver !== 'undefined') {\n resizeObserver = new ResizeObserver(updateCoords);\n resizeObserver.observe(document.body);\n \n const element = currentStep?.attribute \n ? document.querySelector(`[data-onboarding-id=\"${currentStep.attribute}\"]`) \n : null;\n if (element) {\n resizeObserver.observe(element);\n }\n }\n\n return () => {\n window.removeEventListener('resize', updateCoords);\n window.removeEventListener('scroll', updateCoords);\n observer.disconnect();\n if (resizeObserver) resizeObserver.disconnect();\n };\n }, [updateCoords, currentStep?.attribute]);\n\n if (!currentStep || !coords) return null;\n\n const maskStyle = {\n ...config.style?.background,\n transition: 'all 0.3s cubic-bezier(0.25, 0.1, 0.25, 1)',\n };\n\n const stopPropagation = (e: React.PointerEvent | React.MouseEvent) => {\n e.stopPropagation();\n };\n\n const ChevronLeftIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M15 18l-6-6 6-6\" />\n </svg>\n );\n\n const ChevronRightIcon = () => (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M9 18l6-6-6-6\" />\n </svg>\n );\n\n const XIcon = () => (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n\n const overlayContent = (\n <div className=\"fixed inset-0 z-[999999] pointer-events-none\">\n {/* Top Mask */}\n <div\n style={{ height: coords.top, ...maskStyle }}\n className=\"onboard-overlay-mask top-0 left-0 w-full pointer-events-auto\"\n onPointerDown={stopPropagation}\n onMouseDown={stopPropagation}\n onClick={stopPropagation}\n />\n {/* Bottom Mask */}\n <div\n style={{ top: coords.top + coords.height, height: `calc(100vh - ${coords.top + coords.height}px)`, ...maskStyle }}\n className=\"onboard-overlay-mask left-0 w-full pointer-events-auto\"\n onPointerDown={stopPropagation}\n onMouseDown={stopPropagation}\n onClick={stopPropagation}\n />\n {/* Left Mask */}\n <div\n style={{ top: coords.top, height: coords.height, width: coords.left, ...maskStyle }}\n className=\"onboard-overlay-mask left-0 pointer-events-auto\"\n onPointerDown={stopPropagation}\n onMouseDown={stopPropagation}\n onClick={stopPropagation}\n />\n {/* Right Mask */}\n <div\n style={{ \n top: coords.top, \n height: coords.height, \n left: coords.left + coords.width, \n width: `calc(100% - ${coords.left + coords.width}px)`, \n ...maskStyle \n }}\n className=\"onboard-overlay-mask pointer-events-auto\"\n onPointerDown={stopPropagation}\n onMouseDown={stopPropagation}\n onClick={stopPropagation}\n />\n\n {/* Tooltip */}\n <div\n ref={tooltipRef}\n className=\"onboard-tooltip pointer-events-auto\"\n onPointerDown={handlePointerDown}\n style={{ \n zIndex: 1000000, \n ...config.style?.container,\n top: position.top + dragOffset.y,\n left: position.left + dragOffset.x,\n transition: 'top 0.3s cubic-bezier(0.25, 0.1, 0.25, 1), left 0.3s cubic-bezier(0.25, 0.1, 0.25, 1)',\n cursor: config.metadata.draggable ? 'grab' : 'auto',\n touchAction: 'none' // Prevent scrolling on touch devices while dragging\n }}\n onMouseDown={stopPropagation}\n onClick={stopPropagation}\n >\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: '8px' }}>\n <h3 style={{ margin: 0, fontWeight: 'bold', color: '#111827', fontSize: '18px', lineHeight: 1.2 }}>{currentStep.title}</h3>\n <button \n onClick={(e) => { e.stopPropagation(); finish(); }}\n style={{ background: 'none', border: 'none', cursor: 'pointer', padding: '4px', color: '#9ca3af' }}\n >\n <XIcon />\n </button>\n </div>\n <p style={{ margin: 0, color: '#4b5563', fontSize: '14px', marginBottom: '24px', lineHeight: 1.5 }}>\n {currentStep.description}\n </p>\n \n <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>\n <button\n onClick={(e) => { e.stopPropagation(); prevStep(); }}\n disabled={isFirstStep}\n className=\"onboard-button-ghost\"\n style={{ \n background: 'none', \n border: 'none', \n cursor: isFirstStep ? 'not-allowed' : 'pointer',\n ...config.style?.prev \n }}\n >\n <ChevronLeftIcon />\n Prev\n </button>\n \n {isLastStep ? (\n <button\n onClick={(e) => { e.stopPropagation(); finish(); }}\n className=\"onboard-button-primary\"\n style={{ border: 'none', cursor: 'pointer', ...config.style?.finish }}\n >\n Finish\n </button>\n ) : (\n <button\n onClick={(e) => { e.stopPropagation(); nextStep(); }}\n className=\"onboard-button-primary\"\n style={{ \n border: 'none', \n cursor: 'pointer',\n ...(isFirstStep ? config.style?.start : {}),\n ...(!isFirstStep ? config.style?.next : {})\n }}\n >\n {isFirstStep && config.style?.start ? 'Start' : 'Next'}\n {!(isFirstStep && config.style?.start) && <ChevronRightIcon />}\n </button>\n )}\n </div>\n </div>\n </div>\n );\n\n return typeof document !== 'undefined' \n ? createPortal(overlayContent, document.body) \n : null;\n};\n"],"mappings":"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","names":["React","createContext","useContext","useEffect","useState","useCallback","useMemo","Cookies","useState","useEffect","useCallback","useRef","createPortal","jsx","jsxs","OnboardingOverlay","config","currentStep","nextStep","prevStep","finish","isFirstStep","isLastStep","useOnboarding","coords","setCoords","useState","position","setPosition","dragOffset","setDragOffset","isDragging","useRef","dragStart","tooltipRef","useEffect","handlePointerDown","e","handlePointerMove","handlePointerUp","useCallback","newX","newY","calculateBestPosition","rect","spaceAbove","spaceBelow","spaceLeft","spaceRight","top","left","updateCoords","element","padding","paddedRect","newCoords","newPosition","prev","observer","resizeObserver","maskStyle","stopPropagation","ChevronLeftIcon","ChevronRightIcon","XIcon","overlayContent","createPortal","Fragment","jsx","jsxs","OnboardingContext","createContext","COOKIE_NAME","OnboardingProvider","config","ssr","children","isMounted","setIsMounted","useState","state","setState","configRef","React","useEffect","handleNavigation","useCallback","link","isMatch","step","path","pattern","currentConfig","currentPath","matchedStepIndex","savedState","Cookies","parsed","prev","e","currentStep","useMemo","isFirstStep","isLastStep","totalSteps","isLastMainStep","hasSubSteps","nextStep","currentActiveStep","element","nextSubIndex","nextSubStep","nextIndex","nextStepObj","prevStep","prevIndex","prevStepObj","prevSubStepIndex","finish","goToStep","stepIndex","subStepIndex","value","OnboardingOverlay","useOnboarding","context","useContext"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "onboard-engine",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "./dist/index.js",
|
|
5
|
+
"module": "./dist/index.mjs",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.mjs",
|
|
11
|
+
"require": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./index.css": "./dist/index.css",
|
|
14
|
+
"./dist/index.css": "./dist/index.css"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"dev": "tsup --watch",
|
|
21
|
+
"build": "tsup",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest",
|
|
24
|
+
"lint": "tsc --noEmit",
|
|
25
|
+
"prepublishOnly": "npm run build"
|
|
26
|
+
},
|
|
27
|
+
"private": false,
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/Forsrobin/onboard-engine.git"
|
|
31
|
+
},
|
|
32
|
+
"keywords": [],
|
|
33
|
+
"author": "",
|
|
34
|
+
"license": "ISC",
|
|
35
|
+
"type": "commonjs",
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/Forsrobin/onboard-engine/issues"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/Forsrobin/onboard-engine#readme",
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"react": ">=18",
|
|
42
|
+
"react-dom": ">=18"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
46
|
+
"@testing-library/react": "^16.2.0",
|
|
47
|
+
"@types/js-cookie": "^3.0.6",
|
|
48
|
+
"@types/node": "^22.10.6",
|
|
49
|
+
"@types/react": "^19.0.7",
|
|
50
|
+
"@types/react-dom": "^19.0.3",
|
|
51
|
+
"@vitejs/plugin-react": "^4.3.4",
|
|
52
|
+
"jsdom": "^26.0.0",
|
|
53
|
+
"tsup": "^8.3.5",
|
|
54
|
+
"typescript": "^5.7.3",
|
|
55
|
+
"vitest": "^2.1.8"
|
|
56
|
+
},
|
|
57
|
+
"dependencies": {
|
|
58
|
+
"clsx": "^2.1.1",
|
|
59
|
+
"js-cookie": "^3.0.5",
|
|
60
|
+
"tailwind-merge": "^2.6.0"
|
|
61
|
+
}
|
|
62
|
+
}
|