@quantabit/onboarding-sdk 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/dist/index.cjs ADDED
@@ -0,0 +1,742 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var sdkConfig = require('@quantabit/sdk-config');
5
+
6
+ function OnboardingFlow({
7
+ steps = [],
8
+ onComplete,
9
+ onSkip,
10
+ className = ''
11
+ }) {
12
+ const [current, setCurrent] = React.useState(0);
13
+ const step = steps[current];
14
+ if (!step) return null;
15
+ return /*#__PURE__*/React.createElement("div", {
16
+ className: `qob-flow ${className}`,
17
+ style: {
18
+ textAlign: 'center',
19
+ padding: 40,
20
+ maxWidth: 480,
21
+ margin: '0 auto'
22
+ }
23
+ }, step.image && /*#__PURE__*/React.createElement("img", {
24
+ src: step.image,
25
+ alt: "",
26
+ style: {
27
+ maxWidth: 240,
28
+ height: 'auto',
29
+ marginBottom: 24
30
+ }
31
+ }), step.icon && /*#__PURE__*/React.createElement("div", {
32
+ style: {
33
+ fontSize: 56,
34
+ marginBottom: 16
35
+ }
36
+ }, step.icon), /*#__PURE__*/React.createElement("h2", {
37
+ style: {
38
+ fontSize: 24,
39
+ fontWeight: 800,
40
+ color: '#18181b',
41
+ margin: '0 0 8px'
42
+ }
43
+ }, step.title), /*#__PURE__*/React.createElement("p", {
44
+ style: {
45
+ fontSize: 14,
46
+ color: '#71717a',
47
+ lineHeight: 1.6,
48
+ margin: '0 0 32px'
49
+ }
50
+ }, step.description), /*#__PURE__*/React.createElement("div", {
51
+ style: {
52
+ display: 'flex',
53
+ gap: 6,
54
+ justifyContent: 'center',
55
+ marginBottom: 24
56
+ }
57
+ }, steps.map((_, i) => /*#__PURE__*/React.createElement("div", {
58
+ key: i,
59
+ style: {
60
+ width: i === current ? 24 : 8,
61
+ height: 8,
62
+ borderRadius: 4,
63
+ background: i === current ? '#3b82f6' : i < current ? '#93c5fd' : '#e4e4e7',
64
+ transition: 'all 0.3s'
65
+ }
66
+ }))), /*#__PURE__*/React.createElement("div", {
67
+ style: {
68
+ display: 'flex',
69
+ gap: 12,
70
+ justifyContent: 'center'
71
+ }
72
+ }, onSkip && current < steps.length - 1 && /*#__PURE__*/React.createElement("button", {
73
+ onClick: onSkip,
74
+ style: {
75
+ padding: '10px 24px',
76
+ borderRadius: 10,
77
+ border: 'none',
78
+ background: 'transparent',
79
+ color: '#71717a',
80
+ fontSize: 14,
81
+ cursor: 'pointer'
82
+ }
83
+ }, "Skip"), /*#__PURE__*/React.createElement("button", {
84
+ onClick: () => {
85
+ if (current < steps.length - 1) setCurrent(c => c + 1);else onComplete?.();
86
+ },
87
+ style: {
88
+ padding: '10px 32px',
89
+ borderRadius: 10,
90
+ border: 'none',
91
+ background: '#3b82f6',
92
+ color: '#fff',
93
+ fontSize: 14,
94
+ fontWeight: 700,
95
+ cursor: 'pointer',
96
+ transition: 'all 0.2s'
97
+ }
98
+ }, current === steps.length - 1 ? 'Get Started' : 'Next')));
99
+ }
100
+
101
+ function SpotlightTour({
102
+ steps = [],
103
+ active = false,
104
+ onComplete,
105
+ onSkip
106
+ }) {
107
+ const [current, setCurrent] = React.useState(0);
108
+ const step = steps[current];
109
+ const [rect, setRect] = React.useState(null);
110
+ const updateRect = React.useCallback(() => {
111
+ if (!step?.target) return;
112
+ const el = document.querySelector(step.target);
113
+ if (el) {
114
+ const r = el.getBoundingClientRect();
115
+ setRect({
116
+ top: r.top - 4,
117
+ left: r.left - 4,
118
+ width: r.width + 8,
119
+ height: r.height + 8
120
+ });
121
+ }
122
+ }, [step]);
123
+ React.useEffect(() => {
124
+ if (active) {
125
+ updateRect();
126
+ window.addEventListener('resize', updateRect);
127
+ return () => window.removeEventListener('resize', updateRect);
128
+ }
129
+ }, [active, updateRect]);
130
+ if (!active || !step || !rect) return null;
131
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
132
+ style: {
133
+ position: 'fixed',
134
+ inset: 0,
135
+ zIndex: 99998
136
+ }
137
+ }, /*#__PURE__*/React.createElement("svg", {
138
+ width: "100%",
139
+ height: "100%",
140
+ style: {
141
+ position: 'absolute'
142
+ }
143
+ }, /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("mask", {
144
+ id: "qob-mask"
145
+ }, /*#__PURE__*/React.createElement("rect", {
146
+ width: "100%",
147
+ height: "100%",
148
+ fill: "white"
149
+ }), /*#__PURE__*/React.createElement("rect", {
150
+ x: rect.left,
151
+ y: rect.top,
152
+ width: rect.width,
153
+ height: rect.height,
154
+ rx: "8",
155
+ fill: "black"
156
+ }))), /*#__PURE__*/React.createElement("rect", {
157
+ width: "100%",
158
+ height: "100%",
159
+ fill: "rgba(0,0,0,0.5)",
160
+ mask: "url(#qob-mask)"
161
+ }))), /*#__PURE__*/React.createElement("div", {
162
+ style: {
163
+ position: 'fixed',
164
+ zIndex: 99999,
165
+ top: rect.top + rect.height + 12,
166
+ left: Math.max(16, Math.min(rect.left, window.innerWidth - 320)),
167
+ width: 300,
168
+ padding: 20,
169
+ borderRadius: 14,
170
+ background: '#fff',
171
+ boxShadow: '0 16px 48px rgba(0,0,0,0.15)',
172
+ animation: 'qob-pop 0.2s ease-out'
173
+ }
174
+ }, /*#__PURE__*/React.createElement("div", {
175
+ style: {
176
+ fontSize: 12,
177
+ color: '#a1a1aa',
178
+ marginBottom: 4
179
+ }
180
+ }, "Step ", current + 1, " of ", steps.length), /*#__PURE__*/React.createElement("h4", {
181
+ style: {
182
+ fontSize: 15,
183
+ fontWeight: 700,
184
+ color: '#18181b',
185
+ margin: '0 0 6px'
186
+ }
187
+ }, step.title), /*#__PURE__*/React.createElement("p", {
188
+ style: {
189
+ fontSize: 13,
190
+ color: '#71717a',
191
+ margin: '0 0 16px',
192
+ lineHeight: 1.5
193
+ }
194
+ }, step.description), /*#__PURE__*/React.createElement("div", {
195
+ style: {
196
+ display: 'flex',
197
+ justifyContent: 'space-between'
198
+ }
199
+ }, onSkip && /*#__PURE__*/React.createElement("button", {
200
+ onClick: onSkip,
201
+ style: {
202
+ border: 'none',
203
+ background: 'none',
204
+ color: '#a1a1aa',
205
+ fontSize: 12,
206
+ cursor: 'pointer'
207
+ }
208
+ }, "Skip tour"), /*#__PURE__*/React.createElement("button", {
209
+ onClick: () => {
210
+ if (current < steps.length - 1) setCurrent(c => c + 1);else {
211
+ onComplete?.();
212
+ setCurrent(0);
213
+ }
214
+ },
215
+ style: {
216
+ padding: '6px 16px',
217
+ borderRadius: 6,
218
+ border: 'none',
219
+ background: '#3b82f6',
220
+ color: '#fff',
221
+ fontSize: 12,
222
+ fontWeight: 600,
223
+ cursor: 'pointer',
224
+ marginLeft: 'auto'
225
+ }
226
+ }, current === steps.length - 1 ? 'Finish' : 'Next'))));
227
+ }
228
+
229
+ function FeatureHighlight({
230
+ title,
231
+ description,
232
+ isNew = false,
233
+ onDismiss,
234
+ position = 'top-right',
235
+ className = ''
236
+ }) {
237
+ const [visible, setVisible] = React.useState(true);
238
+ if (!visible) return null;
239
+ const dismiss = () => {
240
+ setVisible(false);
241
+ onDismiss?.();
242
+ };
243
+ return /*#__PURE__*/React.createElement("div", {
244
+ className: `qob-highlight ${className}`,
245
+ style: {
246
+ position: 'relative',
247
+ display: 'inline-block'
248
+ }
249
+ }, /*#__PURE__*/React.createElement("div", {
250
+ style: {
251
+ position: 'absolute',
252
+ ...(position === 'top-right' ? {
253
+ top: -8,
254
+ right: -8
255
+ } : position === 'top-left' ? {
256
+ top: -8,
257
+ left: -8
258
+ } : {
259
+ bottom: -8,
260
+ right: -8
261
+ }),
262
+ zIndex: 10
263
+ }
264
+ }, isNew && /*#__PURE__*/React.createElement("span", {
265
+ style: {
266
+ background: '#ef4444',
267
+ color: '#fff',
268
+ fontSize: 10,
269
+ fontWeight: 700,
270
+ padding: '1px 6px',
271
+ borderRadius: 4,
272
+ animation: 'qob-pulse 2s infinite'
273
+ }
274
+ }, "NEW")), /*#__PURE__*/React.createElement("div", {
275
+ className: "qob-tooltip",
276
+ style: {
277
+ position: 'absolute',
278
+ top: 'calc(100% + 8px)',
279
+ left: '50%',
280
+ transform: 'translateX(-50%)',
281
+ padding: '12px 16px',
282
+ borderRadius: 10,
283
+ background: '#18181b',
284
+ color: '#fff',
285
+ fontSize: 12,
286
+ width: 200,
287
+ zIndex: 100,
288
+ boxShadow: '0 8px 24px rgba(0,0,0,0.2)',
289
+ animation: 'qob-pop 0.2s ease-out'
290
+ }
291
+ }, /*#__PURE__*/React.createElement("div", {
292
+ style: {
293
+ fontWeight: 600,
294
+ marginBottom: 4
295
+ }
296
+ }, title), /*#__PURE__*/React.createElement("div", {
297
+ style: {
298
+ opacity: 0.8,
299
+ lineHeight: 1.4
300
+ }
301
+ }, description), /*#__PURE__*/React.createElement("button", {
302
+ onClick: dismiss,
303
+ style: {
304
+ border: 'none',
305
+ background: 'rgba(255,255,255,0.15)',
306
+ color: '#fff',
307
+ padding: '3px 10px',
308
+ borderRadius: 4,
309
+ fontSize: 11,
310
+ cursor: 'pointer',
311
+ marginTop: 8
312
+ }
313
+ }, "Got it")));
314
+ }
315
+
316
+ function WelcomeScreen({
317
+ title = 'Welcome!',
318
+ subtitle,
319
+ features = [],
320
+ cta = 'Get Started',
321
+ onAction,
322
+ logo,
323
+ className = ''
324
+ }) {
325
+ return /*#__PURE__*/React.createElement("div", {
326
+ className: `qob-welcome ${className}`,
327
+ style: {
328
+ textAlign: 'center',
329
+ padding: '48px 32px',
330
+ maxWidth: 560,
331
+ margin: '0 auto'
332
+ }
333
+ }, logo && /*#__PURE__*/React.createElement("div", {
334
+ style: {
335
+ marginBottom: 20
336
+ }
337
+ }, typeof logo === 'string' ? /*#__PURE__*/React.createElement("img", {
338
+ src: logo,
339
+ alt: "",
340
+ style: {
341
+ height: 48
342
+ }
343
+ }) : logo), /*#__PURE__*/React.createElement("h1", {
344
+ style: {
345
+ fontSize: 32,
346
+ fontWeight: 800,
347
+ color: '#18181b',
348
+ margin: '0 0 8px'
349
+ }
350
+ }, title), subtitle && /*#__PURE__*/React.createElement("p", {
351
+ style: {
352
+ fontSize: 16,
353
+ color: '#71717a',
354
+ margin: '0 0 32px',
355
+ lineHeight: 1.6
356
+ }
357
+ }, subtitle), features.length > 0 && /*#__PURE__*/React.createElement("div", {
358
+ style: {
359
+ display: 'grid',
360
+ gridTemplateColumns: 'repeat(auto-fit,minmax(140px,1fr))',
361
+ gap: 16,
362
+ marginBottom: 32,
363
+ textAlign: 'center'
364
+ }
365
+ }, features.map((f, i) => /*#__PURE__*/React.createElement("div", {
366
+ key: i,
367
+ style: {
368
+ padding: 16,
369
+ borderRadius: 12,
370
+ border: '1px solid #f4f4f5'
371
+ }
372
+ }, /*#__PURE__*/React.createElement("div", {
373
+ style: {
374
+ fontSize: 28,
375
+ marginBottom: 8
376
+ }
377
+ }, f.icon), /*#__PURE__*/React.createElement("div", {
378
+ style: {
379
+ fontSize: 13,
380
+ fontWeight: 600,
381
+ color: '#18181b'
382
+ }
383
+ }, f.title), f.description && /*#__PURE__*/React.createElement("div", {
384
+ style: {
385
+ fontSize: 11,
386
+ color: '#71717a',
387
+ marginTop: 4
388
+ }
389
+ }, f.description)))), /*#__PURE__*/React.createElement("button", {
390
+ onClick: onAction,
391
+ style: {
392
+ padding: '14px 40px',
393
+ borderRadius: 12,
394
+ border: 'none',
395
+ background: '#3b82f6',
396
+ color: '#fff',
397
+ fontSize: 16,
398
+ fontWeight: 700,
399
+ cursor: 'pointer',
400
+ transition: 'all 0.2s'
401
+ }
402
+ }, cta));
403
+ }
404
+
405
+ const SUPPORTED_LANGUAGES = ['en', 'zh', 'ja', 'ko'];
406
+ const messages = {
407
+ en: {
408
+ 'ob.next': 'Next',
409
+ 'ob.skip': 'Skip',
410
+ 'ob.done': 'Get Started',
411
+ 'ob.welcome': 'Welcome!'
412
+ },
413
+ zh: {
414
+ 'ob.next': '下一步',
415
+ 'ob.skip': '跳过',
416
+ 'ob.done': '开始使用',
417
+ 'ob.welcome': '欢迎!'
418
+ },
419
+ ja: {
420
+ 'ob.next': '次へ',
421
+ 'ob.skip': 'スキップ',
422
+ 'ob.done': 'はじめる',
423
+ 'ob.welcome': 'ようこそ!'
424
+ },
425
+ ko: {
426
+ 'ob.next': '다음',
427
+ 'ob.skip': '건너뛰기',
428
+ 'ob.done': '시작하기',
429
+ 'ob.welcome': '환영합니다!'
430
+ }
431
+ };
432
+ let currentLang = 'en';
433
+ function setLanguage(l) {
434
+ if (SUPPORTED_LANGUAGES.includes(l)) currentLang = l;
435
+ }
436
+ function getLanguage() {
437
+ return currentLang;
438
+ }
439
+ function t(k, params = {}) {
440
+ let text = messages[currentLang]?.[k] || messages.en?.[k] || k;
441
+ Object.entries(params).forEach(([key, val]) => {
442
+ text = text.replace(new RegExp(`\\{${key}\\}`, 'g'), val);
443
+ });
444
+ return text;
445
+ }
446
+
447
+ function Tooltip({
448
+ title,
449
+ content,
450
+ placement = 'bottom',
451
+ onNext,
452
+ onSkip,
453
+ isLast
454
+ }) {
455
+ return /*#__PURE__*/React.createElement("div", {
456
+ className: `onboarding-tooltip placement-${placement}`
457
+ }, /*#__PURE__*/React.createElement("h4", null, title), /*#__PURE__*/React.createElement("p", null, content), /*#__PURE__*/React.createElement("div", {
458
+ className: "onboarding-tooltip-actions"
459
+ }, /*#__PURE__*/React.createElement("button", {
460
+ className: "onboarding-btn text",
461
+ onClick: onSkip
462
+ }, t('skip')), /*#__PURE__*/React.createElement("button", {
463
+ className: "onboarding-btn primary",
464
+ onClick: onNext
465
+ }, isLast ? t('done') : t('next'))));
466
+ }
467
+ function CoachMark({
468
+ target,
469
+ children
470
+ }) {
471
+ return /*#__PURE__*/React.createElement("div", {
472
+ className: "onboarding-coach-mark"
473
+ }, /*#__PURE__*/React.createElement("div", {
474
+ className: "onboarding-spotlight"
475
+ }), children);
476
+ }
477
+ function StepIndicator({
478
+ total,
479
+ current
480
+ }) {
481
+ return /*#__PURE__*/React.createElement("div", {
482
+ className: "onboarding-step-indicator"
483
+ }, Array.from({
484
+ length: total
485
+ }, (_, i) => /*#__PURE__*/React.createElement("span", {
486
+ key: i,
487
+ className: `step-dot ${i === current ? 'active' : ''} ${i < current ? 'completed' : ''}`
488
+ })));
489
+ }
490
+ function TutorialOverlay({
491
+ tutorial,
492
+ currentStep,
493
+ onNext,
494
+ onPrev,
495
+ onSkip
496
+ }) {
497
+ if (!tutorial) return null;
498
+ const step = tutorial.steps[currentStep];
499
+ const isFirst = currentStep === 0;
500
+ const isLast = currentStep === tutorial.steps.length - 1;
501
+ return /*#__PURE__*/React.createElement("div", {
502
+ className: "onboarding-overlay"
503
+ }, /*#__PURE__*/React.createElement("div", {
504
+ className: "onboarding-modal"
505
+ }, /*#__PURE__*/React.createElement("h3", null, step.title), /*#__PURE__*/React.createElement("p", null, step.content), /*#__PURE__*/React.createElement(StepIndicator, {
506
+ total: tutorial.steps.length,
507
+ current: currentStep
508
+ }), /*#__PURE__*/React.createElement("div", {
509
+ className: "onboarding-modal-actions"
510
+ }, !isFirst && /*#__PURE__*/React.createElement("button", {
511
+ className: "onboarding-btn secondary",
512
+ onClick: onPrev
513
+ }, t('prev')), /*#__PURE__*/React.createElement("button", {
514
+ className: "onboarding-btn text",
515
+ onClick: onSkip
516
+ }, t('skip')), /*#__PURE__*/React.createElement("button", {
517
+ className: "onboarding-btn primary",
518
+ onClick: onNext
519
+ }, isLast ? t('done') : t('next')))));
520
+ }
521
+
522
+ /**
523
+ * Onboarding SDK - 类型定义
524
+ */
525
+
526
+ const StepType = {
527
+ HIGHLIGHT: 'highlight',
528
+ MODAL: 'modal',
529
+ TOOLTIP: 'tooltip',
530
+ COACH_MARK: 'coach_mark'
531
+ };
532
+ const TutorialStatus = {
533
+ NOT_STARTED: 'not_started',
534
+ IN_PROGRESS: 'in_progress',
535
+ COMPLETED: 'completed',
536
+ SKIPPED: 'skipped'
537
+ };
538
+ function createDefaultStep() {
539
+ return {
540
+ id: '',
541
+ type: StepType.TOOLTIP,
542
+ title: '',
543
+ content: '',
544
+ target: null,
545
+ placement: 'bottom',
546
+ order: 0,
547
+ action: null
548
+ };
549
+ }
550
+ function createDefaultTutorial() {
551
+ return {
552
+ id: '',
553
+ name: '',
554
+ description: '',
555
+ steps: [],
556
+ status: TutorialStatus.NOT_STARTED,
557
+ currentStep: 0
558
+ };
559
+ }
560
+
561
+ /**
562
+ * Onboarding SDK - API 客户端
563
+ * 新手引导系统后端接口封装
564
+ *
565
+ * 使用 BaseApiClient 基类,代码从 ~100 行简化到 ~70 行
566
+ */
567
+
568
+
569
+ /**
570
+ * 新手引导 API 客户端
571
+ */
572
+ class OnboardingApiClient extends sdkConfig.BaseApiClient {
573
+ constructor(config = {}) {
574
+ // 只需传入模块路径,所有配置自动处理
575
+ super('/onboarding', config);
576
+ }
577
+
578
+ // ============ 教程管理 ============
579
+
580
+ /**
581
+ * 获取教程列表
582
+ */
583
+ async getTutorials() {
584
+ return this.get('/tutorials');
585
+ }
586
+
587
+ /**
588
+ * 获取教程详情
589
+ * @param {string} tutorialId - 教程 ID
590
+ */
591
+ async getTutorial(tutorialId) {
592
+ return this.get(`/tutorials/${tutorialId}`);
593
+ }
594
+
595
+ /**
596
+ * 开始教程
597
+ * @param {string} tutorialId - 教程 ID
598
+ */
599
+ async startTutorial(tutorialId) {
600
+ return this.post(`/tutorials/${tutorialId}/start`);
601
+ }
602
+
603
+ /**
604
+ * 完成教程步骤
605
+ * @param {string} tutorialId - 教程 ID
606
+ * @param {string} stepId - 步骤 ID
607
+ */
608
+ async completeStep(tutorialId, stepId) {
609
+ return this.post(`/tutorials/${tutorialId}/steps/${stepId}/complete`);
610
+ }
611
+
612
+ /**
613
+ * 跳过教程
614
+ * @param {string} tutorialId - 教程 ID
615
+ */
616
+ async skipTutorial(tutorialId) {
617
+ return this.post(`/tutorials/${tutorialId}/skip`);
618
+ }
619
+
620
+ /**
621
+ * 获取整体进度
622
+ */
623
+ async getProgress() {
624
+ return this.get('/progress');
625
+ }
626
+
627
+ /**
628
+ * 重置教程进度
629
+ * @param {string} tutorialId - 教程 ID(可选,不传则重置全部)
630
+ */
631
+ async resetProgress(tutorialId = null) {
632
+ const endpoint = tutorialId ? `/tutorials/${tutorialId}/reset` : '/progress/reset';
633
+ return this.post(endpoint);
634
+ }
635
+
636
+ /**
637
+ * 获取推荐教程
638
+ */
639
+ async getRecommendedTutorials() {
640
+ return this.get('/tutorials/recommended');
641
+ }
642
+
643
+ /**
644
+ * 标记提示已读
645
+ * @param {string} tipId - 提示 ID
646
+ */
647
+ async dismissTip(tipId) {
648
+ return this.post(`/tips/${tipId}/dismiss`);
649
+ }
650
+
651
+ /**
652
+ * 获取新功能引导
653
+ */
654
+ async getNewFeatures() {
655
+ return this.get('/features/new');
656
+ }
657
+
658
+ /**
659
+ * 标记新功能已查看
660
+ * @param {string} featureId - 功能 ID
661
+ */
662
+ async markFeatureSeen(featureId) {
663
+ return this.post(`/features/${featureId}/seen`);
664
+ }
665
+ }
666
+
667
+ // 创建默认实例
668
+ const onboardingApi = new OnboardingApiClient();
669
+
670
+ /**
671
+ * Onboarding SDK - React Hooks
672
+ */
673
+ function useTutorials() {
674
+ const [tutorials, setTutorials] = React.useState([]);
675
+ const [loading, setLoading] = React.useState(true);
676
+ React.useEffect(() => {
677
+ onboardingApi.getTutorials().then(setTutorials).finally(() => setLoading(false));
678
+ }, []);
679
+ return {
680
+ tutorials,
681
+ loading
682
+ };
683
+ }
684
+ function useTutorial(id) {
685
+ const [tutorial, setTutorial] = React.useState(null);
686
+ const [currentStep, setCurrentStep] = React.useState(0);
687
+ const [loading, setLoading] = React.useState(true);
688
+ React.useEffect(() => {
689
+ if (id) onboardingApi.getTutorial(id).then(setTutorial).finally(() => setLoading(false));
690
+ }, [id]);
691
+ const nextStep = React.useCallback(() => {
692
+ if (tutorial && currentStep < tutorial.steps.length - 1) {
693
+ onboardingApi.completeStep(id, tutorial.steps[currentStep].id);
694
+ setCurrentStep(s => s + 1);
695
+ }
696
+ }, [id, tutorial, currentStep]);
697
+ const prevStep = React.useCallback(() => setCurrentStep(s => Math.max(0, s - 1)), []);
698
+ const skip = React.useCallback(() => onboardingApi.skipTutorial(id), [id]);
699
+ return {
700
+ tutorial,
701
+ currentStep,
702
+ nextStep,
703
+ prevStep,
704
+ skip,
705
+ loading
706
+ };
707
+ }
708
+ function useOnboardingProgress() {
709
+ const [progress, setProgress] = React.useState(null);
710
+ const [loading, setLoading] = React.useState(true);
711
+ React.useEffect(() => {
712
+ onboardingApi.getProgress().then(setProgress).finally(() => setLoading(false));
713
+ }, []);
714
+ return {
715
+ progress,
716
+ loading
717
+ };
718
+ }
719
+
720
+ exports.CoachMark = CoachMark;
721
+ exports.FeatureHighlight = FeatureHighlight;
722
+ exports.OnboardingApiClient = OnboardingApiClient;
723
+ exports.OnboardingFlow = OnboardingFlow;
724
+ exports.SUPPORTED_LANGUAGES = SUPPORTED_LANGUAGES;
725
+ exports.SpotlightTour = SpotlightTour;
726
+ exports.StepIndicator = StepIndicator;
727
+ exports.StepType = StepType;
728
+ exports.Tooltip = Tooltip;
729
+ exports.TutorialOverlay = TutorialOverlay;
730
+ exports.TutorialStatus = TutorialStatus;
731
+ exports.WelcomeScreen = WelcomeScreen;
732
+ exports.createDefaultStep = createDefaultStep;
733
+ exports.createDefaultTutorial = createDefaultTutorial;
734
+ exports.getLanguage = getLanguage;
735
+ exports.messages = messages;
736
+ exports.onboardingApi = onboardingApi;
737
+ exports.setLanguage = setLanguage;
738
+ exports.t = t;
739
+ exports.useOnboardingProgress = useOnboardingProgress;
740
+ exports.useTutorial = useTutorial;
741
+ exports.useTutorials = useTutorials;
742
+ //# sourceMappingURL=index.cjs.map