@eventop/sdk 1.0.4 → 1.0.6
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 +355 -193
- package/dist/index.d.ts +259 -0
- package/dist/react/index.cjs +473 -0
- package/dist/react/index.d.ts +208 -0
- package/dist/react/index.js +467 -0
- package/package.json +25 -13
- package/dist/cjs/client.js +0 -54
- package/dist/cjs/errors.js +0 -28
- package/dist/cjs/index.js +0 -32
- package/dist/cjs/resources/checkout.js +0 -18
- package/dist/cjs/resources/customers.js +0 -1
- package/dist/cjs/resources/subscriptions.js +0 -18
- package/dist/cjs/resources/webhooks.js +0 -60
- package/dist/cjs/types.js +0 -2
- package/dist/client.js +0 -63
- package/dist/errors.js +0 -33
- package/dist/esm/client.js +0 -45
- package/dist/esm/errors.js +0 -26
- package/dist/esm/index.js +0 -14
- package/dist/esm/resources/checkout.js +0 -14
- package/dist/esm/resources/customers.js +0 -1
- package/dist/esm/resources/subscriptions.js +0 -14
- package/dist/esm/resources/webhooks.js +0 -23
- package/dist/esm/types.js +0 -1
- package/dist/resources/checkout.js +0 -33
- package/dist/resources/customers.js +0 -1
- package/dist/resources/subscriptions.js +0 -33
- package/dist/resources/webhooks.js +0 -60
- package/dist/types/client.d.ts +0 -9
- package/dist/types/client.d.ts.map +0 -1
- package/dist/types/errors.d.ts +0 -15
- package/dist/types/errors.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -13
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/resources/checkout.d.ts +0 -10
- package/dist/types/resources/checkout.d.ts.map +0 -1
- package/dist/types/resources/customers.d.ts +0 -1
- package/dist/types/resources/customers.d.ts.map +0 -1
- package/dist/types/resources/subscriptions.d.ts +0 -10
- package/dist/types/resources/subscriptions.d.ts.map +0 -1
- package/dist/types/resources/webhooks.d.ts +0 -9
- package/dist/types/resources/webhooks.d.ts.map +0 -1
- package/dist/types/types.d.ts +0 -44
- package/dist/types/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
package/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
# eventop/sdk
|
|
1
|
+
# @eventop/sdk
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
inside component definitions — so any generic component works with any feature,
|
|
5
|
-
and you never touch the component itself.
|
|
3
|
+
AI-powered guided tours for any React or Next.js app. Drop-in, themeable, works with any component library.
|
|
6
4
|
|
|
7
5
|
---
|
|
8
6
|
|
|
@@ -10,55 +8,75 @@ and you never touch the component itself.
|
|
|
10
8
|
|
|
11
9
|
```bash
|
|
12
10
|
npm install @eventop/sdk
|
|
11
|
+
# or
|
|
12
|
+
yarn add @eventop/sdk
|
|
13
|
+
# or
|
|
14
|
+
pnpm add @eventop/sdk
|
|
13
15
|
```
|
|
14
16
|
|
|
15
17
|
---
|
|
16
18
|
|
|
17
|
-
##
|
|
19
|
+
## How it works
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
// ❌ Old way — registration inside the component, breaks reusability
|
|
21
|
-
function ExportButton() {
|
|
22
|
-
useeventopFeature({ id: 'export', name: 'Export' }); // hardcoded
|
|
23
|
-
return <button>Export</button>;
|
|
24
|
-
}
|
|
21
|
+
You wrap any element with `<EventopTarget>` at the call site. The SDK registers it as a feature the AI can guide users to. When a user types what they need in the chat bubble, the AI picks the right features and walks them through step by step.
|
|
25
22
|
|
|
26
|
-
|
|
27
|
-
function Button({ children, onClick }) {
|
|
28
|
-
return <button onClick={onClick}>{children}</button>;
|
|
29
|
-
}
|
|
23
|
+
The wrapped component stays completely generic — `<Button>`, `<div>`, anything from shadcn, MUI, Radix, whatever. You never modify the component itself.
|
|
30
24
|
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
```jsx
|
|
26
|
+
// Same Button, two different features, two different places in the app
|
|
27
|
+
<EventopTarget id="export" name="Export Design" description="Download as PNG or SVG">
|
|
33
28
|
<Button onClick={handleExport}>Export</Button>
|
|
34
|
-
</
|
|
29
|
+
</EventopTarget>
|
|
35
30
|
|
|
36
|
-
<
|
|
37
|
-
<Button onClick={
|
|
38
|
-
</
|
|
31
|
+
<EventopTarget id="share" name="Share Design" description="Share a link with teammates">
|
|
32
|
+
<Button onClick={handleShare}>Share</Button>
|
|
33
|
+
</EventopTarget>
|
|
39
34
|
```
|
|
40
35
|
|
|
41
36
|
---
|
|
42
37
|
|
|
43
|
-
##
|
|
38
|
+
## React app
|
|
39
|
+
|
|
40
|
+
### 1. Set up the server endpoint
|
|
41
|
+
|
|
42
|
+
Never put API keys in the browser. Create a server route that proxies the AI call.
|
|
43
|
+
|
|
44
|
+
```js
|
|
45
|
+
// server.js (Express)
|
|
46
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
47
|
+
|
|
48
|
+
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
|
|
49
|
+
|
|
50
|
+
app.post('/api/guide', async (req, res) => {
|
|
51
|
+
const { systemPrompt, messages } = req.body;
|
|
52
|
+
const response = await client.messages.create({
|
|
53
|
+
model: 'claude-sonnet-4-20250514',
|
|
54
|
+
max_tokens: 1000,
|
|
55
|
+
system: systemPrompt,
|
|
56
|
+
messages,
|
|
57
|
+
});
|
|
58
|
+
res.json(JSON.parse(response.content[0].text));
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 2. Add the provider at the root
|
|
44
63
|
|
|
45
64
|
```jsx
|
|
46
|
-
// main.jsx
|
|
47
|
-
import { EventopAIProvider } from '@eventop/sdk';
|
|
48
|
-
import eventopAI from 'eventop-ai-sdk';
|
|
65
|
+
// main.jsx
|
|
66
|
+
import { EventopAIProvider } from '@eventop/sdk/react';
|
|
49
67
|
|
|
50
|
-
const provider =
|
|
68
|
+
const provider = async ({ systemPrompt, messages }) => {
|
|
51
69
|
const res = await fetch('/api/guide', {
|
|
52
70
|
method: 'POST',
|
|
53
71
|
headers: { 'Content-Type': 'application/json' },
|
|
54
72
|
body: JSON.stringify({ systemPrompt, messages }),
|
|
55
73
|
});
|
|
56
74
|
return res.json();
|
|
57
|
-
}
|
|
75
|
+
};
|
|
58
76
|
|
|
59
77
|
export default function App() {
|
|
60
78
|
return (
|
|
61
|
-
<
|
|
79
|
+
<EventopAIProvider
|
|
62
80
|
provider={provider}
|
|
63
81
|
appName="My App"
|
|
64
82
|
assistantName="AI Guide"
|
|
@@ -67,207 +85,289 @@ export default function App() {
|
|
|
67
85
|
position={{ corner: 'bottom-right' }}
|
|
68
86
|
>
|
|
69
87
|
<YourApp />
|
|
70
|
-
</
|
|
88
|
+
</EventopAIProvider>
|
|
71
89
|
);
|
|
72
90
|
}
|
|
73
91
|
```
|
|
74
92
|
|
|
75
|
-
|
|
93
|
+
### 3. Wrap features anywhere in the tree
|
|
76
94
|
|
|
77
|
-
|
|
95
|
+
```jsx
|
|
96
|
+
// ExportPanel.jsx
|
|
97
|
+
import { EventopTarget } from '@eventop/sdk/react';
|
|
78
98
|
|
|
79
|
-
|
|
99
|
+
export function ExportPanel() {
|
|
100
|
+
return (
|
|
101
|
+
<EventopTarget
|
|
102
|
+
id="export"
|
|
103
|
+
name="Export Design"
|
|
104
|
+
description="Download the design as PNG, SVG or PDF"
|
|
105
|
+
>
|
|
106
|
+
<div id="export-panel">
|
|
107
|
+
<button>PNG</button>
|
|
108
|
+
<button>SVG</button>
|
|
109
|
+
<button>PDF</button>
|
|
110
|
+
</div>
|
|
111
|
+
</EventopTarget>
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
```
|
|
80
115
|
|
|
81
|
-
|
|
82
|
-
shadcn, MUI, Radix — anything. The wrapped component does not need to accept refs
|
|
83
|
-
or know about eventopAI.
|
|
116
|
+
That's it. The chat bubble appears automatically. Users type what they need and get a guided tour.
|
|
84
117
|
|
|
85
|
-
|
|
86
|
-
import { EventopTarget } from '@eventop/sdk';
|
|
118
|
+
---
|
|
87
119
|
|
|
88
|
-
|
|
89
|
-
<EventopTarget id="export" name="Export Design" description="Download as PNG or SVG">
|
|
90
|
-
<Button>Export</Button>
|
|
91
|
-
</EventopTarget>
|
|
120
|
+
## Next.js app
|
|
92
121
|
|
|
93
|
-
|
|
94
|
-
<EventopTarget
|
|
95
|
-
id="effects"
|
|
96
|
-
name="Effects Panel"
|
|
97
|
-
description="Apply shadows, blur and glow"
|
|
98
|
-
navigate={() => router.push('/canvas')}
|
|
99
|
-
navigateWaitFor="#canvas-stage"
|
|
100
|
-
>
|
|
101
|
-
<EffectsPanel />
|
|
102
|
-
</EventopTarget>
|
|
122
|
+
### 1. Create the API route
|
|
103
123
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
124
|
+
```js
|
|
125
|
+
// app/api/guide/route.js (App Router)
|
|
126
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
127
|
+
|
|
128
|
+
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
|
|
129
|
+
|
|
130
|
+
export async function POST(request) {
|
|
131
|
+
const { systemPrompt, messages } = await request.json();
|
|
132
|
+
const response = await client.messages.create({
|
|
133
|
+
model: 'claude-sonnet-4-20250514',
|
|
134
|
+
max_tokens: 1000,
|
|
135
|
+
system: systemPrompt,
|
|
136
|
+
messages,
|
|
137
|
+
});
|
|
138
|
+
return Response.json(JSON.parse(response.content[0].text));
|
|
139
|
+
}
|
|
113
140
|
```
|
|
114
141
|
|
|
115
|
-
|
|
142
|
+
```js
|
|
143
|
+
// pages/api/guide.js (Pages Router)
|
|
144
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
116
145
|
|
|
117
|
-
|
|
118
|
-
|-------------------|----------|----------|-------------------------------------------------------|
|
|
119
|
-
| `id` | string | ✓ | Unique feature id |
|
|
120
|
-
| `name` | string | ✓ | Human-readable name (AI reads this) |
|
|
121
|
-
| `description` | string | | What it does (AI uses this to match user intent) |
|
|
122
|
-
| `navigate` | function | | Navigate here if component is not currently mounted |
|
|
123
|
-
| `navigateWaitFor` | string | | CSS selector to wait for after navigating |
|
|
124
|
-
| `advanceOn` | object | | `{ event, delay?, selector? }` — auto-advance the tour|
|
|
125
|
-
| `waitFor` | string | | CSS selector to wait for before showing this step |
|
|
146
|
+
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
|
|
126
147
|
|
|
127
|
-
|
|
148
|
+
export default async function handler(req, res) {
|
|
149
|
+
const { systemPrompt, messages } = req.body;
|
|
150
|
+
const response = await client.messages.create({
|
|
151
|
+
model: 'claude-sonnet-4-20250514',
|
|
152
|
+
max_tokens: 1000,
|
|
153
|
+
system: systemPrompt,
|
|
154
|
+
messages,
|
|
155
|
+
});
|
|
156
|
+
res.json(JSON.parse(response.content[0].text));
|
|
157
|
+
}
|
|
158
|
+
```
|
|
128
159
|
|
|
129
|
-
###
|
|
160
|
+
### 2. Add the provider in a client component
|
|
130
161
|
|
|
131
|
-
|
|
132
|
-
tree — it does not need to be inside a `eventopTarget`. Steps self-assemble
|
|
133
|
-
into the correct sequence via the `index` prop.
|
|
162
|
+
The SDK touches the DOM so the provider must be a client component.
|
|
134
163
|
|
|
135
164
|
```jsx
|
|
136
|
-
|
|
165
|
+
// components/EventopProvider.jsx
|
|
166
|
+
'use client';
|
|
137
167
|
|
|
138
|
-
|
|
139
|
-
// They form a flow by sharing the same feature id and sequential indexes
|
|
168
|
+
import { EventopAIProvider } from '@eventop/sdk/react';
|
|
140
169
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
170
|
+
const provider = async ({ systemPrompt, messages }) => {
|
|
171
|
+
const res = await fetch('/api/guide', {
|
|
172
|
+
method: 'POST',
|
|
173
|
+
headers: { 'Content-Type': 'application/json' },
|
|
174
|
+
body: JSON.stringify({ systemPrompt, messages }),
|
|
175
|
+
});
|
|
176
|
+
return res.json();
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
export function EventopProvider({ children }) {
|
|
180
|
+
return (
|
|
181
|
+
<EventopAIProvider
|
|
182
|
+
provider={provider}
|
|
183
|
+
appName="My App"
|
|
184
|
+
assistantName="AI Guide"
|
|
185
|
+
suggestions={['How do I export?', 'Invite a teammate']}
|
|
186
|
+
theme={{ mode: 'auto', tokens: { accent: '#6366f1' } }}
|
|
187
|
+
position={{ corner: 'bottom-right' }}
|
|
188
|
+
>
|
|
189
|
+
{children}
|
|
190
|
+
</EventopAIProvider>
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
```jsx
|
|
196
|
+
// app/layout.jsx
|
|
197
|
+
import { EventopProvider } from '@/components/EventopProvider';
|
|
169
198
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
199
|
+
export default function RootLayout({ children }) {
|
|
200
|
+
return (
|
|
201
|
+
<html lang="en">
|
|
202
|
+
<body>
|
|
203
|
+
<EventopProvider>
|
|
204
|
+
{children}
|
|
205
|
+
</EventopProvider>
|
|
206
|
+
</body>
|
|
207
|
+
</html>
|
|
208
|
+
);
|
|
209
|
+
}
|
|
174
210
|
```
|
|
175
211
|
|
|
176
|
-
|
|
212
|
+
### 3. Wrap features in client components
|
|
177
213
|
|
|
178
|
-
|
|
179
|
-
Useful for things like "open font picker → (select font family → select weight → set size)".
|
|
214
|
+
Any component that uses `EventopTarget`, `EventopStep`, or the hooks needs `'use client'`.
|
|
180
215
|
|
|
181
216
|
```jsx
|
|
182
|
-
//
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
217
|
+
// components/Toolbar.jsx
|
|
218
|
+
'use client';
|
|
219
|
+
|
|
220
|
+
import { EventopTarget } from '@eventop/sdk/react';
|
|
221
|
+
|
|
222
|
+
export function Toolbar() {
|
|
223
|
+
return (
|
|
224
|
+
<div className="toolbar">
|
|
225
|
+
<EventopTarget
|
|
226
|
+
id="export"
|
|
227
|
+
name="Export Design"
|
|
228
|
+
description="Download as PNG, SVG or PDF"
|
|
229
|
+
>
|
|
230
|
+
<button>Export</button>
|
|
231
|
+
</EventopTarget>
|
|
232
|
+
|
|
233
|
+
<EventopTarget
|
|
234
|
+
id="share"
|
|
235
|
+
name="Share Design"
|
|
236
|
+
description="Share a link to this design"
|
|
237
|
+
>
|
|
238
|
+
<button>Share</button>
|
|
239
|
+
</EventopTarget>
|
|
240
|
+
</div>
|
|
241
|
+
);
|
|
242
|
+
}
|
|
194
243
|
```
|
|
195
244
|
|
|
196
|
-
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## Multi-step flows
|
|
197
248
|
|
|
198
|
-
|
|
249
|
+
For features that require multiple actions in sequence (open a panel, toggle a switch, adjust sliders), use `<EventopStep>`. Steps can live in completely different components — they self-assemble by index.
|
|
199
250
|
|
|
200
251
|
```jsx
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
252
|
+
// CanvasStage.jsx — step 0: click an element
|
|
253
|
+
'use client';
|
|
254
|
+
import { EventopStep } from '@eventop/sdk/react';
|
|
255
|
+
|
|
256
|
+
export function CanvasStage() {
|
|
257
|
+
return (
|
|
258
|
+
<EventopStep
|
|
259
|
+
feature="drop-shadow"
|
|
260
|
+
index={0}
|
|
261
|
+
advanceOn={{ selector: '.canvas-el', event: 'click', delay: 300 }}
|
|
262
|
+
>
|
|
263
|
+
<div className="canvas-stage">...</div>
|
|
264
|
+
</EventopStep>
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Toolbar.jsx — step 1: click Effects (different component entirely)
|
|
269
|
+
export function EffectsButton() {
|
|
270
|
+
return (
|
|
271
|
+
<EventopStep
|
|
272
|
+
feature="drop-shadow"
|
|
273
|
+
index={1}
|
|
274
|
+
waitFor=".canvas-el.selected"
|
|
275
|
+
advanceOn={{ event: 'click', delay: 200 }}
|
|
276
|
+
>
|
|
277
|
+
<button id="btn-effects">✨ Effects</button>
|
|
205
278
|
</EventopStep>
|
|
206
|
-
|
|
207
|
-
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// EffectsPanel.jsx — step 2: toggle shadow on
|
|
283
|
+
export function ShadowToggle({ onToggle }) {
|
|
284
|
+
return (
|
|
285
|
+
<EventopStep
|
|
286
|
+
feature="drop-shadow"
|
|
287
|
+
index={2}
|
|
288
|
+
waitFor="#effects-panel.open"
|
|
289
|
+
advanceOn={{ event: 'click', delay: 300 }}
|
|
290
|
+
>
|
|
291
|
+
<button id="shadow-toggle" onClick={onToggle}>Shadow</button>
|
|
208
292
|
</EventopStep>
|
|
209
|
-
|
|
210
|
-
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Step 3: sliders — only rendered when shadow is on
|
|
297
|
+
// SDK waits for them via waitFor before showing this step
|
|
298
|
+
export function ShadowSliders() {
|
|
299
|
+
return (
|
|
300
|
+
<EventopStep feature="drop-shadow" index={3} waitFor="#shadow-controls.visible">
|
|
301
|
+
<div id="shadow-controls" className="visible">...</div>
|
|
302
|
+
</EventopStep>
|
|
303
|
+
);
|
|
304
|
+
}
|
|
211
305
|
```
|
|
212
306
|
|
|
213
|
-
|
|
307
|
+
The parent feature still needs a `<EventopTarget>` somewhere:
|
|
214
308
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
309
|
+
```jsx
|
|
310
|
+
// In whichever component owns the canvas screen
|
|
311
|
+
<EventopTarget
|
|
312
|
+
id="drop-shadow"
|
|
313
|
+
name="Drop Shadow Effect"
|
|
314
|
+
description="Apply a customisable drop shadow to a selected element"
|
|
315
|
+
navigate={() => router.push('/canvas')}
|
|
316
|
+
>
|
|
317
|
+
<div className="canvas-screen">
|
|
318
|
+
<CanvasStage />
|
|
319
|
+
<EffectsButton />
|
|
320
|
+
<ShadowToggle />
|
|
321
|
+
{shadowOn && <ShadowSliders />}
|
|
322
|
+
</div>
|
|
323
|
+
</EventopTarget>
|
|
324
|
+
```
|
|
222
325
|
|
|
223
326
|
---
|
|
224
327
|
|
|
225
|
-
|
|
328
|
+
## Async validation
|
|
226
329
|
|
|
227
|
-
|
|
228
|
-
`stepFail()` when you have async validation the tour should respect.
|
|
330
|
+
Use `useEventopAI` when a tour step depends on the user completing a form action correctly before advancing.
|
|
229
331
|
|
|
230
332
|
```jsx
|
|
231
|
-
|
|
333
|
+
'use client';
|
|
334
|
+
import { useEventopAI } from '@eventop/sdk/react';
|
|
232
335
|
|
|
233
|
-
function
|
|
234
|
-
const { stepComplete, stepFail } =
|
|
336
|
+
export function CheckoutForm() {
|
|
337
|
+
const { stepComplete, stepFail } = useEventopAI();
|
|
338
|
+
const [email, setEmail] = useState('');
|
|
235
339
|
|
|
236
340
|
async function handleContinue() {
|
|
237
|
-
const ok = await
|
|
238
|
-
if (ok) stepComplete();
|
|
239
|
-
else stepFail('
|
|
341
|
+
const ok = await validateEmail(email);
|
|
342
|
+
if (ok) stepComplete();
|
|
343
|
+
else stepFail('Please enter a valid email address.');
|
|
240
344
|
}
|
|
241
345
|
|
|
242
|
-
return
|
|
346
|
+
return (
|
|
347
|
+
<EventopTarget id="email-field" name="Email Address" description="Enter your email">
|
|
348
|
+
<div>
|
|
349
|
+
<input
|
|
350
|
+
type="email"
|
|
351
|
+
value={email}
|
|
352
|
+
onChange={e => setEmail(e.target.value)}
|
|
353
|
+
/>
|
|
354
|
+
<button onClick={handleContinue}>Continue</button>
|
|
355
|
+
</div>
|
|
356
|
+
</EventopTarget>
|
|
357
|
+
);
|
|
243
358
|
}
|
|
244
359
|
```
|
|
245
360
|
|
|
246
|
-
**Returns:**
|
|
247
|
-
|
|
248
|
-
| Method | Description |
|
|
249
|
-
|------------------|-----------------------------------------------------|
|
|
250
|
-
| `stepComplete()` | Advance the active tour step |
|
|
251
|
-
| `stepFail(msg)` | Block advancement and show error in the tooltip |
|
|
252
|
-
| `open()` | Open the chat panel |
|
|
253
|
-
| `close()` | Close the chat panel |
|
|
254
|
-
| `cancelTour()` | Hard cancel — no resume state saved |
|
|
255
|
-
| `resumeTour()` | Resume a paused tour from where it left off |
|
|
256
|
-
| `isActive()` | Returns true if a tour is running |
|
|
257
|
-
| `isPaused()` | Returns true if a tour is paused |
|
|
258
|
-
| `runTour(steps)` | Run a manual tour bypassing the AI |
|
|
259
|
-
|
|
260
361
|
---
|
|
261
362
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
React to tour state in your own UI. Reactive — updates every 300ms.
|
|
363
|
+
## Tour status in your own UI
|
|
265
364
|
|
|
266
365
|
```jsx
|
|
267
|
-
|
|
366
|
+
'use client';
|
|
367
|
+
import { useEventopTour } from '@eventop/sdk/react';
|
|
268
368
|
|
|
269
|
-
function TourStatusBar() {
|
|
270
|
-
const { isActive, isPaused, resume, cancel } =
|
|
369
|
+
export function TourStatusBar() {
|
|
370
|
+
const { isActive, isPaused, resume, cancel } = useEventopTour();
|
|
271
371
|
|
|
272
372
|
if (!isActive && !isPaused) return null;
|
|
273
373
|
|
|
@@ -289,27 +389,89 @@ function TourStatusBar() {
|
|
|
289
389
|
|
|
290
390
|
---
|
|
291
391
|
|
|
292
|
-
##
|
|
392
|
+
## API reference
|
|
393
|
+
|
|
394
|
+
### `<EventopAIProvider>`
|
|
395
|
+
|
|
396
|
+
| Prop | Type | Required | Default | Description |
|
|
397
|
+
|-----------------|------------|----------|----------------|-------------------------------|
|
|
398
|
+
| `provider` | function | ✓ | — | Async function that calls your server route |
|
|
399
|
+
| `appName` | string | ✓ | — | Shown in the chat header |
|
|
400
|
+
| `assistantName` | string | | `'AI Guide'` | Name shown in the chat header |
|
|
401
|
+
| `suggestions` | string[] | | `[]` | Clickable chips on first open |
|
|
402
|
+
| `theme` | object | | dark, default | `{ mode, preset, tokens }` |
|
|
403
|
+
| `position` | object | | bottom-right | `{ corner, offsetX, offsetY }`|
|
|
404
|
+
|
|
405
|
+
### `<EventopTarget>`
|
|
406
|
+
|
|
407
|
+
| Prop | Type | Required | Description |
|
|
408
|
+
|-------------------|----------|----------|---------------------------------------------------------|
|
|
409
|
+
| `id` | string | ✓ | Unique feature id |
|
|
410
|
+
| `name` | string | ✓ | Human-readable name the AI reads |
|
|
411
|
+
| `description` | string | | What it does — AI uses this to match user intent |
|
|
412
|
+
| `navigate` | function | | Navigate here if component is not currently mounted |
|
|
413
|
+
| `navigateWaitFor` | string | | CSS selector to wait for after navigating |
|
|
414
|
+
| `advanceOn` | object | | `{ event, delay?, selector? }` — auto-advance the tour |
|
|
415
|
+
| `waitFor` | string | | CSS selector to wait for before showing this step |
|
|
416
|
+
|
|
417
|
+
### `<EventopStep>`
|
|
418
|
+
|
|
419
|
+
| Prop | Type | Required | Description |
|
|
420
|
+
|-------------|--------|----------|----------------------------------------------------------------|
|
|
421
|
+
| `feature` | string | * | Feature id (*not needed if inside `<EventopTarget>`) |
|
|
422
|
+
| `index` | number | ✓ | Position in the flow, 0-based |
|
|
423
|
+
| `parentStep`| number | | Makes this a sub-step of another step |
|
|
424
|
+
| `waitFor` | string | | CSS selector to wait for before showing |
|
|
425
|
+
| `advanceOn` | object | | `{ event, delay?, selector? }` — auto-advance |
|
|
426
|
+
|
|
427
|
+
### `useEventopAI`
|
|
428
|
+
|
|
429
|
+
| Method | Description |
|
|
430
|
+
|--------------------|------------------------------------------------------|
|
|
431
|
+
| `stepComplete()` | Advance the active tour step |
|
|
432
|
+
| `stepFail(msg)` | Block advancement and show error in the tooltip |
|
|
433
|
+
| `open()` | Open the chat panel |
|
|
434
|
+
| `close()` | Close the chat panel |
|
|
435
|
+
| `cancelTour()` | Hard cancel — no resume state saved |
|
|
436
|
+
| `resumeTour()` | Resume a paused tour from where it left off |
|
|
437
|
+
| `isActive()` | Returns true if a tour is currently running |
|
|
438
|
+
| `isPaused()` | Returns true if a tour is paused |
|
|
439
|
+
| `runTour(steps)` | Run a tour manually, bypassing the AI |
|
|
440
|
+
|
|
441
|
+
### `useEventopTour`
|
|
442
|
+
|
|
443
|
+
| Property / Method | Type | Description |
|
|
444
|
+
|-------------------|----------|------------------------------------------|
|
|
445
|
+
| `isActive` | boolean | True if a tour is running |
|
|
446
|
+
| `isPaused` | boolean | True if a tour is paused |
|
|
447
|
+
| `resume()` | function | Resume a paused tour |
|
|
448
|
+
| `cancel()` | function | Hard cancel |
|
|
449
|
+
| `open()` | function | Open the chat panel |
|
|
450
|
+
| `close()` | function | Close the chat panel |
|
|
293
451
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## Theme tokens
|
|
297
455
|
|
|
298
|
-
|
|
456
|
+
| Token | Default (dark) | Default (light) |
|
|
457
|
+
|-------------------|------------------|-----------------|
|
|
458
|
+
| `accent` | `#e94560` | `#e94560` |
|
|
459
|
+
| `accentSecondary` | `#a855f7` | `#7c3aed` |
|
|
460
|
+
| `bg` | `#0f0f1a` | `#ffffff` |
|
|
461
|
+
| `surface` | `#1a1a2e` | `#f8f8fc` |
|
|
462
|
+
| `border` | `#2a2a4a` | `#e4e4f0` |
|
|
463
|
+
| `text` | `#e0e0f0` | `#1a1a2e` |
|
|
464
|
+
| `radius` | `16px` | `16px` |
|
|
465
|
+
|
|
466
|
+
Override any token:
|
|
299
467
|
|
|
300
468
|
```jsx
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
>
|
|
311
|
-
<div id="effects-panel">...</div>
|
|
312
|
-
</EventopTarget>
|
|
313
|
-
);
|
|
314
|
-
}
|
|
315
|
-
```
|
|
469
|
+
theme={{
|
|
470
|
+
mode: 'dark',
|
|
471
|
+
tokens: {
|
|
472
|
+
accent: '#6366f1',
|
|
473
|
+
radius: '12px',
|
|
474
|
+
fontFamily: "'Inter', sans-serif",
|
|
475
|
+
}
|
|
476
|
+
}}
|
|
477
|
+
```
|