demoghost 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.
@@ -0,0 +1,1855 @@
1
+ var V = Object.defineProperty;
2
+ var q = (n, t, e) => t in n ? V(n, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : n[t] = e;
3
+ var a = (n, t, e) => q(n, typeof t != "symbol" ? t + "" : t, e);
4
+ class $ extends Error {
5
+ constructor(t) {
6
+ super(t), this.name = "DemoGhostError", Object.setPrototypeOf(this, new.target.prototype);
7
+ }
8
+ }
9
+ class z extends $ {
10
+ constructor(e, i, s) {
11
+ const r = typeof s == "number" ? ` during step ${s + 1}` : "";
12
+ super(`DemoGhost could not find target "${e}" within ${i}ms${r}.`);
13
+ a(this, "target");
14
+ a(this, "timeout");
15
+ a(this, "stepIndex");
16
+ this.name = "DemoGhostTargetNotFoundError", this.target = e, this.timeout = i, this.stepIndex = s;
17
+ }
18
+ }
19
+ class x extends $ {
20
+ constructor(e, i) {
21
+ super(`DemoGhost timed out waiting for ${e} after ${i}ms.`);
22
+ a(this, "condition");
23
+ a(this, "timeout");
24
+ this.name = "DemoGhostTimeoutError", this.condition = e, this.timeout = i;
25
+ }
26
+ }
27
+ class F extends $ {
28
+ constructor(e, i) {
29
+ const s = typeof i == "number" ? ` at step ${i + 1}` : "";
30
+ super(`Playback error${s}: ${e}`);
31
+ a(this, "stepIndex");
32
+ this.name = "DemoGhostPlaybackError", this.stepIndex = i;
33
+ }
34
+ }
35
+ class Ct extends $ {
36
+ constructor(t) {
37
+ super(`Recording error: ${t}`), this.name = "DemoGhostRecordingError";
38
+ }
39
+ }
40
+ class Tt extends $ {
41
+ constructor(t) {
42
+ super(`Configuration error: ${t}`), this.name = "DemoGhostConfigurationError";
43
+ }
44
+ }
45
+ class B {
46
+ constructor() {
47
+ a(this, "handlers", /* @__PURE__ */ new Map());
48
+ }
49
+ register(t, e) {
50
+ typeof e == "function" ? this.handlers.set(t, { execute: e }) : this.handlers.set(t, e);
51
+ }
52
+ get(t) {
53
+ const e = this.handlers.get(t);
54
+ if (!e)
55
+ throw new F(
56
+ `Unknown action type "${t}". Did you forget to register it?`
57
+ );
58
+ return e;
59
+ }
60
+ has(t) {
61
+ return this.handlers.has(t);
62
+ }
63
+ }
64
+ function y(n) {
65
+ const t = n.getBoundingClientRect();
66
+ return {
67
+ x: Math.round(t.left + t.width / 2),
68
+ y: Math.round(t.top + t.height / 2)
69
+ };
70
+ }
71
+ function A(n) {
72
+ const t = n.tagName.toLowerCase();
73
+ if (t === "button" || t === "a" || t === "input" || t === "select" || t === "textarea")
74
+ return !0;
75
+ const e = n.getAttribute("role");
76
+ return e === "button" || e === "link" || e === "checkbox" || e === "menuitem" ? !0 : n.hasAttribute("onclick") || window.getComputedStyle(n).cursor === "pointer";
77
+ }
78
+ function D(n = "normal", t = !1) {
79
+ if (typeof n == "number") return n;
80
+ switch (n) {
81
+ case "instant":
82
+ return 0;
83
+ case "fast":
84
+ return 30;
85
+ case "slow":
86
+ return 180;
87
+ case "human":
88
+ return t ? 85 : Math.floor(40 + Math.random() * 100);
89
+ case "normal":
90
+ default:
91
+ return 75;
92
+ }
93
+ }
94
+ function b(n, t, e) {
95
+ let i = Object.getPrototypeOf(n);
96
+ for (; i; ) {
97
+ const s = Object.getOwnPropertyDescriptor(i, t);
98
+ if (s != null && s.set) {
99
+ s.set.call(n, e);
100
+ return;
101
+ }
102
+ i = Object.getPrototypeOf(i);
103
+ }
104
+ n[t] = e;
105
+ }
106
+ function E(n, t = !1) {
107
+ n.dispatchEvent(new Event("input", { bubbles: !0 })), t && n.dispatchEvent(new Event("change", { bubbles: !0 }));
108
+ }
109
+ async function k(n, t, e = !0) {
110
+ const i = e ? Math.max(0.1, Number(n.options.speed) || 1) : 1;
111
+ let s = Math.max(0, t / i);
112
+ for (; s > 0 && !n.signal.aborted; ) {
113
+ if (await n.waitIfPaused(), n.signal.aborted) return;
114
+ const r = Math.min(s, 50), o = performance.now();
115
+ await new Promise((c) => {
116
+ const u = () => {
117
+ clearTimeout(l), c();
118
+ }, l = setTimeout(() => {
119
+ n.signal.removeEventListener("abort", u), c();
120
+ }, r);
121
+ n.signal.addEventListener("abort", u, { once: !0 });
122
+ }), s -= performance.now() - o;
123
+ }
124
+ }
125
+ function j(n) {
126
+ n.register("move", async (t) => {
127
+ const e = t.step, i = await t.targetResolver.resolve(e.target, t.stepIndex, t.signal);
128
+ await t.scrollEngine.scrollIntoView(i);
129
+ const s = y(i);
130
+ t.cursor.setState(A(i) ? "pointer" : "default"), await t.cursor.moveTo(
131
+ s.x,
132
+ s.y,
133
+ (e.duration ?? 500) / Math.max(0.1, Number(t.options.speed) || 1)
134
+ );
135
+ }), n.register("click", async (t) => {
136
+ const e = t.step, i = await t.targetResolver.resolve(e.target, t.stepIndex, t.signal);
137
+ await t.scrollEngine.scrollIntoView(i);
138
+ const s = y(i);
139
+ t.cursor.setState(A(i) ? "pointer" : "default"), await t.cursor.moveTo(s.x, s.y, 450), !t.signal.aborted && (await t.cursor.click(e.button ?? "left"), !t.signal.aborted && (i.dispatchEvent(
140
+ new MouseEvent("mousedown", { bubbles: !0, cancelable: !0, view: window })
141
+ ), i.dispatchEvent(new MouseEvent("mouseup", { bubbles: !0, cancelable: !0, view: window })), (e.button ?? "left") === "left" ? i.click() : i.dispatchEvent(
142
+ new MouseEvent("click", { bubbles: !0, cancelable: !0, view: window, button: 1 })
143
+ ), typeof i.focus == "function" && i.focus()));
144
+ }), n.register("doubleClick", async (t) => {
145
+ const e = t.step, i = await t.targetResolver.resolve(e.target, t.stepIndex, t.signal);
146
+ await t.scrollEngine.scrollIntoView(i);
147
+ const s = y(i);
148
+ t.cursor.setState(A(i) ? "pointer" : "default"), await t.cursor.moveTo(s.x, s.y, 450), await t.cursor.doubleClick(), !t.signal.aborted && (i.click(), i.click(), i.dispatchEvent(new MouseEvent("dblclick", { bubbles: !0, cancelable: !0, view: window })));
149
+ }), n.register("rightClick", async (t) => {
150
+ const e = t.step, i = await t.targetResolver.resolve(e.target, t.stepIndex, t.signal);
151
+ await t.scrollEngine.scrollIntoView(i);
152
+ const s = y(i);
153
+ await t.cursor.moveTo(s.x, s.y, 450), await t.cursor.click("right"), !t.signal.aborted && i.dispatchEvent(
154
+ new MouseEvent("contextmenu", { bubbles: !0, cancelable: !0, view: window })
155
+ );
156
+ }), n.register("type", async (t) => {
157
+ const e = t.step, i = await t.targetResolver.resolve(e.target, t.stepIndex, t.signal);
158
+ await t.scrollEngine.scrollIntoView(i);
159
+ const s = y(i);
160
+ if (t.cursor.setState("text"), await t.cursor.moveTo(s.x, s.y, 450), await t.cursor.click(), t.signal.aborted) return;
161
+ typeof i.focus == "function" && i.focus();
162
+ const r = i;
163
+ e.clearFirst && "value" in r && (b(r, "value", ""), E(r));
164
+ const o = String(e.value || ""), c = e.speed ?? t.options.typingSpeed ?? "human", u = t.options.deterministic ?? !1;
165
+ for (let l = 0; l < o.length; l++) {
166
+ if (await t.waitIfPaused(), t.signal.aborted) return;
167
+ const h = o[l];
168
+ i.dispatchEvent(new KeyboardEvent("keydown", { key: h, bubbles: !0 })), i.dispatchEvent(new KeyboardEvent("keypress", { key: h, bubbles: !0 })), "value" in r && (b(r, "value", r.value + h), E(r)), i.dispatchEvent(new KeyboardEvent("keyup", { key: h, bubbles: !0 }));
169
+ const p = D(c, u);
170
+ p > 0 && await k(t, p);
171
+ }
172
+ "value" in r && r.dispatchEvent(new Event("change", { bubbles: !0 }));
173
+ }), n.register("clear", async (t) => {
174
+ const e = t.step, s = await t.targetResolver.resolve(e.target, t.stepIndex, t.signal);
175
+ "value" in s && (b(s, "value", ""), E(s, !0));
176
+ }), n.register("focus", async (t) => {
177
+ const e = t.step, i = await t.targetResolver.resolve(e.target, t.stepIndex, t.signal);
178
+ await t.scrollEngine.scrollIntoView(i), typeof i.focus == "function" && i.focus();
179
+ }), n.register("blur", async (t) => {
180
+ const e = t.step, i = await t.targetResolver.resolve(e.target, t.stepIndex, t.signal);
181
+ typeof i.blur == "function" && i.blur();
182
+ }), n.register("wait", async (t) => {
183
+ const e = t.step;
184
+ if (e.duration) {
185
+ await k(t, e.duration);
186
+ return;
187
+ }
188
+ if (typeof e.condition == "function") {
189
+ const i = e.timeout ?? 5e3, s = Date.now();
190
+ for (; Date.now() - s < i; ) {
191
+ if (await t.waitIfPaused(), t.signal.aborted || await e.condition()) return;
192
+ await k(t, 50, !1);
193
+ }
194
+ throw new x("custom condition", i);
195
+ }
196
+ if (e.selector) {
197
+ const i = e.timeout ?? 5e3, s = e.state ?? "visible", r = Date.now();
198
+ for (; Date.now() - r < i; ) {
199
+ if (await t.waitIfPaused(), t.signal.aborted) return;
200
+ const o = await t.targetResolver.resolveOptional(e.selector, t.signal);
201
+ if (s === "attached" && o || s === "detached" && !o) return;
202
+ if (s === "visible" && o) {
203
+ const c = o.getBoundingClientRect();
204
+ if (c.width > 0 && c.height > 0) return;
205
+ }
206
+ if (s === "hidden" && (!o || o.offsetParent === null)) return;
207
+ await k(t, 50, !1);
208
+ }
209
+ throw new x(`selector "${e.selector}" state "${s}"`, i);
210
+ }
211
+ }), n.register("scroll", async (t) => {
212
+ const e = t.step;
213
+ if (e.target) {
214
+ const i = await t.targetResolver.resolve(e.target, t.stepIndex, t.signal);
215
+ await t.scrollEngine.scrollIntoView(i, e.offset);
216
+ } else if (typeof e.x == "number" || typeof e.y == "number") {
217
+ const i = e.x ?? window.scrollX, s = e.y ?? window.scrollY;
218
+ await t.scrollEngine.scrollTo(i, s, e.behavior ?? "smooth");
219
+ }
220
+ }), n.register("scrollTo", async (t) => {
221
+ const e = t.step;
222
+ await t.scrollEngine.scrollTo(e.x, e.y, e.behavior ?? "smooth");
223
+ }), n.register("select", async (t) => {
224
+ const e = t.step, i = await t.targetResolver.resolve(
225
+ e.target,
226
+ t.stepIndex,
227
+ t.signal
228
+ );
229
+ await t.scrollEngine.scrollIntoView(i);
230
+ const s = y(i);
231
+ if (await t.cursor.moveTo(s.x, s.y, 400), await t.cursor.click(), i instanceof HTMLSelectElement) {
232
+ const r = new Set(Array.isArray(e.value) ? e.value : [e.value]);
233
+ if (i.multiple)
234
+ for (const o of Array.from(i.options)) o.selected = r.has(o.value);
235
+ else
236
+ b(i, "value", String(e.value));
237
+ E(i, !0);
238
+ }
239
+ }), n.register("check", async (t) => {
240
+ const e = t.step, i = await t.targetResolver.resolve(
241
+ e.target,
242
+ t.stepIndex,
243
+ t.signal
244
+ );
245
+ await t.scrollEngine.scrollIntoView(i);
246
+ const s = y(i);
247
+ await t.cursor.moveTo(s.x, s.y, 400), await t.cursor.click(), "checked" in i && !i.checked && (i.click(), i.checked || (b(i, "checked", !0), E(i, !0)));
248
+ }), n.register("uncheck", async (t) => {
249
+ const e = t.step, i = await t.targetResolver.resolve(
250
+ e.target,
251
+ t.stepIndex,
252
+ t.signal
253
+ );
254
+ await t.scrollEngine.scrollIntoView(i);
255
+ const s = y(i);
256
+ await t.cursor.moveTo(s.x, s.y, 400), await t.cursor.click(), "checked" in i && i.checked && (i.click(), i.checked && (b(i, "checked", !1), E(i, !0)));
257
+ }), n.register("hover", async (t) => {
258
+ const e = t.step, i = await t.targetResolver.resolve(e.target, t.stepIndex, t.signal);
259
+ await t.scrollEngine.scrollIntoView(i);
260
+ const s = y(i);
261
+ t.cursor.setState(A(i) ? "pointer" : "default"), await t.cursor.moveTo(s.x, s.y, 450), i.dispatchEvent(
262
+ new MouseEvent("mouseenter", { bubbles: !0, cancelable: !0, view: window })
263
+ ), i.dispatchEvent(
264
+ new MouseEvent("mouseover", { bubbles: !0, cancelable: !0, view: window })
265
+ ), e.duration && e.duration > 0 && await k(t, e.duration);
266
+ }), n.register("press", async (t) => {
267
+ const e = t.step;
268
+ let i = document.activeElement;
269
+ e.target && (i = await t.targetResolver.resolve(e.target, t.stepIndex, t.signal), typeof i.focus == "function" && i.focus());
270
+ const s = i || document.body;
271
+ s.dispatchEvent(new KeyboardEvent("keydown", { key: e.key, bubbles: !0 })), s.dispatchEvent(new KeyboardEvent("keypress", { key: e.key, bubbles: !0 })), s.dispatchEvent(new KeyboardEvent("keyup", { key: e.key, bubbles: !0 }));
272
+ }), n.register("highlight", async (t) => {
273
+ const e = t.step, i = await t.targetResolver.resolve(e.target, t.stepIndex, t.signal);
274
+ await t.scrollEngine.scrollIntoView(i), await t.spotlightEngine.highlight(i, {
275
+ duration: e.duration ?? 1e3,
276
+ style: e.style ?? "glow"
277
+ });
278
+ }), n.register("caption", async (t) => {
279
+ const e = t.step;
280
+ let i;
281
+ e.target && (i = await t.targetResolver.resolveOptional(e.target, t.signal) || void 0), t.spotlightEngine.showCaption(e.options, i), e.options.duration && (await k(t, e.options.duration), t.spotlightEngine.hideCaption());
282
+ }), n.register("drag", async (t) => {
283
+ const e = t.step, i = await t.targetResolver.resolve(e.source, t.stepIndex, t.signal), s = await t.targetResolver.resolve(e.target, t.stepIndex, t.signal);
284
+ await t.scrollEngine.scrollIntoView(i);
285
+ const r = y(i), o = y(s);
286
+ await t.cursor.moveTo(r.x, r.y, 400), t.cursor.setState("active"), await t.cursor.click(), i.dispatchEvent(
287
+ new MouseEvent("mousedown", { bubbles: !0, clientX: r.x, clientY: r.y })
288
+ ), i.dispatchEvent(
289
+ new DragEvent("dragstart", { bubbles: !0, clientX: r.x, clientY: r.y })
290
+ ), await t.cursor.moveTo(o.x, o.y, e.duration ?? 700), s.dispatchEvent(
291
+ new DragEvent("dragover", { bubbles: !0, clientX: o.x, clientY: o.y })
292
+ ), s.dispatchEvent(
293
+ new DragEvent("drop", { bubbles: !0, clientX: o.x, clientY: o.y })
294
+ ), s.dispatchEvent(
295
+ new MouseEvent("mouseup", { bubbles: !0, clientX: o.x, clientY: o.y })
296
+ ), t.cursor.setState("default");
297
+ });
298
+ }
299
+ class W {
300
+ constructor(t = 5e3) {
301
+ a(this, "defaultTimeout");
302
+ this.defaultTimeout = t;
303
+ }
304
+ async resolve(t, e, i) {
305
+ const s = await this.find(t, void 0, i);
306
+ if (s) return s;
307
+ if (i != null && i.aborted)
308
+ throw new DOMException("Playback stopped", "AbortError");
309
+ const r = this.normalizeTarget(t), o = r.selector, c = r.timeout;
310
+ throw new z(
311
+ typeof o == "string" ? o : "<HTMLElement>",
312
+ c,
313
+ e
314
+ );
315
+ }
316
+ async resolveOptional(t, e) {
317
+ try {
318
+ return await this.find(t, 100, e);
319
+ } catch {
320
+ return null;
321
+ }
322
+ }
323
+ normalizeTarget(t) {
324
+ if (typeof t == "string" || typeof HTMLElement < "u" && t instanceof HTMLElement)
325
+ return { selector: t, timeout: this.defaultTimeout };
326
+ const e = t;
327
+ return {
328
+ selector: e.selector,
329
+ timeout: e.waitForTarget ?? e.timeout ?? this.defaultTimeout,
330
+ offset: e.offset
331
+ };
332
+ }
333
+ async find(t, e, i) {
334
+ if (typeof window > "u" || !document) return null;
335
+ const s = this.normalizeTarget(t), r = s.selector, o = s.timeout, c = e !== void 0 ? e : o;
336
+ if (typeof HTMLElement < "u" && r instanceof HTMLElement)
337
+ return r;
338
+ if (typeof r != "string")
339
+ return null;
340
+ const u = r.trim(), l = this.querySingle(u);
341
+ return l || (c <= 0 || i != null && i.aborted ? null : new Promise((h) => {
342
+ let p = !1, f = null, m = null, v = null;
343
+ const C = () => {
344
+ p = !0, f && clearTimeout(f), m && (m.disconnect(), m = null), v !== null && typeof cancelAnimationFrame < "u" && (cancelAnimationFrame(v), v = null), i == null || i.removeEventListener("abort", L);
345
+ }, L = () => {
346
+ C(), h(null);
347
+ }, M = () => {
348
+ if (p) return;
349
+ const P = this.querySingle(u);
350
+ P && (C(), h(P));
351
+ };
352
+ f = setTimeout(() => {
353
+ C(), h(null);
354
+ }, c), typeof MutationObserver < "u" && (m = new MutationObserver(() => {
355
+ M();
356
+ }), m.observe(document.body || document.documentElement, {
357
+ childList: !0,
358
+ subtree: !0,
359
+ attributes: !0
360
+ })), typeof requestAnimationFrame < "u" && (v = requestAnimationFrame(M)), i == null || i.addEventListener("abort", L, { once: !0 });
361
+ }));
362
+ }
363
+ querySingle(t) {
364
+ if (t.includes(":has-text(") || t.includes(":contains(") || t.startsWith("text="))
365
+ return this.queryByText(t);
366
+ try {
367
+ if (t.startsWith("@")) {
368
+ const s = t.slice(1), r = document.querySelector(
369
+ `[data-demoghost-id="${CSS.escape(s)}"]`
370
+ );
371
+ if (r) return r;
372
+ }
373
+ const e = document.querySelector(t);
374
+ if (e) return e;
375
+ const i = this.pierceShadow(document.body, t);
376
+ if (i) return i;
377
+ } catch {
378
+ if (t.includes(":contains(") || t.includes(":has-text("))
379
+ return this.queryByText(t);
380
+ }
381
+ return null;
382
+ }
383
+ queryByText(t) {
384
+ let e = "*", i = "", s = !1;
385
+ if (t.startsWith("text="))
386
+ i = t.slice(5).trim(), (i.startsWith('"') && i.endsWith('"') || i.startsWith("'") && i.endsWith("'")) && (i = i.slice(1, -1), s = !0);
387
+ else {
388
+ const o = t.match(/^(.*?):(has-text|contains)\(\s*(["']?)(.*?)\3\s*\)$/i);
389
+ if (!o) return null;
390
+ e = o[1].trim() || "*";
391
+ const c = o[2].toLowerCase();
392
+ i = o[4].replace(/\\([\\"'])/g, "$1").trim(), s = c === "contains";
393
+ }
394
+ if (!i) return null;
395
+ const r = i.toLowerCase();
396
+ try {
397
+ const o = Array.from(document.querySelectorAll(e)), c = [];
398
+ for (const u of o) {
399
+ const l = (u.textContent || "").trim();
400
+ s ? l.toLowerCase() === r && c.push(u) : l.toLowerCase().includes(r) && c.push(u);
401
+ }
402
+ return c.length === 0 ? null : (c.sort((u, l) => u.contains(l) ? 1 : l.contains(u) ? -1 : 0), c[0] || null);
403
+ } catch {
404
+ return null;
405
+ }
406
+ }
407
+ pierceShadow(t, e) {
408
+ if (!t) return null;
409
+ try {
410
+ const s = t.querySelector(e);
411
+ if (s) return s;
412
+ } catch {
413
+ }
414
+ const i = Array.from(t.children || []);
415
+ for (const s of i) {
416
+ if (s.shadowRoot) {
417
+ const o = this.pierceShadow(s.shadowRoot, e);
418
+ if (o) return o;
419
+ }
420
+ const r = this.pierceShadow(s, e);
421
+ if (r) return r;
422
+ }
423
+ return null;
424
+ }
425
+ }
426
+ const U = (n) => n * n * n * (n * (n * 6 - 15) + 10);
427
+ function Y(n, t, e, i, s) {
428
+ const r = 1 - s, o = s * s, c = r * r, u = c * r, l = o * s;
429
+ return {
430
+ x: u * n.x + 3 * c * s * t.x + 3 * r * o * e.x + l * i.x,
431
+ y: u * n.y + 3 * c * s * t.y + 3 * r * o * e.y + l * i.y
432
+ };
433
+ }
434
+ function X(n, t, e = !1) {
435
+ const i = t.x - n.x, s = t.y - n.y, r = Math.hypot(i, s);
436
+ if (r < 10)
437
+ return [
438
+ { x: n.x + i * 0.3, y: n.y + s * 0.3 },
439
+ { x: n.x + i * 0.7, y: n.y + s * 0.7 }
440
+ ];
441
+ const o = -s / r, c = i / r, u = Math.min(r * 0.25, 80), l = e ? 0.6 : 0.4 + Math.random() * 0.6, h = e || Math.random() > 0.5 ? 1 : -1, p = u * l * h, f = u * (l * 0.7) * h, m = {
442
+ x: n.x + i * 0.25 + o * p,
443
+ y: n.y + s * 0.25 + c * p
444
+ }, v = {
445
+ x: n.x + i * 0.75 + o * f,
446
+ y: n.y + s * 0.75 + c * f
447
+ };
448
+ return [m, v];
449
+ }
450
+ class K {
451
+ constructor(t = {}) {
452
+ a(this, "element", null);
453
+ a(this, "pointerMode");
454
+ a(this, "config");
455
+ a(this, "position", { x: 100, y: 100 });
456
+ a(this, "activeAnimation", null);
457
+ a(this, "activeAnimationResolve", null);
458
+ a(this, "pendingTimers", /* @__PURE__ */ new Map());
459
+ a(this, "ripples", /* @__PURE__ */ new Set());
460
+ a(this, "container");
461
+ a(this, "deterministic");
462
+ a(this, "prefersReducedMotion", !1);
463
+ this.pointerMode = t.pointerMode ?? "cursor", this.config = t.cursor ?? { style: "classic" }, this.container = t.container ?? (typeof document < "u" ? document.body : null), this.deterministic = t.deterministic ?? !1, typeof window < "u" && window.matchMedia && (this.prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches), this.mount();
464
+ }
465
+ mount() {
466
+ typeof document > "u" || !this.container || (this.element = document.createElement("div"), this.element.className = `dg-cursor dg-cursor--${this.pointerMode}`, this.element.setAttribute("aria-hidden", "true"), this.element.style.transform = `translate3d(${this.position.x}px, ${this.position.y}px, 0)`, this.renderCursorGraphic(), this.container.appendChild(this.element));
467
+ }
468
+ renderCursorGraphic() {
469
+ if (!this.element) return;
470
+ if (this.config.customElement) {
471
+ this.element.innerHTML = "", this.element.appendChild(this.config.customElement.cloneNode(!0));
472
+ return;
473
+ }
474
+ if (this.config.customSvg) {
475
+ this.element.innerHTML = this.config.customSvg;
476
+ return;
477
+ }
478
+ if (this.pointerMode === "touch") {
479
+ this.element.innerHTML = `
480
+ <div class="dg-touch-orb">
481
+ <div class="dg-touch-inner"></div>
482
+ </div>
483
+ `;
484
+ return;
485
+ }
486
+ switch (this.config.style ?? "classic") {
487
+ case "dot":
488
+ this.element.innerHTML = '<div class="dg-cursor-dot"></div>';
489
+ break;
490
+ case "minimal":
491
+ this.element.innerHTML = `
492
+ <svg class="dg-cursor-svg dg-cursor-minimal" width="20" height="20" viewBox="0 0 24 24" fill="none">
493
+ <circle cx="12" cy="12" r="6" fill="var(--demoghost-accent, #6366f1)" />
494
+ <circle cx="12" cy="12" r="9" stroke="white" stroke-width="2" />
495
+ </svg>
496
+ `;
497
+ break;
498
+ case "pointer":
499
+ this.element.innerHTML = `
500
+ <svg class="dg-cursor-svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor">
501
+ <path d="M7 11V4a2 2 0 0 1 4 0v5M11 9V6a2 2 0 0 1 4 0v3M15 9V7a2 2 0 0 1 4 0v7a6 6 0 0 1-6 6H9a6 6 0 0 1-6-6v-3a2 2 0 0 1 4 0v2" fill="var(--demoghost-cursor, #0f172a)" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
502
+ </svg>
503
+ `;
504
+ break;
505
+ case "classic":
506
+ this.element.innerHTML = `
507
+ <svg class="dg-cursor-svg" width="26" height="26" viewBox="0 0 24 24" fill="none">
508
+ <path d="M5.5 3.21V20.8c0 .45.54.67.85.35l4.86-4.86a.5.5 0 0 1 .35-.15h6.87c.45 0 .67-.54.35-.85L6.35 2.86a.5.5 0 0 0-.85.35Z"
509
+ fill="var(--demoghost-cursor, #0f172a)"
510
+ stroke="white"
511
+ stroke-width="1.5"
512
+ stroke-linejoin="round"/>
513
+ </svg>
514
+ `;
515
+ break;
516
+ default:
517
+ this.element.innerHTML = `
518
+ <svg class="dg-cursor-svg" width="26" height="26" viewBox="0 0 24 24" fill="none">
519
+ <path d="M5.5 3.21V20.8c0 .45.54.67.85.35l4.86-4.86a.5.5 0 0 1 .35-.15h6.87c.45 0 .67-.54.35-.85L6.35 2.86a.5.5 0 0 0-.85.35Z"
520
+ fill="var(--demoghost-cursor, #0f172a)"
521
+ stroke="white"
522
+ stroke-width="1.5"
523
+ stroke-linejoin="round"/>
524
+ </svg>
525
+ `;
526
+ break;
527
+ }
528
+ }
529
+ async moveTo(t, e, i = 600) {
530
+ this.finishActiveAnimation();
531
+ const s = { ...this.position }, r = { x: t, y: e };
532
+ if (this.prefersReducedMotion || i <= 0) {
533
+ this.updatePosition(r);
534
+ return;
535
+ }
536
+ const o = X(s, r, this.deterministic), c = o[0], u = o[1];
537
+ return new Promise((l) => {
538
+ this.activeAnimationResolve = l;
539
+ const h = performance.now(), p = (f) => {
540
+ const m = f - h, v = Math.min(m / i, 1), C = U(v), L = Y(s, c, u, r, C);
541
+ this.updatePosition(L), v < 1 ? this.activeAnimation = requestAnimationFrame(p) : (this.updatePosition(r), this.activeAnimation = null, this.activeAnimationResolve = null, l());
542
+ };
543
+ this.activeAnimation = requestAnimationFrame(p);
544
+ });
545
+ }
546
+ async click(t = "left") {
547
+ this.element && (this.element.classList.add("dg-cursor--active"), this.createRipple(), await this.wait(120), this.element && this.element.classList.remove("dg-cursor--active"));
548
+ }
549
+ async doubleClick() {
550
+ await this.click(), await this.wait(80), await this.click();
551
+ }
552
+ createRipple() {
553
+ if (typeof document > "u" || !this.container) return;
554
+ const t = document.createElement("div");
555
+ t.className = "dg-click-ripple", t.style.left = `${this.position.x}px`, t.style.top = `${this.position.y}px`, this.container.appendChild(t), this.ripples.add(t), this.schedule(600, () => this.removeRipple(t));
556
+ }
557
+ wait(t) {
558
+ return new Promise((e) => this.schedule(t, e));
559
+ }
560
+ schedule(t, e) {
561
+ const i = setTimeout(() => {
562
+ this.pendingTimers.delete(i), e();
563
+ }, t);
564
+ this.pendingTimers.set(i, e);
565
+ }
566
+ removeRipple(t) {
567
+ t.remove(), this.ripples.delete(t);
568
+ }
569
+ finishActiveAnimation() {
570
+ if (this.activeAnimation !== null && (cancelAnimationFrame(this.activeAnimation), this.activeAnimation = null), this.activeAnimationResolve) {
571
+ const t = this.activeAnimationResolve;
572
+ this.activeAnimationResolve = null, t();
573
+ }
574
+ }
575
+ show() {
576
+ this.element && (this.element.style.opacity = "1", this.element.style.pointerEvents = "none");
577
+ }
578
+ hide() {
579
+ this.element && (this.element.style.opacity = "0");
580
+ }
581
+ setState(t) {
582
+ this.element && (this.element.classList.remove(
583
+ "dg-state-pointer",
584
+ "dg-state-text",
585
+ "dg-state-active",
586
+ "dg-state-hidden"
587
+ ), t !== "default" && this.element.classList.add(`dg-state-${t}`));
588
+ }
589
+ getPosition() {
590
+ return { ...this.position };
591
+ }
592
+ updatePosition(t) {
593
+ this.position = t, this.element && (this.element.style.transform = `translate3d(${t.x}px, ${t.y}px, 0)`);
594
+ }
595
+ destroy() {
596
+ this.finishActiveAnimation(), this.pendingTimers.forEach((t, e) => {
597
+ clearTimeout(e), t();
598
+ }), this.pendingTimers.clear();
599
+ for (const t of this.ripples) this.removeRipple(t);
600
+ this.ripples.clear(), this.element && this.element.parentNode && (this.element.parentNode.removeChild(this.element), this.element = null);
601
+ }
602
+ }
603
+ class J {
604
+ constructor(t = {}) {
605
+ a(this, "config");
606
+ a(this, "activeScroll", null);
607
+ this.config = {
608
+ behavior: "smooth",
609
+ offset: 80,
610
+ ...t
611
+ };
612
+ }
613
+ async scrollIntoView(t, e) {
614
+ if (typeof window > "u") return;
615
+ const i = e ?? this.config.offset ?? 80, s = t.getBoundingClientRect(), r = window.innerHeight || document.documentElement.clientHeight, o = window.innerWidth || document.documentElement.clientWidth, c = s.top >= i && s.bottom <= r - 20, u = s.left >= 0 && s.right <= o;
616
+ if (c && u)
617
+ return;
618
+ const l = window.scrollY || window.pageYOffset, h = Math.max(0, l + s.top - i);
619
+ await this.scrollTo(window.scrollX || window.pageXOffset, h, this.config.behavior);
620
+ }
621
+ async scrollTo(t, e, i = "smooth") {
622
+ if (typeof window > "u") return;
623
+ if (i === "instant") {
624
+ window.scrollTo(t, e);
625
+ return;
626
+ }
627
+ this.finishActiveScroll();
628
+ const s = window.scrollY, r = window.scrollX;
629
+ if (!(Math.hypot(t - r, e - s) < 5))
630
+ return window.scrollTo({ left: t, top: e, behavior: "smooth" }), new Promise((c) => {
631
+ let u = window.scrollY, l = window.scrollX, h = 0;
632
+ const p = 25, f = setInterval(() => {
633
+ const m = window.scrollY, v = window.scrollX;
634
+ h++, m === u && v === l && h > 2 || h >= p ? this.finishActiveScroll() : (u = m, l = v);
635
+ }, 30);
636
+ this.activeScroll = { interval: f, resolve: c };
637
+ });
638
+ }
639
+ finishActiveScroll() {
640
+ if (!this.activeScroll) return;
641
+ clearInterval(this.activeScroll.interval);
642
+ const t = this.activeScroll.resolve;
643
+ this.activeScroll = null, t();
644
+ }
645
+ destroy() {
646
+ this.finishActiveScroll();
647
+ }
648
+ }
649
+ class G {
650
+ constructor(t) {
651
+ a(this, "container");
652
+ a(this, "overlayEl", null);
653
+ a(this, "captionEl", null);
654
+ a(this, "activeElement", null);
655
+ a(this, "activeStyle", null);
656
+ a(this, "activeTimer", null);
657
+ a(this, "activeTimerResolve", null);
658
+ this.container = t ?? (typeof document < "u" ? document.body : null);
659
+ }
660
+ async highlight(t, e = {}) {
661
+ if (this.clearHighlight(), this.activeElement = t, this.activeStyle = e.style ?? "glow", t.classList.add(`dg-highlight-${this.activeStyle}`), this.activeStyle === "spotlight" && this.renderSpotlightOverlay(t), e.caption) {
662
+ const i = typeof e.caption == "string" ? { text: e.caption } : e.caption;
663
+ this.showCaption(i, t);
664
+ }
665
+ e.duration && e.duration > 0 && (await new Promise((i) => {
666
+ this.activeTimerResolve = i, this.activeTimer = setTimeout(() => {
667
+ this.activeTimer = null, this.activeTimerResolve = null, i();
668
+ }, e.duration);
669
+ }), this.clearHighlight());
670
+ }
671
+ clearHighlight() {
672
+ this.activeElement && this.activeStyle && (this.activeElement.classList.remove(`dg-highlight-${this.activeStyle}`), this.activeElement = null, this.activeStyle = null), this.overlayEl && this.overlayEl.parentNode && (this.overlayEl.parentNode.removeChild(this.overlayEl), this.overlayEl = null), this.hideCaption();
673
+ }
674
+ renderSpotlightOverlay(t) {
675
+ if (typeof document > "u" || !this.container) return;
676
+ this.overlayEl = document.createElement("div"), this.overlayEl.className = "dg-spotlight-backdrop", this.overlayEl.setAttribute("aria-hidden", "true");
677
+ const e = t.getBoundingClientRect(), i = 8;
678
+ this.overlayEl.style.clipPath = `polygon(
679
+ 0% 0%, 0% 100%, 100% 100%, 100% 0%,
680
+ 0% 0%,
681
+ ${e.left - i}px ${e.top - i}px,
682
+ ${e.right + i}px ${e.top - i}px,
683
+ ${e.right + i}px ${e.bottom + i}px,
684
+ ${e.left - i}px ${e.bottom + i}px,
685
+ ${e.left - i}px ${e.top - i}px
686
+ )`, this.container.appendChild(this.overlayEl);
687
+ }
688
+ showCaption(t, e) {
689
+ if (this.hideCaption(), typeof document > "u" || !this.container) return;
690
+ this.captionEl = document.createElement("div"), this.captionEl.className = "dg-caption dg-glass-panel", this.captionEl.setAttribute("role", "status");
691
+ let i = "";
692
+ if (t.title && (i += `<div class="dg-caption-title">${this.escapeHtml(t.title)}</div>`), i += `<div class="dg-caption-text">${this.escapeHtml(t.text)}</div>`, this.captionEl.innerHTML = i, this.container.appendChild(this.captionEl), e) {
693
+ const s = e.getBoundingClientRect(), r = t.position || "bottom", o = 16;
694
+ let c = 0, u = 0;
695
+ r === "top" ? (c = s.top - this.captionEl.offsetHeight - o, u = s.left + s.width / 2 - this.captionEl.offsetWidth / 2) : r === "left" ? (c = s.top + s.height / 2 - this.captionEl.offsetHeight / 2, u = s.left - this.captionEl.offsetWidth - o) : r === "right" ? (c = s.top + s.height / 2 - this.captionEl.offsetHeight / 2, u = s.right + o) : (c = s.bottom + o, u = s.left + s.width / 2 - this.captionEl.offsetWidth / 2);
696
+ const l = 12;
697
+ u = Math.max(l, Math.min(window.innerWidth - this.captionEl.offsetWidth - l, u)), c = Math.max(l, Math.min(window.innerHeight - this.captionEl.offsetHeight - l, c)), this.captionEl.style.transform = `translate3d(${Math.round(u)}px, ${Math.round(c)}px, 0)`;
698
+ } else
699
+ this.captionEl.style.bottom = "80px", this.captionEl.style.left = "50%", this.captionEl.style.transform = "translateX(-50%)";
700
+ requestAnimationFrame(() => {
701
+ this.captionEl && this.captionEl.classList.add("dg-caption--visible");
702
+ });
703
+ }
704
+ hideCaption() {
705
+ this.captionEl && this.captionEl.parentNode && (this.captionEl.parentNode.removeChild(this.captionEl), this.captionEl = null);
706
+ }
707
+ escapeHtml(t) {
708
+ const e = document.createElement("div");
709
+ return e.textContent = t, e.innerHTML;
710
+ }
711
+ destroy() {
712
+ if (this.activeTimer && (clearTimeout(this.activeTimer), this.activeTimer = null), this.activeTimerResolve) {
713
+ const t = this.activeTimerResolve;
714
+ this.activeTimerResolve = null, t();
715
+ }
716
+ this.clearHighlight();
717
+ }
718
+ }
719
+ const S = {
720
+ light: {
721
+ accent: "#6366f1",
722
+ cursor: "#0f172a",
723
+ glassBg: "rgba(255, 255, 255, 0.75)",
724
+ border: "rgba(226, 232, 240, 0.8)",
725
+ text: "#0f172a",
726
+ shadow: "0 20px 40px -15px rgba(0, 0, 0, 0.08)",
727
+ zIndexCursor: 999999,
728
+ zIndexOverlay: 999990
729
+ },
730
+ dark: {
731
+ accent: "#818cf8",
732
+ cursor: "#f8fafc",
733
+ glassBg: "rgba(15, 23, 42, 0.82)",
734
+ border: "rgba(255, 255, 255, 0.12)",
735
+ text: "#f8fafc",
736
+ shadow: "0 25px 50px -12px rgba(0, 0, 0, 0.5)",
737
+ zIndexCursor: 999999,
738
+ zIndexOverlay: 999990
739
+ },
740
+ glass: {
741
+ accent: "#6366f1",
742
+ cursor: "#0f172a",
743
+ glassBg: "rgba(255, 255, 255, 0.65)",
744
+ border: "rgba(255, 255, 255, 0.35)",
745
+ text: "#0f172a",
746
+ shadow: "0 20px 50px rgba(99, 102, 241, 0.15)",
747
+ zIndexCursor: 999999,
748
+ zIndexOverlay: 999990
749
+ }
750
+ };
751
+ class O {
752
+ static apply(t = "glass", e) {
753
+ if (typeof document > "u") return;
754
+ const i = e || document.documentElement;
755
+ let s = S.glass;
756
+ typeof t == "string" ? t === "auto" ? s = typeof window < "u" && window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? S.dark : S.light : S[t] && (s = S[t]) : typeof t == "object" && (s = { ...S.glass, ...t }), s.accent && i.style.setProperty("--demoghost-accent", s.accent), s.cursor && i.style.setProperty("--demoghost-cursor", s.cursor), s.glassBg && i.style.setProperty("--demoghost-glass-bg", s.glassBg), s.border && i.style.setProperty("--demoghost-border", s.border), s.text && i.style.setProperty("--demoghost-text", s.text), s.shadow && i.style.setProperty("--demoghost-shadow", s.shadow), s.zIndexCursor && i.style.setProperty("--demoghost-z-index-cursor", String(s.zIndexCursor)), s.zIndexOverlay && i.style.setProperty("--demoghost-z-index-overlay", String(s.zIndexOverlay));
757
+ }
758
+ }
759
+ class _ {
760
+ constructor() {
761
+ a(this, "liveRegion", null);
762
+ a(this, "previousActiveElement", null);
763
+ a(this, "keydownHandler", null);
764
+ a(this, "announcementTimer", null);
765
+ this.initLiveRegion();
766
+ }
767
+ initLiveRegion() {
768
+ typeof document > "u" || (this.liveRegion = document.createElement("div"), this.liveRegion.className = "dg-sr-only", this.liveRegion.setAttribute("role", "status"), this.liveRegion.setAttribute("aria-live", "polite"), this.liveRegion.setAttribute("aria-atomic", "true"), document.body.appendChild(this.liveRegion));
769
+ }
770
+ saveFocus() {
771
+ typeof document < "u" && document.activeElement instanceof HTMLElement && (this.previousActiveElement = document.activeElement);
772
+ }
773
+ restoreFocus() {
774
+ if (this.previousActiveElement && typeof this.previousActiveElement.focus == "function") {
775
+ try {
776
+ this.previousActiveElement.focus();
777
+ } catch {
778
+ }
779
+ this.previousActiveElement = null;
780
+ }
781
+ }
782
+ announce(t) {
783
+ this.liveRegion && (this.liveRegion.textContent = "", this.announcementTimer && clearTimeout(this.announcementTimer), this.announcementTimer = setTimeout(() => {
784
+ this.announcementTimer = null, this.liveRegion && (this.liveRegion.textContent = t);
785
+ }, 50));
786
+ }
787
+ bindKeyboardControls(t) {
788
+ typeof window > "u" || (this.keydownHandler = (e) => {
789
+ e.key === "Escape" && (e.preventDefault(), t.onStop());
790
+ }, window.addEventListener("keydown", this.keydownHandler));
791
+ }
792
+ destroy() {
793
+ this.announcementTimer && (clearTimeout(this.announcementTimer), this.announcementTimer = null), this.keydownHandler && typeof window < "u" && (window.removeEventListener("keydown", this.keydownHandler), this.keydownHandler = null), this.liveRegion && this.liveRegion.parentNode && (this.liveRegion.parentNode.removeChild(this.liveRegion), this.liveRegion = null), this.restoreFocus();
794
+ }
795
+ }
796
+ class H {
797
+ constructor() {
798
+ a(this, "listeners", {});
799
+ }
800
+ on(t, e) {
801
+ return this.listeners[t] || (this.listeners[t] = []), this.listeners[t].push(e), () => this.off(t, e);
802
+ }
803
+ off(t, e) {
804
+ const i = this.listeners[t];
805
+ i && (this.listeners[t] = i.filter((s) => s !== e));
806
+ }
807
+ emit(t, e) {
808
+ const i = this.listeners[t];
809
+ !i || i.length === 0 || [...i].forEach((s) => {
810
+ try {
811
+ s(e);
812
+ } catch (r) {
813
+ console.error(`[DemoGhost] Error in event listener for "${String(t)}":`, r);
814
+ }
815
+ });
816
+ }
817
+ removeAllListeners() {
818
+ this.listeners = {};
819
+ }
820
+ }
821
+ class Z {
822
+ constructor(t, e = {}, i, s) {
823
+ a(this, "scenario");
824
+ a(this, "options");
825
+ a(this, "actionRegistry");
826
+ a(this, "emitter");
827
+ a(this, "_state", "idle");
828
+ a(this, "_currentStep", 0);
829
+ a(this, "_speed", 1);
830
+ a(this, "abortController", null);
831
+ a(this, "pauseResolver", null);
832
+ a(this, "runPromise", null);
833
+ a(this, "enginesInitialized", !1);
834
+ a(this, "finishResolver");
835
+ a(this, "finishRejecter");
836
+ a(this, "finished");
837
+ // Sub-engines
838
+ a(this, "targetResolver");
839
+ a(this, "cursorEngine");
840
+ a(this, "scrollEngine");
841
+ a(this, "spotlightEngine");
842
+ a(this, "a11y");
843
+ this.scenario = t, this.options = e, this._speed = e.speed ?? 1, this.actionRegistry = i, this.emitter = s || new H(), this.finished = Promise.resolve(), this.resetFinishedPromise(), this.initEngines();
844
+ }
845
+ initEngines() {
846
+ typeof window > "u" || (this.enginesInitialized && this.cleanup(), O.apply(this.options.theme, this.options.container), this.targetResolver = new W(this.options.defaultTimeout ?? 5e3), this.cursorEngine = new K({
847
+ pointerMode: this.options.pointer,
848
+ cursor: this.options.cursor,
849
+ container: this.options.container,
850
+ deterministic: this.options.deterministic
851
+ }), this.scrollEngine = new J(this.options.scroll), this.spotlightEngine = new G(this.options.container), this.a11y = new _(), this.a11y.saveFocus(), this.a11y.bindKeyboardControls({
852
+ onStop: () => this.stop(),
853
+ onTogglePause: () => {
854
+ this._state === "playing" ? this.pause() : this._state === "paused" && this.resume();
855
+ }
856
+ }), this.enginesInitialized = !0);
857
+ }
858
+ resetFinishedPromise() {
859
+ this.finished = new Promise((t, e) => {
860
+ this.finishResolver = t, this.finishRejecter = e;
861
+ }), this.finished.catch(() => {
862
+ });
863
+ }
864
+ get state() {
865
+ return this._state;
866
+ }
867
+ get currentStep() {
868
+ return this._currentStep;
869
+ }
870
+ get totalSteps() {
871
+ return this.scenario.steps.length;
872
+ }
873
+ get speed() {
874
+ return this._speed;
875
+ }
876
+ set speed(t) {
877
+ this._speed = Math.max(0.1, t);
878
+ }
879
+ play() {
880
+ return this._state === "playing" ? this.runPromise ?? this.finished : this._state === "paused" ? (this.resume(), this.runPromise ?? this.finished) : this._state === "completed" || this._state === "stopped" || this._state === "error" ? this.restart() : (this.runPromise = this.runPlayback(), this.runPromise);
881
+ }
882
+ async runPlayback() {
883
+ var t;
884
+ this._state = "playing", this.abortController = new AbortController(), this.emitter.emit("start", { scenario: this.scenario });
885
+ try {
886
+ for (; this._currentStep < this.totalSteps && !(this.abortController.signal.aborted || (await this.waitIfPaused(), this.abortController.signal.aborted)); ) {
887
+ const e = this.scenario.steps[this._currentStep];
888
+ await this.executeStep(e, this._currentStep), this._currentStep++;
889
+ }
890
+ this.abortController.signal.aborted || (this._state = "completed", this.emitter.emit("complete", { scenario: this.scenario }), this.cleanup(), this.finishResolver());
891
+ } catch (e) {
892
+ if ((t = this.abortController) != null && t.signal.aborted)
893
+ return;
894
+ throw this._state = "error", this.emitter.emit("error", { error: e, stepIndex: this._currentStep }), this.cleanup(), this.finishRejecter(e), e;
895
+ } finally {
896
+ this.runPromise = null;
897
+ }
898
+ }
899
+ async executeStep(t, e) {
900
+ var c;
901
+ const i = this.actionRegistry.get(t.type), s = performance.now();
902
+ if (this.emitter.emit("step:start", { step: t, index: e, total: this.totalSteps }), this.log(`Step ${e + 1}/${this.totalSteps} -> ${t.type.toUpperCase()}`), t.caption) {
903
+ const u = typeof t.caption == "string" ? t.caption : t.caption.text;
904
+ this.a11y.announce(u);
905
+ const l = typeof t.caption == "string" ? { text: t.caption } : t.caption;
906
+ let h;
907
+ t.target && (h = await this.targetResolver.resolveOptional(t.target, (c = this.abortController) == null ? void 0 : c.signal) || void 0), this.spotlightEngine.showCaption(l, h);
908
+ }
909
+ t.delayBefore && t.delayBefore > 0 && await this.waitForDuration(t.delayBefore / this._speed);
910
+ const r = {
911
+ step: t,
912
+ stepIndex: e,
913
+ totalSteps: this.totalSteps,
914
+ targetResolver: this.targetResolver,
915
+ cursor: this.cursorEngine,
916
+ scrollEngine: this.scrollEngine,
917
+ spotlightEngine: this.spotlightEngine,
918
+ options: { ...this.options, speed: this._speed },
919
+ signal: this.abortController.signal,
920
+ isPaused: () => this._state === "paused",
921
+ waitIfPaused: () => this.waitIfPaused(),
922
+ log: (u, ...l) => this.log(u, ...l)
923
+ };
924
+ await i.execute(r), t.delayAfter && t.delayAfter > 0 && await this.waitForDuration(t.delayAfter / this._speed);
925
+ const o = Math.round(performance.now() - s);
926
+ this.log(`Step ${e + 1}/${this.totalSteps} completed in ${o}ms`), this.emitter.emit("step:complete", { step: t, index: e, total: this.totalSteps });
927
+ }
928
+ pause() {
929
+ this._state === "playing" && (this._state = "paused", this.emitter.emit("pause", void 0));
930
+ }
931
+ resume() {
932
+ this._state === "paused" && (this._state = "playing", this.pauseResolver && (this.pauseResolver(), this.pauseResolver = null), this.emitter.emit("resume", void 0));
933
+ }
934
+ stop() {
935
+ this._state === "stopped" || this._state === "completed" || (this._state = "stopped", this.abortController && this.abortController.abort(), this.pauseResolver && (this.pauseResolver(), this.pauseResolver = null), this.emitter.emit("stop", void 0), this.cleanup(), this.finishResolver());
936
+ }
937
+ async restart() {
938
+ const t = this.runPromise;
939
+ return this.stop(), t && await t.catch(() => {
940
+ }), this._currentStep = 0, this.initEngines(), this.resetFinishedPromise(), this._state = "idle", this.play();
941
+ }
942
+ async next() {
943
+ if (this._currentStep < this.totalSteps - 1) {
944
+ this._currentStep++;
945
+ const t = this.scenario.steps[this._currentStep];
946
+ await this.executeStep(t, this._currentStep);
947
+ }
948
+ }
949
+ async previous() {
950
+ if (this._currentStep > 0) {
951
+ this._currentStep--;
952
+ const t = this.scenario.steps[this._currentStep];
953
+ await this.executeStep(t, this._currentStep);
954
+ }
955
+ }
956
+ async waitIfPaused() {
957
+ this._state === "paused" && await new Promise((t) => {
958
+ this.pauseResolver = t;
959
+ });
960
+ }
961
+ async waitForDuration(t) {
962
+ var i, s;
963
+ let e = Math.max(0, t);
964
+ for (; e > 0 && !((i = this.abortController) != null && i.signal.aborted); ) {
965
+ if (await this.waitIfPaused(), (s = this.abortController) != null && s.signal.aborted) return;
966
+ const r = Math.min(e, 50), o = performance.now();
967
+ await new Promise((c) => {
968
+ var l;
969
+ const u = setTimeout(c, r);
970
+ (l = this.abortController) == null || l.signal.addEventListener(
971
+ "abort",
972
+ () => {
973
+ clearTimeout(u), c();
974
+ },
975
+ { once: !0 }
976
+ );
977
+ }), e -= performance.now() - o;
978
+ }
979
+ }
980
+ cleanup() {
981
+ this.enginesInitialized && (this.cursorEngine && this.cursorEngine.destroy(), this.scrollEngine && this.scrollEngine.destroy(), this.spotlightEngine && this.spotlightEngine.destroy(), this.a11y && this.a11y.destroy(), this.enginesInitialized = !1);
982
+ }
983
+ then(t, e) {
984
+ return this.finished.then(t, e);
985
+ }
986
+ log(t, ...e) {
987
+ this.options.debug && console.log(`[DemoGhost] ${t}`, ...e);
988
+ }
989
+ on(t, e) {
990
+ return this.emitter.on(t, e);
991
+ }
992
+ off(t, e) {
993
+ this.emitter.off(t, e);
994
+ }
995
+ }
996
+ function Q(n, t = {}) {
997
+ return { type: "move", target: n, ...t };
998
+ }
999
+ function tt(n, t = {}) {
1000
+ return { type: "click", target: n, ...t };
1001
+ }
1002
+ function et(n, t = {}) {
1003
+ return { type: "doubleClick", target: n, ...t };
1004
+ }
1005
+ function it(n, t = {}) {
1006
+ return { type: "rightClick", target: n, ...t };
1007
+ }
1008
+ function st(n, t, e = {}) {
1009
+ return { type: "type", target: n, value: t, ...e };
1010
+ }
1011
+ function nt(n, t = {}) {
1012
+ return { type: "clear", target: n, ...t };
1013
+ }
1014
+ function rt(n, t = {}) {
1015
+ return { type: "focus", target: n, ...t };
1016
+ }
1017
+ function ot(n, t = {}) {
1018
+ return { type: "blur", target: n, ...t };
1019
+ }
1020
+ function at(n, t = {}) {
1021
+ return typeof n == "number" ? { type: "wait", duration: n, ...t } : { type: "wait", condition: n, ...t };
1022
+ }
1023
+ function lt(n, t = {}) {
1024
+ return typeof n == "string" ? { type: "wait", selector: n, state: "visible", ...t } : typeof n == "function" ? { type: "wait", condition: n, ...t } : {
1025
+ type: "wait",
1026
+ selector: n.selector,
1027
+ state: n.state ?? "visible",
1028
+ timeout: n.timeout,
1029
+ ...t
1030
+ };
1031
+ }
1032
+ function ct(n, t = {}) {
1033
+ return typeof n == "string" || n && "tagName" in n ? { type: "scroll", target: n, ...t } : n && typeof n == "object" && !("type" in n) ? { type: "scroll", ...n } : { type: "scroll", ...t };
1034
+ }
1035
+ function ut(n, t, e = "smooth") {
1036
+ return { type: "scrollTo", x: n, y: t, behavior: e };
1037
+ }
1038
+ function ht(n, t, e = {}) {
1039
+ return { type: "select", target: n, value: t, ...e };
1040
+ }
1041
+ function dt(n, t = {}) {
1042
+ return { type: "check", target: n, ...t };
1043
+ }
1044
+ function pt(n, t = {}) {
1045
+ return { type: "uncheck", target: n, ...t };
1046
+ }
1047
+ function ft(n, t = 500, e = {}) {
1048
+ return { type: "hover", target: n, duration: t, ...e };
1049
+ }
1050
+ function gt(n, t = {}) {
1051
+ return { type: "press", key: n, ...t };
1052
+ }
1053
+ function mt(n, t = {}) {
1054
+ return { type: "highlight", target: n, ...t };
1055
+ }
1056
+ function vt(n, t) {
1057
+ return { type: "caption", options: typeof n == "string" ? { text: n } : n, target: t };
1058
+ }
1059
+ function yt(n, t, e = {}) {
1060
+ return { type: "drag", source: n, target: t, ...e };
1061
+ }
1062
+ const g = class g {
1063
+ static configure(t) {
1064
+ g.globalConfig = { ...g.globalConfig, ...t };
1065
+ }
1066
+ static play(t, e = {}) {
1067
+ g.activeController && (g.activeController.state === "playing" || g.activeController.state === "paused") && g.activeController.stop();
1068
+ const i = Array.isArray(t) ? { steps: t } : t, s = {
1069
+ ...g.globalConfig,
1070
+ ...e
1071
+ }, r = new Z(
1072
+ i,
1073
+ s,
1074
+ g.actions,
1075
+ g.globalEmitter
1076
+ );
1077
+ return g.activeController = r, s.autoStart !== !1 && r.play().catch((o) => {
1078
+ s.debug && console.error("[DemoGhost] Playback error:", o);
1079
+ }), r;
1080
+ }
1081
+ static create(t, e = {}) {
1082
+ return {
1083
+ play: (i = {}) => g.play(t, { ...e, ...i })
1084
+ };
1085
+ }
1086
+ static on(t, e) {
1087
+ return g.globalEmitter.on(t, e);
1088
+ }
1089
+ static off(t, e) {
1090
+ g.globalEmitter.off(t, e);
1091
+ }
1092
+ };
1093
+ a(g, "globalConfig", {}), a(g, "actions", new B()), a(g, "globalEmitter", new H()), j(g.actions), a(g, "activeController", null);
1094
+ let w = g;
1095
+ typeof window < "u" && (window.DemoGhostCore = w);
1096
+ class wt {
1097
+ constructor(t = {}) {
1098
+ a(this, "preferredAttributes");
1099
+ a(this, "ignoreClasses");
1100
+ a(this, "maxDepth");
1101
+ this.preferredAttributes = t.preferredAttributes || [
1102
+ "data-demoghost-id",
1103
+ "data-testid",
1104
+ "data-test-id",
1105
+ "data-cy",
1106
+ "data-qa",
1107
+ "data-action"
1108
+ ], this.ignoreClasses = /* @__PURE__ */ new Set([
1109
+ "dg-cursor",
1110
+ "dg-caption",
1111
+ "dg-controls",
1112
+ "active",
1113
+ "focus",
1114
+ "hover",
1115
+ "selected",
1116
+ ...t.ignoreClasses || []
1117
+ ]), this.maxDepth = t.maxDepth || 5;
1118
+ }
1119
+ generate(t) {
1120
+ if (!t || !(t instanceof HTMLElement))
1121
+ return "";
1122
+ const e = t.getAttribute("data-demoghost-id");
1123
+ if (e)
1124
+ return `[data-demoghost-id="${CSS.escape(e)}"]`;
1125
+ if (t.id && this.isValidId(t.id)) {
1126
+ const l = `#${CSS.escape(t.id)}`;
1127
+ if (this.isUnique(l))
1128
+ return l;
1129
+ }
1130
+ for (const l of this.preferredAttributes) {
1131
+ const h = t.getAttribute(l);
1132
+ if (h) {
1133
+ const p = `[${l}="${CSS.escape(h)}"]`;
1134
+ if (this.isUnique(p))
1135
+ return p;
1136
+ }
1137
+ }
1138
+ const i = ["name", "aria-label", "placeholder", "title", "alt"];
1139
+ for (const l of i) {
1140
+ const h = t.getAttribute(l);
1141
+ if (h) {
1142
+ const f = `${t.tagName.toLowerCase()}[${l}="${CSS.escape(h)}"]`;
1143
+ if (this.isUnique(f))
1144
+ return f;
1145
+ }
1146
+ }
1147
+ const s = t.getAttribute("role");
1148
+ if (s) {
1149
+ const h = `${t.tagName.toLowerCase()}[role="${CSS.escape(s)}"]`;
1150
+ if (this.isUnique(h))
1151
+ return h;
1152
+ const p = t.getAttribute("aria-label");
1153
+ if (p) {
1154
+ const f = `[role="${CSS.escape(s)}"][aria-label="${CSS.escape(p)}"]`;
1155
+ if (this.isUnique(f))
1156
+ return f;
1157
+ }
1158
+ }
1159
+ const r = t.tagName.toLowerCase();
1160
+ if (["button", "a", "h1", "h2", "h3", "label", "span"].includes(r)) {
1161
+ const l = (t.textContent || "").trim();
1162
+ if (l && l.length < 30 && !l.includes(`
1163
+ `)) {
1164
+ const h = `${r}:contains("${l.replace(/"/g, '\\"')}")`;
1165
+ if (Array.from(document.querySelectorAll(r)).filter(
1166
+ (f) => (f.textContent || "").trim() === l
1167
+ ).length === 1)
1168
+ return h;
1169
+ }
1170
+ }
1171
+ const o = t.getAttribute("type");
1172
+ if (o && ["input", "button"].includes(r)) {
1173
+ const l = `${r}[type="${CSS.escape(o)}"]`;
1174
+ if (this.isUnique(l))
1175
+ return l;
1176
+ }
1177
+ const c = this.getUniqueClassSelector(t);
1178
+ if (c)
1179
+ return c;
1180
+ const u = this.getContextualSelector(t);
1181
+ return u || this.getHierarchicalPath(t);
1182
+ }
1183
+ getContextualSelector(t) {
1184
+ let e = t.parentElement;
1185
+ for (; e && e !== document.body && e !== document.documentElement; ) {
1186
+ if (e.id && this.isValidId(e.id)) {
1187
+ const i = t.tagName.toLowerCase(), s = `#${CSS.escape(e.id)} ${i}`;
1188
+ if (this.isUnique(s)) return s;
1189
+ const r = Array.from(t.classList).filter((o) => !this.ignoreClasses.has(o));
1190
+ if (r.length > 0) {
1191
+ const o = `#${CSS.escape(e.id)} ${i}.${CSS.escape(r[0])}`;
1192
+ if (this.isUnique(o)) return o;
1193
+ }
1194
+ }
1195
+ e = e.parentElement;
1196
+ }
1197
+ return null;
1198
+ }
1199
+ isValidId(t) {
1200
+ return /^[0-9]/.test(t) || /:[a-z0-9]+:/i.test(t) || /^__/.test(t) ? !1 : /^[a-zA-Z][a-zA-Z0-9_:-]*$/.test(t);
1201
+ }
1202
+ isUnique(t) {
1203
+ try {
1204
+ return document.querySelectorAll(t).length === 1;
1205
+ } catch {
1206
+ return !1;
1207
+ }
1208
+ }
1209
+ getUniqueClassSelector(t) {
1210
+ const e = Array.from(t.classList).filter((s) => !this.ignoreClasses.has(s));
1211
+ if (e.length === 0) return null;
1212
+ const i = t.tagName.toLowerCase();
1213
+ for (const s of e) {
1214
+ const r = `${i}.${CSS.escape(s)}`;
1215
+ if (this.isUnique(r)) return r;
1216
+ }
1217
+ if (e.length > 1) {
1218
+ const s = `${i}.${e.map((r) => CSS.escape(r)).join(".")}`;
1219
+ if (this.isUnique(s)) return s;
1220
+ }
1221
+ return null;
1222
+ }
1223
+ getHierarchicalPath(t) {
1224
+ const e = [];
1225
+ let i = t, s = 0;
1226
+ for (; i && i !== document.body && i !== document.documentElement && s < this.maxDepth; ) {
1227
+ let r = i.tagName.toLowerCase();
1228
+ if (i.id && this.isValidId(i.id)) {
1229
+ r = `#${CSS.escape(i.id)}`, e.unshift(r);
1230
+ break;
1231
+ }
1232
+ const o = i.parentElement;
1233
+ if (o) {
1234
+ const u = Array.from(o.children).filter((l) => l.tagName === i.tagName);
1235
+ if (u.length > 1) {
1236
+ const l = u.indexOf(i) + 1;
1237
+ r += `:nth-of-type(${l})`;
1238
+ }
1239
+ }
1240
+ e.unshift(r);
1241
+ const c = e.join(" > ");
1242
+ if (this.isUnique(c))
1243
+ return c;
1244
+ i = o, s++;
1245
+ }
1246
+ return e.join(" > ");
1247
+ }
1248
+ }
1249
+ class bt {
1250
+ constructor(t = {}) {
1251
+ a(this, "maskPasswords");
1252
+ a(this, "maskSelectors");
1253
+ a(this, "ignoreSelectors");
1254
+ this.maskPasswords = t.maskPasswords !== !1, this.maskSelectors = [
1255
+ "[data-demoghost-private]",
1256
+ "[data-private]",
1257
+ ".secret",
1258
+ ".private",
1259
+ ".confidential",
1260
+ ...t.maskSelectors || []
1261
+ ], this.ignoreSelectors = t.ignoreSelectors || [];
1262
+ }
1263
+ shouldIgnore(t) {
1264
+ if (!t || t.closest(".dg-cursor") || t.closest(".dg-controls") || t.closest(".dg-controls-container") || t.closest(".dg-controls-hud") || t.closest(".dg-caption") || t.closest(".dg-spotlight-backdrop"))
1265
+ return !0;
1266
+ for (const e of this.ignoreSelectors)
1267
+ if (t.matches(e) || t.closest(e))
1268
+ return !0;
1269
+ return !1;
1270
+ }
1271
+ isSensitive(t) {
1272
+ if (!t) return !1;
1273
+ if (this.maskPasswords && t instanceof HTMLInputElement && t.type.toLowerCase() === "password")
1274
+ return !0;
1275
+ const e = ["name", "id", "autocomplete", "placeholder", "aria-label"].map((s) => t.getAttribute(s) || "").join(" ").toLowerCase().replace(/[^a-z0-9]+/g, ""), i = [
1276
+ "password",
1277
+ "secret",
1278
+ "creditcard",
1279
+ "cardnumber",
1280
+ "ccnumber",
1281
+ "cvv",
1282
+ "cvc",
1283
+ "csc",
1284
+ "cccsc",
1285
+ "securitycode",
1286
+ "pin",
1287
+ "passphrase",
1288
+ "ssn",
1289
+ "token",
1290
+ "apikey",
1291
+ "accesstoken",
1292
+ "clientsecret",
1293
+ "onetimecode"
1294
+ ];
1295
+ for (const s of i)
1296
+ if (e.includes(s))
1297
+ return !0;
1298
+ for (const s of this.maskSelectors)
1299
+ try {
1300
+ if (t.matches(s) || t.closest(s))
1301
+ return !0;
1302
+ } catch {
1303
+ }
1304
+ return !1;
1305
+ }
1306
+ maskValue(t, e) {
1307
+ return this.isSensitive(t) ? "••••••••" : e;
1308
+ }
1309
+ }
1310
+ class Et {
1311
+ constructor(t = {}) {
1312
+ a(this, "options");
1313
+ a(this, "selectorGen");
1314
+ a(this, "privacyMasker");
1315
+ a(this, "steps", []);
1316
+ a(this, "isRecording", !1);
1317
+ a(this, "lastActionTime", 0);
1318
+ a(this, "activeInputTimer", null);
1319
+ a(this, "activeInputElement", null);
1320
+ a(this, "activeInputValue", "");
1321
+ a(this, "clickListener", null);
1322
+ a(this, "inputListener", null);
1323
+ a(this, "changeListener", null);
1324
+ a(this, "scrollListener", null);
1325
+ a(this, "keydownListener", null);
1326
+ var e, i, s;
1327
+ this.options = {
1328
+ captureScroll: !0,
1329
+ captureKeyboard: !0,
1330
+ minWaitDuration: 600,
1331
+ ...t
1332
+ }, this.selectorGen = new wt(t.selector), this.privacyMasker = new bt({
1333
+ ...t.privacy,
1334
+ maskPasswords: t.maskPasswords ?? ((e = t.privacy) == null ? void 0 : e.maskPasswords),
1335
+ maskSelectors: t.maskSelectors ?? ((i = t.privacy) == null ? void 0 : i.maskSelectors),
1336
+ ignoreSelectors: t.ignoreSelectors ?? ((s = t.privacy) == null ? void 0 : s.ignoreSelectors)
1337
+ });
1338
+ }
1339
+ start() {
1340
+ typeof window > "u" || this.isRecording || (this.steps = [], this.isRecording = !0, this.lastActionTime = Date.now(), this.bindEvents());
1341
+ }
1342
+ stop() {
1343
+ return this.isRecording ? (this.flushActiveInput(), this.unbindEvents(), this.isRecording = !1, {
1344
+ version: 1,
1345
+ steps: [...this.steps]
1346
+ }) : { steps: this.steps };
1347
+ }
1348
+ bindEvents() {
1349
+ this.clickListener = (t) => this.handleClick(t), this.inputListener = (t) => this.handleInput(t), this.changeListener = (t) => this.handleChange(t), this.keydownListener = (t) => this.handleKeydown(t), document.addEventListener("click", this.clickListener, !0), document.addEventListener("input", this.inputListener, !0), document.addEventListener("change", this.changeListener, !0), this.options.captureKeyboard && document.addEventListener("keydown", this.keydownListener, !0), this.options.captureScroll && (this.scrollListener = () => this.handleScroll(), window.addEventListener("scroll", this.scrollListener, { passive: !0 }));
1350
+ }
1351
+ unbindEvents() {
1352
+ typeof document > "u" || (this.clickListener && document.removeEventListener("click", this.clickListener, !0), this.inputListener && document.removeEventListener("input", this.inputListener, !0), this.changeListener && document.removeEventListener("change", this.changeListener, !0), this.keydownListener && document.removeEventListener("keydown", this.keydownListener, !0), this.scrollListener && window.removeEventListener("scroll", this.scrollListener), this.clickListener = null, this.inputListener = null, this.changeListener = null, this.keydownListener = null, this.scrollListener = null);
1353
+ }
1354
+ appendWaitIfNecessary() {
1355
+ const t = Date.now(), e = t - this.lastActionTime, i = this.options.minWaitDuration ?? 600;
1356
+ if (this.steps.length > 0 && e >= i) {
1357
+ const s = Math.round(e / 100) * 100;
1358
+ this.steps.push({ type: "wait", duration: s });
1359
+ }
1360
+ this.lastActionTime = t;
1361
+ }
1362
+ handleClick(t) {
1363
+ const e = t.target;
1364
+ if (!e || this.privacyMasker.shouldIgnore(e)) return;
1365
+ this.flushActiveInput();
1366
+ const i = e.tagName.toLowerCase();
1367
+ if (i === "select" || i === "textarea" || i === "input" && !["button", "submit", "reset", "image"].includes(
1368
+ e.type.toLowerCase()
1369
+ ))
1370
+ return;
1371
+ const s = this.selectorGen.generate(e);
1372
+ s && (this.appendWaitIfNecessary(), this.steps.push({
1373
+ type: "click",
1374
+ target: s
1375
+ }));
1376
+ }
1377
+ handleInput(t) {
1378
+ const e = t.target;
1379
+ !e || this.privacyMasker.shouldIgnore(e) || this.isTextEntryElement(e) && (this.activeInputElement !== e && (this.flushActiveInput(), this.activeInputElement = e), this.activeInputValue = this.privacyMasker.isSensitive(e) ? this.privacyMasker.maskValue(e, "") : e.value, this.activeInputTimer && clearTimeout(this.activeInputTimer), this.activeInputTimer = setTimeout(() => {
1380
+ this.flushActiveInput();
1381
+ }, 500));
1382
+ }
1383
+ flushActiveInput() {
1384
+ if (this.activeInputTimer && (clearTimeout(this.activeInputTimer), this.activeInputTimer = null), !this.activeInputElement) return;
1385
+ const t = this.activeInputElement, e = this.selectorGen.generate(t);
1386
+ if (e) {
1387
+ const i = this.privacyMasker.maskValue(t, this.activeInputValue);
1388
+ this.appendWaitIfNecessary(), this.steps.push({
1389
+ type: "type",
1390
+ target: e,
1391
+ value: i,
1392
+ clearFirst: !0
1393
+ });
1394
+ }
1395
+ this.activeInputElement = null, this.activeInputValue = "";
1396
+ }
1397
+ handleChange(t) {
1398
+ const e = t.target;
1399
+ if (!e || this.privacyMasker.shouldIgnore(e)) return;
1400
+ this.flushActiveInput();
1401
+ const i = e.tagName.toLowerCase();
1402
+ if (i === "select") {
1403
+ const s = e, r = this.selectorGen.generate(s);
1404
+ r && (this.appendWaitIfNecessary(), this.steps.push({
1405
+ type: "select",
1406
+ target: r,
1407
+ value: s.value
1408
+ }));
1409
+ } else if (i === "input") {
1410
+ const s = e, r = (s.type || "text").toLowerCase();
1411
+ if (r === "checkbox" || r === "radio") {
1412
+ const o = this.selectorGen.generate(s);
1413
+ o && (this.appendWaitIfNecessary(), this.steps.push({
1414
+ type: s.checked ? "check" : "uncheck",
1415
+ target: o
1416
+ }));
1417
+ }
1418
+ }
1419
+ }
1420
+ handleKeydown(t) {
1421
+ if (t.repeat || t.isComposing) return;
1422
+ const e = t.target;
1423
+ if (!e || this.privacyMasker.shouldIgnore(e) || !(/* @__PURE__ */ new Set([
1424
+ "Enter",
1425
+ "Escape",
1426
+ "Tab",
1427
+ "ArrowUp",
1428
+ "ArrowDown",
1429
+ "ArrowLeft",
1430
+ "ArrowRight",
1431
+ "Home",
1432
+ "End",
1433
+ "PageUp",
1434
+ "PageDown"
1435
+ ])).has(t.key)) return;
1436
+ this.flushActiveInput();
1437
+ const s = e === document.body ? void 0 : this.selectorGen.generate(e);
1438
+ this.appendWaitIfNecessary(), this.steps.push({
1439
+ type: "press",
1440
+ key: t.key,
1441
+ ...s ? { target: s } : {}
1442
+ });
1443
+ }
1444
+ isTextEntryElement(t) {
1445
+ return t instanceof HTMLTextAreaElement ? !0 : t instanceof HTMLInputElement ? ![
1446
+ "button",
1447
+ "checkbox",
1448
+ "color",
1449
+ "file",
1450
+ "hidden",
1451
+ "image",
1452
+ "radio",
1453
+ "range",
1454
+ "reset",
1455
+ "submit"
1456
+ ].includes(t.type.toLowerCase()) : !1;
1457
+ }
1458
+ handleScroll() {
1459
+ const t = Date.now();
1460
+ if (t - this.lastActionTime < 1e3) return;
1461
+ const e = window.scrollY, i = window.scrollX;
1462
+ (e > 0 || i > 0) && (this.steps.push({
1463
+ type: "scrollTo",
1464
+ x: i,
1465
+ y: e,
1466
+ behavior: "smooth"
1467
+ }), this.lastActionTime = t);
1468
+ }
1469
+ }
1470
+ const kt = /* @__PURE__ */ new Set([
1471
+ "move",
1472
+ "click",
1473
+ "doubleClick",
1474
+ "rightClick",
1475
+ "type",
1476
+ "clear",
1477
+ "focus",
1478
+ "blur",
1479
+ "wait",
1480
+ "waitFor",
1481
+ "scroll",
1482
+ "scrollTo",
1483
+ "select",
1484
+ "check",
1485
+ "uncheck",
1486
+ "hover",
1487
+ "press",
1488
+ "highlight",
1489
+ "caption",
1490
+ "drag"
1491
+ ]);
1492
+ class I {
1493
+ static serialize(t) {
1494
+ return JSON.stringify(
1495
+ t,
1496
+ (e, i) => {
1497
+ if (typeof i == "function")
1498
+ throw new TypeError(
1499
+ "Function-based steps cannot be serialized. Use waitFor(selector) instead."
1500
+ );
1501
+ if (typeof HTMLElement < "u" && i instanceof HTMLElement)
1502
+ throw new TypeError(
1503
+ "HTMLElement targets cannot be serialized. Use a stable selector string."
1504
+ );
1505
+ return i;
1506
+ },
1507
+ 2
1508
+ );
1509
+ }
1510
+ static deserialize(t) {
1511
+ try {
1512
+ const e = JSON.parse(t);
1513
+ if (!e || typeof e != "object" || !Array.isArray(e.steps))
1514
+ throw new Error("Invalid scenario JSON: 'steps' array is required.");
1515
+ if (!e.steps.every(
1516
+ (i) => i !== null && typeof i == "object" && typeof i.type == "string"
1517
+ ))
1518
+ throw new Error("Invalid scenario JSON: every step requires a string 'type'.");
1519
+ return e;
1520
+ } catch (e) {
1521
+ throw new Error(`Failed to deserialize DemoGhost scenario: ${e.message}`);
1522
+ }
1523
+ }
1524
+ static toTypeScript(t) {
1525
+ const e = /* @__PURE__ */ new Set(), i = t.steps.map((o) => (kt.has(o.type) && e.add(o.type === "wait" && o.selector ? "waitFor" : o.type), this.formatStepCode(o))), s = Array.from(e).sort().join(", ");
1526
+ return `import { DemoGhost${s ? `, ${s}` : ""} } from "demoghost";
1527
+
1528
+ export const scenario = [
1529
+ ${i.join(`,
1530
+ `)}
1531
+ ];
1532
+
1533
+ await DemoGhost.play(scenario);
1534
+ `;
1535
+ }
1536
+ static toJavaScript(t) {
1537
+ return `// DemoGhost Scenario Replay
1538
+ const scenario = [
1539
+ ${t.steps.map((i) => this.formatStepCode(i, "DemoGhost.")).join(`,
1540
+ `)}
1541
+ ];
1542
+
1543
+ await DemoGhost.play(scenario);
1544
+ `;
1545
+ }
1546
+ static formatStepCode(t, e = "") {
1547
+ const i = () => this.formatValue(t.target), s = (o) => this.formatOptions(t, o), r = (o, c) => c ? `${o}, ${c})` : `${o})`;
1548
+ switch (t.type) {
1549
+ case "move":
1550
+ case "click":
1551
+ case "doubleClick":
1552
+ case "rightClick":
1553
+ case "clear":
1554
+ case "focus":
1555
+ case "blur":
1556
+ case "check":
1557
+ case "uncheck":
1558
+ case "highlight": {
1559
+ const o = s(["type", "target"]);
1560
+ return r(`${e}${t.type}(${i()}`, o);
1561
+ }
1562
+ case "type": {
1563
+ const o = s(["type", "target", "value"]);
1564
+ return r(
1565
+ `${e}type(${i()}, ${this.formatValue(t.value)}`,
1566
+ o
1567
+ );
1568
+ }
1569
+ case "wait": {
1570
+ if (t.selector) {
1571
+ const o = {
1572
+ selector: t.selector,
1573
+ ...this.pickOptions(t, ["type", "selector"])
1574
+ };
1575
+ return `${e}waitFor(${this.formatValue(o)})`;
1576
+ }
1577
+ if (typeof t.duration == "number") {
1578
+ const o = s(["type", "duration"]);
1579
+ return r(`${e}wait(${t.duration}`, o);
1580
+ }
1581
+ return this.formatValue(t);
1582
+ }
1583
+ case "scroll": {
1584
+ const o = s(["type", "target"]);
1585
+ return t.target ? r(`${e}scroll(${i()}`, o) : `${e}scroll(${o})`;
1586
+ }
1587
+ case "scrollTo":
1588
+ return `${e}scrollTo(${t.x}, ${t.y}, ${this.formatValue(
1589
+ t.behavior ?? "smooth"
1590
+ )})`;
1591
+ case "select": {
1592
+ const o = s(["type", "target", "value"]);
1593
+ return r(
1594
+ `${e}select(${i()}, ${this.formatValue(t.value)}`,
1595
+ o
1596
+ );
1597
+ }
1598
+ case "hover": {
1599
+ const o = t.duration, c = s(["type", "target", "duration"]), u = `${e}hover(${i()}${o === void 0 ? "" : `, ${o}`}`;
1600
+ return r(u, c);
1601
+ }
1602
+ case "press": {
1603
+ const o = s(["type", "key"]);
1604
+ return r(`${e}press(${this.formatValue(t.key)}`, o);
1605
+ }
1606
+ case "caption":
1607
+ return `${e}caption(${this.formatValue(t.options)}${t.target ? `, ${i()}` : ""})`;
1608
+ case "drag": {
1609
+ const o = s(["type", "source", "target"]);
1610
+ return r(
1611
+ `${e}drag(${this.formatValue(t.source)}, ${i()}`,
1612
+ o
1613
+ );
1614
+ }
1615
+ default:
1616
+ return this.formatValue(t);
1617
+ }
1618
+ }
1619
+ static formatOptions(t, e) {
1620
+ const i = this.pickOptions(t, e);
1621
+ return Object.keys(i).length ? this.formatValue(i) : "";
1622
+ }
1623
+ static pickOptions(t, e) {
1624
+ return Object.fromEntries(
1625
+ Object.entries(t).filter(([i, s]) => !e.includes(i) && s !== void 0)
1626
+ );
1627
+ }
1628
+ static formatValue(t) {
1629
+ const e = JSON.stringify(t);
1630
+ if (e === void 0)
1631
+ throw new TypeError("Scenario contains a value that cannot be exported as code.");
1632
+ return e;
1633
+ }
1634
+ }
1635
+ class T {
1636
+ static record(t = {}) {
1637
+ const e = new Et(t);
1638
+ return e.start(), e;
1639
+ }
1640
+ static serialize(t) {
1641
+ return I.serialize(t);
1642
+ }
1643
+ static deserialize(t) {
1644
+ return I.deserialize(t);
1645
+ }
1646
+ static toTypeScript(t) {
1647
+ return I.toTypeScript(t);
1648
+ }
1649
+ static toJavaScript(t) {
1650
+ return I.toJavaScript(t);
1651
+ }
1652
+ }
1653
+ class N {
1654
+ constructor(t, e = {}) {
1655
+ a(this, "controller");
1656
+ a(this, "options");
1657
+ a(this, "rootElement", null);
1658
+ a(this, "unsubs", []);
1659
+ this.controller = t, this.options = {
1660
+ showStepBadge: !0,
1661
+ showProgress: !0,
1662
+ showSpeed: !0,
1663
+ ...e
1664
+ }, this.mount(), this.bindEvents();
1665
+ }
1666
+ mount() {
1667
+ if (typeof document > "u") return;
1668
+ const t = this.options.container || document.body;
1669
+ this.rootElement = document.createElement("div"), this.rootElement.className = "dg-controls-container", this.rootElement.setAttribute("role", "region"), this.rootElement.setAttribute("aria-label", "Demo playback controls"), this.render(), t.appendChild(this.rootElement);
1670
+ }
1671
+ render() {
1672
+ if (!this.rootElement) return;
1673
+ const t = this.controller.totalSteps, e = Math.min(this.controller.currentStep + 1, t), i = t > 0 ? e / t * 100 : 0, s = this.controller.state === "playing";
1674
+ this.rootElement.innerHTML = `
1675
+ <div class="dg-controls-hud dg-glass-panel">
1676
+ <div class="dg-controls-header">
1677
+ <div class="dg-controls-title" id="dg-controls-title">Interactive Demo</div>
1678
+ ${this.options.showStepBadge ? `<div class="dg-controls-step-badge" id="dg-controls-step">${e} / ${t}</div>` : ""}
1679
+ </div>
1680
+ ${this.options.showProgress ? `
1681
+ <div class="dg-controls-progress">
1682
+ <div class="dg-controls-progress-bar" id="dg-controls-bar" style="width: ${i}%"></div>
1683
+ </div>
1684
+ ` : ""}
1685
+ <div class="dg-controls-buttons">
1686
+ <button type="button" class="dg-btn" id="dg-btn-prev" aria-label="Previous step">
1687
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="19 20 9 12 19 4 19 20"></polygon><line x1="5" y1="19" x2="5" y2="4"></line></svg>
1688
+ </button>
1689
+ <button type="button" class="dg-btn dg-btn--play" id="dg-btn-toggle" aria-label="${s ? "Pause" : "Play"}">
1690
+ ${s ? '<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="4" width="4" height="16"></rect><rect x="14" y="4" width="4" height="16"></rect></svg>' : '<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg>'}
1691
+ </button>
1692
+ <button type="button" class="dg-btn" id="dg-btn-next" aria-label="Next step">
1693
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="5 4 15 12 5 20 5 4"></polygon><line x1="19" y1="5" x2="19" y2="19"></line></svg>
1694
+ </button>
1695
+ <button type="button" class="dg-btn" id="dg-btn-restart" aria-label="Restart demo">
1696
+ <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="23 4 23 10 17 10"></polyline><path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path></svg>
1697
+ </button>
1698
+ ${this.options.showSpeed ? `
1699
+ <select class="dg-speed-select" id="dg-speed" aria-label="Playback speed">
1700
+ <option value="0.5">0.5x</option>
1701
+ <option value="1" selected>1x</option>
1702
+ <option value="1.5">1.5x</option>
1703
+ <option value="2">2x</option>
1704
+ </select>
1705
+ ` : ""}
1706
+ <button type="button" class="dg-btn" id="dg-btn-close" aria-label="Close demo">
1707
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
1708
+ </button>
1709
+ </div>
1710
+ </div>
1711
+ `, this.attachListeners();
1712
+ }
1713
+ attachListeners() {
1714
+ if (!this.rootElement) return;
1715
+ const t = this.rootElement.querySelector("#dg-btn-prev"), e = this.rootElement.querySelector("#dg-btn-toggle"), i = this.rootElement.querySelector("#dg-btn-next"), s = this.rootElement.querySelector("#dg-btn-restart"), r = this.rootElement.querySelector("#dg-btn-close"), o = this.rootElement.querySelector("#dg-speed");
1716
+ t == null || t.addEventListener("click", () => this.controller.previous()), i == null || i.addEventListener("click", () => this.controller.next()), e == null || e.addEventListener("click", () => {
1717
+ this.controller.state === "playing" ? this.controller.pause() : this.controller.state === "paused" ? this.controller.resume() : this.controller.state === "idle" ? this.controller.play() : this.controller.restart();
1718
+ }), s == null || s.addEventListener("click", () => this.controller.restart()), r == null || r.addEventListener("click", () => this.controller.stop()), o == null || o.addEventListener("change", () => {
1719
+ const c = parseFloat(o.value);
1720
+ this.controller.speed = c;
1721
+ });
1722
+ }
1723
+ bindEvents() {
1724
+ const t = (s) => {
1725
+ var u, l, h, p;
1726
+ const r = (u = this.rootElement) == null ? void 0 : u.querySelector("#dg-controls-step");
1727
+ r && (r.textContent = `${s.index + 1} / ${s.total}`);
1728
+ const o = (l = this.rootElement) == null ? void 0 : l.querySelector("#dg-controls-bar");
1729
+ if (o) {
1730
+ const f = (s.index + 1) / s.total * 100;
1731
+ o.style.width = `${f}%`;
1732
+ }
1733
+ const c = (h = this.rootElement) == null ? void 0 : h.querySelector("#dg-controls-title");
1734
+ if (c) {
1735
+ const f = typeof s.step.caption == "string" ? s.step.caption : ((p = s.step.caption) == null ? void 0 : p.title) || s.step.type;
1736
+ c.textContent = f;
1737
+ }
1738
+ }, e = () => {
1739
+ var o;
1740
+ const s = (o = this.rootElement) == null ? void 0 : o.querySelector("#dg-btn-toggle");
1741
+ if (!s) return;
1742
+ const r = this.controller.state === "playing";
1743
+ s.setAttribute("aria-label", r ? "Pause" : "Play"), s.innerHTML = r ? '<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="4" width="4" height="16"></rect><rect x="14" y="4" width="4" height="16"></rect></svg>' : '<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg>';
1744
+ }, i = () => {
1745
+ this.destroy(!0);
1746
+ };
1747
+ this.unsubs.push(this.controller.on("start", e)), this.unsubs.push(this.controller.on("step:start", t)), this.unsubs.push(this.controller.on("pause", e)), this.unsubs.push(this.controller.on("resume", e)), this.unsubs.push(this.controller.on("complete", i)), this.unsubs.push(this.controller.on("stop", i));
1748
+ }
1749
+ destroy(t = !1) {
1750
+ if (this.unsubs.forEach((e) => e()), this.unsubs = [], this.rootElement && this.rootElement.parentNode)
1751
+ if (t)
1752
+ this.rootElement.parentNode.removeChild(this.rootElement), this.rootElement = null;
1753
+ else {
1754
+ const e = this.rootElement;
1755
+ e.classList.add("dg-controls-container--hidden"), setTimeout(() => {
1756
+ e && e.parentNode && e.parentNode.removeChild(e);
1757
+ }, 300), this.rootElement = null;
1758
+ }
1759
+ }
1760
+ }
1761
+ function $t(n, t) {
1762
+ return new N(n, t);
1763
+ }
1764
+ const d = class d {
1765
+ static configure(t) {
1766
+ w.configure(t);
1767
+ }
1768
+ static play(t, e = {}) {
1769
+ const i = w.play(t, e);
1770
+ return e.controls !== !1 && new N(i, {
1771
+ container: e.container
1772
+ }), i;
1773
+ }
1774
+ static record(t = {}) {
1775
+ return T.record(t);
1776
+ }
1777
+ static create(t, e = {}) {
1778
+ return {
1779
+ play: (i = {}) => d.play(t, { ...e, ...i })
1780
+ };
1781
+ }
1782
+ static serialize(t) {
1783
+ return T.serialize(t);
1784
+ }
1785
+ static deserialize(t) {
1786
+ return T.deserialize(t);
1787
+ }
1788
+ static toTypeScript(t) {
1789
+ return T.toTypeScript(t);
1790
+ }
1791
+ static toJavaScript(t) {
1792
+ return T.toJavaScript(t);
1793
+ }
1794
+ static export(t, e = "json") {
1795
+ return e === "ts" ? d.toTypeScript(t) : e === "js" ? d.toJavaScript(t) : d.serialize(t);
1796
+ }
1797
+ static on(t, e) {
1798
+ return w.on(t, e);
1799
+ }
1800
+ static off(t, e) {
1801
+ w.off(t, e);
1802
+ }
1803
+ };
1804
+ a(d, "actions", w.actions), // Direct action creator attachments for CDN / Global access
1805
+ a(d, "move", Q), a(d, "click", tt), a(d, "doubleClick", et), a(d, "rightClick", it), a(d, "type", st), a(d, "clear", nt), a(d, "focus", rt), a(d, "blur", ot), a(d, "wait", at), a(d, "waitFor", lt), a(d, "scroll", ct), a(d, "scrollTo", ut), a(d, "select", ht), a(d, "check", dt), a(d, "uncheck", pt), a(d, "hover", ft), a(d, "press", gt), a(d, "highlight", mt), a(d, "caption", vt), a(d, "drag", yt);
1806
+ let R = d;
1807
+ typeof window < "u" && (window.DemoGhost = R, window.dg = R);
1808
+ export {
1809
+ _ as AccessibilityManager,
1810
+ B as ActionRegistry,
1811
+ K as CursorEngine,
1812
+ R as DemoGhost,
1813
+ Tt as DemoGhostConfigurationError,
1814
+ N as DemoGhostControls,
1815
+ w as DemoGhostCore,
1816
+ $ as DemoGhostError,
1817
+ F as DemoGhostPlaybackError,
1818
+ T as DemoGhostRecorder,
1819
+ Ct as DemoGhostRecordingError,
1820
+ z as DemoGhostTargetNotFoundError,
1821
+ x as DemoGhostTimeoutError,
1822
+ H as EventEmitter,
1823
+ Et as EventRecorder,
1824
+ Z as PlaybackController,
1825
+ bt as PrivacyMasker,
1826
+ I as ScenarioSerializer,
1827
+ J as ScrollEngine,
1828
+ wt as SelectorGenerator,
1829
+ G as SpotlightEngine,
1830
+ W as TargetResolver,
1831
+ O as ThemeManager,
1832
+ $t as attachControls,
1833
+ ot as blur,
1834
+ vt as caption,
1835
+ dt as check,
1836
+ nt as clear,
1837
+ tt as click,
1838
+ R as default,
1839
+ et as doubleClick,
1840
+ yt as drag,
1841
+ rt as focus,
1842
+ mt as highlight,
1843
+ ft as hover,
1844
+ Q as move,
1845
+ gt as press,
1846
+ it as rightClick,
1847
+ ct as scroll,
1848
+ ut as scrollTo,
1849
+ ht as select,
1850
+ st as type,
1851
+ pt as uncheck,
1852
+ at as wait,
1853
+ lt as waitFor
1854
+ };
1855
+ //# sourceMappingURL=demoghost.js.map