@eventop/sdk 1.1.3 → 1.1.4

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