veo-sdk 0.3.14 → 0.3.16

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.
@@ -712,6 +712,24 @@ var GUIDE_STYLES = `
712
712
  cursor: pointer; color: #9ca3af; padding: 0;
713
713
  }
714
714
  .veo-guide-close:hover { color: var(--veo-text); }
715
+ /*
716
+ * Si el PRIMER bloque es una imagen, la \u2715 quedar\xEDa sobre la esquina de la foto
717
+ * (invisible seg\xFAn el color). En ese caso pasa a ser una pastilla flotante con
718
+ * fondo propio, legible sobre cualquier imagen. (Sin soporte de :has() queda el
719
+ * estilo base \u2014 mismo comportamiento de antes, sin regresi\xF3n.)
720
+ */
721
+ .veo-guide-content:has(> .veo-guide-image:first-child) > .veo-guide-close {
722
+ top: 2px; right: 2px;
723
+ display: flex; align-items: center; justify-content: center;
724
+ font-size: 16px; color: #374151;
725
+ background: rgba(255, 255, 255, 0.92);
726
+ border: 1px solid rgba(0, 0, 0, 0.08);
727
+ border-radius: 50%;
728
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.18);
729
+ }
730
+ .veo-guide-content:has(> .veo-guide-image:first-child) > .veo-guide-close:hover {
731
+ color: #111827;
732
+ }
715
733
 
716
734
  .veo-form { display: flex; flex-direction: column; gap: 14px; margin-bottom: 16px; }
717
735
  .veo-form-field { display: flex; flex-direction: column; gap: 6px; }
@@ -856,6 +874,37 @@ var BaseRenderer = class {
856
874
  this.host = null;
857
875
  this.shadow = null;
858
876
  this.cleanups = [];
877
+ // ── Update in-place (preview en vivo del editor) ──
878
+ // La subclase setea estas piezas en render() para habilitarlo: el contenedor
879
+ // del contenido, el nodo de contenido actual y cómo reconstruirlo.
880
+ this.liveContainer = null;
881
+ this.liveContent = null;
882
+ this.liveBuild = null;
883
+ /** Clave de anclaje/estructura fijada en render(); si cambia → remontar. */
884
+ this.liveKey = "";
885
+ }
886
+ /** Clave de anclaje derivada del step (override por subclase). */
887
+ liveKeyOf(_step) {
888
+ return "";
889
+ }
890
+ /** Hook post-swap (reposicionar tooltip, actualizar clase del banner…). */
891
+ onLiveUpdate(_step) {
892
+ }
893
+ /**
894
+ * Actualiza el contenido del step SIN remontar el host — así el preview del
895
+ * editor no parpadea en cada tecla. Devuelve `false` cuando el renderer no
896
+ * lo soporta o el cambio requiere remontar (cambió el ancla/estructura);
897
+ * en ese caso el caller hace el re-render completo.
898
+ */
899
+ updateStep(step) {
900
+ if (!this.host || !this.liveContainer || !this.liveContent || !this.liveBuild) return false;
901
+ if (this.liveKeyOf(step) !== this.liveKey) return false;
902
+ const next = this.liveBuild(step);
903
+ this.liveContainer.replaceChild(next, this.liveContent);
904
+ this.liveContent = next;
905
+ this.applyDesign(step.style);
906
+ this.onLiveUpdate(step);
907
+ return true;
859
908
  }
860
909
  /**
861
910
  * Crea un `<div data-veo-guide>` adjunto a `document.body`, le adjunta
@@ -938,9 +987,21 @@ var BannerRenderer = class extends BaseRenderer {
938
987
  banner.appendChild(content);
939
988
  root.appendChild(banner);
940
989
  if (!context.nav) {
990
+ this.liveContainer = banner;
991
+ this.liveContent = content;
992
+ this.liveBuild = (s) => buildStepContent(s, ownerDocument, {
993
+ onCtaClick: (action, url) => dismiss("cta_clicked", action === "url" ? url : void 0),
994
+ onDismiss: () => dismiss("dismissed")
995
+ });
941
996
  context.onInteraction({ guideId: context.guide.guideId, stepIndex: 0, action: "shown" });
942
997
  }
943
998
  }
999
+ onLiveUpdate(step) {
1000
+ if (this.liveContainer) {
1001
+ const position = step.style?.position === "bottom" ? "bottom" : "top";
1002
+ this.liveContainer.className = `veo-banner veo-banner-${position}`;
1003
+ }
1004
+ }
944
1005
  };
945
1006
 
946
1007
  // src/plugins/guides/wait-for-element.ts
@@ -1264,7 +1325,7 @@ function mountFormContent(card, context, doc) {
1264
1325
  const empty = value === void 0 || value === null || value === "";
1265
1326
  if (empty) {
1266
1327
  if (field.required) {
1267
- error.textContent = `Complet\xE1 "${field.label}"`;
1328
+ error.textContent = `Completa "${field.label}"`;
1268
1329
  error.style.display = "block";
1269
1330
  return;
1270
1331
  }
@@ -1273,7 +1334,7 @@ function mountFormContent(card, context, doc) {
1273
1334
  answers[field.key] = value;
1274
1335
  }
1275
1336
  if (Object.keys(answers).length === 0) {
1276
- error.textContent = "Respond\xE9 al menos un campo";
1337
+ error.textContent = "Responde al menos un campo";
1277
1338
  error.style.display = "block";
1278
1339
  return;
1279
1340
  }
@@ -1282,7 +1343,7 @@ function mountFormContent(card, context, doc) {
1282
1343
  void submitFn(answers).then((ok) => {
1283
1344
  if (!ok) {
1284
1345
  submit.disabled = false;
1285
- error.textContent = "No se pudo enviar. Prob\xE1 de nuevo.";
1346
+ error.textContent = "No se pudo enviar. Prueba de nuevo.";
1286
1347
  error.style.display = "block";
1287
1348
  return;
1288
1349
  }
@@ -1341,7 +1402,7 @@ function buildField(field, doc) {
1341
1402
  select.className = "veo-form-input";
1342
1403
  const blank = doc.createElement("option");
1343
1404
  blank.value = "";
1344
- blank.textContent = field.placeholder || "Eleg\xED una opci\xF3n\u2026";
1405
+ blank.textContent = field.placeholder || "Elige una opci\xF3n\u2026";
1345
1406
  select.appendChild(blank);
1346
1407
  for (const opt of field.options ?? []) {
1347
1408
  const option = doc.createElement("option");
@@ -1615,8 +1676,18 @@ var InlineRenderer = class extends BaseRenderer {
1615
1676
  });
1616
1677
  card.appendChild(content);
1617
1678
  root.appendChild(card);
1679
+ this.liveContainer = card;
1680
+ this.liveContent = content;
1681
+ this.liveKey = `${selector}|${position}`;
1682
+ this.liveBuild = (s) => buildStepContent(s, ownerDocument, {
1683
+ onCtaClick: (action, url) => dismiss("cta_clicked", action === "url" ? url : void 0),
1684
+ onDismiss: () => dismiss("dismissed")
1685
+ });
1618
1686
  context.onInteraction({ guideId: context.guide.guideId, stepIndex: 0, action: "shown" });
1619
1687
  }
1688
+ liveKeyOf(step) {
1689
+ return `${step.selector ?? ""}|${readInlinePosition(step.style)}`;
1690
+ }
1620
1691
  };
1621
1692
 
1622
1693
  // src/plugins/guides/renderers/modal-renderer.ts
@@ -1654,6 +1725,14 @@ var ModalRenderer = class extends BaseRenderer {
1654
1725
  card.appendChild(content);
1655
1726
  overlay.appendChild(card);
1656
1727
  root.appendChild(overlay);
1728
+ if (!context.nav) {
1729
+ this.liveContainer = card;
1730
+ this.liveContent = content;
1731
+ this.liveBuild = (s) => buildStepContent(s, ownerDocument, {
1732
+ onCtaClick: (action, url) => dismiss("cta_clicked", action === "url" ? url : void 0),
1733
+ onDismiss: () => dismiss("dismissed")
1734
+ });
1735
+ }
1657
1736
  overlay.addEventListener("click", (e) => {
1658
1737
  if (e.target === overlay) onBackdropOrEsc();
1659
1738
  });
@@ -1687,6 +1766,12 @@ function positionArrow(arrowEl, placement, data) {
1687
1766
 
1688
1767
  // src/plugins/guides/renderers/tooltip-renderer.ts
1689
1768
  var TooltipRenderer = class extends BaseRenderer {
1769
+ constructor() {
1770
+ super(...arguments);
1771
+ /** Lado preferido (mutable: el update in-place puede cambiarlo). */
1772
+ this.side = "bottom";
1773
+ this.reposition = null;
1774
+ }
1690
1775
  async render(context) {
1691
1776
  const step = context.guide.guideSteps[0];
1692
1777
  if (!step) return;
@@ -1695,7 +1780,7 @@ var TooltipRenderer = class extends BaseRenderer {
1695
1780
  const anchor = await waitForElement(selector);
1696
1781
  if (!anchor) return;
1697
1782
  const rawSide = step.style?.tooltipPlacement;
1698
- const side = rawSide === "top" || rawSide === "left" || rawSide === "right" ? rawSide : "bottom";
1783
+ this.side = rawSide === "top" || rawSide === "left" || rawSide === "right" ? rawSide : "bottom";
1699
1784
  const { root } = this.createHost();
1700
1785
  this.applyDesign(step.style);
1701
1786
  const ownerDocument = root.ownerDocument ?? document;
@@ -1723,7 +1808,7 @@ var TooltipRenderer = class extends BaseRenderer {
1723
1808
  root.appendChild(tooltip);
1724
1809
  const updatePosition = async () => {
1725
1810
  const { x, y, placement, middlewareData } = await computePosition(anchor, tooltip, {
1726
- placement: side,
1811
+ placement: this.side,
1727
1812
  middleware: [offset(10), flip(), shift({ padding: 8 }), arrow({ element: arrowEl })]
1728
1813
  });
1729
1814
  tooltip.style.left = `${x}px`;
@@ -1734,18 +1819,34 @@ var TooltipRenderer = class extends BaseRenderer {
1734
1819
  const reposition = () => {
1735
1820
  void updatePosition();
1736
1821
  };
1822
+ this.reposition = reposition;
1737
1823
  window.addEventListener("scroll", reposition, true);
1738
1824
  window.addEventListener("resize", reposition);
1739
1825
  this.registerCleanup(() => {
1740
1826
  window.removeEventListener("scroll", reposition, true);
1741
1827
  window.removeEventListener("resize", reposition);
1742
1828
  });
1829
+ this.liveContainer = tooltip;
1830
+ this.liveContent = content;
1831
+ this.liveKey = selector;
1832
+ this.liveBuild = (s) => buildStepContent(s, ownerDocument, {
1833
+ onCtaClick: (action, url) => dismiss("cta_clicked", action === "url" ? url : void 0),
1834
+ onDismiss: () => dismiss("dismissed")
1835
+ });
1743
1836
  context.onInteraction({
1744
1837
  guideId: context.guide.guideId,
1745
1838
  stepIndex: 0,
1746
1839
  action: "shown"
1747
1840
  });
1748
1841
  }
1842
+ liveKeyOf(step) {
1843
+ return step.selector ?? "";
1844
+ }
1845
+ onLiveUpdate(step) {
1846
+ const raw = step.style?.tooltipPlacement;
1847
+ this.side = raw === "top" || raw === "left" || raw === "right" ? raw : "bottom";
1848
+ this.reposition?.();
1849
+ }
1749
1850
  };
1750
1851
  var WalkthroughRenderer = class extends BaseRenderer {
1751
1852
  async render(context) {
@@ -1810,6 +1911,11 @@ var GuidePreviewController = class {
1810
1911
  this.input = null;
1811
1912
  }
1812
1913
  preview(input) {
1914
+ const nextStep = input.guideSteps[0];
1915
+ if (this.singleStep && this.input && input.guideType === this.input.guideType && input.guideType !== "walkthrough" && nextStep && this.singleStep.updateStep(nextStep)) {
1916
+ this.input = input;
1917
+ return { close: () => this.close(), ready: Promise.resolve({ rendered: true }) };
1918
+ }
1813
1919
  this.close();
1814
1920
  this.input = input;
1815
1921
  const guide = normalize(input);
@@ -2124,5 +2230,5 @@ function buildSelectorPath(element, maxAncestors = 5) {
2124
2230
  }
2125
2231
 
2126
2232
  export { ALWAYS_BLOCK_SELECTORS, BannerRenderer, CustomRenderer, DEFAULT_AUTOCAPTURE_CONFIG, DEFAULT_TRACKER_BATCH_SIZE, DEFAULT_TRACKER_FLUSH_INTERVAL_MS, DEFAULT_TRACKER_MAX_RETRIES, FREQUENCY_CACHE_KEY_PREFIX, FREQUENCY_CACHE_MAX_ENTRIES, FREQUENCY_CACHE_TTL_MS, FormRenderer, InlineCustomRenderer, InlineFormRenderer, InlineRenderer, MAX_ANCESTORS, ModalRenderer, PRIORITY_ATTRIBUTES, SENSITIVE_ATTRIBUTES, TooltipRenderer, WALKTHROUGH_ABANDONMENT_TIMEOUT_MS, WALKTHROUGH_STATE_KEY_PREFIX, WalkthroughRenderer, buildSelectorPath, clearBuilderToken, closeGuidePreview, filterHumanClasses, hasDocument, hasLocalStorage, hasNavigatorSendBeacon, hasWindow, isBuilderMode, previewGuide, resolveBuilderContext, resolveBuilderToken, uuidv7 };
2127
- //# sourceMappingURL=chunk-3WJDFE7Q.mjs.map
2128
- //# sourceMappingURL=chunk-3WJDFE7Q.mjs.map
2233
+ //# sourceMappingURL=chunk-YHUPUTWH.mjs.map
2234
+ //# sourceMappingURL=chunk-YHUPUTWH.mjs.map