veo-sdk 0.3.5 → 0.3.7
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/builder-7MBMYL26.mjs +5 -0
- package/dist/{builder-FBNBSKCL.mjs.map → builder-7MBMYL26.mjs.map} +1 -1
- package/dist/builder.cjs +502 -151
- package/dist/builder.cjs.map +1 -1
- package/dist/builder.d.cts +2 -2
- package/dist/builder.d.ts +2 -2
- package/dist/builder.mjs +4 -4
- package/dist/{chunk-GHP7ZJCW.mjs → chunk-4VJIILXF.mjs} +504 -153
- package/dist/chunk-4VJIILXF.mjs.map +1 -0
- package/dist/{chunk-TAZXRQYY.mjs → chunk-734ORVMM.mjs} +3 -3
- package/dist/{chunk-TAZXRQYY.mjs.map → chunk-734ORVMM.mjs.map} +1 -1
- package/dist/{chunk-R4E3LIDB.mjs → chunk-RNHOBE2D.mjs} +34 -4
- package/dist/chunk-RNHOBE2D.mjs.map +1 -0
- package/dist/{guide-preview-CO5ShtNf.d.cts → guide-preview-DewCTa-B.d.cts} +26 -1
- package/dist/{guide-preview-CO5ShtNf.d.ts → guide-preview-DewCTa-B.d.ts} +26 -1
- package/dist/index.cjs +552 -158
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +5 -5
- package/dist/veo-builder.js +49 -16
- package/dist/veo-builder.js.map +1 -1
- package/dist/veo-guides.js +44 -11
- package/dist/veo-guides.js.map +1 -1
- package/dist/veo.js +2 -2
- package/dist/veo.js.map +1 -1
- package/package.json +1 -1
- package/dist/builder-FBNBSKCL.mjs +0 -5
- package/dist/chunk-GHP7ZJCW.mjs.map +0 -1
- package/dist/chunk-R4E3LIDB.mjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -58,6 +58,59 @@ function session() {
|
|
|
58
58
|
return null;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
+
function local() {
|
|
62
|
+
try {
|
|
63
|
+
return window.localStorage;
|
|
64
|
+
} catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function lsKey(guide) {
|
|
69
|
+
return LS_PREFIX + (guide || "default");
|
|
70
|
+
}
|
|
71
|
+
function persist(ctx) {
|
|
72
|
+
try {
|
|
73
|
+
session()?.setItem(CTX_KEY, JSON.stringify(ctx));
|
|
74
|
+
} catch {
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const stored = { ...ctx, savedAt: Date.now() };
|
|
78
|
+
local()?.setItem(lsKey(ctx.guide), JSON.stringify(stored));
|
|
79
|
+
} catch {
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function readFreshFromLocal() {
|
|
83
|
+
const store = local();
|
|
84
|
+
if (!store) return null;
|
|
85
|
+
let best = null;
|
|
86
|
+
try {
|
|
87
|
+
for (let i = 0; i < store.length; i++) {
|
|
88
|
+
const key = store.key(i);
|
|
89
|
+
if (!key?.startsWith(LS_PREFIX)) continue;
|
|
90
|
+
const raw = store.getItem(key);
|
|
91
|
+
if (!raw) continue;
|
|
92
|
+
let parsed = null;
|
|
93
|
+
try {
|
|
94
|
+
parsed = JSON.parse(raw);
|
|
95
|
+
} catch {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (typeof parsed?.savedAt !== "number" || Date.now() - parsed.savedAt > PERSIST_TTL_MS) {
|
|
99
|
+
try {
|
|
100
|
+
store.removeItem(key);
|
|
101
|
+
} catch {
|
|
102
|
+
}
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (!best || parsed.savedAt > best.savedAt) best = parsed;
|
|
106
|
+
}
|
|
107
|
+
} catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
if (!best) return null;
|
|
111
|
+
const { savedAt: _savedAt, ...ctx } = best;
|
|
112
|
+
return ctx;
|
|
113
|
+
}
|
|
61
114
|
function urlParams() {
|
|
62
115
|
try {
|
|
63
116
|
return new URLSearchParams(window.location.search);
|
|
@@ -77,18 +130,22 @@ function resolveBuilderContext() {
|
|
|
77
130
|
guide: params?.get(BUILDER_GUIDE_PARAM) ?? null,
|
|
78
131
|
panelPath: params?.get(BUILDER_PANEL_PATH_PARAM) ?? null
|
|
79
132
|
};
|
|
80
|
-
|
|
81
|
-
session()?.setItem(CTX_KEY, JSON.stringify(ctx));
|
|
82
|
-
} catch {
|
|
83
|
-
}
|
|
133
|
+
persist(ctx);
|
|
84
134
|
return ctx;
|
|
85
135
|
}
|
|
86
136
|
try {
|
|
87
137
|
const raw = session()?.getItem(CTX_KEY);
|
|
88
|
-
|
|
138
|
+
if (raw) return JSON.parse(raw);
|
|
89
139
|
} catch {
|
|
90
|
-
return null;
|
|
91
140
|
}
|
|
141
|
+
const fromLocal = readFreshFromLocal();
|
|
142
|
+
if (fromLocal) {
|
|
143
|
+
try {
|
|
144
|
+
session()?.setItem(CTX_KEY, JSON.stringify(fromLocal));
|
|
145
|
+
} catch {
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return fromLocal;
|
|
92
149
|
}
|
|
93
150
|
function resolveBuilderToken() {
|
|
94
151
|
return resolveBuilderContext()?.token ?? null;
|
|
@@ -98,18 +155,30 @@ function isBuilderMode() {
|
|
|
98
155
|
}
|
|
99
156
|
function clearBuilderToken() {
|
|
100
157
|
if (!hasWindow()) return;
|
|
158
|
+
let guide = null;
|
|
159
|
+
try {
|
|
160
|
+
const raw = session()?.getItem(CTX_KEY);
|
|
161
|
+
if (raw) guide = JSON.parse(raw).guide ?? null;
|
|
162
|
+
} catch {
|
|
163
|
+
}
|
|
101
164
|
try {
|
|
102
165
|
session()?.removeItem(CTX_KEY);
|
|
103
166
|
} catch {
|
|
104
167
|
}
|
|
168
|
+
try {
|
|
169
|
+
local()?.removeItem(lsKey(guide));
|
|
170
|
+
} catch {
|
|
171
|
+
}
|
|
105
172
|
}
|
|
106
|
-
var CTX_KEY;
|
|
173
|
+
var CTX_KEY, LS_PREFIX, PERSIST_TTL_MS;
|
|
107
174
|
var init_builder_token = __esm({
|
|
108
175
|
"src/core/builder-token.ts"() {
|
|
109
176
|
init_safe_env();
|
|
110
177
|
init_builder_constants();
|
|
111
178
|
init_builder_constants();
|
|
112
179
|
CTX_KEY = "veo:builder_ctx";
|
|
180
|
+
LS_PREFIX = "veo:builder_ctx:";
|
|
181
|
+
PERSIST_TTL_MS = 12 * 60 * 60 * 1e3;
|
|
113
182
|
}
|
|
114
183
|
});
|
|
115
184
|
|
|
@@ -309,6 +378,16 @@ var init_constants2 = __esm({
|
|
|
309
378
|
function buildStepContent(step, doc, callbacks) {
|
|
310
379
|
const container = doc.createElement("div");
|
|
311
380
|
container.className = "veo-guide-content";
|
|
381
|
+
const blocks = normalizeBlocks(step);
|
|
382
|
+
if (blocks) {
|
|
383
|
+
renderBlocks(container, blocks, doc, callbacks);
|
|
384
|
+
} else {
|
|
385
|
+
renderLegacyStep(container, step, doc, callbacks);
|
|
386
|
+
}
|
|
387
|
+
container.appendChild(createCloseButton(doc, () => callbacks.onDismiss()));
|
|
388
|
+
return container;
|
|
389
|
+
}
|
|
390
|
+
function renderLegacyStep(container, step, doc, callbacks) {
|
|
312
391
|
if (typeof step.imageUrl === "string" && step.imageUrl && isSafeUrl(step.imageUrl)) {
|
|
313
392
|
const img = doc.createElement("img");
|
|
314
393
|
img.className = "veo-guide-image";
|
|
@@ -343,14 +422,114 @@ function buildStepContent(step, doc, callbacks) {
|
|
|
343
422
|
actions.appendChild(cta);
|
|
344
423
|
}
|
|
345
424
|
container.appendChild(actions);
|
|
425
|
+
}
|
|
426
|
+
function normalizeBlocks(step) {
|
|
427
|
+
if (!Array.isArray(step.blocks) || step.blocks.length === 0) return null;
|
|
428
|
+
const valid = step.blocks.filter((b) => {
|
|
429
|
+
if (!b || typeof b !== "object") return false;
|
|
430
|
+
if (b.type === "image") return typeof b.url === "string" && isSafeUrl(b.url);
|
|
431
|
+
return b.type === "title" || b.type === "text" || b.type === "button";
|
|
432
|
+
});
|
|
433
|
+
return valid.length > 0 ? valid : null;
|
|
434
|
+
}
|
|
435
|
+
function renderBlocks(container, blocks, doc, callbacks) {
|
|
436
|
+
let i = 0;
|
|
437
|
+
while (i < blocks.length) {
|
|
438
|
+
const block = blocks[i];
|
|
439
|
+
if (block?.type === "button") {
|
|
440
|
+
const actions = doc.createElement("div");
|
|
441
|
+
actions.className = "veo-guide-actions";
|
|
442
|
+
while (i < blocks.length && blocks[i]?.type === "button") {
|
|
443
|
+
const btnBlock = blocks[i];
|
|
444
|
+
actions.appendChild(buildButtonBlock(btnBlock, doc, callbacks));
|
|
445
|
+
i++;
|
|
446
|
+
}
|
|
447
|
+
container.appendChild(actions);
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
const node = buildContentBlock(block, doc);
|
|
451
|
+
if (node) container.appendChild(node);
|
|
452
|
+
i++;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
function buildContentBlock(block, doc) {
|
|
456
|
+
switch (block.type) {
|
|
457
|
+
case "title": {
|
|
458
|
+
const el = doc.createElement("h2");
|
|
459
|
+
el.className = "veo-guide-title";
|
|
460
|
+
el.textContent = typeof block.text === "string" ? block.text : "";
|
|
461
|
+
applyBlockStyle(el, block.style, "text");
|
|
462
|
+
return el;
|
|
463
|
+
}
|
|
464
|
+
case "text": {
|
|
465
|
+
const el = doc.createElement("p");
|
|
466
|
+
el.className = "veo-guide-text";
|
|
467
|
+
el.textContent = typeof block.text === "string" ? block.text : "";
|
|
468
|
+
applyBlockStyle(el, block.style, "text");
|
|
469
|
+
return el;
|
|
470
|
+
}
|
|
471
|
+
case "image": {
|
|
472
|
+
if (typeof block.url !== "string" || !isSafeUrl(block.url)) return null;
|
|
473
|
+
const el = doc.createElement("img");
|
|
474
|
+
el.className = "veo-guide-image";
|
|
475
|
+
el.src = block.url;
|
|
476
|
+
el.alt = "";
|
|
477
|
+
applyBlockStyle(el, block.style, "image");
|
|
478
|
+
return el;
|
|
479
|
+
}
|
|
480
|
+
default:
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
function buildButtonBlock(block, doc, callbacks) {
|
|
485
|
+
const btn = doc.createElement("button");
|
|
486
|
+
btn.type = "button";
|
|
487
|
+
btn.className = "veo-guide-cta";
|
|
488
|
+
btn.textContent = typeof block.text === "string" && block.text ? block.text : "OK";
|
|
489
|
+
applyBlockStyle(btn, block.style, "button");
|
|
490
|
+
btn.addEventListener("click", () => {
|
|
491
|
+
const action = block.action ?? "dismiss";
|
|
492
|
+
const url = action === "url" && typeof block.url === "string" && isSafeUrl(block.url) ? block.url : void 0;
|
|
493
|
+
callbacks.onCtaClick(action, url);
|
|
494
|
+
});
|
|
495
|
+
return btn;
|
|
496
|
+
}
|
|
497
|
+
function clampNum(n, min, max) {
|
|
498
|
+
return Math.min(max, Math.max(min, n));
|
|
499
|
+
}
|
|
500
|
+
function applyBlockStyle(el, style, kind) {
|
|
501
|
+
if (!style || typeof style !== "object") return;
|
|
502
|
+
const s = style;
|
|
503
|
+
const align = typeof s.align === "string" ? s.align : null;
|
|
504
|
+
if (align && (align === "left" || align === "center" || align === "right")) {
|
|
505
|
+
if (kind === "text") el.style.textAlign = align;
|
|
506
|
+
else el.style.alignSelf = BLOCK_ALIGN_SELF[align];
|
|
507
|
+
}
|
|
508
|
+
if (kind !== "image" && typeof s.color === "string") el.style.color = s.color;
|
|
509
|
+
if (kind === "text" && typeof s.fontSize === "number" && Number.isFinite(s.fontSize)) {
|
|
510
|
+
el.style.fontSize = `${clampNum(s.fontSize, 8, 72)}px`;
|
|
511
|
+
}
|
|
512
|
+
if (kind === "image" && typeof s.width === "number" && Number.isFinite(s.width)) {
|
|
513
|
+
el.style.width = `${clampNum(s.width, 10, 100)}%`;
|
|
514
|
+
}
|
|
515
|
+
if (kind === "image" && typeof s.radius === "number" && Number.isFinite(s.radius)) {
|
|
516
|
+
el.style.borderRadius = `${clampNum(s.radius, 0, 48)}px`;
|
|
517
|
+
}
|
|
518
|
+
if (typeof s.marginTop === "number" && Number.isFinite(s.marginTop)) {
|
|
519
|
+
el.style.marginTop = `${clampNum(s.marginTop, 0, 64)}px`;
|
|
520
|
+
}
|
|
521
|
+
if (typeof s.marginBottom === "number" && Number.isFinite(s.marginBottom)) {
|
|
522
|
+
el.style.marginBottom = `${clampNum(s.marginBottom, 0, 64)}px`;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
function createCloseButton(doc, onClose, className = "veo-guide-close") {
|
|
346
526
|
const closeBtn = doc.createElement("button");
|
|
347
527
|
closeBtn.type = "button";
|
|
348
|
-
closeBtn.className =
|
|
528
|
+
closeBtn.className = className;
|
|
349
529
|
closeBtn.setAttribute("aria-label", "Cerrar");
|
|
350
530
|
closeBtn.textContent = "\xD7";
|
|
351
|
-
closeBtn.addEventListener("click",
|
|
352
|
-
|
|
353
|
-
return container;
|
|
531
|
+
closeBtn.addEventListener("click", onClose);
|
|
532
|
+
return closeBtn;
|
|
354
533
|
}
|
|
355
534
|
function isSafeUrl(url) {
|
|
356
535
|
if (typeof url !== "string" || url.length === 0) return false;
|
|
@@ -367,9 +546,92 @@ function readCtaUrl(step) {
|
|
|
367
546
|
if (typeof candidate !== "string") return void 0;
|
|
368
547
|
return isSafeUrl(candidate) ? candidate : void 0;
|
|
369
548
|
}
|
|
549
|
+
var BLOCK_ALIGN_SELF;
|
|
370
550
|
var init_block_builder = __esm({
|
|
371
551
|
"src/plugins/guides/block-builder.ts"() {
|
|
372
552
|
init_constants2();
|
|
553
|
+
BLOCK_ALIGN_SELF = {
|
|
554
|
+
left: "flex-start",
|
|
555
|
+
center: "center",
|
|
556
|
+
right: "flex-end"
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
// src/plugins/guides/walkthrough-block-builder.ts
|
|
562
|
+
function buildWalkthroughStepContent(step, stepIndex, totalSteps, doc, callbacks) {
|
|
563
|
+
const container = doc.createElement("div");
|
|
564
|
+
container.className = "veo-guide-content";
|
|
565
|
+
const counter = doc.createElement("div");
|
|
566
|
+
counter.className = "veo-walkthrough-counter";
|
|
567
|
+
counter.textContent = `Paso ${stepIndex + 1} de ${totalSteps}`;
|
|
568
|
+
container.appendChild(counter);
|
|
569
|
+
const progress = doc.createElement("div");
|
|
570
|
+
progress.className = "veo-walkthrough-progress";
|
|
571
|
+
for (let i = 0; i < totalSteps; i++) {
|
|
572
|
+
const dot = doc.createElement("span");
|
|
573
|
+
dot.className = "veo-walkthrough-progress-dot";
|
|
574
|
+
if (i < stepIndex) dot.classList.add("completed");
|
|
575
|
+
if (i === stepIndex) dot.classList.add("active");
|
|
576
|
+
progress.appendChild(dot);
|
|
577
|
+
}
|
|
578
|
+
container.appendChild(progress);
|
|
579
|
+
if (typeof step.imageUrl === "string" && step.imageUrl && isSafeUrl(step.imageUrl)) {
|
|
580
|
+
const img = doc.createElement("img");
|
|
581
|
+
img.className = "veo-guide-image";
|
|
582
|
+
img.src = step.imageUrl;
|
|
583
|
+
img.alt = typeof step.title === "string" ? step.title : "";
|
|
584
|
+
container.appendChild(img);
|
|
585
|
+
}
|
|
586
|
+
if (typeof step.title === "string" && step.title) {
|
|
587
|
+
const heading = doc.createElement("h2");
|
|
588
|
+
heading.className = "veo-guide-title";
|
|
589
|
+
heading.textContent = step.title;
|
|
590
|
+
container.appendChild(heading);
|
|
591
|
+
}
|
|
592
|
+
if (typeof step.content === "string" && step.content) {
|
|
593
|
+
const paragraph = doc.createElement("p");
|
|
594
|
+
paragraph.className = "veo-guide-text";
|
|
595
|
+
paragraph.textContent = step.content;
|
|
596
|
+
container.appendChild(paragraph);
|
|
597
|
+
}
|
|
598
|
+
const actions = doc.createElement("div");
|
|
599
|
+
actions.className = "veo-walkthrough-actions";
|
|
600
|
+
const skipBtn = doc.createElement("button");
|
|
601
|
+
skipBtn.type = "button";
|
|
602
|
+
skipBtn.className = "veo-walkthrough-skip";
|
|
603
|
+
skipBtn.textContent = "Omitir";
|
|
604
|
+
skipBtn.addEventListener("click", () => callbacks.onSkip());
|
|
605
|
+
actions.appendChild(skipBtn);
|
|
606
|
+
const rightGroup = doc.createElement("div");
|
|
607
|
+
rightGroup.className = "veo-walkthrough-actions-right";
|
|
608
|
+
if (stepIndex > 0) {
|
|
609
|
+
const backBtn = doc.createElement("button");
|
|
610
|
+
backBtn.type = "button";
|
|
611
|
+
backBtn.className = "veo-walkthrough-btn-secondary";
|
|
612
|
+
backBtn.textContent = "Atr\xE1s";
|
|
613
|
+
backBtn.addEventListener("click", () => callbacks.onBack());
|
|
614
|
+
rightGroup.appendChild(backBtn);
|
|
615
|
+
}
|
|
616
|
+
const isLastStep = stepIndex === totalSteps - 1;
|
|
617
|
+
const primaryBtn = doc.createElement("button");
|
|
618
|
+
primaryBtn.type = "button";
|
|
619
|
+
primaryBtn.className = "veo-guide-cta";
|
|
620
|
+
const defaultLabel = isLastStep ? "Finalizar" : "Siguiente";
|
|
621
|
+
primaryBtn.textContent = typeof step.ctaText === "string" && step.ctaText ? step.ctaText : defaultLabel;
|
|
622
|
+
primaryBtn.addEventListener("click", () => {
|
|
623
|
+
if (isLastStep) callbacks.onComplete();
|
|
624
|
+
else callbacks.onNext();
|
|
625
|
+
});
|
|
626
|
+
rightGroup.appendChild(primaryBtn);
|
|
627
|
+
actions.appendChild(rightGroup);
|
|
628
|
+
container.appendChild(actions);
|
|
629
|
+
container.appendChild(createCloseButton(doc, () => callbacks.onSkip()));
|
|
630
|
+
return container;
|
|
631
|
+
}
|
|
632
|
+
var init_walkthrough_block_builder = __esm({
|
|
633
|
+
"src/plugins/guides/walkthrough-block-builder.ts"() {
|
|
634
|
+
init_block_builder();
|
|
373
635
|
}
|
|
374
636
|
});
|
|
375
637
|
|
|
@@ -383,6 +645,9 @@ function applyDesignVars(host, style) {
|
|
|
383
645
|
if (typeof s.accentColor === "string" && COLOR_RE.test(s.accentColor.trim())) {
|
|
384
646
|
host.style.setProperty("--veo-primary", s.accentColor.trim());
|
|
385
647
|
}
|
|
648
|
+
if (typeof s.fontFamily === "string" && s.fontFamily.length <= 200 && !/[<>{}]/.test(s.fontFamily)) {
|
|
649
|
+
host.style.setProperty("--veo-font", s.fontFamily.trim());
|
|
650
|
+
}
|
|
386
651
|
if (s.theme === "dark") {
|
|
387
652
|
for (const [key, value] of Object.entries(DARK_THEME)) {
|
|
388
653
|
host.style.setProperty(key, value);
|
|
@@ -424,8 +689,45 @@ function applyDesignVars(host, style) {
|
|
|
424
689
|
host.style.setProperty("--veo-pos-x", `${px * 100}%`);
|
|
425
690
|
host.style.setProperty("--veo-pos-y", `${py * 100}%`);
|
|
426
691
|
}
|
|
692
|
+
if (s.elements && typeof s.elements === "object") {
|
|
693
|
+
const el = s.elements;
|
|
694
|
+
applyElementVars(host, "title", el.title);
|
|
695
|
+
applyElementVars(host, "text", el.text);
|
|
696
|
+
applyElementVars(host, "image", el.image);
|
|
697
|
+
const cta = el.cta;
|
|
698
|
+
if (cta && typeof cta.align === "string" && ALIGN_JUSTIFY[cta.align]) {
|
|
699
|
+
host.style.setProperty("--veo-actions-justify", ALIGN_JUSTIFY[cta.align]);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
function applyElementVars(host, prefix, raw) {
|
|
704
|
+
if (!raw || typeof raw !== "object") return;
|
|
705
|
+
const el = raw;
|
|
706
|
+
if (typeof el.align === "string" && (el.align === "left" || el.align === "center" || el.align === "right")) {
|
|
707
|
+
const mode = ELEMENT_ALIGN_MODE[prefix] ?? "text";
|
|
708
|
+
const value = mode === "self" ? ALIGN_SELF[el.align] : el.align;
|
|
709
|
+
host.style.setProperty(`--veo-${prefix}-align`, value);
|
|
710
|
+
}
|
|
711
|
+
if (typeof el.color === "string" && COLOR_RE.test(el.color.trim())) {
|
|
712
|
+
host.style.setProperty(`--veo-${prefix}-color`, el.color.trim());
|
|
713
|
+
}
|
|
714
|
+
if (typeof el.fontSize === "number" && Number.isFinite(el.fontSize)) {
|
|
715
|
+
host.style.setProperty(`--veo-${prefix}-size`, `${clamp(el.fontSize, 8, 72)}px`);
|
|
716
|
+
}
|
|
717
|
+
if (typeof el.width === "number" && Number.isFinite(el.width)) {
|
|
718
|
+
host.style.setProperty(`--veo-${prefix}-width`, `${clamp(el.width, 10, 100)}%`);
|
|
719
|
+
}
|
|
720
|
+
if (typeof el.radius === "number" && Number.isFinite(el.radius)) {
|
|
721
|
+
host.style.setProperty(`--veo-${prefix}-radius`, `${clamp(el.radius, 0, 48)}px`);
|
|
722
|
+
}
|
|
723
|
+
if (typeof el.marginTop === "number" && Number.isFinite(el.marginTop)) {
|
|
724
|
+
host.style.setProperty(`--veo-${prefix}-mt`, `${clamp(el.marginTop, 0, 64)}px`);
|
|
725
|
+
}
|
|
726
|
+
if (typeof el.marginBottom === "number" && Number.isFinite(el.marginBottom)) {
|
|
727
|
+
host.style.setProperty(`--veo-${prefix}-mb`, `${clamp(el.marginBottom, 0, 64)}px`);
|
|
728
|
+
}
|
|
427
729
|
}
|
|
428
|
-
var DARK_THEME, ALIGN_JUSTIFY, SHADOW, PRESET_POS, COLOR_RE;
|
|
730
|
+
var DARK_THEME, ALIGN_JUSTIFY, ALIGN_SELF, ELEMENT_ALIGN_MODE, SHADOW, PRESET_POS, COLOR_RE;
|
|
429
731
|
var init_guide_design = __esm({
|
|
430
732
|
"src/plugins/guides/guide-design.ts"() {
|
|
431
733
|
DARK_THEME = {
|
|
@@ -439,6 +741,16 @@ var init_guide_design = __esm({
|
|
|
439
741
|
center: "center",
|
|
440
742
|
right: "flex-end"
|
|
441
743
|
};
|
|
744
|
+
ALIGN_SELF = {
|
|
745
|
+
left: "flex-start",
|
|
746
|
+
center: "center",
|
|
747
|
+
right: "flex-end"
|
|
748
|
+
};
|
|
749
|
+
ELEMENT_ALIGN_MODE = {
|
|
750
|
+
title: "text",
|
|
751
|
+
text: "text",
|
|
752
|
+
image: "self"
|
|
753
|
+
};
|
|
442
754
|
SHADOW = {
|
|
443
755
|
none: "none",
|
|
444
756
|
soft: "0 4px 14px rgba(0, 0, 0, 0.10)",
|
|
@@ -477,7 +789,7 @@ var init_styles = __esm({
|
|
|
477
789
|
--veo-actions-justify: flex-end;
|
|
478
790
|
all: initial;
|
|
479
791
|
}
|
|
480
|
-
* { box-sizing: border-box; font-family: -apple-system, system-ui, "Segoe UI", Roboto, sans-serif; }
|
|
792
|
+
* { box-sizing: border-box; font-family: var(--veo-font, -apple-system, system-ui, "Segoe UI", Roboto, sans-serif); }
|
|
481
793
|
|
|
482
794
|
.veo-modal-overlay {
|
|
483
795
|
position: fixed; inset: 0;
|
|
@@ -528,6 +840,15 @@ var init_styles = __esm({
|
|
|
528
840
|
box-shadow: var(--veo-shadow, 0 8px 30px rgba(0, 0, 0, 0.18));
|
|
529
841
|
animation: veo-fade-in 150ms ease-out;
|
|
530
842
|
}
|
|
843
|
+
.veo-tooltip-arrow {
|
|
844
|
+
position: absolute;
|
|
845
|
+
width: 12px;
|
|
846
|
+
height: 12px;
|
|
847
|
+
background: var(--veo-bg);
|
|
848
|
+
border: var(--veo-border-width, 0) solid var(--veo-border-color, transparent);
|
|
849
|
+
transform: rotate(45deg);
|
|
850
|
+
pointer-events: none;
|
|
851
|
+
}
|
|
531
852
|
|
|
532
853
|
.veo-inline {
|
|
533
854
|
background: var(--veo-bg);
|
|
@@ -546,17 +867,25 @@ var init_styles = __esm({
|
|
|
546
867
|
display: flex; flex-direction: column;
|
|
547
868
|
}
|
|
548
869
|
.veo-guide-image {
|
|
549
|
-
display: block;
|
|
550
|
-
|
|
551
|
-
|
|
870
|
+
display: block;
|
|
871
|
+
width: var(--veo-image-width, 100%);
|
|
872
|
+
max-height: 180px;
|
|
873
|
+
object-fit: cover;
|
|
874
|
+
align-self: var(--veo-image-align, stretch);
|
|
875
|
+
border-radius: var(--veo-image-radius, 8px);
|
|
876
|
+
margin: var(--veo-image-mt, 0) 0 var(--veo-image-mb, 12px);
|
|
552
877
|
}
|
|
553
878
|
.veo-guide-title {
|
|
554
|
-
font-size: 18px; font-weight: 600; line-height: 1.3;
|
|
555
|
-
|
|
879
|
+
font-size: var(--veo-title-size, 18px); font-weight: 600; line-height: 1.3;
|
|
880
|
+
text-align: var(--veo-title-align, left);
|
|
881
|
+
margin: var(--veo-title-mt, 0) 0 var(--veo-title-mb, 6px);
|
|
882
|
+
color: var(--veo-title-color, var(--veo-text));
|
|
556
883
|
}
|
|
557
884
|
.veo-guide-text {
|
|
558
|
-
font-size: 14px; line-height: 1.5;
|
|
559
|
-
|
|
885
|
+
font-size: var(--veo-text-size, 14px); line-height: 1.5;
|
|
886
|
+
text-align: var(--veo-text-align, left);
|
|
887
|
+
margin: var(--veo-text-mt, 0) 0 var(--veo-text-mb, 16px);
|
|
888
|
+
color: var(--veo-text-color, var(--veo-text-secondary));
|
|
560
889
|
}
|
|
561
890
|
.veo-guide-actions {
|
|
562
891
|
display: flex; gap: 8px; justify-content: var(--veo-actions-justify);
|
|
@@ -693,6 +1022,7 @@ var init_styles = __esm({
|
|
|
693
1022
|
}
|
|
694
1023
|
.veo-custom-inline {
|
|
695
1024
|
display: block;
|
|
1025
|
+
position: relative;
|
|
696
1026
|
margin: 12px 0;
|
|
697
1027
|
}
|
|
698
1028
|
.veo-custom-frame {
|
|
@@ -702,6 +1032,21 @@ var init_styles = __esm({
|
|
|
702
1032
|
background: transparent;
|
|
703
1033
|
color-scheme: normal;
|
|
704
1034
|
}
|
|
1035
|
+
/*
|
|
1036
|
+
* X de cerrar de las gu\xEDas custom: el HTML del cliente vive en un iframe
|
|
1037
|
+
* sandbox, as\xED que el bot\xF3n lo pone el host POR ENCIMA del iframe. Con fondo
|
|
1038
|
+
* propio para ser visible sobre cualquier contenido.
|
|
1039
|
+
*/
|
|
1040
|
+
.veo-custom-close {
|
|
1041
|
+
position: absolute; top: 6px; right: 6px; z-index: 1;
|
|
1042
|
+
width: 22px; height: 22px; padding: 0;
|
|
1043
|
+
display: flex; align-items: center; justify-content: center;
|
|
1044
|
+
font-size: 16px; line-height: 1; color: #6b7280;
|
|
1045
|
+
background: rgba(255, 255, 255, 0.92);
|
|
1046
|
+
border: 1px solid rgba(0, 0, 0, 0.08); border-radius: 50%;
|
|
1047
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.14); cursor: pointer;
|
|
1048
|
+
}
|
|
1049
|
+
.veo-custom-close:hover { color: #111827; }
|
|
705
1050
|
|
|
706
1051
|
@keyframes veo-fade-in { from { opacity: 0; } to { opacity: 1; } }
|
|
707
1052
|
@keyframes veo-slide-up {
|
|
@@ -787,10 +1132,12 @@ var BannerRenderer;
|
|
|
787
1132
|
var init_banner_renderer = __esm({
|
|
788
1133
|
"src/plugins/guides/renderers/banner-renderer.ts"() {
|
|
789
1134
|
init_block_builder();
|
|
1135
|
+
init_walkthrough_block_builder();
|
|
790
1136
|
init_base_renderer();
|
|
791
1137
|
BannerRenderer = class extends BaseRenderer {
|
|
792
1138
|
render(context) {
|
|
793
|
-
const
|
|
1139
|
+
const idx = context.nav?.stepIndex ?? 0;
|
|
1140
|
+
const step = context.guide.guideSteps[idx];
|
|
794
1141
|
if (!step) return;
|
|
795
1142
|
const { root } = this.createHost();
|
|
796
1143
|
this.applyDesign(step.style);
|
|
@@ -799,27 +1146,25 @@ var init_banner_renderer = __esm({
|
|
|
799
1146
|
const banner = ownerDocument.createElement("div");
|
|
800
1147
|
banner.className = `veo-banner veo-banner-${position}`;
|
|
801
1148
|
const dismiss = (action, ctaUrl) => {
|
|
802
|
-
context.onInteraction({
|
|
803
|
-
guideId: context.guide.guideId,
|
|
804
|
-
stepIndex: 0,
|
|
805
|
-
action
|
|
806
|
-
});
|
|
1149
|
+
context.onInteraction({ guideId: context.guide.guideId, stepIndex: idx, action });
|
|
807
1150
|
if (ctaUrl) window.open(ctaUrl, "_blank", "noopener,noreferrer");
|
|
808
1151
|
context.onClose();
|
|
809
1152
|
};
|
|
810
|
-
const content =
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
1153
|
+
const content = context.nav ? buildWalkthroughStepContent(
|
|
1154
|
+
step,
|
|
1155
|
+
context.nav.stepIndex,
|
|
1156
|
+
context.nav.totalSteps,
|
|
1157
|
+
ownerDocument,
|
|
1158
|
+
context.nav.callbacks
|
|
1159
|
+
) : buildStepContent(step, ownerDocument, {
|
|
1160
|
+
onCtaClick: (action, url) => dismiss("cta_clicked", action === "url" ? url : void 0),
|
|
814
1161
|
onDismiss: () => dismiss("dismissed")
|
|
815
1162
|
});
|
|
816
1163
|
banner.appendChild(content);
|
|
817
1164
|
root.appendChild(banner);
|
|
818
|
-
context.
|
|
819
|
-
guideId: context.guide.guideId,
|
|
820
|
-
|
|
821
|
-
action: "shown"
|
|
822
|
-
});
|
|
1165
|
+
if (!context.nav) {
|
|
1166
|
+
context.onInteraction({ guideId: context.guide.guideId, stepIndex: 0, action: "shown" });
|
|
1167
|
+
}
|
|
823
1168
|
}
|
|
824
1169
|
};
|
|
825
1170
|
}
|
|
@@ -872,7 +1217,11 @@ function mountCustomFrame(doc, step, context, opts) {
|
|
|
872
1217
|
const hasFixedHeight = opts.fixedHeight !== void 0 && opts.fixedHeight !== null;
|
|
873
1218
|
if (hasFixedHeight) iframe.style.height = toCssSize(opts.fixedHeight);
|
|
874
1219
|
const token = uuidv7();
|
|
875
|
-
|
|
1220
|
+
const wantsTailwind = step.style?.tailwind === true;
|
|
1221
|
+
iframe.srcdoc = buildSrcdoc(step.html ?? "", step.css ?? "", step.js ?? "", token, {
|
|
1222
|
+
tokens: collectHostTokens(),
|
|
1223
|
+
tailwind: wantsTailwind
|
|
1224
|
+
});
|
|
876
1225
|
const close = () => context.onClose();
|
|
877
1226
|
const onMessage = (event) => {
|
|
878
1227
|
if (event.source !== iframe.contentWindow) return;
|
|
@@ -921,12 +1270,37 @@ function mountCustomFrame(doc, step, context, opts) {
|
|
|
921
1270
|
function toCssSize(value) {
|
|
922
1271
|
return typeof value === "number" ? `${value}px` : value;
|
|
923
1272
|
}
|
|
1273
|
+
function collectHostTokens() {
|
|
1274
|
+
if (typeof window === "undefined" || typeof document === "undefined") return "";
|
|
1275
|
+
try {
|
|
1276
|
+
const rootStyle = getComputedStyle(document.documentElement);
|
|
1277
|
+
const decls = [];
|
|
1278
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1279
|
+
for (let i = 0; i < rootStyle.length && decls.length < 400; i++) {
|
|
1280
|
+
const name = rootStyle.item(i);
|
|
1281
|
+
if (!name.startsWith("--") || seen.has(name)) continue;
|
|
1282
|
+
seen.add(name);
|
|
1283
|
+
const value = rootStyle.getPropertyValue(name).trim();
|
|
1284
|
+
if (!value || value.length > 200 || /[<>{}]/.test(value)) continue;
|
|
1285
|
+
decls.push(`${name}:${value}`);
|
|
1286
|
+
}
|
|
1287
|
+
const bodyFont = getComputedStyle(document.body).fontFamily;
|
|
1288
|
+
if (bodyFont && bodyFont.length <= 200 && !/[<>{}]/.test(bodyFont)) {
|
|
1289
|
+
decls.push(`--veo-host-font:${bodyFont}`);
|
|
1290
|
+
}
|
|
1291
|
+
return decls.length ? `:root{${decls.join(";")}}` : "";
|
|
1292
|
+
} catch {
|
|
1293
|
+
return "";
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
924
1296
|
function isRecord(value) {
|
|
925
1297
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
926
1298
|
}
|
|
927
|
-
function buildSrcdoc(html, css, js, token) {
|
|
1299
|
+
function buildSrcdoc(html, css, js, token, opts) {
|
|
928
1300
|
const bridge = `(function(){var T=${JSON.stringify(token)};function P(m){m.__veo=T;parent.postMessage(m,'*');}window.veo={dismiss:function(){P({type:'dismiss'});},cta:function(u){P({type:'cta',url:u});},track:function(n,p){P({type:'track',name:n,props:p||{}});},navigate:function(u){P({type:'navigate',url:u});}};document.addEventListener('click',function(e){var a=e.target&&e.target.closest?e.target.closest('a[href]'):null;if(!a)return;var h=a.getAttribute('href');if(!h||h.charAt(0)==='#'||/^(javascript|mailto|tel):/i.test(h))return;e.preventDefault();if(a.target==='_blank'){P({type:'cta',url:a.href,close:false});}else{P({type:'navigate',url:h});}},true);function H(){P({type:'resize',height:Math.ceil(document.documentElement.scrollHeight)});}window.addEventListener('load',H);try{if(typeof ResizeObserver!=='undefined'){new ResizeObserver(H).observe(document.documentElement);}}catch(e){}})();`;
|
|
929
|
-
|
|
1301
|
+
const tokensStyle = opts.tokens ? `<style>${escapeClosing(opts.tokens, "style")}</style>` : "";
|
|
1302
|
+
const tailwind = opts.tailwind ? '<script src="https://cdn.tailwindcss.com"></script>' : "";
|
|
1303
|
+
return '<!DOCTYPE html><html><head><meta charset="utf-8"><style>html,body{margin:0;padding:0;background:transparent;font-family:var(--veo-host-font,system-ui,sans-serif);}</style>' + tokensStyle + tailwind + `<style>${escapeClosing(css, "style")}</style></head><body>${html}<script>${bridge}</script>` + (js ? `<script>${escapeClosing(js, "script")}</script>` : "") + "</body></html>";
|
|
930
1304
|
}
|
|
931
1305
|
function escapeClosing(code, tag) {
|
|
932
1306
|
const rx = tag === "script" ? /<\/script/gi : /<\/style/gi;
|
|
@@ -964,6 +1338,7 @@ function applyFloatingPosition(wrapper, placement) {
|
|
|
964
1338
|
var DEFAULT_PLACEMENT, DEFAULT_OFFSET, DEFAULT_WIDTH, CustomRenderer;
|
|
965
1339
|
var init_custom_renderer = __esm({
|
|
966
1340
|
"src/plugins/guides/renderers/custom-renderer.ts"() {
|
|
1341
|
+
init_block_builder();
|
|
967
1342
|
init_wait_for_element();
|
|
968
1343
|
init_base_renderer();
|
|
969
1344
|
init_custom_frame();
|
|
@@ -992,6 +1367,20 @@ var init_custom_renderer = __esm({
|
|
|
992
1367
|
});
|
|
993
1368
|
this.registerCleanup(cleanup);
|
|
994
1369
|
wrapper.appendChild(iframe);
|
|
1370
|
+
wrapper.appendChild(
|
|
1371
|
+
createCloseButton(
|
|
1372
|
+
doc,
|
|
1373
|
+
() => {
|
|
1374
|
+
context.onInteraction({
|
|
1375
|
+
guideId: context.guide.guideId,
|
|
1376
|
+
stepIndex: 0,
|
|
1377
|
+
action: "dismissed"
|
|
1378
|
+
});
|
|
1379
|
+
context.onClose();
|
|
1380
|
+
},
|
|
1381
|
+
"veo-custom-close"
|
|
1382
|
+
)
|
|
1383
|
+
);
|
|
995
1384
|
root.appendChild(wrapper);
|
|
996
1385
|
if (placement.mode === "floating") {
|
|
997
1386
|
applyFloatingPosition(wrapper, placement);
|
|
@@ -1108,13 +1497,7 @@ function mountFormContent(card, context, doc) {
|
|
|
1108
1497
|
});
|
|
1109
1498
|
});
|
|
1110
1499
|
content.appendChild(form);
|
|
1111
|
-
|
|
1112
|
-
closeBtn.type = "button";
|
|
1113
|
-
closeBtn.className = "veo-guide-close";
|
|
1114
|
-
closeBtn.setAttribute("aria-label", "Cerrar");
|
|
1115
|
-
closeBtn.textContent = "\xD7";
|
|
1116
|
-
closeBtn.addEventListener("click", dismiss);
|
|
1117
|
-
content.appendChild(closeBtn);
|
|
1500
|
+
content.appendChild(createCloseButton(doc, dismiss));
|
|
1118
1501
|
card.appendChild(content);
|
|
1119
1502
|
}
|
|
1120
1503
|
function showThanks(card, doc, note) {
|
|
@@ -1298,6 +1681,7 @@ function buildScale(wrapper, doc, min, max, btnClass, symbol) {
|
|
|
1298
1681
|
}
|
|
1299
1682
|
var init_form_content = __esm({
|
|
1300
1683
|
"src/plugins/guides/form-content.ts"() {
|
|
1684
|
+
init_block_builder();
|
|
1301
1685
|
}
|
|
1302
1686
|
});
|
|
1303
1687
|
|
|
@@ -1377,6 +1761,7 @@ var init_inline_host = __esm({
|
|
|
1377
1761
|
var InlineCustomRenderer;
|
|
1378
1762
|
var init_inline_custom_renderer = __esm({
|
|
1379
1763
|
"src/plugins/guides/renderers/inline-custom-renderer.ts"() {
|
|
1764
|
+
init_block_builder();
|
|
1380
1765
|
init_inline_host();
|
|
1381
1766
|
init_wait_for_element();
|
|
1382
1767
|
init_base_renderer();
|
|
@@ -1400,6 +1785,20 @@ var init_inline_custom_renderer = __esm({
|
|
|
1400
1785
|
const { iframe, cleanup } = mountCustomFrame(doc, step, context, { width: "100%" });
|
|
1401
1786
|
this.registerCleanup(cleanup);
|
|
1402
1787
|
wrapper.appendChild(iframe);
|
|
1788
|
+
wrapper.appendChild(
|
|
1789
|
+
createCloseButton(
|
|
1790
|
+
doc,
|
|
1791
|
+
() => {
|
|
1792
|
+
context.onInteraction({
|
|
1793
|
+
guideId: context.guide.guideId,
|
|
1794
|
+
stepIndex: 0,
|
|
1795
|
+
action: "dismissed"
|
|
1796
|
+
});
|
|
1797
|
+
context.onClose();
|
|
1798
|
+
},
|
|
1799
|
+
"veo-custom-close"
|
|
1800
|
+
)
|
|
1801
|
+
);
|
|
1403
1802
|
root.appendChild(wrapper);
|
|
1404
1803
|
context.onInteraction({ guideId: context.guide.guideId, stepIndex: 0, action: "shown" });
|
|
1405
1804
|
}
|
|
@@ -1487,10 +1886,12 @@ var ModalRenderer;
|
|
|
1487
1886
|
var init_modal_renderer = __esm({
|
|
1488
1887
|
"src/plugins/guides/renderers/modal-renderer.ts"() {
|
|
1489
1888
|
init_block_builder();
|
|
1889
|
+
init_walkthrough_block_builder();
|
|
1490
1890
|
init_base_renderer();
|
|
1491
1891
|
ModalRenderer = class extends BaseRenderer {
|
|
1492
1892
|
render(context) {
|
|
1493
|
-
const
|
|
1893
|
+
const idx = context.nav?.stepIndex ?? 0;
|
|
1894
|
+
const step = context.guide.guideSteps[idx];
|
|
1494
1895
|
if (!step) return;
|
|
1495
1896
|
const { root } = this.createHost();
|
|
1496
1897
|
this.applyDesign(step.style);
|
|
@@ -1500,46 +1901,71 @@ var init_modal_renderer = __esm({
|
|
|
1500
1901
|
const card = ownerDocument.createElement("div");
|
|
1501
1902
|
card.className = "veo-modal-card";
|
|
1502
1903
|
const dismiss = (action, ctaUrl) => {
|
|
1503
|
-
context.onInteraction({
|
|
1504
|
-
guideId: context.guide.guideId,
|
|
1505
|
-
stepIndex: 0,
|
|
1506
|
-
action
|
|
1507
|
-
});
|
|
1904
|
+
context.onInteraction({ guideId: context.guide.guideId, stepIndex: idx, action });
|
|
1508
1905
|
if (ctaUrl) window.open(ctaUrl, "_blank", "noopener,noreferrer");
|
|
1509
1906
|
context.onClose();
|
|
1510
1907
|
};
|
|
1511
|
-
const
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1908
|
+
const onBackdropOrEsc = () => {
|
|
1909
|
+
if (context.nav) context.nav.callbacks.onSkip();
|
|
1910
|
+
else dismiss("dismissed");
|
|
1911
|
+
};
|
|
1912
|
+
const content = context.nav ? buildWalkthroughStepContent(
|
|
1913
|
+
step,
|
|
1914
|
+
context.nav.stepIndex,
|
|
1915
|
+
context.nav.totalSteps,
|
|
1916
|
+
ownerDocument,
|
|
1917
|
+
context.nav.callbacks
|
|
1918
|
+
) : buildStepContent(step, ownerDocument, {
|
|
1919
|
+
onCtaClick: (action, url) => dismiss("cta_clicked", action === "url" ? url : void 0),
|
|
1515
1920
|
onDismiss: () => dismiss("dismissed")
|
|
1516
1921
|
});
|
|
1517
1922
|
card.appendChild(content);
|
|
1518
1923
|
overlay.appendChild(card);
|
|
1519
1924
|
root.appendChild(overlay);
|
|
1520
1925
|
overlay.addEventListener("click", (e) => {
|
|
1521
|
-
if (e.target === overlay)
|
|
1926
|
+
if (e.target === overlay) onBackdropOrEsc();
|
|
1522
1927
|
});
|
|
1523
1928
|
const onKey = (e) => {
|
|
1524
|
-
if (e.key === "Escape")
|
|
1929
|
+
if (e.key === "Escape") onBackdropOrEsc();
|
|
1525
1930
|
};
|
|
1526
1931
|
document.addEventListener("keydown", onKey);
|
|
1527
1932
|
this.registerCleanup(() => document.removeEventListener("keydown", onKey));
|
|
1528
|
-
context.
|
|
1529
|
-
guideId: context.guide.guideId,
|
|
1530
|
-
|
|
1531
|
-
action: "shown"
|
|
1532
|
-
});
|
|
1933
|
+
if (!context.nav) {
|
|
1934
|
+
context.onInteraction({ guideId: context.guide.guideId, stepIndex: 0, action: "shown" });
|
|
1935
|
+
}
|
|
1533
1936
|
}
|
|
1534
1937
|
};
|
|
1535
1938
|
}
|
|
1536
1939
|
});
|
|
1940
|
+
|
|
1941
|
+
// src/plugins/guides/renderers/floating-arrow.ts
|
|
1942
|
+
function positionArrow(arrowEl, placement, data) {
|
|
1943
|
+
const side = STATIC_SIDE[placement.split("-")[0] ?? "bottom"] ?? "top";
|
|
1944
|
+
for (const prop of ["top", "bottom", "left", "right"]) {
|
|
1945
|
+
arrowEl.style.setProperty(prop, "");
|
|
1946
|
+
}
|
|
1947
|
+
if (data?.x != null) arrowEl.style.setProperty("left", `${data.x}px`);
|
|
1948
|
+
if (data?.y != null) arrowEl.style.setProperty("top", `${data.y}px`);
|
|
1949
|
+
arrowEl.style.setProperty(side, "-6px");
|
|
1950
|
+
}
|
|
1951
|
+
var STATIC_SIDE;
|
|
1952
|
+
var init_floating_arrow = __esm({
|
|
1953
|
+
"src/plugins/guides/renderers/floating-arrow.ts"() {
|
|
1954
|
+
STATIC_SIDE = {
|
|
1955
|
+
top: "bottom",
|
|
1956
|
+
bottom: "top",
|
|
1957
|
+
left: "right",
|
|
1958
|
+
right: "left"
|
|
1959
|
+
};
|
|
1960
|
+
}
|
|
1961
|
+
});
|
|
1537
1962
|
var TooltipRenderer;
|
|
1538
1963
|
var init_tooltip_renderer = __esm({
|
|
1539
1964
|
"src/plugins/guides/renderers/tooltip-renderer.ts"() {
|
|
1540
1965
|
init_block_builder();
|
|
1541
1966
|
init_wait_for_element();
|
|
1542
1967
|
init_base_renderer();
|
|
1968
|
+
init_floating_arrow();
|
|
1543
1969
|
TooltipRenderer = class extends BaseRenderer {
|
|
1544
1970
|
async render(context) {
|
|
1545
1971
|
const step = context.guide.guideSteps[0];
|
|
@@ -1569,14 +1995,18 @@ var init_tooltip_renderer = __esm({
|
|
|
1569
1995
|
onDismiss: () => dismiss("dismissed")
|
|
1570
1996
|
});
|
|
1571
1997
|
tooltip.appendChild(content);
|
|
1998
|
+
const arrowEl = ownerDocument.createElement("div");
|
|
1999
|
+
arrowEl.className = "veo-tooltip-arrow";
|
|
2000
|
+
tooltip.appendChild(arrowEl);
|
|
1572
2001
|
root.appendChild(tooltip);
|
|
1573
2002
|
const updatePosition = async () => {
|
|
1574
|
-
const { x, y } = await dom.computePosition(anchor, tooltip, {
|
|
2003
|
+
const { x, y, placement, middlewareData } = await dom.computePosition(anchor, tooltip, {
|
|
1575
2004
|
placement: "bottom",
|
|
1576
|
-
middleware: [dom.offset(
|
|
2005
|
+
middleware: [dom.offset(10), dom.flip(), dom.shift({ padding: 8 }), dom.arrow({ element: arrowEl })]
|
|
1577
2006
|
});
|
|
1578
2007
|
tooltip.style.left = `${x}px`;
|
|
1579
2008
|
tooltip.style.top = `${y}px`;
|
|
2009
|
+
positionArrow(arrowEl, placement, middlewareData.arrow);
|
|
1580
2010
|
};
|
|
1581
2011
|
await updatePosition();
|
|
1582
2012
|
const reposition = () => {
|
|
@@ -1597,98 +2027,14 @@ var init_tooltip_renderer = __esm({
|
|
|
1597
2027
|
};
|
|
1598
2028
|
}
|
|
1599
2029
|
});
|
|
1600
|
-
|
|
1601
|
-
// src/plugins/guides/walkthrough-block-builder.ts
|
|
1602
|
-
function buildWalkthroughStepContent(step, stepIndex, totalSteps, doc, callbacks) {
|
|
1603
|
-
const container = doc.createElement("div");
|
|
1604
|
-
container.className = "veo-guide-content";
|
|
1605
|
-
const counter = doc.createElement("div");
|
|
1606
|
-
counter.className = "veo-walkthrough-counter";
|
|
1607
|
-
counter.textContent = `Paso ${stepIndex + 1} de ${totalSteps}`;
|
|
1608
|
-
container.appendChild(counter);
|
|
1609
|
-
const progress = doc.createElement("div");
|
|
1610
|
-
progress.className = "veo-walkthrough-progress";
|
|
1611
|
-
for (let i = 0; i < totalSteps; i++) {
|
|
1612
|
-
const dot = doc.createElement("span");
|
|
1613
|
-
dot.className = "veo-walkthrough-progress-dot";
|
|
1614
|
-
if (i < stepIndex) dot.classList.add("completed");
|
|
1615
|
-
if (i === stepIndex) dot.classList.add("active");
|
|
1616
|
-
progress.appendChild(dot);
|
|
1617
|
-
}
|
|
1618
|
-
container.appendChild(progress);
|
|
1619
|
-
if (typeof step.imageUrl === "string" && step.imageUrl && isSafeUrl(step.imageUrl)) {
|
|
1620
|
-
const img = doc.createElement("img");
|
|
1621
|
-
img.className = "veo-guide-image";
|
|
1622
|
-
img.src = step.imageUrl;
|
|
1623
|
-
img.alt = typeof step.title === "string" ? step.title : "";
|
|
1624
|
-
container.appendChild(img);
|
|
1625
|
-
}
|
|
1626
|
-
if (typeof step.title === "string" && step.title) {
|
|
1627
|
-
const heading = doc.createElement("h2");
|
|
1628
|
-
heading.className = "veo-guide-title";
|
|
1629
|
-
heading.textContent = step.title;
|
|
1630
|
-
container.appendChild(heading);
|
|
1631
|
-
}
|
|
1632
|
-
if (typeof step.content === "string" && step.content) {
|
|
1633
|
-
const paragraph = doc.createElement("p");
|
|
1634
|
-
paragraph.className = "veo-guide-text";
|
|
1635
|
-
paragraph.textContent = step.content;
|
|
1636
|
-
container.appendChild(paragraph);
|
|
1637
|
-
}
|
|
1638
|
-
const actions = doc.createElement("div");
|
|
1639
|
-
actions.className = "veo-walkthrough-actions";
|
|
1640
|
-
const skipBtn = doc.createElement("button");
|
|
1641
|
-
skipBtn.type = "button";
|
|
1642
|
-
skipBtn.className = "veo-walkthrough-skip";
|
|
1643
|
-
skipBtn.textContent = "Omitir";
|
|
1644
|
-
skipBtn.addEventListener("click", () => callbacks.onSkip());
|
|
1645
|
-
actions.appendChild(skipBtn);
|
|
1646
|
-
const rightGroup = doc.createElement("div");
|
|
1647
|
-
rightGroup.className = "veo-walkthrough-actions-right";
|
|
1648
|
-
if (stepIndex > 0) {
|
|
1649
|
-
const backBtn = doc.createElement("button");
|
|
1650
|
-
backBtn.type = "button";
|
|
1651
|
-
backBtn.className = "veo-walkthrough-btn-secondary";
|
|
1652
|
-
backBtn.textContent = "Atr\xE1s";
|
|
1653
|
-
backBtn.addEventListener("click", () => callbacks.onBack());
|
|
1654
|
-
rightGroup.appendChild(backBtn);
|
|
1655
|
-
}
|
|
1656
|
-
const isLastStep = stepIndex === totalSteps - 1;
|
|
1657
|
-
const primaryBtn = doc.createElement("button");
|
|
1658
|
-
primaryBtn.type = "button";
|
|
1659
|
-
primaryBtn.className = "veo-guide-cta";
|
|
1660
|
-
const defaultLabel = isLastStep ? "Finalizar" : "Siguiente";
|
|
1661
|
-
primaryBtn.textContent = typeof step.ctaText === "string" && step.ctaText ? step.ctaText : defaultLabel;
|
|
1662
|
-
primaryBtn.addEventListener("click", () => {
|
|
1663
|
-
if (isLastStep) callbacks.onComplete();
|
|
1664
|
-
else callbacks.onNext();
|
|
1665
|
-
});
|
|
1666
|
-
rightGroup.appendChild(primaryBtn);
|
|
1667
|
-
actions.appendChild(rightGroup);
|
|
1668
|
-
container.appendChild(actions);
|
|
1669
|
-
return container;
|
|
1670
|
-
}
|
|
1671
|
-
var init_walkthrough_block_builder = __esm({
|
|
1672
|
-
"src/plugins/guides/walkthrough-block-builder.ts"() {
|
|
1673
|
-
init_block_builder();
|
|
1674
|
-
}
|
|
1675
|
-
});
|
|
1676
|
-
function positionArrow(arrowEl, placement, data) {
|
|
1677
|
-
const side = STATIC_SIDE[placement.split("-")[0] ?? "bottom"] ?? "top";
|
|
1678
|
-
for (const prop of ["top", "bottom", "left", "right"]) {
|
|
1679
|
-
arrowEl.style.setProperty(prop, "");
|
|
1680
|
-
}
|
|
1681
|
-
if (data?.x != null) arrowEl.style.setProperty("left", `${data.x}px`);
|
|
1682
|
-
if (data?.y != null) arrowEl.style.setProperty("top", `${data.y}px`);
|
|
1683
|
-
arrowEl.style.setProperty(side, "-6px");
|
|
1684
|
-
}
|
|
1685
|
-
var WalkthroughRenderer, STATIC_SIDE;
|
|
2030
|
+
var WalkthroughRenderer;
|
|
1686
2031
|
var init_walkthrough_renderer = __esm({
|
|
1687
2032
|
"src/plugins/guides/renderers/walkthrough-renderer.ts"() {
|
|
1688
2033
|
init_constants2();
|
|
1689
2034
|
init_wait_for_element();
|
|
1690
2035
|
init_walkthrough_block_builder();
|
|
1691
2036
|
init_base_renderer();
|
|
2037
|
+
init_floating_arrow();
|
|
1692
2038
|
WalkthroughRenderer = class extends BaseRenderer {
|
|
1693
2039
|
async render(context) {
|
|
1694
2040
|
const step = context.guide.guideSteps[context.currentStepIndex];
|
|
@@ -1736,12 +2082,6 @@ var init_walkthrough_renderer = __esm({
|
|
|
1736
2082
|
return true;
|
|
1737
2083
|
}
|
|
1738
2084
|
};
|
|
1739
|
-
STATIC_SIDE = {
|
|
1740
|
-
top: "bottom",
|
|
1741
|
-
bottom: "top",
|
|
1742
|
-
left: "right",
|
|
1743
|
-
right: "left"
|
|
1744
|
-
};
|
|
1745
2085
|
}
|
|
1746
2086
|
});
|
|
1747
2087
|
|
|
@@ -1819,6 +2159,7 @@ var init_guide_preview = __esm({
|
|
|
1819
2159
|
GuidePreviewController = class {
|
|
1820
2160
|
constructor() {
|
|
1821
2161
|
this.singleStep = null;
|
|
2162
|
+
/** Renderer del paso de walkthrough activo (walkthrough tooltip o modal/banner). */
|
|
1822
2163
|
this.walkthrough = null;
|
|
1823
2164
|
this.walkthroughGuide = null;
|
|
1824
2165
|
this.walkthroughIndex = 0;
|
|
@@ -1891,7 +2232,6 @@ var init_guide_preview = __esm({
|
|
|
1891
2232
|
safeDestroy(this.walkthrough);
|
|
1892
2233
|
this.walkthrough = null;
|
|
1893
2234
|
}
|
|
1894
|
-
const renderer = new WalkthroughRenderer();
|
|
1895
2235
|
const callbacks = {
|
|
1896
2236
|
onNext: () => {
|
|
1897
2237
|
const next = this.walkthroughIndex + 1;
|
|
@@ -1911,6 +2251,30 @@ var init_guide_preview = __esm({
|
|
|
1911
2251
|
onSkip: () => this.close(),
|
|
1912
2252
|
onComplete: () => this.close()
|
|
1913
2253
|
};
|
|
2254
|
+
const step = guide.guideSteps[index];
|
|
2255
|
+
const render = step?.style?.render;
|
|
2256
|
+
if (render === "modal" || render === "banner") {
|
|
2257
|
+
const renderer2 = render === "modal" ? new ModalRenderer() : new BannerRenderer();
|
|
2258
|
+
try {
|
|
2259
|
+
renderer2.render({
|
|
2260
|
+
guide,
|
|
2261
|
+
onInteraction: () => {
|
|
2262
|
+
},
|
|
2263
|
+
onClose: () => this.close(),
|
|
2264
|
+
nav: { stepIndex: index, totalSteps: guide.guideSteps.length, callbacks }
|
|
2265
|
+
});
|
|
2266
|
+
} catch {
|
|
2267
|
+
safeDestroy(renderer2);
|
|
2268
|
+
return false;
|
|
2269
|
+
}
|
|
2270
|
+
if (this.walkthroughGuide !== guide) {
|
|
2271
|
+
safeDestroy(renderer2);
|
|
2272
|
+
return false;
|
|
2273
|
+
}
|
|
2274
|
+
this.walkthrough = renderer2;
|
|
2275
|
+
return true;
|
|
2276
|
+
}
|
|
2277
|
+
const renderer = new WalkthroughRenderer();
|
|
1914
2278
|
let success = false;
|
|
1915
2279
|
try {
|
|
1916
2280
|
success = await renderer.render({ guide, currentStepIndex: index, callbacks });
|
|
@@ -3978,6 +4342,11 @@ var GuidesController = class {
|
|
|
3978
4342
|
*/
|
|
3979
4343
|
this.activeByGuideId = /* @__PURE__ */ new Map();
|
|
3980
4344
|
this.dispatched = /* @__PURE__ */ new Set();
|
|
4345
|
+
/**
|
|
4346
|
+
* Renderer del paso de walkthrough activo. Puede ser el `WalkthroughRenderer`
|
|
4347
|
+
* (tooltip anclado) o un Modal/Banner con navegación (walkthrough heterogéneo);
|
|
4348
|
+
* tipamos por `destroy()`, lo único que el controller necesita.
|
|
4349
|
+
*/
|
|
3981
4350
|
this.activeWalkthroughRenderer = null;
|
|
3982
4351
|
this.activeWalkthroughGuide = null;
|
|
3983
4352
|
this.debug = config.debug === true;
|
|
@@ -4158,7 +4527,6 @@ var GuidesController = class {
|
|
|
4158
4527
|
this.activeWalkthroughRenderer.destroy();
|
|
4159
4528
|
this.activeWalkthroughRenderer = null;
|
|
4160
4529
|
}
|
|
4161
|
-
const renderer = new WalkthroughRenderer();
|
|
4162
4530
|
this.activeWalkthroughGuide = guide;
|
|
4163
4531
|
const callbacks = {
|
|
4164
4532
|
onNext: () => this.handleWalkthroughNext(endUserId, sessionId, pageUrl),
|
|
@@ -4166,6 +4534,28 @@ var GuidesController = class {
|
|
|
4166
4534
|
onSkip: () => this.handleWalkthroughSkip(endUserId, sessionId, pageUrl),
|
|
4167
4535
|
onComplete: () => this.handleWalkthroughComplete(endUserId, sessionId, pageUrl)
|
|
4168
4536
|
};
|
|
4537
|
+
const step = guide.guideSteps[stepIndex];
|
|
4538
|
+
const render = readStepRender(step);
|
|
4539
|
+
if (render === "modal" || render === "banner") {
|
|
4540
|
+
const renderer2 = render === "modal" ? new ModalRenderer() : new BannerRenderer();
|
|
4541
|
+
try {
|
|
4542
|
+
renderer2.render({
|
|
4543
|
+
guide,
|
|
4544
|
+
onInteraction: () => {
|
|
4545
|
+
},
|
|
4546
|
+
onClose: () => {
|
|
4547
|
+
},
|
|
4548
|
+
nav: { stepIndex, totalSteps: guide.guideSteps.length, callbacks }
|
|
4549
|
+
});
|
|
4550
|
+
} catch (err) {
|
|
4551
|
+
if (this.debug) console.error("[veo] sequence renderer threw:", err);
|
|
4552
|
+
this.tearDownWalkthrough();
|
|
4553
|
+
return false;
|
|
4554
|
+
}
|
|
4555
|
+
this.activeWalkthroughRenderer = renderer2;
|
|
4556
|
+
return true;
|
|
4557
|
+
}
|
|
4558
|
+
const renderer = new WalkthroughRenderer();
|
|
4169
4559
|
let success = false;
|
|
4170
4560
|
try {
|
|
4171
4561
|
success = await renderer.render({ guide, currentStepIndex: stepIndex, callbacks });
|
|
@@ -4388,6 +4778,10 @@ function extractPath(url) {
|
|
|
4388
4778
|
return "/";
|
|
4389
4779
|
}
|
|
4390
4780
|
}
|
|
4781
|
+
function readStepRender(step) {
|
|
4782
|
+
const r = step?.style?.render;
|
|
4783
|
+
return typeof r === "string" ? r : "walkthrough";
|
|
4784
|
+
}
|
|
4391
4785
|
|
|
4392
4786
|
// src/plugins/guides/index.ts
|
|
4393
4787
|
init_guide_preview();
|