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.
package/dist/index.cjs CHANGED
@@ -378,6 +378,16 @@ var init_constants2 = __esm({
378
378
  function buildStepContent(step, doc, callbacks) {
379
379
  const container = doc.createElement("div");
380
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) {
381
391
  if (typeof step.imageUrl === "string" && step.imageUrl && isSafeUrl(step.imageUrl)) {
382
392
  const img = doc.createElement("img");
383
393
  img.className = "veo-guide-image";
@@ -412,8 +422,111 @@ function buildStepContent(step, doc, callbacks) {
412
422
  actions.appendChild(cta);
413
423
  }
414
424
  container.appendChild(actions);
415
- container.appendChild(createCloseButton(doc, () => callbacks.onDismiss()));
416
- return container;
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
+ let rowAlign;
443
+ while (i < blocks.length && blocks[i]?.type === "button") {
444
+ const btnBlock = blocks[i];
445
+ if (!rowAlign) {
446
+ const a = btnBlock.style?.align;
447
+ if (a === "left" || a === "center" || a === "right") rowAlign = a;
448
+ }
449
+ actions.appendChild(buildButtonBlock(btnBlock, doc, callbacks));
450
+ i++;
451
+ }
452
+ if (rowAlign) actions.style.justifyContent = BLOCK_ALIGN_SELF[rowAlign];
453
+ container.appendChild(actions);
454
+ continue;
455
+ }
456
+ const node = buildContentBlock(block, doc);
457
+ if (node) container.appendChild(node);
458
+ i++;
459
+ }
460
+ }
461
+ function buildContentBlock(block, doc) {
462
+ switch (block.type) {
463
+ case "title": {
464
+ const el = doc.createElement("h2");
465
+ el.className = "veo-guide-title";
466
+ el.textContent = typeof block.text === "string" ? block.text : "";
467
+ applyBlockStyle(el, block.style, "text");
468
+ return el;
469
+ }
470
+ case "text": {
471
+ const el = doc.createElement("p");
472
+ el.className = "veo-guide-text";
473
+ el.textContent = typeof block.text === "string" ? block.text : "";
474
+ applyBlockStyle(el, block.style, "text");
475
+ return el;
476
+ }
477
+ case "image": {
478
+ if (typeof block.url !== "string" || !isSafeUrl(block.url)) return null;
479
+ const el = doc.createElement("img");
480
+ el.className = "veo-guide-image";
481
+ el.src = block.url;
482
+ el.alt = "";
483
+ applyBlockStyle(el, block.style, "image");
484
+ return el;
485
+ }
486
+ default:
487
+ return null;
488
+ }
489
+ }
490
+ function buildButtonBlock(block, doc, callbacks) {
491
+ const btn = doc.createElement("button");
492
+ btn.type = "button";
493
+ btn.className = "veo-guide-cta";
494
+ btn.textContent = typeof block.text === "string" && block.text ? block.text : "OK";
495
+ applyBlockStyle(btn, block.style, "button");
496
+ btn.addEventListener("click", () => {
497
+ const action = block.action ?? "dismiss";
498
+ const url = action === "url" && typeof block.url === "string" && isSafeUrl(block.url) ? block.url : void 0;
499
+ callbacks.onCtaClick(action, url);
500
+ });
501
+ return btn;
502
+ }
503
+ function clampNum(n, min, max) {
504
+ return Math.min(max, Math.max(min, n));
505
+ }
506
+ function applyBlockStyle(el, style, kind) {
507
+ if (!style || typeof style !== "object") return;
508
+ const s = style;
509
+ const align = typeof s.align === "string" ? s.align : null;
510
+ if (align && (align === "left" || align === "center" || align === "right")) {
511
+ if (kind === "text") el.style.textAlign = align;
512
+ else if (kind === "image") el.style.alignSelf = BLOCK_ALIGN_SELF[align];
513
+ }
514
+ if (kind !== "image" && typeof s.color === "string") el.style.color = s.color;
515
+ if (kind === "text" && typeof s.fontSize === "number" && Number.isFinite(s.fontSize)) {
516
+ el.style.fontSize = `${clampNum(s.fontSize, 8, 72)}px`;
517
+ }
518
+ if (kind === "image" && typeof s.width === "number" && Number.isFinite(s.width)) {
519
+ el.style.width = `${clampNum(s.width, 10, 100)}%`;
520
+ }
521
+ if (kind === "image" && typeof s.radius === "number" && Number.isFinite(s.radius)) {
522
+ el.style.borderRadius = `${clampNum(s.radius, 0, 48)}px`;
523
+ }
524
+ if (typeof s.marginTop === "number" && Number.isFinite(s.marginTop)) {
525
+ el.style.marginTop = `${clampNum(s.marginTop, 0, 64)}px`;
526
+ }
527
+ if (typeof s.marginBottom === "number" && Number.isFinite(s.marginBottom)) {
528
+ el.style.marginBottom = `${clampNum(s.marginBottom, 0, 64)}px`;
529
+ }
417
530
  }
418
531
  function createCloseButton(doc, onClose, className = "veo-guide-close") {
419
532
  const closeBtn = doc.createElement("button");
@@ -439,9 +552,92 @@ function readCtaUrl(step) {
439
552
  if (typeof candidate !== "string") return void 0;
440
553
  return isSafeUrl(candidate) ? candidate : void 0;
441
554
  }
555
+ var BLOCK_ALIGN_SELF;
442
556
  var init_block_builder = __esm({
443
557
  "src/plugins/guides/block-builder.ts"() {
444
558
  init_constants2();
559
+ BLOCK_ALIGN_SELF = {
560
+ left: "flex-start",
561
+ center: "center",
562
+ right: "flex-end"
563
+ };
564
+ }
565
+ });
566
+
567
+ // src/plugins/guides/walkthrough-block-builder.ts
568
+ function buildWalkthroughStepContent(step, stepIndex, totalSteps, doc, callbacks) {
569
+ const container = doc.createElement("div");
570
+ container.className = "veo-guide-content";
571
+ const counter = doc.createElement("div");
572
+ counter.className = "veo-walkthrough-counter";
573
+ counter.textContent = `Paso ${stepIndex + 1} de ${totalSteps}`;
574
+ container.appendChild(counter);
575
+ const progress = doc.createElement("div");
576
+ progress.className = "veo-walkthrough-progress";
577
+ for (let i = 0; i < totalSteps; i++) {
578
+ const dot = doc.createElement("span");
579
+ dot.className = "veo-walkthrough-progress-dot";
580
+ if (i < stepIndex) dot.classList.add("completed");
581
+ if (i === stepIndex) dot.classList.add("active");
582
+ progress.appendChild(dot);
583
+ }
584
+ container.appendChild(progress);
585
+ if (typeof step.imageUrl === "string" && step.imageUrl && isSafeUrl(step.imageUrl)) {
586
+ const img = doc.createElement("img");
587
+ img.className = "veo-guide-image";
588
+ img.src = step.imageUrl;
589
+ img.alt = typeof step.title === "string" ? step.title : "";
590
+ container.appendChild(img);
591
+ }
592
+ if (typeof step.title === "string" && step.title) {
593
+ const heading = doc.createElement("h2");
594
+ heading.className = "veo-guide-title";
595
+ heading.textContent = step.title;
596
+ container.appendChild(heading);
597
+ }
598
+ if (typeof step.content === "string" && step.content) {
599
+ const paragraph = doc.createElement("p");
600
+ paragraph.className = "veo-guide-text";
601
+ paragraph.textContent = step.content;
602
+ container.appendChild(paragraph);
603
+ }
604
+ const actions = doc.createElement("div");
605
+ actions.className = "veo-walkthrough-actions";
606
+ const skipBtn = doc.createElement("button");
607
+ skipBtn.type = "button";
608
+ skipBtn.className = "veo-walkthrough-skip";
609
+ skipBtn.textContent = "Omitir";
610
+ skipBtn.addEventListener("click", () => callbacks.onSkip());
611
+ actions.appendChild(skipBtn);
612
+ const rightGroup = doc.createElement("div");
613
+ rightGroup.className = "veo-walkthrough-actions-right";
614
+ if (stepIndex > 0) {
615
+ const backBtn = doc.createElement("button");
616
+ backBtn.type = "button";
617
+ backBtn.className = "veo-walkthrough-btn-secondary";
618
+ backBtn.textContent = "Atr\xE1s";
619
+ backBtn.addEventListener("click", () => callbacks.onBack());
620
+ rightGroup.appendChild(backBtn);
621
+ }
622
+ const isLastStep = stepIndex === totalSteps - 1;
623
+ const primaryBtn = doc.createElement("button");
624
+ primaryBtn.type = "button";
625
+ primaryBtn.className = "veo-guide-cta";
626
+ const defaultLabel = isLastStep ? "Finalizar" : "Siguiente";
627
+ primaryBtn.textContent = typeof step.ctaText === "string" && step.ctaText ? step.ctaText : defaultLabel;
628
+ primaryBtn.addEventListener("click", () => {
629
+ if (isLastStep) callbacks.onComplete();
630
+ else callbacks.onNext();
631
+ });
632
+ rightGroup.appendChild(primaryBtn);
633
+ actions.appendChild(rightGroup);
634
+ container.appendChild(actions);
635
+ container.appendChild(createCloseButton(doc, () => callbacks.onSkip()));
636
+ return container;
637
+ }
638
+ var init_walkthrough_block_builder = __esm({
639
+ "src/plugins/guides/walkthrough-block-builder.ts"() {
640
+ init_block_builder();
445
641
  }
446
642
  });
447
643
 
@@ -455,6 +651,9 @@ function applyDesignVars(host, style) {
455
651
  if (typeof s.accentColor === "string" && COLOR_RE.test(s.accentColor.trim())) {
456
652
  host.style.setProperty("--veo-primary", s.accentColor.trim());
457
653
  }
654
+ if (typeof s.fontFamily === "string" && s.fontFamily.length <= 200 && !/[<>{}]/.test(s.fontFamily)) {
655
+ host.style.setProperty("--veo-font", s.fontFamily.trim());
656
+ }
458
657
  if (s.theme === "dark") {
459
658
  for (const [key, value] of Object.entries(DARK_THEME)) {
460
659
  host.style.setProperty(key, value);
@@ -596,7 +795,7 @@ var init_styles = __esm({
596
795
  --veo-actions-justify: flex-end;
597
796
  all: initial;
598
797
  }
599
- * { box-sizing: border-box; font-family: -apple-system, system-ui, "Segoe UI", Roboto, sans-serif; }
798
+ * { box-sizing: border-box; font-family: var(--veo-font, -apple-system, system-ui, "Segoe UI", Roboto, sans-serif); }
600
799
 
601
800
  .veo-modal-overlay {
602
801
  position: fixed; inset: 0;
@@ -673,6 +872,12 @@ var init_styles = __esm({
673
872
  position: relative;
674
873
  display: flex; flex-direction: column;
675
874
  }
875
+ /* Reserva espacio para la \u2715 (esquina sup. derecha) SOLO en el primer bloque:
876
+ as\xED el texto alineado a la derecha no queda tapado por el bot\xF3n de cerrar. */
877
+ .veo-guide-content > .veo-guide-title:first-child,
878
+ .veo-guide-content > .veo-guide-text:first-child {
879
+ padding-right: 20px;
880
+ }
676
881
  .veo-guide-image {
677
882
  display: block;
678
883
  width: var(--veo-image-width, 100%);
@@ -939,10 +1144,12 @@ var BannerRenderer;
939
1144
  var init_banner_renderer = __esm({
940
1145
  "src/plugins/guides/renderers/banner-renderer.ts"() {
941
1146
  init_block_builder();
1147
+ init_walkthrough_block_builder();
942
1148
  init_base_renderer();
943
1149
  BannerRenderer = class extends BaseRenderer {
944
1150
  render(context) {
945
- const step = context.guide.guideSteps[0];
1151
+ const idx = context.nav?.stepIndex ?? 0;
1152
+ const step = context.guide.guideSteps[idx];
946
1153
  if (!step) return;
947
1154
  const { root } = this.createHost();
948
1155
  this.applyDesign(step.style);
@@ -951,27 +1158,25 @@ var init_banner_renderer = __esm({
951
1158
  const banner = ownerDocument.createElement("div");
952
1159
  banner.className = `veo-banner veo-banner-${position}`;
953
1160
  const dismiss = (action, ctaUrl) => {
954
- context.onInteraction({
955
- guideId: context.guide.guideId,
956
- stepIndex: 0,
957
- action
958
- });
1161
+ context.onInteraction({ guideId: context.guide.guideId, stepIndex: idx, action });
959
1162
  if (ctaUrl) window.open(ctaUrl, "_blank", "noopener,noreferrer");
960
1163
  context.onClose();
961
1164
  };
962
- const content = buildStepContent(step, ownerDocument, {
963
- onCtaClick: (action, url) => {
964
- dismiss("cta_clicked", action === "url" ? url : void 0);
965
- },
1165
+ const content = context.nav ? buildWalkthroughStepContent(
1166
+ step,
1167
+ context.nav.stepIndex,
1168
+ context.nav.totalSteps,
1169
+ ownerDocument,
1170
+ context.nav.callbacks
1171
+ ) : buildStepContent(step, ownerDocument, {
1172
+ onCtaClick: (action, url) => dismiss("cta_clicked", action === "url" ? url : void 0),
966
1173
  onDismiss: () => dismiss("dismissed")
967
1174
  });
968
1175
  banner.appendChild(content);
969
1176
  root.appendChild(banner);
970
- context.onInteraction({
971
- guideId: context.guide.guideId,
972
- stepIndex: 0,
973
- action: "shown"
974
- });
1177
+ if (!context.nav) {
1178
+ context.onInteraction({ guideId: context.guide.guideId, stepIndex: 0, action: "shown" });
1179
+ }
975
1180
  }
976
1181
  };
977
1182
  }
@@ -1693,10 +1898,12 @@ var ModalRenderer;
1693
1898
  var init_modal_renderer = __esm({
1694
1899
  "src/plugins/guides/renderers/modal-renderer.ts"() {
1695
1900
  init_block_builder();
1901
+ init_walkthrough_block_builder();
1696
1902
  init_base_renderer();
1697
1903
  ModalRenderer = class extends BaseRenderer {
1698
1904
  render(context) {
1699
- const step = context.guide.guideSteps[0];
1905
+ const idx = context.nav?.stepIndex ?? 0;
1906
+ const step = context.guide.guideSteps[idx];
1700
1907
  if (!step) return;
1701
1908
  const { root } = this.createHost();
1702
1909
  this.applyDesign(step.style);
@@ -1706,36 +1913,38 @@ var init_modal_renderer = __esm({
1706
1913
  const card = ownerDocument.createElement("div");
1707
1914
  card.className = "veo-modal-card";
1708
1915
  const dismiss = (action, ctaUrl) => {
1709
- context.onInteraction({
1710
- guideId: context.guide.guideId,
1711
- stepIndex: 0,
1712
- action
1713
- });
1916
+ context.onInteraction({ guideId: context.guide.guideId, stepIndex: idx, action });
1714
1917
  if (ctaUrl) window.open(ctaUrl, "_blank", "noopener,noreferrer");
1715
1918
  context.onClose();
1716
1919
  };
1717
- const content = buildStepContent(step, ownerDocument, {
1718
- onCtaClick: (action, url) => {
1719
- dismiss("cta_clicked", action === "url" ? url : void 0);
1720
- },
1920
+ const onBackdropOrEsc = () => {
1921
+ if (context.nav) context.nav.callbacks.onSkip();
1922
+ else dismiss("dismissed");
1923
+ };
1924
+ const content = context.nav ? buildWalkthroughStepContent(
1925
+ step,
1926
+ context.nav.stepIndex,
1927
+ context.nav.totalSteps,
1928
+ ownerDocument,
1929
+ context.nav.callbacks
1930
+ ) : buildStepContent(step, ownerDocument, {
1931
+ onCtaClick: (action, url) => dismiss("cta_clicked", action === "url" ? url : void 0),
1721
1932
  onDismiss: () => dismiss("dismissed")
1722
1933
  });
1723
1934
  card.appendChild(content);
1724
1935
  overlay.appendChild(card);
1725
1936
  root.appendChild(overlay);
1726
1937
  overlay.addEventListener("click", (e) => {
1727
- if (e.target === overlay) dismiss("dismissed");
1938
+ if (e.target === overlay) onBackdropOrEsc();
1728
1939
  });
1729
1940
  const onKey = (e) => {
1730
- if (e.key === "Escape") dismiss("dismissed");
1941
+ if (e.key === "Escape") onBackdropOrEsc();
1731
1942
  };
1732
1943
  document.addEventListener("keydown", onKey);
1733
1944
  this.registerCleanup(() => document.removeEventListener("keydown", onKey));
1734
- context.onInteraction({
1735
- guideId: context.guide.guideId,
1736
- stepIndex: 0,
1737
- action: "shown"
1738
- });
1945
+ if (!context.nav) {
1946
+ context.onInteraction({ guideId: context.guide.guideId, stepIndex: 0, action: "shown" });
1947
+ }
1739
1948
  }
1740
1949
  };
1741
1950
  }
@@ -1777,6 +1986,8 @@ var init_tooltip_renderer = __esm({
1777
1986
  if (typeof selector !== "string" || selector.length === 0) return;
1778
1987
  const anchor = await waitForElement(selector);
1779
1988
  if (!anchor) return;
1989
+ const rawSide = step.style?.tooltipPlacement;
1990
+ const side = rawSide === "top" || rawSide === "left" || rawSide === "right" ? rawSide : "bottom";
1780
1991
  const { root } = this.createHost();
1781
1992
  this.applyDesign(step.style);
1782
1993
  const ownerDocument = root.ownerDocument ?? document;
@@ -1804,7 +2015,7 @@ var init_tooltip_renderer = __esm({
1804
2015
  root.appendChild(tooltip);
1805
2016
  const updatePosition = async () => {
1806
2017
  const { x, y, placement, middlewareData } = await dom.computePosition(anchor, tooltip, {
1807
- placement: "bottom",
2018
+ placement: side,
1808
2019
  middleware: [dom.offset(10), dom.flip(), dom.shift({ padding: 8 }), dom.arrow({ element: arrowEl })]
1809
2020
  });
1810
2021
  tooltip.style.left = `${x}px`;
@@ -1830,83 +2041,6 @@ var init_tooltip_renderer = __esm({
1830
2041
  };
1831
2042
  }
1832
2043
  });
1833
-
1834
- // src/plugins/guides/walkthrough-block-builder.ts
1835
- function buildWalkthroughStepContent(step, stepIndex, totalSteps, doc, callbacks) {
1836
- const container = doc.createElement("div");
1837
- container.className = "veo-guide-content";
1838
- const counter = doc.createElement("div");
1839
- counter.className = "veo-walkthrough-counter";
1840
- counter.textContent = `Paso ${stepIndex + 1} de ${totalSteps}`;
1841
- container.appendChild(counter);
1842
- const progress = doc.createElement("div");
1843
- progress.className = "veo-walkthrough-progress";
1844
- for (let i = 0; i < totalSteps; i++) {
1845
- const dot = doc.createElement("span");
1846
- dot.className = "veo-walkthrough-progress-dot";
1847
- if (i < stepIndex) dot.classList.add("completed");
1848
- if (i === stepIndex) dot.classList.add("active");
1849
- progress.appendChild(dot);
1850
- }
1851
- container.appendChild(progress);
1852
- if (typeof step.imageUrl === "string" && step.imageUrl && isSafeUrl(step.imageUrl)) {
1853
- const img = doc.createElement("img");
1854
- img.className = "veo-guide-image";
1855
- img.src = step.imageUrl;
1856
- img.alt = typeof step.title === "string" ? step.title : "";
1857
- container.appendChild(img);
1858
- }
1859
- if (typeof step.title === "string" && step.title) {
1860
- const heading = doc.createElement("h2");
1861
- heading.className = "veo-guide-title";
1862
- heading.textContent = step.title;
1863
- container.appendChild(heading);
1864
- }
1865
- if (typeof step.content === "string" && step.content) {
1866
- const paragraph = doc.createElement("p");
1867
- paragraph.className = "veo-guide-text";
1868
- paragraph.textContent = step.content;
1869
- container.appendChild(paragraph);
1870
- }
1871
- const actions = doc.createElement("div");
1872
- actions.className = "veo-walkthrough-actions";
1873
- const skipBtn = doc.createElement("button");
1874
- skipBtn.type = "button";
1875
- skipBtn.className = "veo-walkthrough-skip";
1876
- skipBtn.textContent = "Omitir";
1877
- skipBtn.addEventListener("click", () => callbacks.onSkip());
1878
- actions.appendChild(skipBtn);
1879
- const rightGroup = doc.createElement("div");
1880
- rightGroup.className = "veo-walkthrough-actions-right";
1881
- if (stepIndex > 0) {
1882
- const backBtn = doc.createElement("button");
1883
- backBtn.type = "button";
1884
- backBtn.className = "veo-walkthrough-btn-secondary";
1885
- backBtn.textContent = "Atr\xE1s";
1886
- backBtn.addEventListener("click", () => callbacks.onBack());
1887
- rightGroup.appendChild(backBtn);
1888
- }
1889
- const isLastStep = stepIndex === totalSteps - 1;
1890
- const primaryBtn = doc.createElement("button");
1891
- primaryBtn.type = "button";
1892
- primaryBtn.className = "veo-guide-cta";
1893
- const defaultLabel = isLastStep ? "Finalizar" : "Siguiente";
1894
- primaryBtn.textContent = typeof step.ctaText === "string" && step.ctaText ? step.ctaText : defaultLabel;
1895
- primaryBtn.addEventListener("click", () => {
1896
- if (isLastStep) callbacks.onComplete();
1897
- else callbacks.onNext();
1898
- });
1899
- rightGroup.appendChild(primaryBtn);
1900
- actions.appendChild(rightGroup);
1901
- container.appendChild(actions);
1902
- container.appendChild(createCloseButton(doc, () => callbacks.onSkip()));
1903
- return container;
1904
- }
1905
- var init_walkthrough_block_builder = __esm({
1906
- "src/plugins/guides/walkthrough-block-builder.ts"() {
1907
- init_block_builder();
1908
- }
1909
- });
1910
2044
  var WalkthroughRenderer;
1911
2045
  var init_walkthrough_renderer = __esm({
1912
2046
  "src/plugins/guides/renderers/walkthrough-renderer.ts"() {
@@ -1923,6 +2057,8 @@ var init_walkthrough_renderer = __esm({
1923
2057
  if (typeof selector !== "string" || selector.length === 0) return false;
1924
2058
  const anchor = await waitForElement(selector, WALKTHROUGH_STEP_SELECTOR_TIMEOUT_MS);
1925
2059
  if (!anchor) return false;
2060
+ const rawSide = step.style?.tooltipPlacement;
2061
+ const side = rawSide === "top" || rawSide === "left" || rawSide === "right" ? rawSide : "bottom";
1926
2062
  const { root } = this.createHost();
1927
2063
  this.applyDesign(step.style);
1928
2064
  const ownerDocument = root.ownerDocument ?? document;
@@ -1942,7 +2078,7 @@ var init_walkthrough_renderer = __esm({
1942
2078
  root.appendChild(tooltip);
1943
2079
  const updatePosition = async () => {
1944
2080
  const { x, y, placement, middlewareData } = await dom.computePosition(anchor, tooltip, {
1945
- placement: "bottom",
2081
+ placement: side,
1946
2082
  middleware: [dom.offset(10), dom.flip(), dom.shift({ padding: 8 }), dom.arrow({ element: arrowEl })]
1947
2083
  });
1948
2084
  tooltip.style.left = `${x}px`;
@@ -2039,6 +2175,7 @@ var init_guide_preview = __esm({
2039
2175
  GuidePreviewController = class {
2040
2176
  constructor() {
2041
2177
  this.singleStep = null;
2178
+ /** Renderer del paso de walkthrough activo (walkthrough tooltip o modal/banner). */
2042
2179
  this.walkthrough = null;
2043
2180
  this.walkthroughGuide = null;
2044
2181
  this.walkthroughIndex = 0;
@@ -2111,7 +2248,6 @@ var init_guide_preview = __esm({
2111
2248
  safeDestroy(this.walkthrough);
2112
2249
  this.walkthrough = null;
2113
2250
  }
2114
- const renderer = new WalkthroughRenderer();
2115
2251
  const callbacks = {
2116
2252
  onNext: () => {
2117
2253
  const next = this.walkthroughIndex + 1;
@@ -2131,6 +2267,30 @@ var init_guide_preview = __esm({
2131
2267
  onSkip: () => this.close(),
2132
2268
  onComplete: () => this.close()
2133
2269
  };
2270
+ const step = guide.guideSteps[index];
2271
+ const render = step?.style?.render;
2272
+ if (render === "modal" || render === "banner") {
2273
+ const renderer2 = render === "modal" ? new ModalRenderer() : new BannerRenderer();
2274
+ try {
2275
+ renderer2.render({
2276
+ guide,
2277
+ onInteraction: () => {
2278
+ },
2279
+ onClose: () => this.close(),
2280
+ nav: { stepIndex: index, totalSteps: guide.guideSteps.length, callbacks }
2281
+ });
2282
+ } catch {
2283
+ safeDestroy(renderer2);
2284
+ return false;
2285
+ }
2286
+ if (this.walkthroughGuide !== guide) {
2287
+ safeDestroy(renderer2);
2288
+ return false;
2289
+ }
2290
+ this.walkthrough = renderer2;
2291
+ return true;
2292
+ }
2293
+ const renderer = new WalkthroughRenderer();
2134
2294
  let success = false;
2135
2295
  try {
2136
2296
  success = await renderer.render({ guide, currentStepIndex: index, callbacks });
@@ -4198,6 +4358,11 @@ var GuidesController = class {
4198
4358
  */
4199
4359
  this.activeByGuideId = /* @__PURE__ */ new Map();
4200
4360
  this.dispatched = /* @__PURE__ */ new Set();
4361
+ /**
4362
+ * Renderer del paso de walkthrough activo. Puede ser el `WalkthroughRenderer`
4363
+ * (tooltip anclado) o un Modal/Banner con navegación (walkthrough heterogéneo);
4364
+ * tipamos por `destroy()`, lo único que el controller necesita.
4365
+ */
4201
4366
  this.activeWalkthroughRenderer = null;
4202
4367
  this.activeWalkthroughGuide = null;
4203
4368
  this.debug = config.debug === true;
@@ -4378,7 +4543,6 @@ var GuidesController = class {
4378
4543
  this.activeWalkthroughRenderer.destroy();
4379
4544
  this.activeWalkthroughRenderer = null;
4380
4545
  }
4381
- const renderer = new WalkthroughRenderer();
4382
4546
  this.activeWalkthroughGuide = guide;
4383
4547
  const callbacks = {
4384
4548
  onNext: () => this.handleWalkthroughNext(endUserId, sessionId, pageUrl),
@@ -4386,6 +4550,28 @@ var GuidesController = class {
4386
4550
  onSkip: () => this.handleWalkthroughSkip(endUserId, sessionId, pageUrl),
4387
4551
  onComplete: () => this.handleWalkthroughComplete(endUserId, sessionId, pageUrl)
4388
4552
  };
4553
+ const step = guide.guideSteps[stepIndex];
4554
+ const render = readStepRender(step);
4555
+ if (render === "modal" || render === "banner") {
4556
+ const renderer2 = render === "modal" ? new ModalRenderer() : new BannerRenderer();
4557
+ try {
4558
+ renderer2.render({
4559
+ guide,
4560
+ onInteraction: () => {
4561
+ },
4562
+ onClose: () => {
4563
+ },
4564
+ nav: { stepIndex, totalSteps: guide.guideSteps.length, callbacks }
4565
+ });
4566
+ } catch (err) {
4567
+ if (this.debug) console.error("[veo] sequence renderer threw:", err);
4568
+ this.tearDownWalkthrough();
4569
+ return false;
4570
+ }
4571
+ this.activeWalkthroughRenderer = renderer2;
4572
+ return true;
4573
+ }
4574
+ const renderer = new WalkthroughRenderer();
4389
4575
  let success = false;
4390
4576
  try {
4391
4577
  success = await renderer.render({ guide, currentStepIndex: stepIndex, callbacks });
@@ -4608,6 +4794,10 @@ function extractPath(url) {
4608
4794
  return "/";
4609
4795
  }
4610
4796
  }
4797
+ function readStepRender(step) {
4798
+ const r = step?.style?.render;
4799
+ return typeof r === "string" ? r : "walkthrough";
4800
+ }
4611
4801
 
4612
4802
  // src/plugins/guides/index.ts
4613
4803
  init_guide_preview();