veo-sdk 0.3.6 → 0.3.8

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,5 @@
1
+ export { createBuilderSession, initBuilderMode, startElementPicker, stopElementPicker } from './chunk-T4BZ53QV.mjs';
2
+ import './chunk-E2KQJBUT.mjs';
3
+ import './chunk-PTG3BTJE.mjs';
4
+ //# sourceMappingURL=builder-YYMD7MNK.mjs.map
5
+ //# sourceMappingURL=builder-YYMD7MNK.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"builder-MIPJRGOD.mjs"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"builder-YYMD7MNK.mjs"}
package/dist/builder.cjs CHANGED
@@ -146,6 +146,16 @@ var WALKTHROUGH_STEP_SELECTOR_TIMEOUT_MS = 5e3;
146
146
  function buildStepContent(step, doc, callbacks) {
147
147
  const container = doc.createElement("div");
148
148
  container.className = "veo-guide-content";
149
+ const blocks = normalizeBlocks(step);
150
+ if (blocks) {
151
+ renderBlocks(container, blocks, doc, callbacks);
152
+ } else {
153
+ renderLegacyStep(container, step, doc, callbacks);
154
+ }
155
+ container.appendChild(createCloseButton(doc, () => callbacks.onDismiss()));
156
+ return container;
157
+ }
158
+ function renderLegacyStep(container, step, doc, callbacks) {
149
159
  if (typeof step.imageUrl === "string" && step.imageUrl && isSafeUrl(step.imageUrl)) {
150
160
  const img = doc.createElement("img");
151
161
  img.className = "veo-guide-image";
@@ -180,8 +190,116 @@ function buildStepContent(step, doc, callbacks) {
180
190
  actions.appendChild(cta);
181
191
  }
182
192
  container.appendChild(actions);
183
- container.appendChild(createCloseButton(doc, () => callbacks.onDismiss()));
184
- return container;
193
+ }
194
+ function normalizeBlocks(step) {
195
+ if (!Array.isArray(step.blocks) || step.blocks.length === 0) return null;
196
+ const valid = step.blocks.filter((b) => {
197
+ if (!b || typeof b !== "object") return false;
198
+ if (b.type === "image") return typeof b.url === "string" && isSafeUrl(b.url);
199
+ return b.type === "title" || b.type === "text" || b.type === "button";
200
+ });
201
+ return valid.length > 0 ? valid : null;
202
+ }
203
+ function renderBlocks(container, blocks, doc, callbacks) {
204
+ let i = 0;
205
+ while (i < blocks.length) {
206
+ const block = blocks[i];
207
+ if (block?.type === "button") {
208
+ const actions = doc.createElement("div");
209
+ actions.className = "veo-guide-actions";
210
+ let rowAlign;
211
+ while (i < blocks.length && blocks[i]?.type === "button") {
212
+ const btnBlock = blocks[i];
213
+ if (!rowAlign) {
214
+ const a = btnBlock.style?.align;
215
+ if (a === "left" || a === "center" || a === "right") rowAlign = a;
216
+ }
217
+ actions.appendChild(buildButtonBlock(btnBlock, doc, callbacks));
218
+ i++;
219
+ }
220
+ if (rowAlign) actions.style.justifyContent = BLOCK_ALIGN_SELF[rowAlign];
221
+ container.appendChild(actions);
222
+ continue;
223
+ }
224
+ const node = buildContentBlock(block, doc);
225
+ if (node) container.appendChild(node);
226
+ i++;
227
+ }
228
+ }
229
+ function buildContentBlock(block, doc) {
230
+ switch (block.type) {
231
+ case "title": {
232
+ const el = doc.createElement("h2");
233
+ el.className = "veo-guide-title";
234
+ el.textContent = typeof block.text === "string" ? block.text : "";
235
+ applyBlockStyle(el, block.style, "text");
236
+ return el;
237
+ }
238
+ case "text": {
239
+ const el = doc.createElement("p");
240
+ el.className = "veo-guide-text";
241
+ el.textContent = typeof block.text === "string" ? block.text : "";
242
+ applyBlockStyle(el, block.style, "text");
243
+ return el;
244
+ }
245
+ case "image": {
246
+ if (typeof block.url !== "string" || !isSafeUrl(block.url)) return null;
247
+ const el = doc.createElement("img");
248
+ el.className = "veo-guide-image";
249
+ el.src = block.url;
250
+ el.alt = "";
251
+ applyBlockStyle(el, block.style, "image");
252
+ return el;
253
+ }
254
+ default:
255
+ return null;
256
+ }
257
+ }
258
+ function buildButtonBlock(block, doc, callbacks) {
259
+ const btn = doc.createElement("button");
260
+ btn.type = "button";
261
+ btn.className = "veo-guide-cta";
262
+ btn.textContent = typeof block.text === "string" && block.text ? block.text : "OK";
263
+ applyBlockStyle(btn, block.style, "button");
264
+ btn.addEventListener("click", () => {
265
+ const action = block.action ?? "dismiss";
266
+ const url = action === "url" && typeof block.url === "string" && isSafeUrl(block.url) ? block.url : void 0;
267
+ callbacks.onCtaClick(action, url);
268
+ });
269
+ return btn;
270
+ }
271
+ var BLOCK_ALIGN_SELF = {
272
+ left: "flex-start",
273
+ center: "center",
274
+ right: "flex-end"
275
+ };
276
+ function clampNum(n, min, max) {
277
+ return Math.min(max, Math.max(min, n));
278
+ }
279
+ function applyBlockStyle(el, style, kind) {
280
+ if (!style || typeof style !== "object") return;
281
+ const s = style;
282
+ const align = typeof s.align === "string" ? s.align : null;
283
+ if (align && (align === "left" || align === "center" || align === "right")) {
284
+ if (kind === "text") el.style.textAlign = align;
285
+ else if (kind === "image") el.style.alignSelf = BLOCK_ALIGN_SELF[align];
286
+ }
287
+ if (kind !== "image" && typeof s.color === "string") el.style.color = s.color;
288
+ if (kind === "text" && typeof s.fontSize === "number" && Number.isFinite(s.fontSize)) {
289
+ el.style.fontSize = `${clampNum(s.fontSize, 8, 72)}px`;
290
+ }
291
+ if (kind === "image" && typeof s.width === "number" && Number.isFinite(s.width)) {
292
+ el.style.width = `${clampNum(s.width, 10, 100)}%`;
293
+ }
294
+ if (kind === "image" && typeof s.radius === "number" && Number.isFinite(s.radius)) {
295
+ el.style.borderRadius = `${clampNum(s.radius, 0, 48)}px`;
296
+ }
297
+ if (typeof s.marginTop === "number" && Number.isFinite(s.marginTop)) {
298
+ el.style.marginTop = `${clampNum(s.marginTop, 0, 64)}px`;
299
+ }
300
+ if (typeof s.marginBottom === "number" && Number.isFinite(s.marginBottom)) {
301
+ el.style.marginBottom = `${clampNum(s.marginBottom, 0, 64)}px`;
302
+ }
185
303
  }
186
304
  function createCloseButton(doc, onClose, className = "veo-guide-close") {
187
305
  const closeBtn = doc.createElement("button");
@@ -208,6 +326,78 @@ function readCtaUrl(step) {
208
326
  return isSafeUrl(candidate) ? candidate : void 0;
209
327
  }
210
328
 
329
+ // src/plugins/guides/walkthrough-block-builder.ts
330
+ function buildWalkthroughStepContent(step, stepIndex, totalSteps, doc, callbacks) {
331
+ const container = doc.createElement("div");
332
+ container.className = "veo-guide-content";
333
+ const counter = doc.createElement("div");
334
+ counter.className = "veo-walkthrough-counter";
335
+ counter.textContent = `Paso ${stepIndex + 1} de ${totalSteps}`;
336
+ container.appendChild(counter);
337
+ const progress = doc.createElement("div");
338
+ progress.className = "veo-walkthrough-progress";
339
+ for (let i = 0; i < totalSteps; i++) {
340
+ const dot = doc.createElement("span");
341
+ dot.className = "veo-walkthrough-progress-dot";
342
+ if (i < stepIndex) dot.classList.add("completed");
343
+ if (i === stepIndex) dot.classList.add("active");
344
+ progress.appendChild(dot);
345
+ }
346
+ container.appendChild(progress);
347
+ if (typeof step.imageUrl === "string" && step.imageUrl && isSafeUrl(step.imageUrl)) {
348
+ const img = doc.createElement("img");
349
+ img.className = "veo-guide-image";
350
+ img.src = step.imageUrl;
351
+ img.alt = typeof step.title === "string" ? step.title : "";
352
+ container.appendChild(img);
353
+ }
354
+ if (typeof step.title === "string" && step.title) {
355
+ const heading = doc.createElement("h2");
356
+ heading.className = "veo-guide-title";
357
+ heading.textContent = step.title;
358
+ container.appendChild(heading);
359
+ }
360
+ if (typeof step.content === "string" && step.content) {
361
+ const paragraph = doc.createElement("p");
362
+ paragraph.className = "veo-guide-text";
363
+ paragraph.textContent = step.content;
364
+ container.appendChild(paragraph);
365
+ }
366
+ const actions = doc.createElement("div");
367
+ actions.className = "veo-walkthrough-actions";
368
+ const skipBtn = doc.createElement("button");
369
+ skipBtn.type = "button";
370
+ skipBtn.className = "veo-walkthrough-skip";
371
+ skipBtn.textContent = "Omitir";
372
+ skipBtn.addEventListener("click", () => callbacks.onSkip());
373
+ actions.appendChild(skipBtn);
374
+ const rightGroup = doc.createElement("div");
375
+ rightGroup.className = "veo-walkthrough-actions-right";
376
+ if (stepIndex > 0) {
377
+ const backBtn = doc.createElement("button");
378
+ backBtn.type = "button";
379
+ backBtn.className = "veo-walkthrough-btn-secondary";
380
+ backBtn.textContent = "Atr\xE1s";
381
+ backBtn.addEventListener("click", () => callbacks.onBack());
382
+ rightGroup.appendChild(backBtn);
383
+ }
384
+ const isLastStep = stepIndex === totalSteps - 1;
385
+ const primaryBtn = doc.createElement("button");
386
+ primaryBtn.type = "button";
387
+ primaryBtn.className = "veo-guide-cta";
388
+ const defaultLabel = isLastStep ? "Finalizar" : "Siguiente";
389
+ primaryBtn.textContent = typeof step.ctaText === "string" && step.ctaText ? step.ctaText : defaultLabel;
390
+ primaryBtn.addEventListener("click", () => {
391
+ if (isLastStep) callbacks.onComplete();
392
+ else callbacks.onNext();
393
+ });
394
+ rightGroup.appendChild(primaryBtn);
395
+ actions.appendChild(rightGroup);
396
+ container.appendChild(actions);
397
+ container.appendChild(createCloseButton(doc, () => callbacks.onSkip()));
398
+ return container;
399
+ }
400
+
211
401
  // src/plugins/guides/guide-design.ts
212
402
  var DARK_THEME = {
213
403
  "--veo-bg": "#1f2937",
@@ -257,6 +447,9 @@ function applyDesignVars(host, style) {
257
447
  if (typeof s.accentColor === "string" && COLOR_RE.test(s.accentColor.trim())) {
258
448
  host.style.setProperty("--veo-primary", s.accentColor.trim());
259
449
  }
450
+ if (typeof s.fontFamily === "string" && s.fontFamily.length <= 200 && !/[<>{}]/.test(s.fontFamily)) {
451
+ host.style.setProperty("--veo-font", s.fontFamily.trim());
452
+ }
260
453
  if (s.theme === "dark") {
261
454
  for (const [key, value] of Object.entries(DARK_THEME)) {
262
455
  host.style.setProperty(key, value);
@@ -350,7 +543,7 @@ var GUIDE_STYLES = `
350
543
  --veo-actions-justify: flex-end;
351
544
  all: initial;
352
545
  }
353
- * { box-sizing: border-box; font-family: -apple-system, system-ui, "Segoe UI", Roboto, sans-serif; }
546
+ * { box-sizing: border-box; font-family: var(--veo-font, -apple-system, system-ui, "Segoe UI", Roboto, sans-serif); }
354
547
 
355
548
  .veo-modal-overlay {
356
549
  position: fixed; inset: 0;
@@ -427,6 +620,12 @@ var GUIDE_STYLES = `
427
620
  position: relative;
428
621
  display: flex; flex-direction: column;
429
622
  }
623
+ /* Reserva espacio para la \u2715 (esquina sup. derecha) SOLO en el primer bloque:
624
+ as\xED el texto alineado a la derecha no queda tapado por el bot\xF3n de cerrar. */
625
+ .veo-guide-content > .veo-guide-title:first-child,
626
+ .veo-guide-content > .veo-guide-text:first-child {
627
+ padding-right: 20px;
628
+ }
430
629
  .veo-guide-image {
431
630
  display: block;
432
631
  width: var(--veo-image-width, 100%);
@@ -681,7 +880,8 @@ var BaseRenderer = class {
681
880
  // src/plugins/guides/renderers/banner-renderer.ts
682
881
  var BannerRenderer = class extends BaseRenderer {
683
882
  render(context) {
684
- const step = context.guide.guideSteps[0];
883
+ const idx = context.nav?.stepIndex ?? 0;
884
+ const step = context.guide.guideSteps[idx];
685
885
  if (!step) return;
686
886
  const { root } = this.createHost();
687
887
  this.applyDesign(step.style);
@@ -690,27 +890,25 @@ var BannerRenderer = class extends BaseRenderer {
690
890
  const banner = ownerDocument.createElement("div");
691
891
  banner.className = `veo-banner veo-banner-${position}`;
692
892
  const dismiss = (action, ctaUrl) => {
693
- context.onInteraction({
694
- guideId: context.guide.guideId,
695
- stepIndex: 0,
696
- action
697
- });
893
+ context.onInteraction({ guideId: context.guide.guideId, stepIndex: idx, action });
698
894
  if (ctaUrl) window.open(ctaUrl, "_blank", "noopener,noreferrer");
699
895
  context.onClose();
700
896
  };
701
- const content = buildStepContent(step, ownerDocument, {
702
- onCtaClick: (action, url) => {
703
- dismiss("cta_clicked", action === "url" ? url : void 0);
704
- },
897
+ const content = context.nav ? buildWalkthroughStepContent(
898
+ step,
899
+ context.nav.stepIndex,
900
+ context.nav.totalSteps,
901
+ ownerDocument,
902
+ context.nav.callbacks
903
+ ) : buildStepContent(step, ownerDocument, {
904
+ onCtaClick: (action, url) => dismiss("cta_clicked", action === "url" ? url : void 0),
705
905
  onDismiss: () => dismiss("dismissed")
706
906
  });
707
907
  banner.appendChild(content);
708
908
  root.appendChild(banner);
709
- context.onInteraction({
710
- guideId: context.guide.guideId,
711
- stepIndex: 0,
712
- action: "shown"
713
- });
909
+ if (!context.nav) {
910
+ context.onInteraction({ guideId: context.guide.guideId, stepIndex: 0, action: "shown" });
911
+ }
714
912
  }
715
913
  };
716
914
 
@@ -1390,7 +1588,8 @@ var InlineRenderer = class extends BaseRenderer {
1390
1588
  // src/plugins/guides/renderers/modal-renderer.ts
1391
1589
  var ModalRenderer = class extends BaseRenderer {
1392
1590
  render(context) {
1393
- const step = context.guide.guideSteps[0];
1591
+ const idx = context.nav?.stepIndex ?? 0;
1592
+ const step = context.guide.guideSteps[idx];
1394
1593
  if (!step) return;
1395
1594
  const { root } = this.createHost();
1396
1595
  this.applyDesign(step.style);
@@ -1400,36 +1599,38 @@ var ModalRenderer = class extends BaseRenderer {
1400
1599
  const card = ownerDocument.createElement("div");
1401
1600
  card.className = "veo-modal-card";
1402
1601
  const dismiss = (action, ctaUrl) => {
1403
- context.onInteraction({
1404
- guideId: context.guide.guideId,
1405
- stepIndex: 0,
1406
- action
1407
- });
1602
+ context.onInteraction({ guideId: context.guide.guideId, stepIndex: idx, action });
1408
1603
  if (ctaUrl) window.open(ctaUrl, "_blank", "noopener,noreferrer");
1409
1604
  context.onClose();
1410
1605
  };
1411
- const content = buildStepContent(step, ownerDocument, {
1412
- onCtaClick: (action, url) => {
1413
- dismiss("cta_clicked", action === "url" ? url : void 0);
1414
- },
1606
+ const onBackdropOrEsc = () => {
1607
+ if (context.nav) context.nav.callbacks.onSkip();
1608
+ else dismiss("dismissed");
1609
+ };
1610
+ const content = context.nav ? buildWalkthroughStepContent(
1611
+ step,
1612
+ context.nav.stepIndex,
1613
+ context.nav.totalSteps,
1614
+ ownerDocument,
1615
+ context.nav.callbacks
1616
+ ) : buildStepContent(step, ownerDocument, {
1617
+ onCtaClick: (action, url) => dismiss("cta_clicked", action === "url" ? url : void 0),
1415
1618
  onDismiss: () => dismiss("dismissed")
1416
1619
  });
1417
1620
  card.appendChild(content);
1418
1621
  overlay.appendChild(card);
1419
1622
  root.appendChild(overlay);
1420
1623
  overlay.addEventListener("click", (e) => {
1421
- if (e.target === overlay) dismiss("dismissed");
1624
+ if (e.target === overlay) onBackdropOrEsc();
1422
1625
  });
1423
1626
  const onKey = (e) => {
1424
- if (e.key === "Escape") dismiss("dismissed");
1627
+ if (e.key === "Escape") onBackdropOrEsc();
1425
1628
  };
1426
1629
  document.addEventListener("keydown", onKey);
1427
1630
  this.registerCleanup(() => document.removeEventListener("keydown", onKey));
1428
- context.onInteraction({
1429
- guideId: context.guide.guideId,
1430
- stepIndex: 0,
1431
- action: "shown"
1432
- });
1631
+ if (!context.nav) {
1632
+ context.onInteraction({ guideId: context.guide.guideId, stepIndex: 0, action: "shown" });
1633
+ }
1433
1634
  }
1434
1635
  };
1435
1636
 
@@ -1459,6 +1660,8 @@ var TooltipRenderer = class extends BaseRenderer {
1459
1660
  if (typeof selector !== "string" || selector.length === 0) return;
1460
1661
  const anchor = await waitForElement(selector);
1461
1662
  if (!anchor) return;
1663
+ const rawSide = step.style?.tooltipPlacement;
1664
+ const side = rawSide === "top" || rawSide === "left" || rawSide === "right" ? rawSide : "bottom";
1462
1665
  const { root } = this.createHost();
1463
1666
  this.applyDesign(step.style);
1464
1667
  const ownerDocument = root.ownerDocument ?? document;
@@ -1486,7 +1689,7 @@ var TooltipRenderer = class extends BaseRenderer {
1486
1689
  root.appendChild(tooltip);
1487
1690
  const updatePosition = async () => {
1488
1691
  const { x, y, placement, middlewareData } = await dom.computePosition(anchor, tooltip, {
1489
- placement: "bottom",
1692
+ placement: side,
1490
1693
  middleware: [dom.offset(10), dom.flip(), dom.shift({ padding: 8 }), dom.arrow({ element: arrowEl })]
1491
1694
  });
1492
1695
  tooltip.style.left = `${x}px`;
@@ -1510,80 +1713,6 @@ var TooltipRenderer = class extends BaseRenderer {
1510
1713
  });
1511
1714
  }
1512
1715
  };
1513
-
1514
- // src/plugins/guides/walkthrough-block-builder.ts
1515
- function buildWalkthroughStepContent(step, stepIndex, totalSteps, doc, callbacks) {
1516
- const container = doc.createElement("div");
1517
- container.className = "veo-guide-content";
1518
- const counter = doc.createElement("div");
1519
- counter.className = "veo-walkthrough-counter";
1520
- counter.textContent = `Paso ${stepIndex + 1} de ${totalSteps}`;
1521
- container.appendChild(counter);
1522
- const progress = doc.createElement("div");
1523
- progress.className = "veo-walkthrough-progress";
1524
- for (let i = 0; i < totalSteps; i++) {
1525
- const dot = doc.createElement("span");
1526
- dot.className = "veo-walkthrough-progress-dot";
1527
- if (i < stepIndex) dot.classList.add("completed");
1528
- if (i === stepIndex) dot.classList.add("active");
1529
- progress.appendChild(dot);
1530
- }
1531
- container.appendChild(progress);
1532
- if (typeof step.imageUrl === "string" && step.imageUrl && isSafeUrl(step.imageUrl)) {
1533
- const img = doc.createElement("img");
1534
- img.className = "veo-guide-image";
1535
- img.src = step.imageUrl;
1536
- img.alt = typeof step.title === "string" ? step.title : "";
1537
- container.appendChild(img);
1538
- }
1539
- if (typeof step.title === "string" && step.title) {
1540
- const heading = doc.createElement("h2");
1541
- heading.className = "veo-guide-title";
1542
- heading.textContent = step.title;
1543
- container.appendChild(heading);
1544
- }
1545
- if (typeof step.content === "string" && step.content) {
1546
- const paragraph = doc.createElement("p");
1547
- paragraph.className = "veo-guide-text";
1548
- paragraph.textContent = step.content;
1549
- container.appendChild(paragraph);
1550
- }
1551
- const actions = doc.createElement("div");
1552
- actions.className = "veo-walkthrough-actions";
1553
- const skipBtn = doc.createElement("button");
1554
- skipBtn.type = "button";
1555
- skipBtn.className = "veo-walkthrough-skip";
1556
- skipBtn.textContent = "Omitir";
1557
- skipBtn.addEventListener("click", () => callbacks.onSkip());
1558
- actions.appendChild(skipBtn);
1559
- const rightGroup = doc.createElement("div");
1560
- rightGroup.className = "veo-walkthrough-actions-right";
1561
- if (stepIndex > 0) {
1562
- const backBtn = doc.createElement("button");
1563
- backBtn.type = "button";
1564
- backBtn.className = "veo-walkthrough-btn-secondary";
1565
- backBtn.textContent = "Atr\xE1s";
1566
- backBtn.addEventListener("click", () => callbacks.onBack());
1567
- rightGroup.appendChild(backBtn);
1568
- }
1569
- const isLastStep = stepIndex === totalSteps - 1;
1570
- const primaryBtn = doc.createElement("button");
1571
- primaryBtn.type = "button";
1572
- primaryBtn.className = "veo-guide-cta";
1573
- const defaultLabel = isLastStep ? "Finalizar" : "Siguiente";
1574
- primaryBtn.textContent = typeof step.ctaText === "string" && step.ctaText ? step.ctaText : defaultLabel;
1575
- primaryBtn.addEventListener("click", () => {
1576
- if (isLastStep) callbacks.onComplete();
1577
- else callbacks.onNext();
1578
- });
1579
- rightGroup.appendChild(primaryBtn);
1580
- actions.appendChild(rightGroup);
1581
- container.appendChild(actions);
1582
- container.appendChild(createCloseButton(doc, () => callbacks.onSkip()));
1583
- return container;
1584
- }
1585
-
1586
- // src/plugins/guides/renderers/walkthrough-renderer.ts
1587
1716
  var WalkthroughRenderer = class extends BaseRenderer {
1588
1717
  async render(context) {
1589
1718
  const step = context.guide.guideSteps[context.currentStepIndex];
@@ -1592,6 +1721,8 @@ var WalkthroughRenderer = class extends BaseRenderer {
1592
1721
  if (typeof selector !== "string" || selector.length === 0) return false;
1593
1722
  const anchor = await waitForElement(selector, WALKTHROUGH_STEP_SELECTOR_TIMEOUT_MS);
1594
1723
  if (!anchor) return false;
1724
+ const rawSide = step.style?.tooltipPlacement;
1725
+ const side = rawSide === "top" || rawSide === "left" || rawSide === "right" ? rawSide : "bottom";
1595
1726
  const { root } = this.createHost();
1596
1727
  this.applyDesign(step.style);
1597
1728
  const ownerDocument = root.ownerDocument ?? document;
@@ -1611,7 +1742,7 @@ var WalkthroughRenderer = class extends BaseRenderer {
1611
1742
  root.appendChild(tooltip);
1612
1743
  const updatePosition = async () => {
1613
1744
  const { x, y, placement, middlewareData } = await dom.computePosition(anchor, tooltip, {
1614
- placement: "bottom",
1745
+ placement: side,
1615
1746
  middleware: [dom.offset(10), dom.flip(), dom.shift({ padding: 8 }), dom.arrow({ element: arrowEl })]
1616
1747
  });
1617
1748
  tooltip.style.left = `${x}px`;
@@ -1637,6 +1768,7 @@ var PREVIEW_GUIDE_ID = "__veo_preview__";
1637
1768
  var GuidePreviewController = class {
1638
1769
  constructor() {
1639
1770
  this.singleStep = null;
1771
+ /** Renderer del paso de walkthrough activo (walkthrough tooltip o modal/banner). */
1640
1772
  this.walkthrough = null;
1641
1773
  this.walkthroughGuide = null;
1642
1774
  this.walkthroughIndex = 0;
@@ -1709,7 +1841,6 @@ var GuidePreviewController = class {
1709
1841
  safeDestroy(this.walkthrough);
1710
1842
  this.walkthrough = null;
1711
1843
  }
1712
- const renderer = new WalkthroughRenderer();
1713
1844
  const callbacks = {
1714
1845
  onNext: () => {
1715
1846
  const next = this.walkthroughIndex + 1;
@@ -1729,6 +1860,30 @@ var GuidePreviewController = class {
1729
1860
  onSkip: () => this.close(),
1730
1861
  onComplete: () => this.close()
1731
1862
  };
1863
+ const step = guide.guideSteps[index];
1864
+ const render = step?.style?.render;
1865
+ if (render === "modal" || render === "banner") {
1866
+ const renderer2 = render === "modal" ? new ModalRenderer() : new BannerRenderer();
1867
+ try {
1868
+ renderer2.render({
1869
+ guide,
1870
+ onInteraction: () => {
1871
+ },
1872
+ onClose: () => this.close(),
1873
+ nav: { stepIndex: index, totalSteps: guide.guideSteps.length, callbacks }
1874
+ });
1875
+ } catch {
1876
+ safeDestroy(renderer2);
1877
+ return false;
1878
+ }
1879
+ if (this.walkthroughGuide !== guide) {
1880
+ safeDestroy(renderer2);
1881
+ return false;
1882
+ }
1883
+ this.walkthrough = renderer2;
1884
+ return true;
1885
+ }
1886
+ const renderer = new WalkthroughRenderer();
1732
1887
  let success = false;
1733
1888
  try {
1734
1889
  success = await renderer.render({ guide, currentStepIndex: index, callbacks });