@eventop/sdk 1.1.4 → 1.1.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.
@@ -1,4 +1,4 @@
1
- import { createContext, useContext, useRef, useEffect, Children, cloneElement, useState, useCallback } from 'react';
1
+ import { createContext, useContext, useRef, useCallback, useEffect, Children, cloneElement, useState } from 'react';
2
2
  import { jsx } from 'react/jsx-runtime';
3
3
 
4
4
  /**
@@ -24,202 +24,6 @@ function useFeatureScope() {
24
24
  return useContext(EventopFeatureScopeContext); // null is fine — steps can declare feature explicitly
25
25
  }
26
26
 
27
- function EventopTarget({
28
- children,
29
- id,
30
- name,
31
- description,
32
- navigate,
33
- navigateWaitFor,
34
- advanceOn,
35
- waitFor,
36
- ...rest
37
- }) {
38
- const registry = useRegistry();
39
- const ref = useRef(null);
40
- const dataAttr = `data-evtp-${id}`;
41
- const selector = `[${dataAttr}]`;
42
- useEffect(() => {
43
- if (!id || !name) {
44
- console.warn('[Eventop] <EventopTarget> requires id and name props.');
45
- return;
46
- }
47
- registry.registerFeature({
48
- id,
49
- name,
50
- description,
51
- selector,
52
- navigate,
53
- navigateWaitFor,
54
- waitFor,
55
- advanceOn: advanceOn ? {
56
- selector,
57
- ...advanceOn
58
- } : null
59
- });
60
- return () => registry.unregisterFeature(id);
61
- }, [id, name, description]);
62
- const child = Children.only(children);
63
- let wrapped;
64
- try {
65
- wrapped = /*#__PURE__*/cloneElement(child, {
66
- [dataAttr]: '',
67
- ref: node => {
68
- ref.current = node;
69
- const originalRef = child.ref;
70
- if (typeof originalRef === 'function') originalRef(node);else if (originalRef && 'current' in originalRef) originalRef.current = node;
71
- }
72
- });
73
- } catch {
74
- wrapped = /*#__PURE__*/jsx("span", {
75
- [dataAttr]: '',
76
- ref: ref,
77
- style: {
78
- display: 'contents'
79
- },
80
- children: child
81
- });
82
- }
83
- return /*#__PURE__*/jsx(EventopFeatureScopeContext.Provider, {
84
- value: id,
85
- children: wrapped
86
- });
87
- }
88
-
89
- function EventopStep({
90
- children,
91
- feature,
92
- index,
93
- parentStep,
94
- waitFor,
95
- advanceOn
96
- }) {
97
- const registry = useRegistry();
98
- const featureScope = useFeatureScope();
99
- const featureId = feature || featureScope;
100
- const ref = useRef(null);
101
- if (!featureId) {
102
- console.warn('[Eventop] <EventopStep> needs either a feature prop or an <EventopTarget> ancestor.');
103
- }
104
- if (index == null) {
105
- console.warn('[Eventop] <EventopStep> requires an index prop.');
106
- }
107
- const dataAttr = `data-evtp-step-${featureId}-${parentStep != null ? `${parentStep}-` : ''}${index}`;
108
- const selector = `[${dataAttr}]`;
109
- useEffect(() => {
110
- if (!featureId || index == null) return;
111
- registry.registerStep(featureId, index, parentStep ?? null, {
112
- selector,
113
- waitFor: waitFor || null,
114
- advanceOn: advanceOn ? {
115
- selector,
116
- ...advanceOn
117
- } : null
118
- });
119
- return () => registry.unregisterStep(featureId, index, parentStep ?? null);
120
- }, [featureId, index, parentStep]);
121
- const child = Children.only(children);
122
- let wrapped;
123
- try {
124
- wrapped = /*#__PURE__*/cloneElement(child, {
125
- [dataAttr]: '',
126
- ref: node => {
127
- ref.current = node;
128
- const originalRef = child.ref;
129
- if (typeof originalRef === 'function') originalRef(node);else if (originalRef && 'current' in originalRef) originalRef.current = node;
130
- }
131
- });
132
- } catch {
133
- wrapped = /*#__PURE__*/jsx("span", {
134
- [dataAttr]: '',
135
- ref: ref,
136
- style: {
137
- display: 'contents'
138
- },
139
- children: child
140
- });
141
- }
142
- return wrapped;
143
- }
144
-
145
- // ═══════════════════════════════════════════════════════════════════════════
146
- // useEventopAI
147
- //
148
- // Access the SDK programmatic API from inside any component.
149
- // Use for stepComplete(), stepFail(), open(), close() etc.
150
- //
151
- // @example
152
- // function CheckoutForm() {
153
- // const { stepComplete, stepFail } = useEventopAI();
154
- //
155
- // async function handleNext() {
156
- // const ok = await validateEmail(email);
157
- // if (ok) stepComplete();
158
- // else stepFail('Please enter a valid email address.');
159
- // }
160
- // }
161
- // ═══════════════════════════════════════════════════════════════════════════
162
-
163
- function useEventopAI() {
164
- const sdk = () => window.Eventop;
165
- return {
166
- open: () => sdk()?.open(),
167
- close: () => sdk()?.close(),
168
- cancelTour: () => sdk()?.cancelTour(),
169
- resumeTour: () => sdk()?.resumeTour(),
170
- isActive: () => sdk()?.isActive() ?? false,
171
- isPaused: () => sdk()?.isPaused() ?? false,
172
- stepComplete: () => sdk()?.stepComplete(),
173
- stepFail: msg => sdk()?.stepFail(msg),
174
- runTour: steps => sdk()?.runTour(steps)
175
- };
176
- }
177
-
178
- // ═══════════════════════════════════════════════════════════════════════════
179
- // useEventopTour
180
- //
181
- // Reactively tracks tour state so you can render your own UI.
182
- // Polls at 300ms — lightweight enough for a status indicator.
183
- //
184
- // @example
185
- // function TourBar() {
186
- // const { isActive, isPaused, resume, cancel } = useEventopTour();
187
- // if (!isActive && !isPaused) return null;
188
- // return (
189
- // <div>
190
- // {isPaused && <button onClick={resume}>Resume tour</button>}
191
- // <button onClick={cancel}>End</button>
192
- // </div>
193
- // );
194
- // }
195
- // ═══════════════════════════════════════════════════════════════════════════
196
-
197
- function useEventopTour() {
198
- const [state, setState] = useState({
199
- isActive: false,
200
- isPaused: false
201
- });
202
- useEffect(() => {
203
- const id = setInterval(() => {
204
- const sdk = window.Eventop;
205
- if (!sdk) return;
206
- const next = {
207
- isActive: sdk.isActive(),
208
- isPaused: sdk.isPaused()
209
- };
210
- setState(prev => prev.isActive !== next.isActive || prev.isPaused !== next.isPaused ? next : prev);
211
- }, 300);
212
- return () => clearInterval(id);
213
- }, []);
214
- return {
215
- ...state,
216
- resume: useCallback(() => window.Eventop?.resumeTour(), []),
217
- cancel: useCallback(() => window.Eventop?.cancelTour(), []),
218
- open: useCallback(() => window.Eventop?.open(), []),
219
- close: useCallback(() => window.Eventop?.close(), [])
220
- };
221
- }
222
-
223
27
  /**
224
28
  * FeatureRegistry
225
29
  *
@@ -396,13 +200,17 @@ function EventopProvider({
396
200
  const registry = useRef(createFeatureRegistry()).current;
397
201
  const sdkReady = useRef(false);
398
202
  const syncToSDK = useCallback(() => {
203
+ var _window$Eventop$_upda, _window$Eventop;
399
204
  if (!sdkReady.current || !window.Eventop) return;
400
- window.Eventop._updateConfig?.({
205
+ (_window$Eventop$_upda = (_window$Eventop = window.Eventop)._updateConfig) === null || _window$Eventop$_upda === void 0 || _window$Eventop$_upda.call(_window$Eventop, {
401
206
  features: registry.snapshot()
402
207
  });
403
208
  }, [registry]);
404
209
  useEffect(() => {
405
- function boot() {
210
+ // Dynamically import core.js only in the browser
211
+ async function boot() {
212
+ // Import the core SDK (this only runs on client)
213
+ await import('./core.js').then(function (n) { return n.c; });
406
214
  window.Eventop.init({
407
215
  provider,
408
216
  config: {
@@ -422,9 +230,12 @@ function EventopProvider({
422
230
  const unsub = registry.subscribe(syncToSDK);
423
231
  return () => {
424
232
  unsub();
425
- window.Eventop?.cancelTour();
233
+ if (typeof window !== 'undefined') {
234
+ var _window$Eventop2;
235
+ (_window$Eventop2 = window.Eventop) === null || _window$Eventop2 === void 0 || _window$Eventop2.cancelTour();
236
+ }
426
237
  };
427
- }, []);
238
+ }, [provider, appName, assistantName, suggestions, theme, position, registry, syncToSDK]);
428
239
  const ctx = {
429
240
  registerFeature: registry.registerFeature,
430
241
  unregisterFeature: registry.unregisterFeature,
@@ -438,20 +249,239 @@ function EventopProvider({
438
249
  });
439
250
  }
440
251
 
441
- window.EventopAI = {
442
- init,
443
- open,
444
- close,
445
- cancelTour,
446
- resumeTour,
447
- stepComplete,
448
- stepFail,
449
- isActive,
450
- isPaused,
451
- runTour,
452
- _updateConfig,
453
- providers
454
- };
455
- var index = window.EventopAI;
252
+ function EventopTarget({
253
+ children,
254
+ id,
255
+ name,
256
+ description,
257
+ navigate,
258
+ navigateWaitFor,
259
+ advanceOn,
260
+ waitFor,
261
+ ...rest
262
+ }) {
263
+ const registry = useRegistry();
264
+ const ref = useRef(null);
265
+ const dataAttr = `data-evtp-${id}`;
266
+ const selector = `[${dataAttr}]`;
267
+ useEffect(() => {
268
+ if (!id || !name) {
269
+ console.warn('[Eventop] <EventopTarget> requires id and name props.');
270
+ return;
271
+ }
272
+ registry.registerFeature({
273
+ id,
274
+ name,
275
+ description,
276
+ selector,
277
+ navigate,
278
+ navigateWaitFor,
279
+ waitFor,
280
+ advanceOn: advanceOn ? {
281
+ selector,
282
+ ...advanceOn
283
+ } : null
284
+ });
285
+ return () => registry.unregisterFeature(id);
286
+ }, [id, name, description]);
287
+ const child = Children.only(children);
288
+ let wrapped;
289
+ try {
290
+ wrapped = /*#__PURE__*/cloneElement(child, {
291
+ [dataAttr]: '',
292
+ ref: node => {
293
+ ref.current = node;
294
+ const originalRef = child.ref;
295
+ if (typeof originalRef === 'function') originalRef(node);else if (originalRef && 'current' in originalRef) originalRef.current = node;
296
+ }
297
+ });
298
+ } catch {
299
+ wrapped = /*#__PURE__*/jsx("span", {
300
+ [dataAttr]: '',
301
+ ref: ref,
302
+ style: {
303
+ display: 'contents'
304
+ },
305
+ children: child
306
+ });
307
+ }
308
+ return /*#__PURE__*/jsx(EventopFeatureScopeContext.Provider, {
309
+ value: id,
310
+ children: wrapped
311
+ });
312
+ }
313
+
314
+ function EventopStep({
315
+ children,
316
+ feature,
317
+ index,
318
+ parentStep,
319
+ waitFor,
320
+ advanceOn
321
+ }) {
322
+ const registry = useRegistry();
323
+ const featureScope = useFeatureScope();
324
+ const featureId = feature || featureScope;
325
+ const ref = useRef(null);
326
+ if (!featureId) {
327
+ console.warn('[Eventop] <EventopStep> needs either a feature prop or an <EventopTarget> ancestor.');
328
+ }
329
+ if (index == null) {
330
+ console.warn('[Eventop] <EventopStep> requires an index prop.');
331
+ }
332
+ const dataAttr = `data-evtp-step-${featureId}-${parentStep != null ? `${parentStep}-` : ''}${index}`;
333
+ const selector = `[${dataAttr}]`;
334
+ useEffect(() => {
335
+ if (!featureId || index == null) return;
336
+ registry.registerStep(featureId, index, parentStep ?? null, {
337
+ selector,
338
+ waitFor: waitFor || null,
339
+ advanceOn: advanceOn ? {
340
+ selector,
341
+ ...advanceOn
342
+ } : null
343
+ });
344
+ return () => registry.unregisterStep(featureId, index, parentStep ?? null);
345
+ }, [featureId, index, parentStep]);
346
+ const child = Children.only(children);
347
+ let wrapped;
348
+ try {
349
+ wrapped = /*#__PURE__*/cloneElement(child, {
350
+ [dataAttr]: '',
351
+ ref: node => {
352
+ ref.current = node;
353
+ const originalRef = child.ref;
354
+ if (typeof originalRef === 'function') originalRef(node);else if (originalRef && 'current' in originalRef) originalRef.current = node;
355
+ }
356
+ });
357
+ } catch {
358
+ wrapped = /*#__PURE__*/jsx("span", {
359
+ [dataAttr]: '',
360
+ ref: ref,
361
+ style: {
362
+ display: 'contents'
363
+ },
364
+ children: child
365
+ });
366
+ }
367
+ return wrapped;
368
+ }
369
+
370
+ // ═══════════════════════════════════════════════════════════════════════════
371
+ // useEventopAI
372
+ //
373
+ // Access the SDK programmatic API from inside any component.
374
+ // Use for stepComplete(), stepFail(), open(), close() etc.
375
+ //
376
+ // @example
377
+ // function CheckoutForm() {
378
+ // const { stepComplete, stepFail } = useEventopAI();
379
+ //
380
+ // async function handleNext() {
381
+ // const ok = await validateEmail(email);
382
+ // if (ok) stepComplete();
383
+ // else stepFail('Please enter a valid email address.');
384
+ // }
385
+ // }
386
+ // ═══════════════════════════════════════════════════════════════════════════
387
+
388
+ function useEventopAI() {
389
+ const sdk = () => window.Eventop;
390
+ return {
391
+ open: () => {
392
+ var _sdk;
393
+ return (_sdk = sdk()) === null || _sdk === void 0 ? void 0 : _sdk.open();
394
+ },
395
+ close: () => {
396
+ var _sdk2;
397
+ return (_sdk2 = sdk()) === null || _sdk2 === void 0 ? void 0 : _sdk2.close();
398
+ },
399
+ cancelTour: () => {
400
+ var _sdk3;
401
+ return (_sdk3 = sdk()) === null || _sdk3 === void 0 ? void 0 : _sdk3.cancelTour();
402
+ },
403
+ resumeTour: () => {
404
+ var _sdk4;
405
+ return (_sdk4 = sdk()) === null || _sdk4 === void 0 ? void 0 : _sdk4.resumeTour();
406
+ },
407
+ isActive: () => {
408
+ var _sdk5;
409
+ return ((_sdk5 = sdk()) === null || _sdk5 === void 0 ? void 0 : _sdk5.isActive()) ?? false;
410
+ },
411
+ isPaused: () => {
412
+ var _sdk6;
413
+ return ((_sdk6 = sdk()) === null || _sdk6 === void 0 ? void 0 : _sdk6.isPaused()) ?? false;
414
+ },
415
+ stepComplete: () => {
416
+ var _sdk7;
417
+ return (_sdk7 = sdk()) === null || _sdk7 === void 0 ? void 0 : _sdk7.stepComplete();
418
+ },
419
+ stepFail: msg => {
420
+ var _sdk8;
421
+ return (_sdk8 = sdk()) === null || _sdk8 === void 0 ? void 0 : _sdk8.stepFail(msg);
422
+ },
423
+ runTour: steps => {
424
+ var _sdk9;
425
+ return (_sdk9 = sdk()) === null || _sdk9 === void 0 ? void 0 : _sdk9.runTour(steps);
426
+ }
427
+ };
428
+ }
429
+
430
+ // ═══════════════════════════════════════════════════════════════════════════
431
+ // useEventopTour
432
+ //
433
+ // Reactively tracks tour state so you can render your own UI.
434
+ // Polls at 300ms — lightweight enough for a status indicator.
435
+ //
436
+ // @example
437
+ // function TourBar() {
438
+ // const { isActive, isPaused, resume, cancel } = useEventopTour();
439
+ // if (!isActive && !isPaused) return null;
440
+ // return (
441
+ // <div>
442
+ // {isPaused && <button onClick={resume}>Resume tour</button>}
443
+ // <button onClick={cancel}>End</button>
444
+ // </div>
445
+ // );
446
+ // }
447
+ // ═══════════════════════════════════════════════════════════════════════════
448
+
449
+ function useEventopTour() {
450
+ const [state, setState] = useState({
451
+ isActive: false,
452
+ isPaused: false
453
+ });
454
+ useEffect(() => {
455
+ const id = setInterval(() => {
456
+ const sdk = window.Eventop;
457
+ if (!sdk) return;
458
+ const next = {
459
+ isActive: sdk.isActive(),
460
+ isPaused: sdk.isPaused()
461
+ };
462
+ setState(prev => prev.isActive !== next.isActive || prev.isPaused !== next.isPaused ? next : prev);
463
+ }, 300);
464
+ return () => clearInterval(id);
465
+ }, []);
466
+ return {
467
+ ...state,
468
+ resume: useCallback(() => {
469
+ var _window$Eventop;
470
+ return (_window$Eventop = window.Eventop) === null || _window$Eventop === void 0 ? void 0 : _window$Eventop.resumeTour();
471
+ }, []),
472
+ cancel: useCallback(() => {
473
+ var _window$Eventop2;
474
+ return (_window$Eventop2 = window.Eventop) === null || _window$Eventop2 === void 0 ? void 0 : _window$Eventop2.cancelTour();
475
+ }, []),
476
+ open: useCallback(() => {
477
+ var _window$Eventop3;
478
+ return (_window$Eventop3 = window.Eventop) === null || _window$Eventop3 === void 0 ? void 0 : _window$Eventop3.open();
479
+ }, []),
480
+ close: useCallback(() => {
481
+ var _window$Eventop4;
482
+ return (_window$Eventop4 = window.Eventop) === null || _window$Eventop4 === void 0 ? void 0 : _window$Eventop4.close();
483
+ }, [])
484
+ };
485
+ }
456
486
 
457
- export { EventopProvider as EventopAIProvider, EventopStep, EventopTarget, index as default, useEventopAI, useEventopTour };
487
+ export { EventopProvider as EventopAIProvider, EventopStep, EventopTarget, useEventopAI, useEventopTour };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventop/sdk",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "AI-powered guided tours for any web app. Drop-in, themeable, provider-agnostic.",
5
5
  "keywords": [
6
6
  "onboarding",
@@ -53,6 +53,7 @@
53
53
  "devDependencies": {
54
54
  "@babel/core": "^7.23.9",
55
55
  "@babel/plugin-transform-react-jsx": "^7.28.6",
56
+ "@babel/preset-env": "^7.29.0",
56
57
  "@babel/preset-react": "^7.23.3",
57
58
  "@rollup/plugin-babel": "^6.0.4",
58
59
  "@rollup/plugin-commonjs": "^25.0.7",