@destyler/tour 0.0.7-beta.1

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,918 @@
1
+ 'use strict';
2
+
3
+ const anatomy$1 = require('@zag-js/anatomy');
4
+ const core = require('@zag-js/core');
5
+ const domQuery = require('@zag-js/dom-query');
6
+ const popper = require('@zag-js/popper');
7
+ const dismissable = require('@zag-js/dismissable');
8
+ const focusTrap = require('@zag-js/focus-trap');
9
+ const interactOutside = require('@zag-js/interact-outside');
10
+ const utils = require('@zag-js/utils');
11
+ const types = require('@zag-js/types');
12
+
13
+ const anatomy = anatomy$1.createAnatomy("tour").parts(
14
+ "content",
15
+ "actionTrigger",
16
+ "closeTrigger",
17
+ "progressText",
18
+ "title",
19
+ "description",
20
+ "positioner",
21
+ "arrow",
22
+ "arrowTip",
23
+ "backdrop",
24
+ "spotlight"
25
+ );
26
+ const parts = anatomy.build();
27
+
28
+ const dom = domQuery.createScope({
29
+ getPositionerId: (ctx) => ctx.ids?.positioner ?? `tour-positioner-${ctx.id}`,
30
+ getContentId: (ctx) => ctx.ids?.content ?? `tour-content-${ctx.id}`,
31
+ getTitleId: (ctx) => ctx.ids?.title ?? `tour-title-${ctx.id}`,
32
+ getDescriptionId: (ctx) => ctx.ids?.description ?? `tour-desc-${ctx.id}`,
33
+ getArrowId: (ctx) => ctx.ids?.arrow ?? `tour-arrow-${ctx.id}`,
34
+ getBackdropId: (ctx) => ctx.ids?.backdrop ?? `tour-backdrop-${ctx.id}`,
35
+ getContentEl: (ctx) => dom.getById(ctx, dom.getContentId(ctx)),
36
+ getPositionerEl: (ctx) => dom.getById(ctx, dom.getPositionerId(ctx)),
37
+ getBackdropEl: (ctx) => dom.getById(ctx, dom.getBackdropId(ctx))
38
+ });
39
+
40
+ function getClipPath(options) {
41
+ const {
42
+ radius = 0,
43
+ rootSize: { width: w, height: h },
44
+ rect: { width, height, x, y },
45
+ enabled = true
46
+ } = options;
47
+ if (!enabled)
48
+ return "";
49
+ const {
50
+ topLeft = 0,
51
+ topRight = 0,
52
+ bottomRight = 0,
53
+ bottomLeft = 0
54
+ } = typeof radius === "number" ? { topLeft: radius, topRight: radius, bottomRight: radius, bottomLeft: radius } : radius;
55
+ return `M${w},${h} H0 V0 H${w} V${h} Z M${x + topLeft},${y} a${topLeft},${topLeft},0,0,0-${topLeft},${topLeft} V${height + y - bottomLeft} a${bottomLeft},${bottomLeft},0,0,0,${bottomLeft},${bottomLeft} H${width + x - bottomRight} a${bottomRight},${bottomRight},0,0,0,${bottomRight}-${bottomRight} V${y + topRight} a${topRight},${topRight},0,0,0-${topRight}-${topRight} Z`;
56
+ }
57
+
58
+ function isTooltipStep(step) {
59
+ return step?.type === "tooltip";
60
+ }
61
+ function isTooltipPlacement(placement) {
62
+ return placement != null && placement !== "center";
63
+ }
64
+ function normalizeStep(step) {
65
+ if (step.type === "floating") {
66
+ return { backdrop: false, arrow: false, placement: "bottom-end", ...step };
67
+ }
68
+ if (step.target == null || step.type === "dialog") {
69
+ return { type: "dialog", placement: "center", backdrop: true, ...step };
70
+ }
71
+ if (!step.type || step.type === "tooltip") {
72
+ return { type: "tooltip", arrow: true, backdrop: true, ...step };
73
+ }
74
+ return step;
75
+ }
76
+ function findStep(steps, id) {
77
+ const res = id != null ? steps.find((step) => step.id === id) : null;
78
+ return res ? normalizeStep(res) : null;
79
+ }
80
+ function findStepIndex(steps, id) {
81
+ return id != null ? steps.findIndex((step) => step.id === id) : -1;
82
+ }
83
+
84
+ function connect(state, send, normalize) {
85
+ const open = state.hasTag("open");
86
+ const steps = Array.from(state.context.steps);
87
+ const stepIndex = state.context.stepIndex;
88
+ const step = state.context.step;
89
+ const hasTarget = typeof step?.target?.() !== "undefined";
90
+ const hasNextStep = state.context.hasNextStep;
91
+ const hasPrevStep = state.context.hasPrevStep;
92
+ const firstStep = state.context.isFirstStep;
93
+ const lastStep = state.context.isLastStep;
94
+ const placement = state.context.currentPlacement;
95
+ const targetRect = state.context.targetRect;
96
+ const popperStyles = popper.getPlacementStyles({
97
+ strategy: "absolute",
98
+ placement: isTooltipPlacement(placement) ? placement : void 0
99
+ });
100
+ const clipPath = getClipPath({
101
+ enabled: isTooltipStep(step),
102
+ rect: targetRect,
103
+ rootSize: state.context.boundarySize,
104
+ radius: state.context.spotlightRadius
105
+ });
106
+ const actionMap = {
107
+ next() {
108
+ send({ type: "STEP.NEXT", src: "actionTrigger" });
109
+ },
110
+ prev() {
111
+ send({ type: "STEP.PREV", src: "actionTrigger" });
112
+ },
113
+ dismiss() {
114
+ send({ type: "DISMISS", src: "actionTrigger" });
115
+ },
116
+ goto(id) {
117
+ send({ type: "STEP.SET", value: id, src: "actionTrigger" });
118
+ }
119
+ };
120
+ return {
121
+ open,
122
+ totalSteps: steps.length,
123
+ stepIndex,
124
+ step,
125
+ hasNextStep,
126
+ hasPrevStep,
127
+ firstStep,
128
+ lastStep,
129
+ addStep(step2) {
130
+ const next = steps.concat(step2);
131
+ send({ type: "STEPS.SET", value: next, src: "addStep" });
132
+ },
133
+ removeStep(id) {
134
+ const next = steps.filter((step2) => step2.id !== id);
135
+ send({ type: "STEPS.SET", value: next, src: "removeStep" });
136
+ },
137
+ updateStep(id, stepOverrides) {
138
+ const next = steps.map((step2) => step2.id === id ? core.mergeProps(step2, stepOverrides) : step2);
139
+ send({ type: "STEPS.SET", value: next, src: "updateStep" });
140
+ },
141
+ setSteps(steps2) {
142
+ send({ type: "STEPS.SET", value: steps2, src: "setSteps" });
143
+ },
144
+ setStep(id) {
145
+ send({ type: "STEP.SET", value: id });
146
+ },
147
+ start(id) {
148
+ send({ type: "START", id });
149
+ },
150
+ isValidStep(id) {
151
+ return steps.some((step2) => step2.id === id);
152
+ },
153
+ isCurrentStep(id) {
154
+ return Boolean(step?.id === id);
155
+ },
156
+ next() {
157
+ send({ type: "STEP.NEXT" });
158
+ },
159
+ prev() {
160
+ send({ type: "STEP.PREV" });
161
+ },
162
+ getProgressPercent() {
163
+ return stepIndex / steps.length * 100;
164
+ },
165
+ getProgressText() {
166
+ const effectiveSteps = steps.filter((step2) => step2.type !== "wait");
167
+ const index = findStepIndex(effectiveSteps, step?.id);
168
+ const details = { current: index, total: effectiveSteps.length };
169
+ return state.context.translations.progressText?.(details) ?? "";
170
+ },
171
+ getBackdropProps() {
172
+ return normalize.element({
173
+ ...parts.backdrop.attrs,
174
+ "id": dom.getBackdropId(state.context),
175
+ "dir": state.context.dir,
176
+ "hidden": !open,
177
+ "data-state": open ? "open" : "closed",
178
+ "style": {
179
+ clipPath: isTooltipStep(step) ? `path("${clipPath}")` : void 0,
180
+ position: "absolute",
181
+ inset: "0",
182
+ willChange: "clip-path"
183
+ }
184
+ });
185
+ },
186
+ getSpotlightProps() {
187
+ return normalize.element({
188
+ ...parts.spotlight.attrs,
189
+ hidden: !open || !step?.target?.(),
190
+ style: {
191
+ position: "absolute",
192
+ width: `${targetRect.width}px`,
193
+ height: `${targetRect.height}px`,
194
+ left: `${targetRect.x}px`,
195
+ top: `${targetRect.y}px`,
196
+ borderRadius: `${state.context.spotlightRadius}px`,
197
+ pointerEvents: "none"
198
+ }
199
+ });
200
+ },
201
+ getProgressTextProps() {
202
+ return normalize.element({
203
+ ...parts.progressText.attrs
204
+ });
205
+ },
206
+ getPositionerProps() {
207
+ return normalize.element({
208
+ ...parts.positioner.attrs,
209
+ "dir": state.context.dir,
210
+ "id": dom.getPositionerId(state.context),
211
+ "data-type": step?.type,
212
+ "data-placement": state.context.currentPlacement,
213
+ "style": step?.type === "tooltip" ? popperStyles.floating : { zIndex: domQuery.MAX_Z_INDEX }
214
+ });
215
+ },
216
+ getArrowProps() {
217
+ return normalize.element({
218
+ id: dom.getArrowId(state.context),
219
+ ...parts.arrow.attrs,
220
+ dir: state.context.dir,
221
+ hidden: step?.type !== "tooltip",
222
+ style: step?.type === "tooltip" ? popperStyles.arrow : void 0,
223
+ opacity: hasTarget ? void 0 : 0
224
+ });
225
+ },
226
+ getArrowTipProps() {
227
+ return normalize.element({
228
+ ...parts.arrowTip.attrs,
229
+ dir: state.context.dir,
230
+ style: popperStyles.arrowTip
231
+ });
232
+ },
233
+ getContentProps() {
234
+ return normalize.element({
235
+ ...parts.content.attrs,
236
+ "id": dom.getContentId(state.context),
237
+ "dir": state.context.dir,
238
+ "role": "alertdialog",
239
+ "aria-modal": "true",
240
+ "aria-live": "polite",
241
+ "aria-atomic": "true",
242
+ "hidden": !open,
243
+ "data-state": open ? "open" : "closed",
244
+ "data-type": step?.type,
245
+ "data-placement": state.context.currentPlacement,
246
+ "data-step": step?.id,
247
+ "aria-labelledby": dom.getTitleId(state.context),
248
+ "aria-describedby": dom.getDescriptionId(state.context),
249
+ "tabIndex": -1,
250
+ "style": { zIndex: domQuery.MAX_Z_INDEX },
251
+ onKeyDown(event) {
252
+ if (event.defaultPrevented)
253
+ return;
254
+ if (!state.context.keyboardNavigation)
255
+ return;
256
+ const isRtl = state.context.dir === "rtl";
257
+ switch (event.key) {
258
+ case "ArrowRight":
259
+ if (!hasNextStep)
260
+ return;
261
+ send({ type: isRtl ? "STEP.PREV" : "STEP.NEXT", src: "keydown" });
262
+ break;
263
+ case "ArrowLeft":
264
+ if (!hasPrevStep)
265
+ return;
266
+ send({ type: isRtl ? "STEP.NEXT" : "STEP.PREV", src: "keydown" });
267
+ break;
268
+ }
269
+ }
270
+ });
271
+ },
272
+ getTitleProps() {
273
+ return normalize.element({
274
+ ...parts.title.attrs,
275
+ "id": dom.getTitleId(state.context),
276
+ "data-placement": hasTarget ? state.context.currentPlacement : "center"
277
+ });
278
+ },
279
+ getDescriptionProps() {
280
+ return normalize.element({
281
+ ...parts.description.attrs,
282
+ "id": dom.getDescriptionId(state.context),
283
+ "data-placement": hasTarget ? state.context.currentPlacement : "center"
284
+ });
285
+ },
286
+ getCloseTriggerProps() {
287
+ return normalize.element({
288
+ ...parts.closeTrigger.attrs,
289
+ "data-type": step?.type,
290
+ "aria-label": state.context.translations.close,
291
+ "onClick": actionMap.dismiss
292
+ });
293
+ },
294
+ getActionTriggerProps(props) {
295
+ const { action, attrs } = props.action;
296
+ let actionProps = {};
297
+ switch (action) {
298
+ case "next":
299
+ actionProps = {
300
+ "data-type": "next",
301
+ "disabled": !hasNextStep,
302
+ "data-disabled": domQuery.dataAttr(!hasNextStep),
303
+ "aria-label": state.context.translations.nextStep,
304
+ "onClick": actionMap.next
305
+ };
306
+ break;
307
+ case "prev":
308
+ actionProps = {
309
+ "data-type": "prev",
310
+ "disabled": !hasPrevStep,
311
+ "data-disabled": domQuery.dataAttr(!hasPrevStep),
312
+ "aria-label": state.context.translations.prevStep,
313
+ "onClick": actionMap.prev
314
+ };
315
+ break;
316
+ case "dismiss":
317
+ actionProps = {
318
+ "data-type": "close",
319
+ "aria-label": state.context.translations.close,
320
+ "onClick": actionMap.dismiss
321
+ };
322
+ break;
323
+ default:
324
+ actionProps = {
325
+ "data-type": "custom",
326
+ onClick() {
327
+ if (typeof action === "function") {
328
+ action(actionMap);
329
+ }
330
+ }
331
+ };
332
+ break;
333
+ }
334
+ return normalize.button({
335
+ ...parts.actionTrigger.attrs,
336
+ type: "button",
337
+ ...attrs,
338
+ ...actionProps
339
+ });
340
+ }
341
+ };
342
+ }
343
+
344
+ function getFrameElement(win) {
345
+ return win.parent && Object.getPrototypeOf(win.parent) ? win.frameElement : null;
346
+ }
347
+ function normalizeEventPoint(event) {
348
+ let clientX = event.clientX;
349
+ let clientY = event.clientY;
350
+ let win = event.view || window;
351
+ let frame = getFrameElement(win);
352
+ while (frame) {
353
+ const iframeRect = frame.getBoundingClientRect();
354
+ const css = getComputedStyle(frame);
355
+ const left = iframeRect.left + (frame.clientLeft + Number.parseFloat(css.paddingLeft));
356
+ const top = iframeRect.top + (frame.clientTop + Number.parseFloat(css.paddingTop));
357
+ clientX += left;
358
+ clientY += top;
359
+ win = domQuery.getWindow(frame);
360
+ frame = getFrameElement(win);
361
+ }
362
+ return { clientX, clientY };
363
+ }
364
+ function isEventInRect(rect, event) {
365
+ const { clientX, clientY } = normalizeEventPoint(event);
366
+ return rect.y <= clientY && clientY <= rect.y + rect.height && rect.x <= clientX && clientX <= rect.x + rect.width;
367
+ }
368
+ function offset(r, i) {
369
+ const dx = i.x || 0;
370
+ const dy = i.y || 0;
371
+ return {
372
+ x: r.x - dx,
373
+ y: r.y - dy,
374
+ width: r.width + dx + dx,
375
+ height: r.height + dy + dy
376
+ };
377
+ }
378
+
379
+ const { and } = core.guards;
380
+ const invoke = {
381
+ stepChange(ctx) {
382
+ const effectiveLength = ctx.steps.filter((step) => step.type !== "wait").length;
383
+ const progress = (ctx.stepIndex + 1) / effectiveLength;
384
+ ctx.onStepChange?.({
385
+ complete: ctx.isLastStep,
386
+ stepId: ctx.stepId,
387
+ totalSteps: ctx.steps.length,
388
+ stepIndex: ctx.stepIndex,
389
+ progress
390
+ });
391
+ ctx._effectCleanup?.();
392
+ ctx._effectCleanup = void 0;
393
+ },
394
+ statusChange(ctx, status) {
395
+ ctx.onStatusChange?.({
396
+ status,
397
+ stepId: ctx.stepId,
398
+ stepIndex: ctx.stepIndex
399
+ });
400
+ }
401
+ };
402
+ const set = {
403
+ step(ctx, idx) {
404
+ const step = ctx.steps[idx];
405
+ if (!step) {
406
+ ctx.stepId = null;
407
+ invoke.stepChange(ctx);
408
+ return;
409
+ }
410
+ if (utils.isEqual(ctx.stepId, step.id))
411
+ return;
412
+ const update = (data) => {
413
+ ctx.steps[idx] = { ...step, ...data };
414
+ };
415
+ const next = () => {
416
+ const idx2 = utils.nextIndex(ctx.steps, ctx.stepIndex);
417
+ ctx.stepId = ctx.steps[idx2].id;
418
+ invoke.stepChange(ctx);
419
+ };
420
+ const goto = (id) => {
421
+ const idx2 = ctx.steps.findIndex((s) => s.id === id);
422
+ ctx.stepId = ctx.steps[idx2].id;
423
+ invoke.stepChange(ctx);
424
+ };
425
+ const dismiss = () => {
426
+ ctx.stepId = null;
427
+ invoke.stepChange(ctx);
428
+ invoke.statusChange(ctx, "dismissed");
429
+ };
430
+ const show = () => {
431
+ ctx.stepId = step.id;
432
+ invoke.stepChange(ctx);
433
+ };
434
+ if (!step.effect) {
435
+ show();
436
+ return;
437
+ }
438
+ ctx._effectCleanup = step.effect({
439
+ show,
440
+ next,
441
+ update,
442
+ target: step.target,
443
+ dismiss,
444
+ goto
445
+ });
446
+ }
447
+ };
448
+ function machine(userContext) {
449
+ const ctx = utils.compact(userContext);
450
+ return core.createMachine(
451
+ {
452
+ id: "tour",
453
+ initial: "tour.inactive",
454
+ context: {
455
+ stepId: null,
456
+ steps: [],
457
+ preventInteraction: false,
458
+ closeOnInteractOutside: true,
459
+ closeOnEscape: true,
460
+ keyboardNavigation: true,
461
+ spotlightOffset: { x: 10, y: 10 },
462
+ spotlightRadius: 4,
463
+ translations: {
464
+ nextStep: "next step",
465
+ prevStep: "previous step",
466
+ close: "close tour",
467
+ progressText: ({ current, total }) => `${current + 1} of ${total}`,
468
+ skip: "skip tour",
469
+ ...ctx.translations
470
+ },
471
+ ...ctx,
472
+ resolvedTarget: core.ref({ value: null }),
473
+ targetRect: core.ref({ width: 0, height: 0, x: 0, y: 0 }),
474
+ boundarySize: core.ref({ width: 0, height: 0 })
475
+ },
476
+ computed: {
477
+ stepIndex: (ctx2) => findStepIndex(ctx2.steps, ctx2.stepId),
478
+ step: (ctx2) => findStep(ctx2.steps, ctx2.stepId),
479
+ hasNextStep: (ctx2) => ctx2.stepIndex < ctx2.steps.length - 1,
480
+ hasPrevStep: (ctx2) => ctx2.stepIndex > 0,
481
+ isFirstStep: (ctx2) => ctx2.stepIndex === 0,
482
+ isLastStep: (ctx2) => ctx2.stepIndex === ctx2.steps.length - 1
483
+ },
484
+ created: ["validateSteps"],
485
+ watch: {
486
+ stepId: ["setResolvedTarget", "raiseStepChange", "syncTargetAttrs"]
487
+ },
488
+ activities: ["trackBoundarySize"],
489
+ exit: ["clearStep", "cleanupFns"],
490
+ on: {
491
+ "STEPS.SET": {
492
+ actions: ["setSteps"]
493
+ },
494
+ "STEP.SET": {
495
+ actions: ["setStep"]
496
+ },
497
+ "STEP.NEXT": {
498
+ actions: ["setNextStep"]
499
+ },
500
+ "STEP.PREV": {
501
+ actions: ["setPrevStep"]
502
+ },
503
+ "STEP.CHANGED": [
504
+ {
505
+ guard: and("isValidStep", "hasResolvedTarget"),
506
+ target: "target.scrolling"
507
+ },
508
+ {
509
+ guard: and("isValidStep", "hasTarget"),
510
+ target: "target.resolving"
511
+ },
512
+ {
513
+ guard: and("isValidStep", "isWaitingStep"),
514
+ target: "step.waiting"
515
+ },
516
+ {
517
+ guard: "isValidStep",
518
+ target: "tour.active"
519
+ }
520
+ ],
521
+ "DISMISS": [
522
+ {
523
+ guard: "isLastStep",
524
+ target: "tour.inactive",
525
+ actions: ["invokeOnDismiss", "invokeOnComplete", "clearStep"]
526
+ },
527
+ {
528
+ target: "tour.inactive",
529
+ actions: ["invokeOnDismiss", "clearStep"]
530
+ }
531
+ ]
532
+ },
533
+ states: {
534
+ "tour.inactive": {
535
+ tags: ["closed"],
536
+ on: {
537
+ START: {
538
+ actions: ["setInitialStep", "invokeOnStart"]
539
+ }
540
+ }
541
+ },
542
+ "target.resolving": {
543
+ tags: ["closed"],
544
+ activities: ["waitForTarget"],
545
+ after: {
546
+ MISSING_TARGET_TIMEOUT: {
547
+ target: "tour.inactive",
548
+ actions: ["invokeOnNotFound", "clearStep"]
549
+ }
550
+ },
551
+ on: {
552
+ "TARGET.RESOLVED": {
553
+ target: "target.scrolling",
554
+ actions: ["setResolvedTarget"]
555
+ }
556
+ }
557
+ },
558
+ "target.scrolling": {
559
+ tags: ["open"],
560
+ entry: ["scrollToTarget"],
561
+ activities: [
562
+ "trapFocus",
563
+ "trackPlacement",
564
+ "trackDismissableBranch",
565
+ "trackInteractOutside",
566
+ "trackEscapeKeydown"
567
+ ],
568
+ after: {
569
+ 100: "tour.active"
570
+ }
571
+ },
572
+ "step.waiting": {
573
+ tags: ["closed"]
574
+ },
575
+ "tour.active": {
576
+ tags: ["open"],
577
+ activities: [
578
+ "trapFocus",
579
+ "trackPlacement",
580
+ "trackDismissableBranch",
581
+ "trackInteractOutside",
582
+ "trackEscapeKeydown"
583
+ ]
584
+ }
585
+ }
586
+ },
587
+ {
588
+ delays: {
589
+ MISSING_TARGET_TIMEOUT: 3e3
590
+ },
591
+ guards: {
592
+ isLastStep: (ctx2) => ctx2.isLastStep,
593
+ isValidStep: (ctx2) => ctx2.stepId != null,
594
+ hasTarget: (ctx2) => ctx2.step?.target != null,
595
+ hasResolvedTarget: (ctx2) => ctx2.resolvedTarget.value != null,
596
+ isWaitingStep: (ctx2) => ctx2.step?.type === "wait"
597
+ },
598
+ actions: {
599
+ scrollToTarget(ctx2, _evt) {
600
+ const node = ctx2.resolvedTarget.value;
601
+ node?.scrollIntoView({ behavior: "instant", block: "center", inline: "center" });
602
+ },
603
+ setStep(ctx2, evt) {
604
+ set.step(ctx2, evt.value);
605
+ },
606
+ clearStep(ctx2) {
607
+ ctx2.targetRect = core.ref({ width: 0, height: 0, x: 0, y: 0 });
608
+ set.step(ctx2, -1);
609
+ },
610
+ setInitialStep(ctx2, evt) {
611
+ if (ctx2.steps.length === 0)
612
+ return;
613
+ if (utils.isString(evt.id)) {
614
+ const idx = findStepIndex(ctx2.steps, evt.id);
615
+ set.step(ctx2, idx);
616
+ return;
617
+ }
618
+ set.step(ctx2, 0);
619
+ },
620
+ setNextStep(ctx2) {
621
+ const idx = utils.nextIndex(ctx2.steps, ctx2.stepIndex);
622
+ set.step(ctx2, idx);
623
+ },
624
+ setPrevStep(ctx2) {
625
+ const idx = utils.prevIndex(ctx2.steps, ctx2.stepIndex);
626
+ set.step(ctx2, idx);
627
+ },
628
+ invokeOnStart(ctx2) {
629
+ invoke.statusChange(ctx2, "started");
630
+ },
631
+ invokeOnDismiss(ctx2) {
632
+ invoke.statusChange(ctx2, "dismissed");
633
+ },
634
+ invokeOnComplete(ctx2) {
635
+ invoke.statusChange(ctx2, "completed");
636
+ },
637
+ invokeOnSkip(ctx2) {
638
+ invoke.statusChange(ctx2, "skipped");
639
+ },
640
+ invokeOnNotFound(ctx2) {
641
+ invoke.statusChange(ctx2, "not-found");
642
+ },
643
+ raiseStepChange(_ctx, _evt, { send }) {
644
+ send({ type: "STEP.CHANGED" });
645
+ },
646
+ setResolvedTarget(ctx2, evt) {
647
+ const node = evt.node ?? ctx2.step?.target?.();
648
+ ctx2.resolvedTarget.value = node ?? null;
649
+ },
650
+ syncTargetAttrs(ctx2) {
651
+ ctx2._targetCleanup?.();
652
+ ctx2._targetCleanup = void 0;
653
+ const targetEl = ctx2.resolvedTarget.value;
654
+ if (!targetEl)
655
+ return;
656
+ if (ctx2.preventInteraction)
657
+ targetEl.inert = true;
658
+ targetEl.setAttribute("data-tour-highlighted", "");
659
+ ctx2._targetCleanup = () => {
660
+ if (ctx2.preventInteraction)
661
+ targetEl.inert = false;
662
+ targetEl.removeAttribute("data-tour-highlighted");
663
+ };
664
+ },
665
+ cleanupFns(ctx2) {
666
+ ctx2._targetCleanup?.();
667
+ ctx2._targetCleanup = void 0;
668
+ ctx2._effectCleanup?.();
669
+ ctx2._effectCleanup = void 0;
670
+ },
671
+ validateSteps(ctx2) {
672
+ const ids = /* @__PURE__ */ new Set();
673
+ ctx2.steps.forEach((step) => {
674
+ if (ids.has(step.id)) {
675
+ throw new Error(`[destyler/tour] Duplicate step id: ${step.id}`);
676
+ }
677
+ if (step.target == null && step.type == null) {
678
+ throw new Error(`[destyler/tour] Step ${step.id} has no target or type. At least one of those is required.`);
679
+ }
680
+ ids.add(step.id);
681
+ });
682
+ }
683
+ },
684
+ activities: {
685
+ waitForTarget(ctx2, _evt, { send }) {
686
+ const targetEl = ctx2.step?.target;
687
+ const win = dom.getWin(ctx2);
688
+ const rootNode = dom.getRootNode(ctx2);
689
+ const observer = new win.MutationObserver(() => {
690
+ const node = targetEl?.();
691
+ if (node) {
692
+ send({ type: "TARGET.RESOLVED", node });
693
+ observer.disconnect();
694
+ }
695
+ });
696
+ observer.observe(rootNode, {
697
+ childList: true,
698
+ subtree: true,
699
+ characterData: true
700
+ });
701
+ return () => {
702
+ observer.disconnect();
703
+ };
704
+ },
705
+ trackBoundarySize(ctx2) {
706
+ const win = dom.getWin(ctx2);
707
+ const doc = dom.getDoc(ctx2);
708
+ const onResize = () => {
709
+ const width = visualViewport?.width ?? win.innerWidth;
710
+ const height = doc.documentElement.scrollHeight;
711
+ ctx2.boundarySize = { width, height };
712
+ };
713
+ onResize();
714
+ const viewport = win.visualViewport ?? win;
715
+ viewport.addEventListener("resize", onResize);
716
+ return () => viewport.removeEventListener("resize", onResize);
717
+ },
718
+ trackEscapeKeydown(ctx2, _evt, { send }) {
719
+ if (!ctx2.closeOnEscape)
720
+ return;
721
+ const doc = dom.getDoc(ctx2);
722
+ const onKeyDown = (event) => {
723
+ if (event.key === "Escape") {
724
+ event.preventDefault();
725
+ event.stopPropagation();
726
+ send({ type: "DISMISS", src: "esc" });
727
+ }
728
+ };
729
+ doc.addEventListener("keydown", onKeyDown, true);
730
+ return () => {
731
+ doc.removeEventListener("keydown", onKeyDown, true);
732
+ };
733
+ },
734
+ trackInteractOutside(ctx2, _evt, { send }) {
735
+ if (ctx2.step == null)
736
+ return;
737
+ const contentEl = () => dom.getContentEl(ctx2);
738
+ return interactOutside.trackInteractOutside(contentEl, {
739
+ defer: true,
740
+ exclude(target) {
741
+ return domQuery.contains(ctx2.step?.target?.(), target);
742
+ },
743
+ onFocusOutside(event) {
744
+ ctx2.onFocusOutside?.(event);
745
+ if (!ctx2.closeOnInteractOutside) {
746
+ event.preventDefault();
747
+ }
748
+ },
749
+ onPointerDownOutside(event) {
750
+ ctx2.onPointerDownOutside?.(event);
751
+ const isWithin = isEventInRect(ctx2.targetRect, event.detail.originalEvent);
752
+ if (isWithin) {
753
+ event.preventDefault();
754
+ return;
755
+ }
756
+ if (!ctx2.closeOnInteractOutside) {
757
+ event.preventDefault();
758
+ }
759
+ },
760
+ onInteractOutside(event) {
761
+ ctx2.onInteractOutside?.(event);
762
+ if (event.defaultPrevented)
763
+ return;
764
+ send({ type: "DISMISS", src: "interact-outside" });
765
+ }
766
+ });
767
+ },
768
+ trackDismissableBranch(ctx2) {
769
+ if (ctx2.step == null)
770
+ return;
771
+ const contentEl = () => dom.getContentEl(ctx2);
772
+ return dismissable.trackDismissableBranch(contentEl, { defer: !contentEl() });
773
+ },
774
+ trapFocus(ctx2) {
775
+ const contentEl = () => dom.getContentEl(ctx2);
776
+ return focusTrap.trapFocus(contentEl, {
777
+ escapeDeactivates: false,
778
+ allowOutsideClick: true,
779
+ preventScroll: true,
780
+ returnFocusOnDeactivate: false
781
+ });
782
+ },
783
+ trackPlacement(ctx2) {
784
+ if (ctx2.step == null)
785
+ return;
786
+ ctx2.currentPlacement = ctx2.step.placement ?? "bottom";
787
+ if (!isTooltipStep(ctx2.step))
788
+ return;
789
+ const positionerEl = () => dom.getPositionerEl(ctx2);
790
+ return popper.getPlacement(ctx2.resolvedTarget.value, positionerEl, {
791
+ defer: true,
792
+ placement: ctx2.step.placement ?? "bottom",
793
+ strategy: "absolute",
794
+ gutter: 10,
795
+ offset: ctx2.step.offset,
796
+ getAnchorRect(el) {
797
+ if (!domQuery.isHTMLElement(el))
798
+ return null;
799
+ const rect = el.getBoundingClientRect();
800
+ return offset(rect, ctx2.spotlightOffset);
801
+ },
802
+ onComplete(data) {
803
+ const { rects } = data.middlewareData;
804
+ ctx2.currentPlacement = data.placement;
805
+ ctx2.targetRect = rects.reference;
806
+ }
807
+ });
808
+ }
809
+ }
810
+ }
811
+ );
812
+ }
813
+
814
+ const props = types.createProps()([
815
+ "closeOnEscape",
816
+ "closeOnInteractOutside",
817
+ "dir",
818
+ "getRootNode",
819
+ "id",
820
+ "ids",
821
+ "keyboardNavigation",
822
+ "onFocusOutside",
823
+ "onInteractOutside",
824
+ "onPointerDownOutside",
825
+ "onStatusChange",
826
+ "onStepChange",
827
+ "preventInteraction",
828
+ "spotlightOffset",
829
+ "spotlightRadius",
830
+ "stepId",
831
+ "steps",
832
+ "translations"
833
+ ]);
834
+ const splitProps = utils.createSplitProps(props);
835
+
836
+ function waitForPromise(promise, controller, timeout) {
837
+ const { signal } = controller;
838
+ const wrappedPromise = new Promise((resolve, reject) => {
839
+ const timeoutId = setTimeout(() => {
840
+ reject(new Error(`Timeout of ${timeout}ms exceeded`));
841
+ }, timeout);
842
+ signal.addEventListener("abort", () => {
843
+ clearTimeout(timeoutId);
844
+ reject(new Error("Promise aborted"));
845
+ });
846
+ promise.then((result) => {
847
+ if (!signal.aborted) {
848
+ clearTimeout(timeoutId);
849
+ resolve(result);
850
+ }
851
+ }).catch((error) => {
852
+ if (!signal.aborted) {
853
+ clearTimeout(timeoutId);
854
+ reject(error);
855
+ }
856
+ });
857
+ });
858
+ const abort = () => controller.abort();
859
+ return [wrappedPromise, abort];
860
+ }
861
+ function waitForElement(target, options) {
862
+ const { timeout, rootNode } = options;
863
+ const win = domQuery.getWindow(rootNode);
864
+ const doc = domQuery.getDocument(rootNode);
865
+ const controller = new win.AbortController();
866
+ return waitForPromise(
867
+ new Promise((resolve) => {
868
+ const el = target();
869
+ if (el) {
870
+ resolve(el);
871
+ return;
872
+ }
873
+ const observer = new win.MutationObserver(() => {
874
+ const el2 = target();
875
+ if (el2) {
876
+ observer.disconnect();
877
+ resolve(el2);
878
+ }
879
+ });
880
+ observer.observe(doc.body, {
881
+ childList: true,
882
+ subtree: true
883
+ });
884
+ }),
885
+ controller,
886
+ timeout
887
+ );
888
+ }
889
+ function waitForElementValue(target, value, options) {
890
+ const { timeout, rootNode } = options;
891
+ const win = domQuery.getWindow(rootNode);
892
+ const controller = new win.AbortController();
893
+ return waitForPromise(
894
+ new Promise((resolve) => {
895
+ const el = target();
896
+ if (!el)
897
+ return;
898
+ const checkValue = () => {
899
+ if (el.value === value) {
900
+ resolve();
901
+ el.removeEventListener("input", checkValue);
902
+ }
903
+ };
904
+ checkValue();
905
+ el.addEventListener("input", checkValue, { signal: controller.signal });
906
+ }),
907
+ controller,
908
+ timeout
909
+ );
910
+ }
911
+
912
+ exports.anatomy = anatomy;
913
+ exports.connect = connect;
914
+ exports.machine = machine;
915
+ exports.props = props;
916
+ exports.splitProps = splitProps;
917
+ exports.waitForElement = waitForElement;
918
+ exports.waitForElementValue = waitForElementValue;