veo-sdk 0.5.4 → 0.5.6

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
@@ -654,7 +654,8 @@ function buildButtonBlock(block, doc, callbacks) {
654
654
  btn.textContent = typeof block.text === "string" && block.text ? block.text : "OK";
655
655
  applyBlockStyle(btn, block.style, "button");
656
656
  btn.addEventListener("click", () => {
657
- const action = block.action ?? "dismiss";
657
+ const raw = block.action ?? "dismiss";
658
+ const action = raw === "next" || raw === "url" || raw === "guide" ? raw : "dismiss";
658
659
  const target = action === "url" && typeof block.url === "string" && isSafeUrl(block.url) ? block.url : action === "guide" && typeof block.targetGuideId === "string" && block.targetGuideId ? block.targetGuideId : void 0;
659
660
  const meta = {
660
661
  ...typeof block.id === "string" && block.id ? { buttonId: block.id } : {},
@@ -1075,6 +1076,35 @@ var init_styles = __esm({
1075
1076
  animation: veo-fade-in 160ms ease-out;
1076
1077
  }
1077
1078
 
1079
+ /* \u2500\u2500 Modelo unificado (composite) \u2500\u2500 */
1080
+ .veo-composite-overlay {
1081
+ position: fixed; inset: 0;
1082
+ z-index: ${GUIDE_Z_INDEX};
1083
+ pointer-events: none;
1084
+ }
1085
+ /* Backdrop atenuado (solo centro con backdrop activo). */
1086
+ .veo-composite-overlay--dim {
1087
+ background: rgba(0, 0, 0, 0.5);
1088
+ pointer-events: auto;
1089
+ }
1090
+ .veo-composite-anchored {
1091
+ position: fixed;
1092
+ z-index: ${GUIDE_Z_INDEX};
1093
+ }
1094
+ /* Card gen\xE9rica del modelo unificado. El dise\xF1o (bg/borde/padding/\u2026) lo aplica
1095
+ el renderer como estilos inline desde step.design; ac\xE1 van los defaults. */
1096
+ .veo-card {
1097
+ pointer-events: auto;
1098
+ background: var(--veo-bg, #ffffff);
1099
+ color: var(--veo-text, #1f2937);
1100
+ border-radius: var(--veo-radius, 12px);
1101
+ padding: 20px;
1102
+ max-width: 90vw;
1103
+ box-shadow: var(--veo-shadow, 0 12px 40px rgba(0, 0, 0, 0.18));
1104
+ animation: veo-fade-in 160ms ease-out;
1105
+ }
1106
+ .veo-composite-anchored .veo-card, .veo-composite-overlay .veo-card { position: relative; }
1107
+
1078
1108
  .veo-guide-content {
1079
1109
  position: relative;
1080
1110
  display: flex; flex-direction: column;
@@ -1920,6 +1950,191 @@ var init_banner_renderer = __esm({
1920
1950
  };
1921
1951
  }
1922
1952
  });
1953
+ function inlinePosOf(p) {
1954
+ return p === "before" || p === "prepend" || p === "append" ? p : "after";
1955
+ }
1956
+ function applyViewportPosition(card, position) {
1957
+ const s = card.style;
1958
+ s.position = "fixed";
1959
+ const M = "16px";
1960
+ const v = position.includes("top") ? "top" : position.includes("bottom") ? "bottom" : "middle";
1961
+ const h = position.includes("left") ? "left" : position.includes("right") ? "right" : "middle";
1962
+ if (position === "center") {
1963
+ s.top = "50%";
1964
+ s.left = "50%";
1965
+ s.transform = "translate(-50%, -50%)";
1966
+ return;
1967
+ }
1968
+ if (v === "top") s.top = M;
1969
+ else if (v === "bottom") s.bottom = M;
1970
+ else {
1971
+ s.top = "50%";
1972
+ s.transform = "translateY(-50%)";
1973
+ }
1974
+ if (h === "left") s.left = M;
1975
+ else if (h === "right") s.right = M;
1976
+ else {
1977
+ s.left = "50%";
1978
+ s.transform = `${s.transform} translateX(-50%)`.trim();
1979
+ }
1980
+ }
1981
+ async function anchorPosition(anchor, wrapper) {
1982
+ const update = async () => {
1983
+ const { x, y } = await dom.computePosition(anchor, wrapper, {
1984
+ placement: "bottom",
1985
+ strategy: "fixed",
1986
+ middleware: [dom.offset(8), dom.flip(), dom.shift({ padding: 8 })]
1987
+ });
1988
+ wrapper.style.left = `${x}px`;
1989
+ wrapper.style.top = `${y}px`;
1990
+ };
1991
+ await update();
1992
+ const reposition = () => void update();
1993
+ window.addEventListener("scroll", reposition, true);
1994
+ window.addEventListener("resize", reposition);
1995
+ return () => {
1996
+ window.removeEventListener("scroll", reposition, true);
1997
+ window.removeEventListener("resize", reposition);
1998
+ };
1999
+ }
2000
+ function applyCompositeDesign(card, design) {
2001
+ const s = card.style;
2002
+ const px = (v) => typeof v === "number" && Number.isFinite(v) ? `${v}px` : null;
2003
+ const strv = (v) => typeof v === "string" && v ? v : null;
2004
+ if (strv(design.background)) s.background = design.background;
2005
+ if (strv(design.textColor)) s.color = design.textColor;
2006
+ if (px(design.fontSize)) s.fontSize = px(design.fontSize);
2007
+ if (strv(design.fontWeight)) s.fontWeight = design.fontWeight;
2008
+ if (strv(design.align)) s.textAlign = design.align;
2009
+ if (typeof design.lineHeight === "number") s.lineHeight = `${design.lineHeight}%`;
2010
+ if (px(design.radius)) s.borderRadius = px(design.radius);
2011
+ if (px(design.width)) s.width = px(design.width);
2012
+ const bw = px(design.borderWidth);
2013
+ if (bw) s.border = `${bw} solid ${strv(design.borderColor) ?? "#e5e5e5"}`;
2014
+ for (const side of ["Top", "Right", "Bottom", "Left"]) {
2015
+ const p = px(design[`padding${side}`]);
2016
+ if (p) s.setProperty(`padding-${side.toLowerCase()}`, p);
2017
+ const m = px(design[`margin${side}`]);
2018
+ if (m) s.setProperty(`margin-${side.toLowerCase()}`, m);
2019
+ }
2020
+ }
2021
+ var CompositeRenderer;
2022
+ var init_composite_renderer = __esm({
2023
+ "src/plugins/guides/renderers/composite-renderer.ts"() {
2024
+ init_block_builder();
2025
+ init_inline_host();
2026
+ init_wait_for_element();
2027
+ init_base_renderer();
2028
+ CompositeRenderer = class extends BaseRenderer {
2029
+ async render(context) {
2030
+ const idx = context.nav?.stepIndex ?? 0;
2031
+ const step = context.guide.guideSteps[idx];
2032
+ if (!step) return;
2033
+ const anchorSelector = step.position === "relative-to-element" || step.presentation === "inline" ? step.anchorSelector?.trim() || void 0 : void 0;
2034
+ let anchor = null;
2035
+ if (anchorSelector) {
2036
+ anchor = await waitForElement(anchorSelector);
2037
+ if (!anchor) return;
2038
+ }
2039
+ const { host, root } = this.createHost();
2040
+ const doc = root.ownerDocument ?? document;
2041
+ const card = doc.createElement("div");
2042
+ card.className = "veo-card";
2043
+ applyCompositeDesign(card, step.design ?? {});
2044
+ const dismiss = (action, meta) => {
2045
+ context.onInteraction({
2046
+ guideId: context.guide.guideId,
2047
+ stepIndex: idx,
2048
+ action,
2049
+ ...meta?.id ? { metadata: { buttonId: meta.id } } : {}
2050
+ });
2051
+ };
2052
+ const synthetic = { blocks: step.blocks ?? [] };
2053
+ for (const node of buildContentNodes(synthetic, doc)) card.appendChild(node);
2054
+ const buttons = (step.blocks ?? []).filter((b) => b.type === "button");
2055
+ if (buttons.length) {
2056
+ const row = doc.createElement("div");
2057
+ row.className = "veo-guide-actions";
2058
+ for (const b of buttons) row.appendChild(this.buildButton(b, doc, context, dismiss));
2059
+ card.appendChild(row);
2060
+ }
2061
+ card.appendChild(
2062
+ createCloseButton(doc, () => {
2063
+ dismiss("dismissed");
2064
+ this.closeOrSkip(context);
2065
+ })
2066
+ );
2067
+ if (step.presentation === "inline" && anchor) {
2068
+ host.style.display = "block";
2069
+ const pos = inlinePosOf(step.inlinePosition);
2070
+ root.appendChild(card);
2071
+ insertHost(anchor, host, pos);
2072
+ this.registerCleanup(keepHostAttached(host, anchorSelector, pos));
2073
+ } else if (step.position === "relative-to-element" && anchor) {
2074
+ const wrapper = doc.createElement("div");
2075
+ wrapper.className = "veo-composite-anchored";
2076
+ wrapper.appendChild(card);
2077
+ root.appendChild(wrapper);
2078
+ this.registerCleanup(await anchorPosition(anchor, wrapper));
2079
+ } else {
2080
+ const overlay = doc.createElement("div");
2081
+ overlay.className = "veo-composite-overlay";
2082
+ if (step.position === "center" && step.design?.backdrop !== false) {
2083
+ overlay.classList.add("veo-composite-overlay--dim");
2084
+ overlay.addEventListener("click", (e) => {
2085
+ if (e.target === overlay) {
2086
+ dismiss("dismissed");
2087
+ this.closeOrSkip(context);
2088
+ }
2089
+ });
2090
+ }
2091
+ applyViewportPosition(card, step.position);
2092
+ overlay.appendChild(card);
2093
+ root.appendChild(overlay);
2094
+ }
2095
+ context.onInteraction({ guideId: context.guide.guideId, stepIndex: idx, action: "shown" });
2096
+ }
2097
+ /** Botón con enrutado de acción (navegación / cierre / url / guía). */
2098
+ buildButton(block, doc, context, emit) {
2099
+ const btn = doc.createElement("button");
2100
+ btn.type = "button";
2101
+ btn.className = "veo-guide-cta";
2102
+ btn.textContent = block.text?.trim() || "OK";
2103
+ btn.addEventListener("click", () => {
2104
+ emit("cta_clicked", block);
2105
+ const nav = context.nav?.callbacks;
2106
+ switch (block.action) {
2107
+ case "next":
2108
+ case "submit-forms":
2109
+ case "submit-forms-advance":
2110
+ if (nav) nav.onNext();
2111
+ else context.onClose();
2112
+ break;
2113
+ case "prev":
2114
+ nav?.onBack();
2115
+ break;
2116
+ case "url":
2117
+ if (typeof block.url === "string" && isSafeUrl(block.url)) {
2118
+ window.open(block.url, "_blank", "noopener,noreferrer");
2119
+ }
2120
+ break;
2121
+ case "guide":
2122
+ if (block.targetGuideId) context.onOpenGuide?.(block.targetGuideId);
2123
+ this.closeOrSkip(context);
2124
+ break;
2125
+ default:
2126
+ this.closeOrSkip(context);
2127
+ }
2128
+ });
2129
+ return btn;
2130
+ }
2131
+ closeOrSkip(context) {
2132
+ if (context.nav?.callbacks) context.nav.callbacks.onSkip();
2133
+ else context.onClose();
2134
+ }
2135
+ };
2136
+ }
2137
+ });
1923
2138
 
1924
2139
  // src/plugins/guides/renderers/custom-frame.ts
1925
2140
  function mountCustomFrame(doc, step, context, opts) {
@@ -2880,8 +3095,12 @@ function createSingleStepRenderer(type) {
2880
3095
  return new InlineFormRenderer();
2881
3096
  case "badge":
2882
3097
  return new BadgeRenderer();
3098
+ case "composite":
3099
+ return new CompositeRenderer();
2883
3100
  case "walkthrough":
2884
3101
  return null;
3102
+ default:
3103
+ return null;
2885
3104
  }
2886
3105
  }
2887
3106
  function safeDestroy(renderer) {
@@ -2897,6 +3116,7 @@ var init_guide_preview = __esm({
2897
3116
  init_badge_renderer();
2898
3117
  init_banner_renderer();
2899
3118
  init_base_renderer();
3119
+ init_composite_renderer();
2900
3120
  init_custom_renderer();
2901
3121
  init_form_renderer();
2902
3122
  init_inline_custom_renderer();
@@ -2930,6 +3150,13 @@ var init_guide_preview = __esm({
2930
3150
  this.input = input;
2931
3151
  const guide = normalize(input);
2932
3152
  const start = typeof input.startStepIndex === "number" ? input.startStepIndex : 0;
3153
+ if (guide.guideType === "composite") {
3154
+ const s = Math.min(Math.max(0, start), guide.guideSteps.length - 1);
3155
+ const active2 = guide.guideSteps[s];
3156
+ if (active2) guide.guideSteps = [active2];
3157
+ const ready2 = this.renderSingleStep(guide);
3158
+ return { close: () => this.close(), ready: ready2, host: () => this.activeHost() };
3159
+ }
2933
3160
  const ready = guide.guideType === "walkthrough" ? this.startWalkthrough(guide, start) : this.renderSingleStep(guide);
2934
3161
  return { close: () => this.close(), ready, host: () => this.activeHost() };
2935
3162
  }
@@ -3093,7 +3320,8 @@ function attachBlockDropTarget(options) {
3093
3320
  const types = event.dataTransfer?.types;
3094
3321
  return !!types && Array.from(types).includes(VEO_BLOCK_MIME);
3095
3322
  };
3096
- const locate = (event) => {
3323
+ const NEAR_PX = 48;
3324
+ const locate = (clientY) => {
3097
3325
  const container = contentEl();
3098
3326
  if (!container) return null;
3099
3327
  const rect = container.getBoundingClientRect();
@@ -3102,7 +3330,7 @@ function attachBlockDropTarget(options) {
3102
3330
  let y = kids.length === 0 ? rect.top + rect.height / 2 : 0;
3103
3331
  for (const kid of kids) {
3104
3332
  const r = kid.getBoundingClientRect();
3105
- if (event.clientY < r.top + r.height / 2) {
3333
+ if (clientY < r.top + r.height / 2) {
3106
3334
  const idx = Number(kid.dataset.veoIdx);
3107
3335
  beforeIndex = Number.isFinite(idx) ? idx : null;
3108
3336
  y = r.top;
@@ -3112,9 +3340,26 @@ function attachBlockDropTarget(options) {
3112
3340
  }
3113
3341
  return { beforeIndex, y, rect };
3114
3342
  };
3343
+ const overContent = (x, y, rect) => x >= rect.left - NEAR_PX && x <= rect.right + NEAR_PX && y >= rect.top - NEAR_PX && y <= rect.bottom + NEAR_PX;
3344
+ const hoverAt = (x, y) => {
3345
+ const at = locate(y);
3346
+ if (!at || !overContent(x, y, at.rect)) {
3347
+ hideLine();
3348
+ return false;
3349
+ }
3350
+ spot = at;
3351
+ showLine(at);
3352
+ return true;
3353
+ };
3354
+ const dropAt = (x, y) => {
3355
+ const at = locate(y);
3356
+ hideLine();
3357
+ if (!at || !overContent(x, y, at.rect)) return null;
3358
+ return { beforeIndex: at.beforeIndex };
3359
+ };
3115
3360
  const onDragOver = (event) => {
3116
3361
  if (!isBlockDrag(event)) return;
3117
- const at = locate(event);
3362
+ const at = locate(event.clientY);
3118
3363
  if (!at) return;
3119
3364
  event.preventDefault();
3120
3365
  if (event.dataTransfer) event.dataTransfer.dropEffect = "copy";
@@ -3125,7 +3370,7 @@ function attachBlockDropTarget(options) {
3125
3370
  if (!isBlockDrag(event)) return;
3126
3371
  event.preventDefault();
3127
3372
  const blockType = event.dataTransfer?.getData(VEO_BLOCK_MIME) ?? "";
3128
- const at = spot ?? locate(event);
3373
+ const at = spot ?? locate(event.clientY);
3129
3374
  hideLine();
3130
3375
  if (!blockType || !at) return;
3131
3376
  onDrop({ stepIndex, blockType, beforeIndex: at.beforeIndex });
@@ -3139,6 +3384,9 @@ function attachBlockDropTarget(options) {
3139
3384
  host.addEventListener("drop", onDropEvent);
3140
3385
  host.addEventListener("dragleave", onDragLeave);
3141
3386
  return {
3387
+ hoverAt,
3388
+ dropAt,
3389
+ cancelHover: hideLine,
3142
3390
  detach() {
3143
3391
  host.removeEventListener("dragover", onDragOver);
3144
3392
  host.removeEventListener("drop", onDropEvent);
@@ -3166,7 +3414,7 @@ var init_bridge_protocol = __esm({
3166
3414
  // src/plugins/builder/builder-panel.ts
3167
3415
  function injectBuilderPanel(opts) {
3168
3416
  if (!hasWindow() || !hasDocument()) {
3169
- return { target: () => null, teardown: () => {
3417
+ return { target: () => null, frameRect: () => null, teardown: () => {
3170
3418
  } };
3171
3419
  }
3172
3420
  const panelUrl = buildPanelUrl(opts);
@@ -3283,6 +3531,7 @@ function injectBuilderPanel(opts) {
3283
3531
  });
3284
3532
  return {
3285
3533
  target: () => popped && !popped.closed ? popped : iframe.contentWindow,
3534
+ frameRect: () => popped && !popped.closed ? null : iframe.getBoundingClientRect(),
3286
3535
  teardown: () => {
3287
3536
  stopPoll();
3288
3537
  if (popped && !popped.closed) popped.close();
@@ -3805,6 +4054,8 @@ function initBuilderMode() {
3805
4054
  let staticTarget = null;
3806
4055
  let manipulator = null;
3807
4056
  let dropTarget = null;
4057
+ let dragGhost = null;
4058
+ let previewStepIndex = 0;
3808
4059
  let pendingPreview = null;
3809
4060
  const getTarget = () => panel ? panel.target() : staticTarget;
3810
4061
  const post = (event) => {
@@ -3815,6 +4066,7 @@ function initBuilderMode() {
3815
4066
  manipulator = null;
3816
4067
  dropTarget?.detach();
3817
4068
  dropTarget = null;
4069
+ previewStepIndex = cmd.guide.startStepIndex ?? 0;
3818
4070
  const handle = previewGuide(cmd.guide);
3819
4071
  if (!cmd.editable) return;
3820
4072
  void handle.ready.then((result) => {
@@ -3840,6 +4092,47 @@ function initBuilderMode() {
3840
4092
  });
3841
4093
  });
3842
4094
  };
4095
+ const hideDragGhost = () => {
4096
+ dragGhost?.remove();
4097
+ dragGhost = null;
4098
+ };
4099
+ const moveDragGhost = (x, y, label) => {
4100
+ if (!dragGhost) {
4101
+ dragGhost = document.createElement("div");
4102
+ dragGhost.style.cssText = "position:fixed;padding:4px 10px;border-radius:999px;background:#1c1917;color:#fff;font:12px/1.4 system-ui,sans-serif;box-shadow:0 4px 14px rgba(0,0,0,0.35);border:1px solid rgba(255,255,255,0.25);pointer-events:none;z-index:2147483647;";
4103
+ document.body.appendChild(dragGhost);
4104
+ }
4105
+ dragGhost.textContent = label;
4106
+ dragGhost.style.left = `${x + 14}px`;
4107
+ dragGhost.style.top = `${y + 12}px`;
4108
+ };
4109
+ const handleBlockDrag = (cmd) => {
4110
+ const rect = panel?.frameRect();
4111
+ if (!rect || !dropTarget) {
4112
+ if (cmd.phase !== "move") hideDragGhost();
4113
+ dropTarget?.cancelHover();
4114
+ return;
4115
+ }
4116
+ const x = rect.left + cmd.x;
4117
+ const y = rect.top + cmd.y;
4118
+ if (cmd.phase === "move") {
4119
+ moveDragGhost(x, y, cmd.label || cmd.blockType);
4120
+ dropTarget.hoverAt(x, y);
4121
+ return;
4122
+ }
4123
+ hideDragGhost();
4124
+ if (cmd.phase === "cancel") {
4125
+ dropTarget.cancelHover();
4126
+ return;
4127
+ }
4128
+ const spotAt = dropTarget.dropAt(x, y);
4129
+ if (spotAt) {
4130
+ post({
4131
+ type: "block-dropped",
4132
+ payload: { stepIndex: previewStepIndex, blockType: cmd.blockType, ...spotAt }
4133
+ });
4134
+ }
4135
+ };
3843
4136
  const handleCommand = (cmd) => {
3844
4137
  switch (cmd.type) {
3845
4138
  case "panel-ready":
@@ -3869,11 +4162,15 @@ function initBuilderMode() {
3869
4162
  if (manipulator?.isDragging()) pendingPreview = cmd;
3870
4163
  else applyPreview(cmd);
3871
4164
  break;
4165
+ case "block-drag":
4166
+ handleBlockDrag(cmd);
4167
+ break;
3872
4168
  case "close-preview":
3873
4169
  manipulator?.detach();
3874
4170
  manipulator = null;
3875
4171
  dropTarget?.detach();
3876
4172
  dropTarget = null;
4173
+ hideDragGhost();
3877
4174
  pendingPreview = null;
3878
4175
  closeGuidePreview();
3879
4176
  break;
@@ -3898,6 +4195,7 @@ function initBuilderMode() {
3898
4195
  manipulator = null;
3899
4196
  dropTarget?.detach();
3900
4197
  dropTarget = null;
4198
+ hideDragGhost();
3901
4199
  pendingPreview = null;
3902
4200
  closeGuidePreview();
3903
4201
  post({ type: "closed" });
@@ -5363,6 +5661,7 @@ var GuideTrackerQueue = class {
5363
5661
  // src/plugins/guides/guides-controller.ts
5364
5662
  init_badge_renderer();
5365
5663
  init_banner_renderer();
5664
+ init_composite_renderer();
5366
5665
  init_custom_renderer();
5367
5666
  init_form_renderer();
5368
5667
  init_inline_custom_renderer();
@@ -6037,8 +6336,12 @@ ${pageUrl}`;
6037
6336
  return new InlineFormRenderer();
6038
6337
  case "badge":
6039
6338
  return new BadgeRenderer();
6339
+ case "composite":
6340
+ return new CompositeRenderer();
6040
6341
  case "walkthrough":
6041
6342
  return null;
6343
+ default:
6344
+ return null;
6042
6345
  }
6043
6346
  }
6044
6347
  /**