@eventop/sdk 1.2.2 → 1.2.11

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 CHANGED
@@ -61,8 +61,11 @@ app.post('/api/guide', async (req, res) => {
61
61
 
62
62
  ### 2. Add the provider at the root
63
63
 
64
+ Pass your router's navigate function so the SDK can move users between pages automatically.
65
+
64
66
  ```jsx
65
67
  // main.jsx
68
+ import { useNavigate } from 'react-router-dom';
66
69
  import { EventopAIProvider } from '@eventop/sdk/react';
67
70
 
68
71
  const provider = async ({ systemPrompt, messages }) => {
@@ -75,9 +78,12 @@ const provider = async ({ systemPrompt, messages }) => {
75
78
  };
76
79
 
77
80
  export default function App() {
81
+ const navigate = useNavigate();
82
+
78
83
  return (
79
84
  <EventopAIProvider
80
85
  provider={provider}
86
+ router={navigate}
81
87
  appName="My App"
82
88
  assistantName="AI Guide"
83
89
  suggestions={['How do I export?', 'Invite a teammate']}
@@ -92,8 +98,10 @@ export default function App() {
92
98
 
93
99
  ### 3. Wrap features anywhere in the tree
94
100
 
101
+ Add `route` to any feature that lives on a different page. The SDK navigates there automatically when a tour needs it.
102
+
95
103
  ```jsx
96
- // ExportPanel.jsx
104
+ // ExportPanel.jsx — lives on /canvas
97
105
  import { EventopTarget } from '@eventop/sdk/react';
98
106
 
99
107
  export function ExportPanel() {
@@ -102,6 +110,7 @@ export function ExportPanel() {
102
110
  id="export"
103
111
  name="Export Design"
104
112
  description="Download the design as PNG, SVG or PDF"
113
+ route="/canvas"
105
114
  >
106
115
  <div id="export-panel">
107
116
  <button>PNG</button>
@@ -113,7 +122,7 @@ export function ExportPanel() {
113
122
  }
114
123
  ```
115
124
 
116
- That's it. The chat bubble appears automatically. Users type what they need and get a guided tour.
125
+ That's it. The chat bubble appears automatically. Users type what they need, the SDK figures out which page the feature is on, navigates there, and walks them through step by step.
117
126
 
118
127
  ---
119
128
 
@@ -159,12 +168,16 @@ export default async function handler(req, res) {
159
168
 
160
169
  ### 2. Add the provider in a client component
161
170
 
162
- The SDK touches the DOM so the provider must be a client component.
171
+ The SDK touches the DOM so the provider must be a client component. Pass `router` so
172
+ the SDK can navigate between pages during a tour.
163
173
 
164
174
  ```jsx
165
175
  // components/EventopProvider.jsx
166
176
  'use client';
167
177
 
178
+ import { useRouter } from 'next/navigation'; // App Router
179
+ // import { useRouter } from 'next/router'; // Pages Router
180
+
168
181
  import { EventopAIProvider } from '@eventop/sdk/react';
169
182
 
170
183
  const provider = async ({ systemPrompt, messages }) => {
@@ -177,9 +190,12 @@ const provider = async ({ systemPrompt, messages }) => {
177
190
  };
178
191
 
179
192
  export function EventopProvider({ children }) {
193
+ const router = useRouter();
194
+
180
195
  return (
181
196
  <EventopAIProvider
182
197
  provider={provider}
198
+ router={(path) => router.push(path)}
183
199
  appName="My App"
184
200
  assistantName="AI Guide"
185
201
  suggestions={['How do I export?', 'Invite a teammate']}
@@ -212,9 +228,10 @@ export default function RootLayout({ children }) {
212
228
  ### 3. Wrap features in client components
213
229
 
214
230
  Any component that uses `EventopTarget`, `EventopStep`, or the hooks needs `'use client'`.
231
+ Add `route` to features that live on a different page than where tours are typically started.
215
232
 
216
233
  ```jsx
217
- // components/Toolbar.jsx
234
+ // components/Toolbar.jsx — lives on /canvas
218
235
  'use client';
219
236
 
220
237
  import { EventopTarget } from '@eventop/sdk/react';
@@ -226,6 +243,7 @@ export function Toolbar() {
226
243
  id="export"
227
244
  name="Export Design"
228
245
  description="Download as PNG, SVG or PDF"
246
+ route="/canvas"
229
247
  >
230
248
  <button>Export</button>
231
249
  </EventopTarget>
@@ -234,6 +252,7 @@ export function Toolbar() {
234
252
  id="share"
235
253
  name="Share Design"
236
254
  description="Share a link to this design"
255
+ route="/canvas"
237
256
  >
238
257
  <button>Share</button>
239
258
  </EventopTarget>
@@ -244,6 +263,76 @@ export function Toolbar() {
244
263
 
245
264
  ---
246
265
 
266
+ ## Smart navigation
267
+
268
+ When a user asks about a feature that lives on a different page, the SDK handles
269
+ everything automatically — no manual navigation code needed.
270
+
271
+ **What the user sees:**
272
+
273
+ Before the tour starts, the chat panel tells them which pages will be visited:
274
+
275
+ > 🗺 This tour visits 2 areas: Export Design and Billing Settings. I'll navigate between them automatically.
276
+
277
+ Mid-tour, just before each page change:
278
+
279
+ > ↗ Taking you to the Billing Settings area…
280
+
281
+ The page changes, the target element appears, and the tooltip shows — all without
282
+ the user doing anything.
283
+
284
+ **How to set it up:**
285
+
286
+ Two things are required: `router` on the provider, and `route` on any `EventopTarget`
287
+ that lives on a different page.
288
+
289
+ ```jsx
290
+ // Provider — pass your router once
291
+ <EventopAIProvider router={navigate} ...>
292
+
293
+ // Feature on /settings/billing
294
+ <EventopTarget id="billing" name="Billing" route="/settings/billing">
295
+ <BillingSection />
296
+ </EventopTarget>
297
+
298
+ // Feature on /canvas — no route needed if tours always start here
299
+ <EventopTarget id="export" name="Export">
300
+ <ExportButton />
301
+ </EventopTarget>
302
+ ```
303
+
304
+ Features that share the page where tours are typically started don't need `route`.
305
+ Only add it to features on other pages.
306
+
307
+ ### How the registry stays aware of every page
308
+
309
+ When you navigate away from a page, its `EventopTarget` components unmount. Rather
310
+ than removing them from the registry entirely, the SDK downgrades them to **ghost
311
+ entries** — the metadata (`id`, `name`, `description`, `route`) is kept, only the
312
+ live DOM selector is nulled out.
313
+
314
+ ```
315
+ EventopTarget mounts → full entry { id, name, description, route, selector }
316
+ EventopTarget unmounts → ghost entry { id, name, description, route, selector: null }
317
+ EventopTarget remounts → full entry (selector restored)
318
+ ```
319
+
320
+ This means the AI system prompt always contains every feature the app has ever
321
+ rendered, regardless of which page you're currently on. The AI can plan cross-page
322
+ tours from any starting point without you doing anything extra.
323
+
324
+ The selector is resolved lazily — after navigation completes and the target page's
325
+ components remount, the ghost upgrades back to a full entry and the tour picks up
326
+ the correct selector just before showing the step.
327
+
328
+ > **Note on `id` stability** — ghost entries accumulate for the lifetime of the
329
+ > session, so `id` should identify a **UI capability**, not a data record.
330
+ > Wrapping dynamic list items with unique ids (e.g. `` `project-${p.id}` ``)
331
+ > will create an unbounded number of ghosts. Use a single `EventopTarget` for
332
+ > the repeating pattern instead.
333
+
334
+ ---
335
+
247
336
  ## Multi-step flows
248
337
 
249
338
  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.
@@ -312,7 +401,7 @@ The parent feature still needs a `<EventopTarget>` somewhere:
312
401
  id="drop-shadow"
313
402
  name="Drop Shadow Effect"
314
403
  description="Apply a customisable drop shadow to a selected element"
315
- navigate={() => router.push('/canvas')}
404
+ route="/canvas"
316
405
  >
317
406
  <div className="canvas-screen">
318
407
  <CanvasStage />
@@ -393,26 +482,28 @@ export function TourStatusBar() {
393
482
 
394
483
  ### `<EventopAIProvider>`
395
484
 
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 }`|
485
+ | Prop | Type | Required | Default | Description |
486
+ |-----------------|------------|----------|----------------|----------------------------------------------------------------|
487
+ | `provider` | function | ✓ | — | Async function that calls your server route |
488
+ | `appName` | string | ✓ | — | Shown in the chat header |
489
+ | `assistantName` | string | | `'AI Guide'` | Name shown in the chat header |
490
+ | `router` | function | | — | `(path: string) => void` your framework's navigate function. Used for cross-page tours. React Router: pass `useNavigate()`. Next.js: pass `(path) => router.push(path)`. Falls back to `history.pushState` if omitted. |
491
+ | `suggestions` | string[] | | `[]` | Clickable chips on first open |
492
+ | `theme` | object | | dark, default | `{ mode, preset, tokens }` |
493
+ | `position` | object | | bottom-right | `{ corner, offsetX, offsetY }` |
404
494
 
405
495
  ### `<EventopTarget>`
406
496
 
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 |
497
+ | Prop | Type | Required | Description |
498
+ |-------------------|----------|----------|------------------------------------------------------------------------------|
499
+ | `id` | string | ✓ | Unique feature id |
500
+ | `name` | string | ✓ | Human-readable name the AI reads |
501
+ | `description` | string | | What it does — AI uses this to match user intent |
502
+ | `route` | string | | Pathname where this feature lives (e.g. `"/settings/billing"`). When set, the SDK auto-navigates here before showing this step and explains the navigation to the user. |
503
+ | `navigate` | function | | Legacy: navigate here if component is not mounted. Prefer `route` + `router`.|
504
+ | `navigateWaitFor` | string | | CSS selector to wait for after navigating |
505
+ | `advanceOn` | object | | `{ event, delay?, selector? }` auto-advance the tour |
506
+ | `waitFor` | string | | CSS selector to wait for before showing this step |
416
507
 
417
508
  ### `<EventopStep>`
418
509