veo-sdk 0.5.32 → 0.5.34

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.
@@ -1,4 +1,4 @@
1
- import { hasDocument, hasWindow, resolveBuilderContext, closeGuidePreview, clearBuilderToken, buildSelectorPath, filterHumanClasses, stepMatchesPage, previewGuide } from './chunk-X27GD7IT.mjs';
1
+ import { hasDocument, hasWindow, resolveBuilderContext, closeGuidePreview, clearBuilderToken, buildSelectorPath, filterHumanClasses, isDeviceAllowed, stepMatchesPage, isAutomaticActivation, activationDelayMs, previewGuide } from './chunk-W4R4XCWL.mjs';
2
2
  import { BUILDER_TOKEN_PARAM, BUILDER_ORIGIN_PARAM } from './chunk-PTG3BTJE.mjs';
3
3
 
4
4
  // src/plugins/builder/block-drop-target.ts
@@ -10,7 +10,7 @@ function attachBlockDropTarget(options) {
10
10
  let spot = null;
11
11
  const contentEl = () => host.shadowRoot?.querySelector(".veo-guide-content") ?? null;
12
12
  const blockChildren = (container) => Array.from(container.children).filter(
13
- (el) => el instanceof HTMLElement && el.dataset.veoIdx !== void 0
13
+ (el2) => el2 instanceof HTMLElement && el2.dataset.veoIdx !== void 0
14
14
  );
15
15
  const hideLine = () => {
16
16
  line?.remove();
@@ -110,17 +110,375 @@ function attachBlockDropTarget(options) {
110
110
  // src/plugins/builder/bridge-protocol.ts
111
111
  var VEO_BUILDER_SOURCE = "veo-builder";
112
112
 
113
+ // src/plugins/builder/builder-chrome.ts
114
+ var CHROME_TOPBAR_H = 64;
115
+ var CHROME_STEPS_H = 128;
116
+ var ICONS = {
117
+ bolt: '<path stroke-linecap="round" stroke-linejoin="round" d="m3.75 13.5 10.5-11.25L12 10.5h8.25L9.75 21.75 12 13.5H3.75Z"/>',
118
+ desktop: '<path stroke-linecap="round" stroke-linejoin="round" d="M9 17.25v1.007a3 3 0 0 1-.879 2.122L7.5 21h9l-.621-.621A3 3 0 0 1 15 18.257V17.25m6-12V15a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 15V5.25m18 0A2.25 2.25 0 0 0 18.75 3H5.25A2.25 2.25 0 0 0 3 5.25m18 0V12a2.25 2.25 0 0 1-2.25 2.25H5.25A2.25 2.25 0 0 1 3 12V5.25"/>',
119
+ updown: '<path stroke-linecap="round" stroke-linejoin="round" d="M3 7.5 7.5 3m0 0L12 7.5M7.5 3v13.5m13.5 0L16.5 21m0 0L12 16.5m4.5 4.5V7.5"/>',
120
+ map: '<path stroke-linecap="round" stroke-linejoin="round" d="M9 6.75V15m6-6v8.25m.503 3.498 4.875-2.437c.381-.19.622-.58.622-1.006V4.82c0-.836-.88-1.38-1.628-1.006l-3.869 1.934c-.317.159-.69.159-1.006 0L9.503 3.252a1.125 1.125 0 0 0-1.006 0L3.622 5.689C3.24 5.88 3 6.27 3 6.695V19.18c0 .836.88 1.38 1.628 1.006l3.869-1.934c.317-.159.69-.159 1.006 0l4.994 2.497c.317.158.69.158 1.006 0Z"/>',
121
+ eye: '<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z"/><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/>',
122
+ chevronDown: '<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5"/>',
123
+ chevronUp: '<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 15.75 7.5-7.5 7.5 7.5"/>',
124
+ plus: '<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15"/>',
125
+ cursor: '<path stroke-linecap="round" stroke-linejoin="round" d="M15.042 21.672 13.684 16.6m0 0-2.51 2.225.569-9.47 5.227 7.917-3.286-.672ZM12 2.25V4.5m5.834.166-1.591 1.591M20.25 10.5H18M7.757 14.743l-1.59 1.59M6 10.5H3.75m4.007-4.243-1.59-1.59"/>',
126
+ spinner: '<path stroke-linecap="round" stroke-linejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182"/>'
127
+ };
128
+ function svg(name, size = 20) {
129
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">${ICONS[name]}</svg>`;
130
+ }
131
+ function shortDate(iso) {
132
+ if (!iso) return "";
133
+ const d = new Date(iso);
134
+ if (Number.isNaN(d.getTime())) return "";
135
+ return d.toLocaleDateString("es", { day: "numeric", month: "short" }).replace(".", "");
136
+ }
137
+ function el(tag, className, html) {
138
+ const node = document.createElement(tag);
139
+ node.className = className;
140
+ if (html !== void 0) node.innerHTML = html;
141
+ return node;
142
+ }
143
+ function iconButton(name, title, className = "") {
144
+ const b = el("button", `veo-tb-icon ${className}`.trim(), svg(name));
145
+ b.type = "button";
146
+ b.title = title;
147
+ b.setAttribute("aria-label", title);
148
+ return b;
149
+ }
150
+ function injectBuilderChrome(opts) {
151
+ if (!hasWindow() || !hasDocument()) {
152
+ return {
153
+ setState: () => {
154
+ },
155
+ height: () => 0,
156
+ dock: () => "top",
157
+ setPreview: () => {
158
+ },
159
+ setHidden: () => {
160
+ },
161
+ onHeightChange: () => {
162
+ },
163
+ teardown: () => {
164
+ }
165
+ };
166
+ }
167
+ const host = document.createElement("div");
168
+ host.setAttribute("data-veo-builder-chrome", "");
169
+ host.setAttribute("data-veo-ignore", "");
170
+ const shadow = host.attachShadow({ mode: "open" });
171
+ const style = document.createElement("style");
172
+ style.textContent = CHROME_CSS;
173
+ const root = el("div", "veo-chrome");
174
+ const topbar = el("div", "veo-tb");
175
+ const brand = el("div", "veo-tb-brand", svg("bolt", 18));
176
+ const nameEl = el("div", "veo-tb-name");
177
+ const statusEl = el("span", "veo-tb-status");
178
+ statusEl.hidden = true;
179
+ const sep = el("span", "veo-tb-sep");
180
+ const appEl = el("div", "veo-tb-app", `${svg("desktop", 16)}<span></span>`);
181
+ appEl.querySelector("span").textContent = opts.appLabel;
182
+ const left = el("div", "veo-tb-left");
183
+ left.append(brand, nameEl, statusEl, sep, appEl);
184
+ const right = el("div", "veo-tb-right");
185
+ const dockBtn = iconButton("updown", "Mover la barra abajo");
186
+ const showPanel = iconButton("map", "Mostrar el editor");
187
+ const preview = iconButton("eye", "Vista previa");
188
+ const exit = el("button", "veo-tb-text", "Salir");
189
+ exit.type = "button";
190
+ const saveGroup = el("div", "veo-tb-save");
191
+ const save = el("button", "veo-tb-save-main", "<span>Guardar</span>");
192
+ save.type = "button";
193
+ const saveMore = el("button", "veo-tb-save-more", svg("chevronDown", 16));
194
+ saveMore.type = "button";
195
+ saveMore.title = "M\xE1s opciones de guardado";
196
+ saveMore.setAttribute("aria-label", "M\xE1s opciones de guardado");
197
+ const saveMenu = el("div", "veo-tb-menu");
198
+ const saveExit = el("button", "veo-tb-menu-item", "Guardar y salir");
199
+ saveExit.type = "button";
200
+ saveMenu.append(saveExit);
201
+ saveMenu.hidden = true;
202
+ saveGroup.append(save, saveMore, saveMenu);
203
+ right.append(dockBtn, showPanel, preview, el("span", "veo-tb-vsep"), exit, saveGroup);
204
+ topbar.append(left, right);
205
+ const stepsBar = el("div", "veo-steps");
206
+ const stepsList = el("div", "veo-steps-list");
207
+ stepsBar.append(stepsList);
208
+ const togglePill = el("button", "veo-steps-toggle");
209
+ togglePill.type = "button";
210
+ root.append(topbar, stepsBar, togglePill);
211
+ const previewPill = el("div", "veo-preview-pill");
212
+ const previewLabel = el(
213
+ "span",
214
+ "veo-preview-label",
215
+ `${svg("eye", 18)}<span>Est\xE1s en vista previa</span>`
216
+ );
217
+ const previewExit = el("button", "veo-preview-exit", "Salir");
218
+ previewExit.type = "button";
219
+ previewPill.append(previewLabel, previewExit);
220
+ previewPill.hidden = true;
221
+ shadow.append(style, root, previewPill);
222
+ document.body.appendChild(host);
223
+ const html = document.documentElement;
224
+ const prevMarginTop = html.style.marginTop;
225
+ const prevMarginBottom = html.style.marginBottom;
226
+ let collapsed = false;
227
+ let dock = "top";
228
+ let previewOn = false;
229
+ let hiddenOn = false;
230
+ let heightCb = null;
231
+ const height = () => CHROME_TOPBAR_H + (collapsed ? 0 : CHROME_STEPS_H);
232
+ const applyHeight = () => {
233
+ const h = previewOn || hiddenOn ? 0 : height();
234
+ html.style.marginTop = dock === "top" ? `${h}px` : prevMarginTop;
235
+ html.style.marginBottom = dock === "bottom" ? `${h}px` : prevMarginBottom;
236
+ root.style.setProperty("--veo-chrome-h", `${height()}px`);
237
+ root.classList.toggle("is-bottom", dock === "bottom");
238
+ stepsBar.hidden = collapsed;
239
+ const open = dock === "top" ? "chevronUp" : "chevronDown";
240
+ const closedIcon = dock === "top" ? "chevronDown" : "chevronUp";
241
+ togglePill.innerHTML = `<span>${collapsed ? "Mostrar pasos" : "Ocultar pasos"}</span>${svg(
242
+ collapsed ? closedIcon : open,
243
+ 16
244
+ )}`;
245
+ dockBtn.title = dock === "top" ? "Mover la barra abajo" : "Mover la barra arriba";
246
+ dockBtn.setAttribute("aria-label", dockBtn.title);
247
+ heightCb?.(h);
248
+ };
249
+ const setPreview = (on) => {
250
+ previewOn = on;
251
+ root.hidden = on || hiddenOn;
252
+ previewPill.hidden = !on;
253
+ applyHeight();
254
+ };
255
+ const setHidden = (on) => {
256
+ hiddenOn = on;
257
+ root.hidden = on || previewOn;
258
+ applyHeight();
259
+ };
260
+ togglePill.addEventListener("click", () => {
261
+ collapsed = !collapsed;
262
+ applyHeight();
263
+ });
264
+ const act = (a) => opts.onAction(a);
265
+ dockBtn.addEventListener("click", () => {
266
+ dock = dock === "top" ? "bottom" : "top";
267
+ applyHeight();
268
+ act({ action: "dock", position: dock });
269
+ });
270
+ showPanel.addEventListener("click", () => act({ action: "show-panel" }));
271
+ preview.addEventListener("click", () => act({ action: "preview" }));
272
+ previewExit.addEventListener("click", () => act({ action: "exit-preview" }));
273
+ exit.addEventListener("click", () => act({ action: "exit" }));
274
+ save.addEventListener("click", () => act({ action: "save", exit: false }));
275
+ saveMore.addEventListener("click", (e) => {
276
+ e.stopPropagation();
277
+ saveMenu.hidden = !saveMenu.hidden;
278
+ });
279
+ saveExit.addEventListener("click", () => {
280
+ saveMenu.hidden = true;
281
+ act({ action: "save", exit: true });
282
+ });
283
+ const closeMenu = () => {
284
+ saveMenu.hidden = true;
285
+ };
286
+ document.addEventListener("click", closeMenu);
287
+ let current = null;
288
+ const render = () => {
289
+ const s = current;
290
+ if (!s) return;
291
+ const date = shortDate(s.createdAt);
292
+ nameEl.textContent = `${s.guideName.trim() || "Sin nombre"}${date ? ` \xB7 ${date}` : ""}`;
293
+ if (s.status) {
294
+ statusEl.hidden = false;
295
+ statusEl.textContent = s.status.label;
296
+ statusEl.dataset.tone = s.status.tone;
297
+ statusEl.title = "Estado de la gu\xEDa (se cambia desde la lista de gu\xEDas)";
298
+ } else {
299
+ statusEl.hidden = true;
300
+ }
301
+ save.innerHTML = s.saving ? `${svg("spinner", 16)}<span>Guardando\u2026</span>` : "<span>Guardar</span>";
302
+ save.disabled = s.saving;
303
+ saveExit.disabled = s.saving;
304
+ stepsList.replaceChildren();
305
+ const activation = stepCard(svg("cursor", 22), "Activaci\xF3n", s.section === "activation");
306
+ activation.addEventListener("click", () => act({ action: "select-activation" }));
307
+ stepsList.append(activation);
308
+ s.steps.forEach((st, i) => {
309
+ const thumb = st.presentation === "inline" ? '<div class="veo-thumb veo-thumb-inline"><i></i><i></i><i></i></div>' : '<div class="veo-thumb"><i></i><i></i><b></b></div>';
310
+ const card = stepCard(thumb, st.label, s.section === "step" && s.activeStep === i);
311
+ card.addEventListener("click", () => act({ action: "select-step", index: i }));
312
+ stepsList.append(card);
313
+ });
314
+ const add = el("button", "veo-step-add", `${svg("plus", 18)}<span>Agregar paso</span>`);
315
+ add.type = "button";
316
+ add.addEventListener("click", () => act({ action: "add-step" }));
317
+ stepsList.append(add);
318
+ };
319
+ applyHeight();
320
+ return {
321
+ setState: (state) => {
322
+ current = state;
323
+ render();
324
+ },
325
+ height,
326
+ dock: () => dock,
327
+ setPreview,
328
+ setHidden,
329
+ onHeightChange: (cb) => {
330
+ heightCb = cb;
331
+ },
332
+ teardown: () => {
333
+ document.removeEventListener("click", closeMenu);
334
+ html.style.marginTop = prevMarginTop;
335
+ html.style.marginBottom = prevMarginBottom;
336
+ host.remove();
337
+ }
338
+ };
339
+ }
340
+ function stepCard(inner, label, active) {
341
+ const b = el(
342
+ "button",
343
+ `veo-step${active ? " is-active" : ""}`,
344
+ `<div class="veo-step-box">${inner}</div><span class="veo-step-label"></span>`
345
+ );
346
+ b.type = "button";
347
+ b.querySelector(".veo-step-label").textContent = label;
348
+ b.setAttribute("aria-pressed", active ? "true" : "false");
349
+ return b;
350
+ }
351
+ var CHROME_CSS = `
352
+ :host { all: initial; }
353
+ .veo-chrome {
354
+ position: fixed; top: 0; left: 0; right: 0;
355
+ display: flex; flex-direction: column;
356
+ z-index: 2147483646;
357
+ font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
358
+ font-size: 14px; color: #1c1917;
359
+ }
360
+ .veo-chrome[hidden] { display: none; }
361
+ .veo-chrome.is-bottom { top: auto; bottom: 0; flex-direction: column-reverse; }
362
+ .veo-chrome.is-bottom .veo-tb-menu { top: auto; bottom: calc(100% + 8px); }
363
+ .veo-chrome.is-bottom .veo-steps { border-bottom: 0; border-top: 1px solid #d6cfc8; }
364
+ .veo-chrome.is-bottom .veo-steps-toggle { top: auto; bottom: var(--veo-chrome-h, ${CHROME_TOPBAR_H + CHROME_STEPS_H}px); transform: translate(-50%, 50%); }
365
+ .veo-preview-pill {
366
+ position: fixed; top: 28px; left: 50%; transform: translateX(-50%);
367
+ z-index: 2147483646;
368
+ display: inline-flex; align-items: center; gap: 12px;
369
+ background: #2b2623; color: #fff; border-radius: 999px; padding: 12px 20px;
370
+ font-family: system-ui, -apple-system, "Segoe UI", sans-serif; font-size: 15px; font-weight: 500;
371
+ box-shadow: 0 8px 24px rgba(0,0,0,0.3);
372
+ }
373
+ .veo-preview-pill[hidden] { display: none; }
374
+ .veo-preview-label { display: inline-flex; align-items: center; gap: 10px; padding-right: 12px; border-right: 1px solid rgba(255,255,255,0.3); }
375
+ .veo-preview-exit { border: 0; background: transparent; color: #fff; font: inherit; cursor: pointer; padding: 0 2px; }
376
+ .veo-preview-exit:hover { text-decoration: underline; }
377
+ .veo-tb {
378
+ height: ${CHROME_TOPBAR_H}px; box-sizing: border-box;
379
+ display: flex; align-items: center; justify-content: space-between;
380
+ padding: 0 20px; gap: 16px;
381
+ background: #2b2623; color: #fff;
382
+ }
383
+ .veo-tb-left, .veo-tb-right { display: flex; align-items: center; gap: 12px; min-width: 0; }
384
+ .veo-tb-brand {
385
+ width: 36px; height: 36px; border-radius: 999px; background: #b74d00;
386
+ display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
387
+ }
388
+ .veo-tb-name { font-weight: 700; font-size: 16px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
389
+ .veo-tb-status { display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 999px; font-size: 11px; font-weight: 600; letter-spacing: 0.02em; white-space: nowrap; background: rgba(255,255,255,0.18); color: #fff; }
390
+ .veo-tb-status[data-tone="live"] { background: #16a34a; }
391
+ .veo-tb-status[data-tone="testing"] { background: #b45309; }
392
+ .veo-tb-status[data-tone="review"] { background: #7c3aed; }
393
+ .veo-tb-status[data-tone="draft"] { background: #0f766e; }
394
+ .veo-tb-status[data-tone="paused"] { background: rgba(255,255,255,0.28); }
395
+ .veo-tb-sep { width: 1px; height: 24px; background: rgba(255,255,255,0.25); }
396
+ .veo-tb-vsep { width: 1px; height: 28px; background: rgba(255,255,255,0.25); margin: 0 4px; }
397
+ .veo-tb-app { display: inline-flex; align-items: center; gap: 8px; color: rgba(255,255,255,0.85); white-space: nowrap; }
398
+ .veo-tb-icon {
399
+ width: 42px; height: 42px; border-radius: 10px; border: 0;
400
+ background: rgba(255,255,255,0.12); color: #fff; cursor: pointer;
401
+ display: inline-flex; align-items: center; justify-content: center;
402
+ }
403
+ .veo-tb-icon:hover { background: rgba(255,255,255,0.22); }
404
+ .veo-tb-text { border: 0; background: transparent; color: #fff; font: inherit; font-size: 15px; cursor: pointer; padding: 8px 6px; }
405
+ .veo-tb-text:hover { text-decoration: underline; }
406
+ .veo-tb-save { position: relative; display: inline-flex; border-radius: 10px; overflow: visible; }
407
+ .veo-tb-save-main, .veo-tb-save-more {
408
+ border: 0; background: #b74d00; color: #fff; font: inherit; font-weight: 600; font-size: 15px;
409
+ cursor: pointer; display: inline-flex; align-items: center; gap: 8px; height: 42px;
410
+ }
411
+ .veo-tb-save-main { padding: 0 8px 0 18px; border-radius: 10px 0 0 10px; }
412
+ .veo-tb-save-more { padding: 0 12px 0 6px; border-radius: 0 10px 10px 0; }
413
+ .veo-tb-save-main:hover, .veo-tb-save-more:hover { background: #953c00; }
414
+ .veo-tb-save-main:disabled { opacity: 0.7; cursor: default; }
415
+ .veo-tb-menu {
416
+ position: absolute; right: 0; top: calc(100% + 8px); min-width: 220px;
417
+ background: #fff; color: #1c1917; border-radius: 12px; padding: 6px;
418
+ box-shadow: 0 12px 32px rgba(0,0,0,0.22);
419
+ }
420
+ .veo-tb-menu-item {
421
+ display: block; width: 100%; text-align: left; border: 0; background: transparent;
422
+ font: inherit; font-size: 15px; padding: 10px 14px; border-radius: 8px; cursor: pointer;
423
+ }
424
+ .veo-tb-menu-item:hover { background: #f5efe9; }
425
+ .veo-steps {
426
+ height: ${CHROME_STEPS_H}px; box-sizing: border-box;
427
+ background: #e7e1dc; border-bottom: 1px solid #d6cfc8;
428
+ padding: 16px 28px 0; overflow-x: auto;
429
+ }
430
+ .veo-steps[hidden] { display: none; }
431
+ .veo-steps-list { display: flex; align-items: flex-start; gap: 20px; }
432
+ .veo-step { border: 0; background: transparent; padding: 0; cursor: pointer; font: inherit; display: flex; flex-direction: column; align-items: center; gap: 8px; flex: 0 0 auto; }
433
+ .veo-step-box {
434
+ width: 116px; height: 64px; border-radius: 10px; background: #fff; border: 2px solid transparent;
435
+ display: flex; align-items: center; justify-content: center; color: #2b2623;
436
+ box-shadow: 0 1px 2px rgba(0,0,0,0.06);
437
+ }
438
+ .veo-step.is-active .veo-step-box { border-color: #b74d00; }
439
+ .veo-step-label { font-size: 13px; color: #6b635d; }
440
+ .veo-step.is-active .veo-step-label { color: #2b2623; font-weight: 600; }
441
+ .veo-thumb { width: 72px; height: 36px; border: 1.5px solid #c9c2bb; border-radius: 6px; padding: 6px 7px; box-sizing: border-box; display: flex; flex-direction: column; gap: 4px; }
442
+ .veo-thumb i { display: block; height: 3px; border-radius: 2px; background: #2b2623; width: 70%; }
443
+ .veo-thumb i + i { width: 45%; background: #c9c2bb; }
444
+ .veo-thumb b { display: block; height: 6px; width: 24px; border-radius: 2px; background: #b74d00; align-self: flex-end; }
445
+ .veo-thumb-inline { border-style: dashed; }
446
+ .veo-thumb-inline i { width: 100%; }
447
+ .veo-step-add { border: 0; background: transparent; font: inherit; font-size: 15px; color: #6b635d; cursor: pointer; display: inline-flex; align-items: center; gap: 8px; height: 64px; padding: 0 8px; }
448
+ .veo-step-add:hover { color: #2b2623; }
449
+ .veo-steps-toggle {
450
+ position: absolute; left: 50%; top: var(--veo-chrome-h, ${CHROME_TOPBAR_H + CHROME_STEPS_H}px);
451
+ transform: translate(-50%, -50%);
452
+ border: 0; background: #2b2623; color: #fff; font: inherit; font-size: 14px; font-weight: 500;
453
+ border-radius: 999px; padding: 10px 18px; cursor: pointer;
454
+ display: inline-flex; align-items: center; gap: 8px;
455
+ box-shadow: 0 6px 18px rgba(0,0,0,0.25);
456
+ }
457
+ `;
458
+
113
459
  // src/plugins/builder/builder-panel.ts
114
460
  var DEFAULT_PANEL_PATH = "/guides/design";
115
- var PANEL_W = 400;
116
- var PANEL_H = 640;
461
+ var PANEL_W = 484;
462
+ var PANEL_H = 660;
117
463
  var MIN_W = 320;
118
464
  var MIN_H = 320;
119
465
  var MARGIN = 16;
466
+ var HEADER_H = 52;
120
467
  function injectBuilderPanel(opts) {
121
468
  if (!hasWindow() || !hasDocument()) {
122
- return { target: () => null, frameRect: () => null, teardown: () => {
123
- } };
469
+ return {
470
+ target: () => null,
471
+ frameRect: () => null,
472
+ teardown: () => {
473
+ },
474
+ setTitle: () => {
475
+ },
476
+ setVisible: () => {
477
+ },
478
+ isVisible: () => false,
479
+ setTopOffset: () => {
480
+ }
481
+ };
124
482
  }
125
483
  const panelUrl = buildPanelUrl(opts);
126
484
  const host = document.createElement("div");
@@ -130,43 +488,68 @@ function injectBuilderPanel(opts) {
130
488
  style.textContent = PANEL_CSS;
131
489
  const card = document.createElement("div");
132
490
  card.className = "veo-panel";
133
- let left = Math.max(MARGIN, window.innerWidth - PANEL_W - MARGIN);
134
- let top = MARGIN;
491
+ let topOffset = opts.topOffset ?? 0;
492
+ let left = 40;
493
+ let top = topOffset + MARGIN;
135
494
  card.style.left = `${left}px`;
136
495
  card.style.top = `${top}px`;
137
496
  card.style.width = `${PANEL_W}px`;
138
497
  card.style.height = `${PANEL_H}px`;
139
498
  const header = document.createElement("div");
140
499
  header.className = "veo-panel-header";
500
+ const grip = document.createElement("span");
501
+ grip.className = "veo-panel-grip";
502
+ grip.setAttribute("aria-hidden", "true");
503
+ grip.textContent = "\xB7\xB7\xB7";
141
504
  const title = document.createElement("span");
142
505
  title.className = "veo-panel-title";
143
506
  title.textContent = "OnUser \xB7 Editor";
144
507
  const actions = document.createElement("div");
145
508
  actions.className = "veo-panel-actions";
146
- const popout = document.createElement("button");
147
- popout.className = "veo-panel-btn";
148
- popout.type = "button";
149
- popout.title = "Abrir en ventana aparte";
150
- popout.setAttribute("aria-label", "Abrir en ventana aparte");
151
- popout.textContent = "\u29C9";
152
- const close = document.createElement("button");
153
- close.className = "veo-panel-btn veo-panel-close";
154
- close.type = "button";
155
- close.title = "Cerrar";
156
- close.setAttribute("aria-label", "Cerrar");
157
- close.textContent = "\u2715";
158
- actions.append(popout, close);
159
- header.append(title, actions);
509
+ const popout = panelButton(ICON_POPOUT, "Abrir en ventana aparte");
510
+ const maximize = panelButton(ICON_EXPAND, "Maximizar");
511
+ const minimize = panelButton(ICON_MINUS, "Minimizar");
512
+ actions.append(popout, maximize, minimize);
513
+ header.append(grip, title, actions);
160
514
  const iframe = document.createElement("iframe");
161
515
  iframe.className = "veo-panel-frame";
162
516
  iframe.title = "Editor de Veo";
163
517
  iframe.src = panelUrl;
164
- const grip = document.createElement("div");
165
- grip.className = "veo-panel-resize";
166
- grip.setAttribute("aria-hidden", "true");
167
- card.append(header, iframe, grip);
518
+ const resizeGrip = document.createElement("div");
519
+ resizeGrip.className = "veo-panel-resize";
520
+ resizeGrip.setAttribute("aria-hidden", "true");
521
+ card.append(header, iframe, resizeGrip);
168
522
  shadow.append(style, card);
169
523
  document.body.appendChild(host);
524
+ let visible = true;
525
+ let maximized = false;
526
+ let restore = null;
527
+ const setVisible = (next) => {
528
+ visible = next;
529
+ card.style.display = next && !(popped && !popped.closed) ? "" : "none";
530
+ };
531
+ minimize.addEventListener("click", () => setVisible(false));
532
+ maximize.addEventListener("click", () => {
533
+ maximized = !maximized;
534
+ if (maximized) {
535
+ restore = { left, top, w: card.offsetWidth, h: card.offsetHeight };
536
+ left = MARGIN;
537
+ top = topOffset + MARGIN;
538
+ card.style.left = `${left}px`;
539
+ card.style.top = `${top}px`;
540
+ card.style.width = `${Math.max(MIN_W, window.innerWidth - MARGIN * 2)}px`;
541
+ card.style.height = `${Math.max(MIN_H, window.innerHeight - top - MARGIN)}px`;
542
+ maximize.title = "Restaurar";
543
+ } else if (restore) {
544
+ left = restore.left;
545
+ top = restore.top;
546
+ card.style.left = `${left}px`;
547
+ card.style.top = `${top}px`;
548
+ card.style.width = `${restore.w}px`;
549
+ card.style.height = `${restore.h}px`;
550
+ maximize.title = "Maximizar";
551
+ }
552
+ });
170
553
  let popped = null;
171
554
  let pollTimer;
172
555
  const stopPoll = () => {
@@ -175,7 +558,6 @@ function injectBuilderPanel(opts) {
175
558
  pollTimer = void 0;
176
559
  }
177
560
  };
178
- close.addEventListener("click", () => opts.onClose());
179
561
  popout.addEventListener("click", () => {
180
562
  const win = window.open(
181
563
  panelUrl,
@@ -193,7 +575,7 @@ function injectBuilderPanel(opts) {
193
575
  }, 600);
194
576
  });
195
577
  header.addEventListener("mousedown", (e) => {
196
- if (e.target?.classList.contains("veo-panel-btn")) return;
578
+ if (e.target?.closest(".veo-panel-btn")) return;
197
579
  e.preventDefault();
198
580
  const sx = e.clientX;
199
581
  const sy = e.clientY;
@@ -202,7 +584,7 @@ function injectBuilderPanel(opts) {
202
584
  iframe.style.pointerEvents = "none";
203
585
  const move = (ev) => {
204
586
  left = clamp(ol + (ev.clientX - sx), 0, Math.max(0, window.innerWidth - card.offsetWidth));
205
- top = clamp(ot + (ev.clientY - sy), 0, Math.max(0, window.innerHeight - 40));
587
+ top = clamp(ot + (ev.clientY - sy), topOffset, Math.max(topOffset, window.innerHeight - 40));
206
588
  card.style.left = `${left}px`;
207
589
  card.style.top = `${top}px`;
208
590
  };
@@ -214,7 +596,7 @@ function injectBuilderPanel(opts) {
214
596
  window.addEventListener("mousemove", move);
215
597
  window.addEventListener("mouseup", up);
216
598
  });
217
- grip.addEventListener("mousedown", (e) => {
599
+ resizeGrip.addEventListener("mousedown", (e) => {
218
600
  e.preventDefault();
219
601
  e.stopPropagation();
220
602
  const sx = e.clientX;
@@ -241,9 +623,33 @@ function injectBuilderPanel(opts) {
241
623
  stopPoll();
242
624
  if (popped && !popped.closed) popped.close();
243
625
  host.remove();
626
+ },
627
+ setTitle: (t) => {
628
+ title.textContent = t;
629
+ },
630
+ setVisible,
631
+ isVisible: () => visible,
632
+ setTopOffset: (px) => {
633
+ topOffset = px;
634
+ if (top < topOffset + MARGIN) {
635
+ top = topOffset + MARGIN;
636
+ card.style.top = `${top}px`;
637
+ }
244
638
  }
245
639
  };
246
640
  }
641
+ var ICON_POPOUT = '<path stroke-linecap="round" stroke-linejoin="round" d="m6.75 7.5 3 2.25-3 2.25m4.5 0h3m-9 8.25h13.5A2.25 2.25 0 0 0 21 18V6a2.25 2.25 0 0 0-2.25-2.25H5.25A2.25 2.25 0 0 0 3 6v12a2.25 2.25 0 0 0 2.25 2.25Z"/>';
642
+ var ICON_EXPAND = '<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15"/>';
643
+ var ICON_MINUS = '<path stroke-linecap="round" stroke-linejoin="round" d="M5 12h14"/>';
644
+ function panelButton(iconPath, label) {
645
+ const b = document.createElement("button");
646
+ b.className = "veo-panel-btn";
647
+ b.type = "button";
648
+ b.title = label;
649
+ b.setAttribute("aria-label", label);
650
+ b.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true">${iconPath}</svg>`;
651
+ return b;
652
+ }
247
653
  function clamp(v, min, max) {
248
654
  return Math.min(Math.max(v, min), max);
249
655
  }
@@ -263,28 +669,33 @@ var PANEL_CSS = `
263
669
  max-width: 96vw; max-height: 94vh;
264
670
  display: flex; flex-direction: column;
265
671
  background: #fff;
266
- border-radius: 12px;
267
- box-shadow: 0 12px 40px rgba(0,0,0,0.28);
672
+ border-radius: 14px;
673
+ box-shadow: 0 12px 40px rgba(0,0,0,0.22);
268
674
  overflow: hidden;
269
675
  z-index: 2147483647;
270
676
  font-family: system-ui, -apple-system, sans-serif;
271
677
  }
272
678
  .veo-panel-header {
273
- flex: 0 0 auto;
679
+ position: relative; flex: 0 0 auto; height: ${HEADER_H}px; box-sizing: border-box;
274
680
  display: flex; align-items: center; justify-content: space-between;
275
- padding: 8px 10px 8px 12px;
276
- background: #1b1714; color: #f7f1eb;
277
- font-size: 13px; font-weight: 600;
681
+ padding: 10px 14px 0 22px;
682
+ background: #fbf8f5; color: #1c1917; border-bottom: 1px solid #e8e2dc;
683
+ font-size: 17px; font-weight: 700;
278
684
  cursor: grab;
279
685
  }
280
686
  .veo-panel-header:active { cursor: grabbing; }
687
+ .veo-panel-grip {
688
+ position: absolute; top: 0; left: 50%; transform: translateX(-50%);
689
+ color: #b5aca4; font-size: 14px; letter-spacing: 1px; line-height: 12px;
690
+ }
691
+ .veo-panel-title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
281
692
  .veo-panel-actions { display: flex; gap: 2px; }
282
693
  .veo-panel-btn {
283
- border: 0; background: transparent; color: #fff;
284
- font-size: 14px; cursor: pointer; line-height: 1;
285
- padding: 4px 7px; border-radius: 6px;
694
+ border: 0; background: transparent; color: #4b4540;
695
+ cursor: pointer; line-height: 1; display: inline-flex; align-items: center;
696
+ padding: 6px; border-radius: 8px;
286
697
  }
287
- .veo-panel-btn:hover { background: rgba(255,255,255,0.15); }
698
+ .veo-panel-btn:hover { background: rgba(0,0,0,0.06); color: #1c1917; }
288
699
  .veo-panel-frame { flex: 1 1 auto; width: 100%; border: 0; background: #fff; }
289
700
  .veo-panel-resize {
290
701
  position: absolute; right: 0; bottom: 0;
@@ -538,9 +949,9 @@ var PICKER_STYLES = `
538
949
  z-index: ${PICKER_Z};
539
950
  pointer-events: none;
540
951
  box-sizing: border-box;
541
- background: rgba(99, 102, 241, 0.22);
542
- border: 1px dashed rgba(99, 102, 241, 0.95);
543
- border-radius: 2px;
952
+ background: transparent;
953
+ border: 3px dashed #b74d00;
954
+ border-radius: 8px;
544
955
  transition: top 60ms ease-out, left 60ms ease-out, width 60ms ease-out, height 60ms ease-out;
545
956
  }
546
957
  .veo-pick-label {
@@ -548,30 +959,48 @@ var PICKER_STYLES = `
548
959
  z-index: ${PICKER_Z};
549
960
  pointer-events: none;
550
961
  max-width: 360px;
551
- background: #1e1b4b;
552
- color: #e0e7ff;
962
+ background: #2b2623;
963
+ color: #f5efe9;
553
964
  font: 12px/1.45 ui-monospace, SFMono-Regular, Menlo, monospace;
554
965
  padding: 6px 9px;
555
966
  border-radius: 6px;
556
967
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);
557
968
  }
558
- .veo-pick-label .veo-pick-sel { color: #c7d2fe; word-break: break-all; }
559
- .veo-pick-label .veo-pick-dim { color: #a5b4fc; margin-top: 3px; }
969
+ .veo-pick-label .veo-pick-sel { color: #ffd1ad; word-break: break-all; }
970
+ .veo-pick-label .veo-pick-dim { color: #c9c2bb; margin-top: 3px; }
560
971
  .veo-pick-hint {
561
972
  position: fixed;
562
- top: 12px;
973
+ top: 28px;
563
974
  left: 50%;
564
975
  transform: translateX(-50%);
565
976
  z-index: ${PICKER_Z};
566
977
  pointer-events: none;
567
- background: #4338ca;
978
+ display: flex; align-items: center; gap: 16px;
979
+ max-width: min(760px, calc(100vw - 32px));
980
+ background: #2b2623;
568
981
  color: #fff;
569
- font: 13px/1 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
570
- padding: 8px 14px;
571
- border-radius: 999px;
572
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
982
+ font: 15px/1.4 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
983
+ padding: 14px 18px 14px 16px;
984
+ border-radius: 14px;
985
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
986
+ }
987
+ .veo-pick-hint-icon {
988
+ flex: 0 0 auto; width: 44px; height: 44px; border-radius: 999px;
989
+ background: rgba(255,255,255,0.12);
990
+ display: inline-flex; align-items: center; justify-content: center;
991
+ }
992
+ .veo-pick-hint-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
993
+ .veo-pick-hint-title { font-weight: 700; }
994
+ .veo-pick-hint-sub { font-size: 13px; color: rgba(255,255,255,0.75); }
995
+ .veo-pick-cancel {
996
+ flex: 0 0 auto; pointer-events: auto;
997
+ border: 0; border-radius: 10px; padding: 12px 18px;
998
+ background: rgba(255,255,255,0.14); color: #fff;
999
+ font: inherit; font-weight: 600; cursor: pointer;
573
1000
  }
1001
+ .veo-pick-cancel:hover { background: rgba(255,255,255,0.24); }
574
1002
  `;
1003
+ var HINT_ICON = '<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M7.5 3.75H6A2.25 2.25 0 0 0 3.75 6v1.5M16.5 3.75H18A2.25 2.25 0 0 1 20.25 6v1.5m0 9V18A2.25 2.25 0 0 1 18 20.25h-1.5m-9 0H6A2.25 2.25 0 0 1 3.75 18v-1.5M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/></svg>';
575
1004
  var ElementPicker = class {
576
1005
  constructor() {
577
1006
  this.host = null;
@@ -588,6 +1017,7 @@ var ElementPicker = class {
588
1017
  this.draw(target);
589
1018
  };
590
1019
  this.onClick = (event) => {
1020
+ if (event.altKey) return;
591
1021
  const target = this.current ?? (event.target instanceof Element ? event.target : null);
592
1022
  if (!target || this.isOwn(target)) return;
593
1023
  event.preventDefault();
@@ -608,7 +1038,7 @@ var ElementPicker = class {
608
1038
  };
609
1039
  /** Traga mousedown/mouseup durante el picking (evita focus/active de la app). */
610
1040
  this.swallow = (event) => {
611
- if (this.isOwn(event.target)) return;
1041
+ if (event.altKey || this.isOwn(event.target)) return;
612
1042
  event.preventDefault();
613
1043
  event.stopPropagation();
614
1044
  };
@@ -634,7 +1064,29 @@ var ElementPicker = class {
634
1064
  this.label.style.display = "none";
635
1065
  const hint = document.createElement("div");
636
1066
  hint.className = "veo-pick-hint";
637
- hint.textContent = options.hint ?? "Selecciona un elemento \xB7 Esc para cancelar";
1067
+ const icon = document.createElement("span");
1068
+ icon.className = "veo-pick-hint-icon";
1069
+ icon.innerHTML = HINT_ICON;
1070
+ const text = document.createElement("div");
1071
+ text.className = "veo-pick-hint-text";
1072
+ const title = document.createElement("span");
1073
+ title.className = "veo-pick-hint-title";
1074
+ title.textContent = options.hint ?? "Selecciona un elemento existente para colocar la gu\xEDa.";
1075
+ const sub = document.createElement("span");
1076
+ sub.className = "veo-pick-hint-sub";
1077
+ sub.textContent = options.subhint ?? "Usa Alt + clic u Opci\xF3n + clic para abrir men\xFAs y desplegables.";
1078
+ text.append(title, sub);
1079
+ const cancel = document.createElement("button");
1080
+ cancel.className = "veo-pick-cancel";
1081
+ cancel.type = "button";
1082
+ cancel.textContent = "Cancelar";
1083
+ cancel.addEventListener("click", (e) => {
1084
+ e.stopPropagation();
1085
+ const cb = this.onCancel;
1086
+ this.stop();
1087
+ cb?.();
1088
+ });
1089
+ hint.append(icon, text, cancel);
638
1090
  shadow.append(style, this.box, this.label, hint);
639
1091
  document.body.appendChild(host);
640
1092
  this.host = host;
@@ -732,6 +1184,7 @@ function initBuilderMode() {
732
1184
  if (!dashboardOrigin) return null;
733
1185
  let picker = null;
734
1186
  let panel = null;
1187
+ let chrome = null;
735
1188
  let staticTarget = null;
736
1189
  let manipulator = null;
737
1190
  let dropTarget = null;
@@ -739,26 +1192,98 @@ function initBuilderMode() {
739
1192
  let previewStepIndex = 0;
740
1193
  let pendingPreview = null;
741
1194
  let lastPreview = null;
1195
+ let previewMode = false;
1196
+ let previewTrigger = null;
1197
+ let previewFired = false;
1198
+ let previewDelay = null;
1199
+ let previewDismissed = false;
1200
+ let panelWasVisible = true;
742
1201
  const getTarget = () => panel ? panel.target() : staticTarget;
743
1202
  const post = (event) => {
744
1203
  getTarget()?.postMessage({ source: VEO_BUILDER_SOURCE, token, ...event }, dashboardOrigin);
745
1204
  };
746
- const previewMatchesPage = (cmd) => {
1205
+ const previewStep = (cmd) => {
747
1206
  const steps = cmd.guide.guideSteps;
748
- const step = steps?.[cmd.guide.startStepIndex ?? 0];
749
- return stepMatchesPage(step?.pageLocation, window.location.href);
1207
+ return steps?.[cmd.guide.startStepIndex ?? 0];
1208
+ };
1209
+ const previewMatchesPage = (cmd) => stepMatchesPage(previewStep(cmd)?.pageLocation, window.location.href);
1210
+ const postPreviewStatus = (payload) => post({ type: "preview-status", payload });
1211
+ const withholdPreview = () => {
1212
+ manipulator?.detach();
1213
+ manipulator = null;
1214
+ dropTarget?.detach();
1215
+ dropTarget = null;
1216
+ closeGuidePreview();
750
1217
  };
751
1218
  const applyPreviewGated = (cmd) => {
752
- lastPreview = cmd;
753
- if (previewMatchesPage(cmd)) {
754
- applyPreview(cmd);
755
- } else {
756
- manipulator?.detach();
757
- manipulator = null;
758
- dropTarget?.detach();
759
- dropTarget = null;
760
- closeGuidePreview();
1219
+ const showNow = !cmd.honorTrigger;
1220
+ if (showNow) {
1221
+ disarmPreviewTrigger();
1222
+ cancelPreviewDelay();
1223
+ previewFired = true;
1224
+ previewDismissed = false;
1225
+ }
1226
+ lastPreview = showNow ? { ...cmd, honorTrigger: true } : cmd;
1227
+ if (!previewMatchesPage(cmd)) {
1228
+ cancelPreviewDelay();
1229
+ withholdPreview();
1230
+ postPreviewStatus({
1231
+ state: "page-mismatch",
1232
+ pattern: previewStep(cmd)?.pageLocation?.pattern ?? ""
1233
+ });
1234
+ return;
761
1235
  }
1236
+ const devices = cmd.guide.activationRules?.devices;
1237
+ if (!showNow && !previewMode && devices && !isDeviceAllowed(devices)) {
1238
+ cancelPreviewDelay();
1239
+ withholdPreview();
1240
+ postPreviewStatus({ state: "device-mismatch", devices });
1241
+ return;
1242
+ }
1243
+ applyPreview(lastPreview);
1244
+ };
1245
+ const disarmPreviewTrigger = () => {
1246
+ previewTrigger?.();
1247
+ previewTrigger = null;
1248
+ };
1249
+ const cancelPreviewDelay = () => {
1250
+ if (previewDelay) clearTimeout(previewDelay);
1251
+ previewDelay = null;
1252
+ };
1253
+ const armPreviewTrigger = (selector, trigger) => {
1254
+ disarmPreviewTrigger();
1255
+ const onFire = (e) => {
1256
+ const target = e.target;
1257
+ if (!(target instanceof Element)) return;
1258
+ if (target.closest("[data-veo-builder-chrome],[data-veo-builder-panel],[data-veo-picker]")) {
1259
+ return;
1260
+ }
1261
+ try {
1262
+ if (!target.closest(selector)) return;
1263
+ } catch {
1264
+ return;
1265
+ }
1266
+ disarmPreviewTrigger();
1267
+ previewFired = true;
1268
+ previewDismissed = false;
1269
+ if (lastPreview) applyPreviewGated(lastPreview);
1270
+ };
1271
+ document.addEventListener("click", onFire, true);
1272
+ if (trigger === "on_hover") document.addEventListener("mouseover", onFire, true);
1273
+ previewTrigger = () => {
1274
+ document.removeEventListener("click", onFire, true);
1275
+ document.removeEventListener("mouseover", onFire, true);
1276
+ };
1277
+ postPreviewStatus({ state: "waiting-trigger", trigger, selector });
1278
+ };
1279
+ const armPreviewDelay = (delayMs) => {
1280
+ cancelPreviewDelay();
1281
+ previewDelay = setTimeout(() => {
1282
+ previewDelay = null;
1283
+ previewFired = true;
1284
+ if (lastPreview) applyPreviewGated(lastPreview);
1285
+ }, delayMs);
1286
+ postPreviewStatus({ state: "waiting-delay", delayMs });
762
1287
  };
763
1288
  const applyPreview = (cmd) => {
764
1289
  manipulator?.detach();
@@ -766,8 +1291,47 @@ function initBuilderMode() {
766
1291
  dropTarget?.detach();
767
1292
  dropTarget = null;
768
1293
  previewStepIndex = cmd.guide.startStepIndex ?? 0;
769
- const handle = previewGuide(cmd.guide);
770
- if (!cmd.editable) return;
1294
+ const rules = cmd.guide.activationRules;
1295
+ const trig = rules?.trigger;
1296
+ const sel = rules?.selector?.trim();
1297
+ const gate = cmd.honorTrigger && !previewFired && !previewMode;
1298
+ const waitsForTarget = (trig === "on_click" || trig === "on_hover") && (!isAutomaticActivation(rules) || previewDismissed);
1299
+ if (gate && waitsForTarget && sel) {
1300
+ cancelPreviewDelay();
1301
+ closeGuidePreview();
1302
+ armPreviewTrigger(sel, trig);
1303
+ return;
1304
+ }
1305
+ const delayMs = activationDelayMs(rules);
1306
+ if (gate && delayMs > 0) {
1307
+ disarmPreviewTrigger();
1308
+ closeGuidePreview();
1309
+ if (!previewDelay) armPreviewDelay(delayMs);
1310
+ return;
1311
+ }
1312
+ disarmPreviewTrigger();
1313
+ cancelPreviewDelay();
1314
+ const handle = previewGuide({
1315
+ ...cmd.guide,
1316
+ onClosed: () => {
1317
+ manipulator?.detach();
1318
+ manipulator = null;
1319
+ dropTarget?.detach();
1320
+ dropTarget = null;
1321
+ previewFired = false;
1322
+ previewDismissed = true;
1323
+ if (previewMode) {
1324
+ const r = lastPreview?.guide.activationRules;
1325
+ const t = r?.trigger;
1326
+ const selector = r?.selector?.trim();
1327
+ if ((t === "on_click" || t === "on_hover") && selector) armPreviewTrigger(selector, t);
1328
+ return;
1329
+ }
1330
+ if (lastPreview) applyPreviewGated(lastPreview);
1331
+ }
1332
+ });
1333
+ if (cmd.honorTrigger) postPreviewStatus({ state: "shown" });
1334
+ if (!cmd.editable || previewMode) return;
771
1335
  void handle.ready.then((result) => {
772
1336
  if (!result.rendered) return;
773
1337
  const host = handle.host();
@@ -835,26 +1399,57 @@ function initBuilderMode() {
835
1399
  const handleCommand = (cmd) => {
836
1400
  switch (cmd.type) {
837
1401
  case "panel-ready":
838
- post({ type: "ready" });
1402
+ post(chrome ? { type: "ready", chrome: true } : { type: "ready" });
839
1403
  break;
840
- case "start-picker":
1404
+ case "editor-state":
1405
+ chrome?.setState(cmd.state);
1406
+ panel?.setTitle(
1407
+ cmd.state.section === "activation" ? "Ajustes de activaci\xF3n" : cmd.state.section === "badge" ? "Ajustes de badge" : cmd.state.section === "target" ? "Ajustes del elemento objetivo" : cmd.state.steps[cmd.state.activeStep]?.label ?? "Paso"
1408
+ );
1409
+ break;
1410
+ case "panel-visibility":
1411
+ panel?.setVisible(cmd.visible);
1412
+ break;
1413
+ case "start-picker": {
841
1414
  picker?.stop();
1415
+ const panelWasShown = panel?.isVisible() ?? false;
1416
+ if (panelWasShown) panel?.setVisible(false);
1417
+ chrome?.setHidden(true);
1418
+ const previewToRestore = lastPreview;
1419
+ if (previewToRestore) {
1420
+ manipulator?.detach();
1421
+ manipulator = null;
1422
+ dropTarget?.detach();
1423
+ dropTarget = null;
1424
+ closeGuidePreview();
1425
+ }
1426
+ const restorePanel = () => {
1427
+ chrome?.setHidden(false);
1428
+ if (panelWasShown) panel?.setVisible(true);
1429
+ if (previewToRestore && lastPreview === previewToRestore) {
1430
+ applyPreviewGated(previewToRestore);
1431
+ }
1432
+ };
842
1433
  picker = startElementPicker({
843
1434
  onPick: (payload) => {
844
1435
  picker = null;
1436
+ restorePanel();
845
1437
  post({ type: "picked", payload });
846
1438
  },
847
1439
  onCancel: () => {
848
1440
  picker = null;
1441
+ restorePanel();
849
1442
  post({ type: "pick-cancelled" });
850
1443
  },
851
1444
  ...cmd.maxAncestors !== void 0 ? { maxAncestors: cmd.maxAncestors } : {},
852
1445
  ...cmd.hint !== void 0 ? { hint: cmd.hint } : {}
853
1446
  });
854
1447
  break;
1448
+ }
855
1449
  case "stop-picker":
856
1450
  picker?.stop();
857
1451
  picker = null;
1452
+ chrome?.setHidden(false);
858
1453
  break;
859
1454
  case "preview":
860
1455
  if (!cmd.guide) break;
@@ -872,6 +1467,10 @@ function initBuilderMode() {
872
1467
  hideDragGhost();
873
1468
  pendingPreview = null;
874
1469
  lastPreview = null;
1470
+ disarmPreviewTrigger();
1471
+ cancelPreviewDelay();
1472
+ previewFired = false;
1473
+ previewDismissed = false;
875
1474
  closeGuidePreview();
876
1475
  break;
877
1476
  case "teardown":
@@ -923,21 +1522,62 @@ function initBuilderMode() {
923
1522
  dropTarget = null;
924
1523
  hideDragGhost();
925
1524
  pendingPreview = null;
1525
+ disarmPreviewTrigger();
1526
+ cancelPreviewDelay();
926
1527
  closeGuidePreview();
927
1528
  post({ type: "closed" });
928
1529
  panel?.teardown();
929
1530
  panel = null;
1531
+ chrome?.teardown();
1532
+ chrome = null;
930
1533
  clearBuilderToken();
931
1534
  };
932
1535
  if (ctx.panel) {
1536
+ chrome = injectBuilderChrome({
1537
+ appLabel: window.location.hostname,
1538
+ onAction: (action) => {
1539
+ switch (action.action) {
1540
+ // Controles que resuelve el SDK solo (no van al panel).
1541
+ case "dock":
1542
+ panel?.setTopOffset(action.position === "top" ? chrome?.height() ?? 0 : 0);
1543
+ return;
1544
+ case "show-panel":
1545
+ panel?.setVisible(true);
1546
+ return;
1547
+ case "preview":
1548
+ if (previewMode) return;
1549
+ previewMode = true;
1550
+ panelWasVisible = panel?.isVisible() ?? true;
1551
+ panel?.setVisible(false);
1552
+ chrome?.setPreview(true);
1553
+ if (lastPreview) applyPreviewGated(lastPreview);
1554
+ return;
1555
+ case "exit-preview":
1556
+ if (!previewMode) return;
1557
+ previewMode = false;
1558
+ chrome?.setPreview(false);
1559
+ panel?.setVisible(panelWasVisible);
1560
+ if (lastPreview) applyPreviewGated(lastPreview);
1561
+ return;
1562
+ case "select-activation":
1563
+ case "select-step":
1564
+ case "add-step":
1565
+ panel?.setVisible(true);
1566
+ break;
1567
+ }
1568
+ post({ type: "chrome-action", payload: action });
1569
+ }
1570
+ });
933
1571
  panel = injectBuilderPanel({
934
1572
  dashboardOrigin,
935
1573
  token,
936
1574
  appOrigin: window.location.origin,
937
1575
  guide: ctx.guide,
938
1576
  panelPath: ctx.panelPath,
939
- onClose: () => teardown()
1577
+ onClose: () => teardown(),
1578
+ topOffset: chrome.height()
940
1579
  });
1580
+ chrome.onHeightChange((h) => panel?.setTopOffset(chrome?.dock() === "top" ? h : 0));
941
1581
  } else {
942
1582
  staticTarget = resolveTarget();
943
1583
  if (!staticTarget) return null;
@@ -1117,5 +1757,5 @@ function noopSession() {
1117
1757
  }
1118
1758
 
1119
1759
  export { VEO_BLOCK_MIME, attachBlockDropTarget, attachDesignManipulator, createBuilderSession, initBuilderMode, startElementPicker, stopElementPicker };
1120
- //# sourceMappingURL=chunk-AFU5ZG6Z.mjs.map
1121
- //# sourceMappingURL=chunk-AFU5ZG6Z.mjs.map
1760
+ //# sourceMappingURL=chunk-IZXJA55N.mjs.map
1761
+ //# sourceMappingURL=chunk-IZXJA55N.mjs.map