veo-sdk 0.3.3 → 0.3.4
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/builder-LXIR3WMJ.mjs +5 -0
- package/dist/{builder-VPQDAUIL.mjs.map → builder-LXIR3WMJ.mjs.map} +1 -1
- package/dist/builder.cjs +103 -36
- package/dist/builder.cjs.map +1 -1
- package/dist/builder.mjs +2 -2
- package/dist/{chunk-PASI5SAK.mjs → chunk-IKFTO7MX.mjs} +105 -38
- package/dist/chunk-IKFTO7MX.mjs.map +1 -0
- package/dist/index.cjs +104 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/veo-builder.js +22 -16
- package/dist/veo-builder.js.map +1 -1
- package/package.json +1 -1
- package/dist/builder-VPQDAUIL.mjs +0 -5
- package/dist/chunk-PASI5SAK.mjs.map +0 -1
package/dist/builder.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import './chunk-R4E3LIDB.mjs';
|
|
2
|
-
import { initBuilderMode } from './chunk-
|
|
3
|
-
export { createBuilderSession, initBuilderMode, startElementPicker, stopElementPicker } from './chunk-
|
|
2
|
+
import { initBuilderMode } from './chunk-IKFTO7MX.mjs';
|
|
3
|
+
export { createBuilderSession, initBuilderMode, startElementPicker, stopElementPicker } from './chunk-IKFTO7MX.mjs';
|
|
4
4
|
export { closeGuidePreview, previewGuide } from './chunk-GHP7ZJCW.mjs';
|
|
5
5
|
import './chunk-PTG3BTJE.mjs';
|
|
6
6
|
|
|
@@ -8,12 +8,15 @@ var VEO_BUILDER_SOURCE = "veo-builder";
|
|
|
8
8
|
var DEFAULT_PANEL_PATH = "/guides/design";
|
|
9
9
|
var PANEL_W = 400;
|
|
10
10
|
var PANEL_H = 640;
|
|
11
|
+
var MIN_W = 320;
|
|
12
|
+
var MIN_H = 320;
|
|
11
13
|
var MARGIN = 16;
|
|
12
14
|
function injectBuilderPanel(opts) {
|
|
13
15
|
if (!hasWindow() || !hasDocument()) {
|
|
14
16
|
return { target: () => null, teardown: () => {
|
|
15
17
|
} };
|
|
16
18
|
}
|
|
19
|
+
const panelUrl = buildPanelUrl(opts);
|
|
17
20
|
const host = document.createElement("div");
|
|
18
21
|
host.setAttribute("data-veo-builder-panel", "");
|
|
19
22
|
const shadow = host.attachShadow({ mode: "open" });
|
|
@@ -25,55 +28,113 @@ function injectBuilderPanel(opts) {
|
|
|
25
28
|
let top = MARGIN;
|
|
26
29
|
card.style.left = `${left}px`;
|
|
27
30
|
card.style.top = `${top}px`;
|
|
31
|
+
card.style.width = `${PANEL_W}px`;
|
|
32
|
+
card.style.height = `${PANEL_H}px`;
|
|
28
33
|
const header = document.createElement("div");
|
|
29
34
|
header.className = "veo-panel-header";
|
|
30
35
|
const title = document.createElement("span");
|
|
31
36
|
title.className = "veo-panel-title";
|
|
32
37
|
title.textContent = "Veo \xB7 Editor";
|
|
38
|
+
const actions = document.createElement("div");
|
|
39
|
+
actions.className = "veo-panel-actions";
|
|
40
|
+
const popout = document.createElement("button");
|
|
41
|
+
popout.className = "veo-panel-btn";
|
|
42
|
+
popout.type = "button";
|
|
43
|
+
popout.title = "Abrir en ventana aparte";
|
|
44
|
+
popout.setAttribute("aria-label", "Abrir en ventana aparte");
|
|
45
|
+
popout.textContent = "\u29C9";
|
|
33
46
|
const close = document.createElement("button");
|
|
34
|
-
close.className = "veo-panel-close";
|
|
47
|
+
close.className = "veo-panel-btn veo-panel-close";
|
|
35
48
|
close.type = "button";
|
|
49
|
+
close.title = "Cerrar";
|
|
36
50
|
close.setAttribute("aria-label", "Cerrar");
|
|
37
51
|
close.textContent = "\u2715";
|
|
38
|
-
|
|
39
|
-
header.append(title,
|
|
52
|
+
actions.append(popout, close);
|
|
53
|
+
header.append(title, actions);
|
|
40
54
|
const iframe = document.createElement("iframe");
|
|
41
55
|
iframe.className = "veo-panel-frame";
|
|
42
56
|
iframe.title = "Editor de Veo";
|
|
43
|
-
iframe.src =
|
|
44
|
-
|
|
57
|
+
iframe.src = panelUrl;
|
|
58
|
+
const grip = document.createElement("div");
|
|
59
|
+
grip.className = "veo-panel-resize";
|
|
60
|
+
grip.setAttribute("aria-hidden", "true");
|
|
61
|
+
card.append(header, iframe, grip);
|
|
45
62
|
shadow.append(style, card);
|
|
46
63
|
document.body.appendChild(host);
|
|
47
|
-
|
|
48
|
-
|
|
64
|
+
let popped = null;
|
|
65
|
+
let pollTimer;
|
|
66
|
+
const stopPoll = () => {
|
|
67
|
+
if (pollTimer !== void 0) {
|
|
68
|
+
clearInterval(pollTimer);
|
|
69
|
+
pollTimer = void 0;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
close.addEventListener("click", () => opts.onClose());
|
|
73
|
+
popout.addEventListener("click", () => {
|
|
74
|
+
const win = window.open(
|
|
75
|
+
panelUrl,
|
|
76
|
+
"veo-editor",
|
|
77
|
+
`popup,width=${Math.round(card.offsetWidth)},height=${Math.round(card.offsetHeight) + 60}`
|
|
78
|
+
);
|
|
79
|
+
if (!win) return;
|
|
80
|
+
popped = win;
|
|
81
|
+
card.style.display = "none";
|
|
82
|
+
pollTimer = setInterval(() => {
|
|
83
|
+
if (popped?.closed) {
|
|
84
|
+
stopPoll();
|
|
85
|
+
opts.onClose();
|
|
86
|
+
}
|
|
87
|
+
}, 600);
|
|
88
|
+
});
|
|
89
|
+
header.addEventListener("mousedown", (e) => {
|
|
90
|
+
if (e.target?.classList.contains("veo-panel-btn")) return;
|
|
49
91
|
e.preventDefault();
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
const
|
|
92
|
+
const sx = e.clientX;
|
|
93
|
+
const sy = e.clientY;
|
|
94
|
+
const ol = left;
|
|
95
|
+
const ot = top;
|
|
54
96
|
iframe.style.pointerEvents = "none";
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const maxTop = window.innerHeight - 40;
|
|
59
|
-
left = clamp(origLeft + (ev.clientX - startX), 0, Math.max(0, maxLeft));
|
|
60
|
-
top = clamp(origTop + (ev.clientY - startY), 0, Math.max(0, maxTop));
|
|
97
|
+
const move = (ev) => {
|
|
98
|
+
left = clamp(ol + (ev.clientX - sx), 0, Math.max(0, window.innerWidth - card.offsetWidth));
|
|
99
|
+
top = clamp(ot + (ev.clientY - sy), 0, Math.max(0, window.innerHeight - 40));
|
|
61
100
|
card.style.left = `${left}px`;
|
|
62
101
|
card.style.top = `${top}px`;
|
|
63
102
|
};
|
|
64
|
-
const
|
|
65
|
-
window.removeEventListener("mousemove",
|
|
66
|
-
window.removeEventListener("mouseup",
|
|
103
|
+
const up = () => {
|
|
104
|
+
window.removeEventListener("mousemove", move);
|
|
105
|
+
window.removeEventListener("mouseup", up);
|
|
67
106
|
iframe.style.pointerEvents = "";
|
|
68
|
-
card.classList.remove("dragging");
|
|
69
107
|
};
|
|
70
|
-
window.addEventListener("mousemove",
|
|
71
|
-
window.addEventListener("mouseup",
|
|
72
|
-
};
|
|
73
|
-
|
|
108
|
+
window.addEventListener("mousemove", move);
|
|
109
|
+
window.addEventListener("mouseup", up);
|
|
110
|
+
});
|
|
111
|
+
grip.addEventListener("mousedown", (e) => {
|
|
112
|
+
e.preventDefault();
|
|
113
|
+
e.stopPropagation();
|
|
114
|
+
const sx = e.clientX;
|
|
115
|
+
const sy = e.clientY;
|
|
116
|
+
const sw = card.offsetWidth;
|
|
117
|
+
const sh = card.offsetHeight;
|
|
118
|
+
iframe.style.pointerEvents = "none";
|
|
119
|
+
const move = (ev) => {
|
|
120
|
+
card.style.width = `${clamp(sw + (ev.clientX - sx), MIN_W, window.innerWidth)}px`;
|
|
121
|
+
card.style.height = `${clamp(sh + (ev.clientY - sy), MIN_H, window.innerHeight)}px`;
|
|
122
|
+
};
|
|
123
|
+
const up = () => {
|
|
124
|
+
window.removeEventListener("mousemove", move);
|
|
125
|
+
window.removeEventListener("mouseup", up);
|
|
126
|
+
iframe.style.pointerEvents = "";
|
|
127
|
+
};
|
|
128
|
+
window.addEventListener("mousemove", move);
|
|
129
|
+
window.addEventListener("mouseup", up);
|
|
130
|
+
});
|
|
74
131
|
return {
|
|
75
|
-
target: () => iframe.contentWindow,
|
|
76
|
-
teardown: () =>
|
|
132
|
+
target: () => popped && !popped.closed ? popped : iframe.contentWindow,
|
|
133
|
+
teardown: () => {
|
|
134
|
+
stopPoll();
|
|
135
|
+
if (popped && !popped.closed) popped.close();
|
|
136
|
+
host.remove();
|
|
137
|
+
}
|
|
77
138
|
};
|
|
78
139
|
}
|
|
79
140
|
function clamp(v, min, max) {
|
|
@@ -91,35 +152,41 @@ var PANEL_CSS = `
|
|
|
91
152
|
:host { all: initial; }
|
|
92
153
|
.veo-panel {
|
|
93
154
|
position: fixed;
|
|
94
|
-
width: ${
|
|
95
|
-
min-width: 320px; min-height: 320px;
|
|
155
|
+
min-width: ${MIN_W}px; min-height: ${MIN_H}px;
|
|
96
156
|
max-width: 96vw; max-height: 94vh;
|
|
97
157
|
display: flex; flex-direction: column;
|
|
98
158
|
background: #fff;
|
|
99
159
|
border-radius: 12px;
|
|
100
160
|
box-shadow: 0 12px 40px rgba(0,0,0,0.28);
|
|
101
161
|
overflow: hidden;
|
|
102
|
-
resize: both;
|
|
103
162
|
z-index: 2147483647;
|
|
104
163
|
font-family: system-ui, -apple-system, sans-serif;
|
|
105
164
|
}
|
|
106
|
-
.veo-panel.dragging { user-select: none; }
|
|
107
165
|
.veo-panel-header {
|
|
108
166
|
flex: 0 0 auto;
|
|
109
167
|
display: flex; align-items: center; justify-content: space-between;
|
|
110
|
-
padding: 8px 12px;
|
|
168
|
+
padding: 8px 10px 8px 12px;
|
|
111
169
|
background: #0f172a; color: #fff;
|
|
112
170
|
font-size: 13px; font-weight: 600;
|
|
113
171
|
cursor: grab;
|
|
114
172
|
}
|
|
115
173
|
.veo-panel-header:active { cursor: grabbing; }
|
|
116
|
-
.veo-panel-
|
|
174
|
+
.veo-panel-actions { display: flex; gap: 2px; }
|
|
175
|
+
.veo-panel-btn {
|
|
117
176
|
border: 0; background: transparent; color: #fff;
|
|
118
|
-
font-size:
|
|
119
|
-
padding: 4px
|
|
177
|
+
font-size: 14px; cursor: pointer; line-height: 1;
|
|
178
|
+
padding: 4px 7px; border-radius: 6px;
|
|
120
179
|
}
|
|
121
|
-
.veo-panel-
|
|
180
|
+
.veo-panel-btn:hover { background: rgba(255,255,255,0.15); }
|
|
122
181
|
.veo-panel-frame { flex: 1 1 auto; width: 100%; border: 0; background: #fff; }
|
|
182
|
+
.veo-panel-resize {
|
|
183
|
+
position: absolute; right: 0; bottom: 0;
|
|
184
|
+
width: 16px; height: 16px;
|
|
185
|
+
cursor: nwse-resize;
|
|
186
|
+
background:
|
|
187
|
+
linear-gradient(135deg, transparent 50%, rgba(0,0,0,0.25) 50%, rgba(0,0,0,0.25) 60%,
|
|
188
|
+
transparent 60%, transparent 72%, rgba(0,0,0,0.25) 72%, rgba(0,0,0,0.25) 82%, transparent 82%);
|
|
189
|
+
}
|
|
123
190
|
`;
|
|
124
191
|
|
|
125
192
|
// src/plugins/builder/element-picker.ts
|
|
@@ -572,5 +639,5 @@ function noopSession() {
|
|
|
572
639
|
}
|
|
573
640
|
|
|
574
641
|
export { createBuilderSession, initBuilderMode, startElementPicker, stopElementPicker };
|
|
575
|
-
//# sourceMappingURL=chunk-
|
|
576
|
-
//# sourceMappingURL=chunk-
|
|
642
|
+
//# sourceMappingURL=chunk-IKFTO7MX.mjs.map
|
|
643
|
+
//# sourceMappingURL=chunk-IKFTO7MX.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugins/builder/bridge-protocol.ts","../src/plugins/builder/builder-panel.ts","../src/plugins/builder/element-picker.ts","../src/plugins/builder/builder-mode.ts","../src/plugins/builder/builder-session.ts"],"names":[],"mappings":";;;;AAaO,IAAM,kBAAA,GAAqB,aAAA;;;ACElC,IAAM,kBAAA,GAAqB,gBAAA;AAC3B,IAAM,OAAA,GAAU,GAAA;AAChB,IAAM,OAAA,GAAU,GAAA;AAChB,IAAM,KAAA,GAAQ,GAAA;AACd,IAAM,KAAA,GAAQ,GAAA;AACd,IAAM,MAAA,GAAS,EAAA;AAmBR,SAAS,mBAAmB,IAAA,EAA+C;AAChF,EAAA,IAAI,CAAC,SAAA,EAAU,IAAK,CAAC,aAAY,EAAG;AAClC,IAAA,OAAO,EAAE,MAAA,EAAQ,MAAM,IAAA,EAAM,UAAU,MAAM;AAAA,IAAC,CAAA,EAAE;AAAA,EAClD;AAEA,EAAA,MAAM,QAAA,GAAW,cAAc,IAAI,CAAA;AAEnC,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACzC,EAAA,IAAA,CAAK,YAAA,CAAa,0BAA0B,EAAE,CAAA;AAC9C,EAAA,MAAM,SAAS,IAAA,CAAK,YAAA,CAAa,EAAE,IAAA,EAAM,QAAQ,CAAA;AAEjD,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AAC5C,EAAA,KAAA,CAAM,WAAA,GAAc,SAAA;AAEpB,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACzC,EAAA,IAAA,CAAK,SAAA,GAAY,WAAA;AACjB,EAAA,IAAI,OAAO,IAAA,CAAK,GAAA,CAAI,QAAQ,MAAA,CAAO,UAAA,GAAa,UAAU,MAAM,CAAA;AAChE,EAAA,IAAI,GAAA,GAAM,MAAA;AACV,EAAA,IAAA,CAAK,KAAA,CAAM,IAAA,GAAO,CAAA,EAAG,IAAI,CAAA,EAAA,CAAA;AACzB,EAAA,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,CAAA,EAAG,GAAG,CAAA,EAAA,CAAA;AACvB,EAAA,IAAA,CAAK,KAAA,CAAM,KAAA,GAAQ,CAAA,EAAG,OAAO,CAAA,EAAA,CAAA;AAC7B,EAAA,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG,OAAO,CAAA,EAAA,CAAA;AAG9B,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC3C,EAAA,MAAA,CAAO,SAAA,GAAY,kBAAA;AACnB,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,MAAM,CAAA;AAC3C,EAAA,KAAA,CAAM,SAAA,GAAY,iBAAA;AAClB,EAAA,KAAA,CAAM,WAAA,GAAc,iBAAA;AACpB,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC5C,EAAA,OAAA,CAAQ,SAAA,GAAY,mBAAA;AACpB,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AAC9C,EAAA,MAAA,CAAO,SAAA,GAAY,eAAA;AACnB,EAAA,MAAA,CAAO,IAAA,GAAO,QAAA;AACd,EAAA,MAAA,CAAO,KAAA,GAAQ,yBAAA;AACf,EAAA,MAAA,CAAO,YAAA,CAAa,cAAc,yBAAyB,CAAA;AAC3D,EAAA,MAAA,CAAO,WAAA,GAAc,QAAA;AACrB,EAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AAC7C,EAAA,KAAA,CAAM,SAAA,GAAY,+BAAA;AAClB,EAAA,KAAA,CAAM,IAAA,GAAO,QAAA;AACb,EAAA,KAAA,CAAM,KAAA,GAAQ,QAAA;AACd,EAAA,KAAA,CAAM,YAAA,CAAa,cAAc,QAAQ,CAAA;AACzC,EAAA,KAAA,CAAM,WAAA,GAAc,QAAA;AACpB,EAAA,OAAA,CAAQ,MAAA,CAAO,QAAQ,KAAK,CAAA;AAC5B,EAAA,MAAA,CAAO,MAAA,CAAO,OAAO,OAAO,CAAA;AAE5B,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AAC9C,EAAA,MAAA,CAAO,SAAA,GAAY,iBAAA;AACnB,EAAA,MAAA,CAAO,KAAA,GAAQ,eAAA;AACf,EAAA,MAAA,CAAO,GAAA,GAAM,QAAA;AAEb,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACzC,EAAA,IAAA,CAAK,SAAA,GAAY,kBAAA;AACjB,EAAA,IAAA,CAAK,YAAA,CAAa,eAAe,MAAM,CAAA;AAEvC,EAAA,IAAA,CAAK,MAAA,CAAO,MAAA,EAAQ,MAAA,EAAQ,IAAI,CAAA;AAChC,EAAA,MAAA,CAAO,MAAA,CAAO,OAAO,IAAI,CAAA;AACzB,EAAA,QAAA,CAAS,IAAA,CAAK,YAAY,IAAI,CAAA;AAG9B,EAAA,IAAI,MAAA,GAAwB,IAAA;AAC5B,EAAA,IAAI,SAAA;AAEJ,EAAA,MAAM,WAAW,MAAY;AAC3B,IAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,MAAA,aAAA,CAAc,SAAS,CAAA;AACvB,MAAA,SAAA,GAAY,MAAA;AAAA,IACd;AAAA,EACF,CAAA;AAEA,EAAA,KAAA,CAAM,gBAAA,CAAiB,OAAA,EAAS,MAAM,IAAA,CAAK,SAAS,CAAA;AACpD,EAAA,MAAA,CAAO,gBAAA,CAAiB,SAAS,MAAM;AACrC,IAAA,MAAM,MAAM,MAAA,CAAO,IAAA;AAAA,MACjB,QAAA;AAAA,MACA,YAAA;AAAA,MACA,CAAA,YAAA,EAAe,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,WAAW,CAAC,CAAA,QAAA,EAAW,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,YAAY,CAAA,GAAI,EAAE,CAAA;AAAA,KAC1F;AACA,IAAA,IAAI,CAAC,GAAA,EAAK;AACV,IAAA,MAAA,GAAS,GAAA;AACT,IAAA,IAAA,CAAK,MAAM,OAAA,GAAU,MAAA;AACrB,IAAA,SAAA,GAAY,YAAY,MAAM;AAC5B,MAAA,IAAI,QAAQ,MAAA,EAAQ;AAClB,QAAA,QAAA,EAAS;AACT,QAAA,IAAA,CAAK,OAAA,EAAQ;AAAA,MACf;AAAA,IACF,GAAG,GAAG,CAAA;AAAA,EACR,CAAC,CAAA;AAGD,EAAA,MAAA,CAAO,gBAAA,CAAiB,WAAA,EAAa,CAAC,CAAA,KAAM;AAC1C,IAAA,IAAK,CAAA,CAAE,MAAA,EAAwB,SAAA,CAAU,QAAA,CAAS,eAAe,CAAA,EAAG;AACpE,IAAA,CAAA,CAAE,cAAA,EAAe;AACjB,IAAA,MAAM,KAAK,CAAA,CAAE,OAAA;AACb,IAAA,MAAM,KAAK,CAAA,CAAE,OAAA;AACb,IAAA,MAAM,EAAA,GAAK,IAAA;AACX,IAAA,MAAM,EAAA,GAAK,GAAA;AACX,IAAA,MAAA,CAAO,MAAM,aAAA,GAAgB,MAAA;AAC7B,IAAA,MAAM,IAAA,GAAO,CAAC,EAAA,KAAyB;AACrC,MAAA,IAAA,GAAO,KAAA,CAAM,EAAA,IAAM,EAAA,CAAG,OAAA,GAAU,EAAA,CAAA,EAAK,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,MAAA,CAAO,UAAA,GAAa,IAAA,CAAK,WAAW,CAAC,CAAA;AACzF,MAAA,GAAA,GAAM,KAAA,CAAM,EAAA,IAAM,EAAA,CAAG,OAAA,GAAU,EAAA,CAAA,EAAK,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,MAAA,CAAO,WAAA,GAAc,EAAE,CAAC,CAAA;AAC3E,MAAA,IAAA,CAAK,KAAA,CAAM,IAAA,GAAO,CAAA,EAAG,IAAI,CAAA,EAAA,CAAA;AACzB,MAAA,IAAA,CAAK,KAAA,CAAM,GAAA,GAAM,CAAA,EAAG,GAAG,CAAA,EAAA,CAAA;AAAA,IACzB,CAAA;AACA,IAAA,MAAM,KAAK,MAAY;AACrB,MAAA,MAAA,CAAO,mBAAA,CAAoB,aAAa,IAAI,CAAA;AAC5C,MAAA,MAAA,CAAO,mBAAA,CAAoB,WAAW,EAAE,CAAA;AACxC,MAAA,MAAA,CAAO,MAAM,aAAA,GAAgB,EAAA;AAAA,IAC/B,CAAA;AACA,IAAA,MAAA,CAAO,gBAAA,CAAiB,aAAa,IAAI,CAAA;AACzC,IAAA,MAAA,CAAO,gBAAA,CAAiB,WAAW,EAAE,CAAA;AAAA,EACvC,CAAC,CAAA;AAGD,EAAA,IAAA,CAAK,gBAAA,CAAiB,WAAA,EAAa,CAAC,CAAA,KAAM;AACxC,IAAA,CAAA,CAAE,cAAA,EAAe;AACjB,IAAA,CAAA,CAAE,eAAA,EAAgB;AAClB,IAAA,MAAM,KAAK,CAAA,CAAE,OAAA;AACb,IAAA,MAAM,KAAK,CAAA,CAAE,OAAA;AACb,IAAA,MAAM,KAAK,IAAA,CAAK,WAAA;AAChB,IAAA,MAAM,KAAK,IAAA,CAAK,YAAA;AAChB,IAAA,MAAA,CAAO,MAAM,aAAA,GAAgB,MAAA;AAC7B,IAAA,MAAM,IAAA,GAAO,CAAC,EAAA,KAAyB;AACrC,MAAA,IAAA,CAAK,KAAA,CAAM,KAAA,GAAQ,CAAA,EAAG,KAAA,CAAM,EAAA,IAAM,EAAA,CAAG,OAAA,GAAU,EAAA,CAAA,EAAK,KAAA,EAAO,MAAA,CAAO,UAAU,CAAC,CAAA,EAAA,CAAA;AAC7E,MAAA,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG,KAAA,CAAM,EAAA,IAAM,EAAA,CAAG,OAAA,GAAU,EAAA,CAAA,EAAK,KAAA,EAAO,MAAA,CAAO,WAAW,CAAC,CAAA,EAAA,CAAA;AAAA,IACjF,CAAA;AACA,IAAA,MAAM,KAAK,MAAY;AACrB,MAAA,MAAA,CAAO,mBAAA,CAAoB,aAAa,IAAI,CAAA;AAC5C,MAAA,MAAA,CAAO,mBAAA,CAAoB,WAAW,EAAE,CAAA;AACxC,MAAA,MAAA,CAAO,MAAM,aAAA,GAAgB,EAAA;AAAA,IAC/B,CAAA;AACA,IAAA,MAAA,CAAO,gBAAA,CAAiB,aAAa,IAAI,CAAA;AACzC,IAAA,MAAA,CAAO,gBAAA,CAAiB,WAAW,EAAE,CAAA;AAAA,EACvC,CAAC,CAAA;AAED,EAAA,OAAO;AAAA,IACL,QAAQ,MAAO,MAAA,IAAU,CAAC,MAAA,CAAO,MAAA,GAAS,SAAS,MAAA,CAAO,aAAA;AAAA,IAC1D,UAAU,MAAM;AACd,MAAA,QAAA,EAAS;AACT,MAAA,IAAI,MAAA,IAAU,CAAC,MAAA,CAAO,MAAA,SAAe,KAAA,EAAM;AAC3C,MAAA,IAAA,CAAK,MAAA,EAAO;AAAA,IACd;AAAA,GACF;AACF;AAEA,SAAS,KAAA,CAAM,CAAA,EAAW,GAAA,EAAa,GAAA,EAAqB;AAC1D,EAAA,OAAO,KAAK,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA,EAAG,GAAG,GAAG,GAAG,CAAA;AACvC;AAEA,SAAS,cAAc,IAAA,EAAmC;AACxD,EAAA,MAAM,IAAA,GAAO,KAAK,SAAA,IAAa,kBAAA;AAC/B,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,IAAA,EAAM,KAAK,eAAe,CAAA;AAC9C,EAAA,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,UAAA,EAAY,IAAA,CAAK,KAAK,CAAA;AAC3C,EAAA,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,QAAA,EAAU,IAAA,CAAK,SAAS,CAAA;AAC7C,EAAA,IAAI,KAAK,KAAA,EAAO,GAAA,CAAI,aAAa,GAAA,CAAI,UAAA,EAAY,KAAK,KAAK,CAAA;AAC3D,EAAA,OAAO,IAAI,QAAA,EAAS;AACtB;AAEA,IAAM,SAAA,GAAY;AAAA;AAAA;AAAA;AAAA,aAAA,EAIH,KAAK,mBAAmB,KAAK,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;;;ACpL5C,IAAM,QAAA,GAAW,UAAA;AACjB,IAAM,gBAAA,GAAmB,iBAAA;AACzB,IAAM,qBAAA,GAAwB,CAAA;AA+B9B,IAAM,aAAA,GAAgB;AAAA;AAAA;AAAA;AAAA,WAAA,EAIT,QAAQ,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAAA,EAUR,QAAQ,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAAA,EAiBR,QAAQ,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAgBrB,IAAM,gBAAN,MAAoB;AAAA,EAApB,WAAA,GAAA;AACE,IAAA,IAAA,CAAQ,IAAA,GAA2B,IAAA;AACnC,IAAA,IAAA,CAAQ,GAAA,GAA0B,IAAA;AAClC,IAAA,IAAA,CAAQ,KAAA,GAA4B,IAAA;AACpC,IAAA,IAAA,CAAQ,OAAA,GAA0B,IAAA;AAClC,IAAA,IAAA,CAAQ,YAAA,GAAe,qBAAA;AACvB,IAAA,IAAA,CAAQ,MAAA,GAA8C,IAAA;AACtD,IAAA,IAAA,CAAQ,QAAA,GAAgC,IAAA;AAgExC,IAAA,IAAA,CAAQ,MAAA,GAAS,CAAC,KAAA,KAA4B;AAC5C,MAAA,MAAM,SAAS,KAAA,CAAM,MAAA;AACrB,MAAA,IAAI,EAAE,MAAA,YAAkB,OAAA,CAAA,IAAY,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA,EAAG;AACxD,MAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AACf,MAAA,IAAA,CAAK,KAAK,MAAM,CAAA;AAAA,IAClB,CAAA;AAEA,IAAA,IAAA,CAAQ,OAAA,GAAU,CAAC,KAAA,KAA4B;AAC7C,MAAA,MAAM,SAAS,IAAA,CAAK,OAAA,KAAY,MAAM,MAAA,YAAkB,OAAA,GAAU,MAAM,MAAA,GAAS,IAAA,CAAA;AACjF,MAAA,IAAI,CAAC,MAAA,IAAU,IAAA,CAAK,KAAA,CAAM,MAAM,CAAA,EAAG;AAGnC,MAAA,KAAA,CAAM,cAAA,EAAe;AACrB,MAAA,KAAA,CAAM,eAAA,EAAgB;AACtB,MAAA,KAAA,CAAM,wBAAA,EAAyB;AAE/B,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,QAAA,CAAS,MAAM,CAAA;AACnC,MAAA,MAAM,KAAK,IAAA,CAAK,MAAA;AAChB,MAAA,IAAA,CAAK,IAAA,EAAK;AACV,MAAA,EAAA,GAAK,MAAM,CAAA;AAAA,IACb,CAAA;AAEA,IAAA,IAAA,CAAQ,KAAA,GAAQ,CAAC,KAAA,KAA+B;AAC9C,MAAA,IAAI,KAAA,CAAM,QAAQ,QAAA,EAAU;AAC5B,MAAA,KAAA,CAAM,cAAA,EAAe;AACrB,MAAA,KAAA,CAAM,eAAA,EAAgB;AACtB,MAAA,MAAM,KAAK,IAAA,CAAK,QAAA;AAChB,MAAA,IAAA,CAAK,IAAA,EAAK;AACV,MAAA,EAAA,IAAK;AAAA,IACP,CAAA;AAGA;AAAA,IAAA,IAAA,CAAQ,OAAA,GAAU,CAAC,KAAA,KAA4B;AAC7C,MAAA,IAAI,IAAA,CAAK,KAAA,CAAM,KAAA,CAAM,MAAM,CAAA,EAAG;AAC9B,MAAA,KAAA,CAAM,cAAA,EAAe;AACrB,MAAA,KAAA,CAAM,eAAA,EAAgB;AAAA,IACxB,CAAA;AAEA,IAAA,IAAA,CAAQ,aAAa,MAAY;AAC/B,MAAA,IAAI,IAAA,CAAK,OAAA,EAAS,IAAA,CAAK,IAAA,CAAK,KAAK,OAAO,CAAA;AAAA,IAC1C,CAAA;AAAA,EAAA;AAAA,EAtGA,MAAM,OAAA,EAAqC;AACzC,IAAA,IAAA,CAAK,IAAA,EAAK;AAEV,IAAA,IAAA,CAAK,YAAA,GAAe,QAAQ,YAAA,IAAgB,qBAAA;AAC5C,IAAA,IAAA,CAAK,SAAS,OAAA,CAAQ,MAAA;AACtB,IAAA,IAAA,CAAK,QAAA,GAAW,QAAQ,QAAA,IAAY,IAAA;AAEpC,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACzC,IAAA,IAAA,CAAK,YAAA,CAAa,kBAAkB,EAAE,CAAA;AACtC,IAAA,MAAM,SAAS,IAAA,CAAK,YAAA,CAAa,EAAE,IAAA,EAAM,QAAQ,CAAA;AAEjD,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AAC5C,IAAA,KAAA,CAAM,WAAA,GAAc,aAAA;AAEpB,IAAA,IAAA,CAAK,GAAA,GAAM,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACvC,IAAA,IAAA,CAAK,IAAI,SAAA,GAAY,cAAA;AACrB,IAAA,IAAA,CAAK,GAAA,CAAI,MAAM,OAAA,GAAU,MAAA;AAEzB,IAAA,IAAA,CAAK,KAAA,GAAQ,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACzC,IAAA,IAAA,CAAK,MAAM,SAAA,GAAY,gBAAA;AACvB,IAAA,IAAA,CAAK,KAAA,CAAM,MAAM,OAAA,GAAU,MAAA;AAE3B,IAAA,MAAM,IAAA,GAAO,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACzC,IAAA,IAAA,CAAK,SAAA,GAAY,eAAA;AACjB,IAAA,IAAA,CAAK,WAAA,GAAc,QAAQ,IAAA,IAAQ,kDAAA;AAEnC,IAAA,MAAA,CAAO,OAAO,KAAA,EAAO,IAAA,CAAK,GAAA,EAAK,IAAA,CAAK,OAAO,IAAI,CAAA;AAC/C,IAAA,QAAA,CAAS,IAAA,CAAK,YAAY,IAAI,CAAA;AAC9B,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAEZ,IAAA,QAAA,CAAS,gBAAA,CAAiB,WAAA,EAAa,IAAA,CAAK,MAAA,EAAQ,IAAI,CAAA;AACxD,IAAA,QAAA,CAAS,gBAAA,CAAiB,OAAA,EAAS,IAAA,CAAK,OAAA,EAAS,IAAI,CAAA;AACrD,IAAA,QAAA,CAAS,gBAAA,CAAiB,WAAA,EAAa,IAAA,CAAK,OAAA,EAAS,IAAI,CAAA;AACzD,IAAA,QAAA,CAAS,gBAAA,CAAiB,SAAA,EAAW,IAAA,CAAK,OAAA,EAAS,IAAI,CAAA;AACvD,IAAA,QAAA,CAAS,gBAAA,CAAiB,SAAA,EAAW,IAAA,CAAK,KAAA,EAAO,IAAI,CAAA;AACrD,IAAA,MAAA,CAAO,gBAAA,CAAiB,QAAA,EAAU,IAAA,CAAK,UAAA,EAAY,IAAI,CAAA;AACvD,IAAA,MAAA,CAAO,gBAAA,CAAiB,QAAA,EAAU,IAAA,CAAK,UAAU,CAAA;AAAA,EACnD;AAAA,EAEA,IAAA,GAAa;AACX,IAAA,QAAA,CAAS,mBAAA,CAAoB,WAAA,EAAa,IAAA,CAAK,MAAA,EAAQ,IAAI,CAAA;AAC3D,IAAA,QAAA,CAAS,mBAAA,CAAoB,OAAA,EAAS,IAAA,CAAK,OAAA,EAAS,IAAI,CAAA;AACxD,IAAA,QAAA,CAAS,mBAAA,CAAoB,WAAA,EAAa,IAAA,CAAK,OAAA,EAAS,IAAI,CAAA;AAC5D,IAAA,QAAA,CAAS,mBAAA,CAAoB,SAAA,EAAW,IAAA,CAAK,OAAA,EAAS,IAAI,CAAA;AAC1D,IAAA,QAAA,CAAS,mBAAA,CAAoB,SAAA,EAAW,IAAA,CAAK,KAAA,EAAO,IAAI,CAAA;AACxD,IAAA,MAAA,CAAO,mBAAA,CAAoB,QAAA,EAAU,IAAA,CAAK,UAAA,EAAY,IAAI,CAAA;AAC1D,IAAA,MAAA,CAAO,mBAAA,CAAoB,QAAA,EAAU,IAAA,CAAK,UAAU,CAAA;AAEpD,IAAA,IAAI,IAAA,CAAK,MAAM,UAAA,EAAY,IAAA,CAAK,KAAK,UAAA,CAAW,WAAA,CAAY,KAAK,IAAI,CAAA;AACrE,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,GAAA,GAAM,IAAA;AACX,IAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AACb,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,IAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AACd,IAAA,IAAA,CAAK,QAAA,GAAW,IAAA;AAAA,EAClB;AAAA;AAAA,EAGQ,MAAM,MAAA,EAAqC;AACjD,IAAA,OAAO,MAAA,YAAkB,QAAQ,IAAA,CAAK,IAAA,KAAS,QAAQ,IAAA,CAAK,IAAA,CAAK,SAAS,MAAM,CAAA;AAAA,EAClF;AAAA;AAAA,EA6CQ,KAAK,OAAA,EAAwB;AACnC,IAAA,IAAI,CAAC,IAAA,CAAK,GAAA,IAAO,CAAC,KAAK,KAAA,EAAO;AAC9B,IAAA,MAAM,IAAA,GAAO,QAAQ,qBAAA,EAAsB;AAE3C,IAAA,IAAA,CAAK,GAAA,CAAI,MAAM,OAAA,GAAU,OAAA;AACzB,IAAA,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,GAAA,GAAM,CAAA,EAAG,KAAK,GAAG,CAAA,EAAA,CAAA;AAChC,IAAA,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,IAAA,GAAO,CAAA,EAAG,KAAK,IAAI,CAAA,EAAA,CAAA;AAClC,IAAA,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,KAAA,GAAQ,CAAA,EAAG,KAAK,KAAK,CAAA,EAAA,CAAA;AACpC,IAAA,IAAA,CAAK,GAAA,CAAI,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG,KAAK,MAAM,CAAA,EAAA,CAAA;AAEtC,IAAA,MAAM,QAAA,GAAW,iBAAA,CAAkB,OAAA,EAAS,CAAC,CAAA;AAC7C,IAAA,IAAA,CAAK,MAAM,WAAA,GAAc,EAAA;AACzB,IAAA,MAAM,GAAA,GAAM,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACxC,IAAA,GAAA,CAAI,SAAA,GAAY,cAAA;AAChB,IAAA,GAAA,CAAI,WAAA,GAAc,QAAA;AAClB,IAAA,MAAM,GAAA,GAAM,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AACxC,IAAA,GAAA,CAAI,SAAA,GAAY,cAAA;AAChB,IAAA,GAAA,CAAI,WAAA,GAAc,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,KAAK,CAAC,CAAA,MAAA,EAAM,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,MAAM,CAAC,CAAA,CAAA;AACxE,IAAA,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,GAAA,EAAK,GAAG,CAAA;AAG1B,IAAA,IAAA,CAAK,KAAA,CAAM,MAAM,OAAA,GAAU,OAAA;AAC3B,IAAA,MAAM,OAAA,GAAU,EAAA;AAChB,IAAA,MAAM,UAAA,GAAa,IAAA,CAAK,MAAA,GAAS,CAAA,GAAI,UAAU,MAAA,CAAO,WAAA;AACtD,IAAA,IAAA,CAAK,MAAM,KAAA,CAAM,GAAA,GAAM,UAAA,GACnB,CAAA,EAAG,KAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,GAAM,UAAU,CAAC,CAAC,OACtC,CAAA,EAAG,IAAA,CAAK,SAAS,CAAC,CAAA,EAAA,CAAA;AACtB,IAAA,IAAA,CAAK,KAAA,CAAM,MAAM,IAAA,GAAO,CAAA,EAAG,KAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,IAAI,CAAC,CAAA,EAAA,CAAA;AAAA,EACnD;AAAA,EAEQ,SAAS,OAAA,EAAiC;AAChD,IAAA,MAAM,IAAA,GAAO,QAAQ,qBAAA,EAAsB;AAC3C,IAAA,OAAO;AAAA,MACL,QAAA,EAAU,iBAAA,CAAkB,OAAA,EAAS,IAAA,CAAK,YAAY,CAAA;AAAA,MACtD,aAAA,EAAe,iBAAA,CAAkB,OAAA,EAAS,CAAC,CAAA;AAAA,MAC3C,GAAA,EAAK,OAAA,CAAQ,OAAA,CAAQ,WAAA,EAAY;AAAA,MACjC,EAAA,EAAI,QAAQ,EAAA,IAAM,IAAA;AAAA,MAClB,OAAA,EAAS,mBAAmB,OAAO,CAAA;AAAA,MACnC,IAAA,EAAA,CAAO,QAAQ,WAAA,IAAe,EAAA,EAAI,MAAK,CAAE,KAAA,CAAM,GAAG,GAAG,CAAA;AAAA,MACrD,IAAA,EAAM;AAAA,QACJ,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,IAAI,CAAA;AAAA,QACvB,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,GAAG,CAAA;AAAA,QACtB,KAAA,EAAO,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,KAAK,CAAA;AAAA,QAC5B,MAAA,EAAQ,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,MAAM;AAAA;AAChC,KACF;AAAA,EACF;AACF,CAAA;AAEA,IAAI,YAAA,GAAqC,IAAA;AAkBlC,SAAS,mBAAmB,OAAA,EAAoD;AACrF,EAAA,IAAI,CAAC,aAAY,EAAG;AAClB,IAAA,OAAO,EAAE,MAAM,MAAM;AAAA,IAAC,CAAA,EAAE;AAAA,EAC1B;AACA,EAAA,IAAI,CAAC,YAAA,EAAc,YAAA,GAAe,IAAI,aAAA,EAAc;AACpD,EAAA,YAAA,CAAa,MAAM,OAAO,CAAA;AAC1B,EAAA,OAAO,EAAE,IAAA,EAAM,MAAM,YAAA,EAAc,MAAK,EAAE;AAC5C;AAGO,SAAS,iBAAA,GAA0B;AACxC,EAAA,YAAA,EAAc,IAAA,EAAK;AACrB;;;ACjQO,SAAS,eAAA,GAA4C;AAC1D,EAAA,IAAI,CAAC,SAAA,EAAU,IAAK,CAAC,WAAA,IAAe,OAAO,IAAA;AAI3C,EAAA,MAAM,MAAM,qBAAA,EAAsB;AAClC,EAAA,IAAI,CAAC,KAAK,OAAO,IAAA;AAEjB,EAAA,MAAM,QAAQ,GAAA,CAAI,KAAA;AAClB,EAAA,MAAM,eAAA,GAAkB,sBAAA,CAAuB,GAAA,CAAI,MAAM,CAAA;AACzD,EAAA,IAAI,CAAC,iBAAiB,OAAO,IAAA;AAE7B,EAAA,IAAI,MAAA,GAAqC,IAAA;AACzC,EAAA,IAAI,KAAA,GAAmC,IAAA;AACvC,EAAA,IAAI,YAAA,GAA8B,IAAA;AAClC,EAAA,MAAM,SAAA,GAAY,MAAsB,KAAA,GAAQ,KAAA,CAAM,QAAO,GAAI,YAAA;AAEjE,EAAA,MAAM,IAAA,GAAO,CAAC,KAAA,KAA8B;AAC1C,IAAA,SAAA,EAAU,EAAG,YAAY,EAAE,MAAA,EAAQ,oBAAoB,KAAA,EAAO,GAAG,KAAA,EAAM,EAAG,eAAe,CAAA;AAAA,EAC3F,CAAA;AAEA,EAAA,MAAM,aAAA,GAAgB,CAAC,GAAA,KAA8B;AACnD,IAAA,QAAQ,IAAI,IAAA;AAAM,MAChB,KAAK,aAAA;AAEH,QAAA,IAAA,CAAK,EAAE,IAAA,EAAM,OAAA,EAAS,CAAA;AACtB,QAAA;AAAA,MACF,KAAK,cAAA;AACH,QAAA,MAAA,EAAQ,IAAA,EAAK;AACb,QAAA,MAAA,GAAS,kBAAA,CAAmB;AAAA,UAC1B,MAAA,EAAQ,CAAC,OAAA,KAAY;AACnB,YAAA,MAAA,GAAS,IAAA;AACT,YAAA,IAAA,CAAK,EAAE,IAAA,EAAM,QAAA,EAAU,OAAA,EAAS,CAAA;AAAA,UAClC,CAAA;AAAA,UACA,UAAU,MAAM;AACd,YAAA,MAAA,GAAS,IAAA;AACT,YAAA,IAAA,CAAK,EAAE,IAAA,EAAM,gBAAA,EAAkB,CAAA;AAAA,UACjC,CAAA;AAAA,UACA,GAAI,IAAI,YAAA,KAAiB,MAAA,GAAY,EAAE,YAAA,EAAc,GAAA,CAAI,YAAA,EAAa,GAAI,EAAC;AAAA,UAC3E,GAAI,IAAI,IAAA,KAAS,MAAA,GAAY,EAAE,IAAA,EAAM,GAAA,CAAI,IAAA,EAAK,GAAI;AAAC,SACpD,CAAA;AACD,QAAA;AAAA,MACF,KAAK,aAAA;AACH,QAAA,MAAA,EAAQ,IAAA,EAAK;AACb,QAAA,MAAA,GAAS,IAAA;AACT,QAAA;AAAA,MACF,KAAK,SAAA;AACH,QAAA,IAAI,IAAI,KAAA,EAAO,KAAK,YAAA,CAAa,GAAA,CAAI,KAAK,CAAA,CAAE,KAAA;AAC5C,QAAA;AAAA,MACF,KAAK,eAAA;AACH,QAAA,iBAAA,EAAkB;AAClB,QAAA;AAAA,MACF,KAAK,UAAA;AACH,QAAA,QAAA,EAAS;AACT,QAAA;AAAA;AACJ,EACF,CAAA;AAEA,EAAA,MAAM,SAAA,GAAY,CAAC,KAAA,KAA8B;AAC/C,IAAA,IAAI,KAAA,CAAM,WAAW,eAAA,EAAiB;AACtC,IAAA,MAAM,OAAO,KAAA,CAAM,IAAA;AACnB,IAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,CAAK,WAAW,kBAAA,IAAsB,IAAA,CAAK,UAAU,KAAA,EAAO;AACzE,IAAA,aAAA,CAAc,IAAsB,CAAA;AAAA,EACtC,CAAA;AAEA,EAAA,MAAM,aAAa,MAAY,IAAA,CAAK,EAAE,IAAA,EAAM,UAAU,CAAA;AAEtD,EAAA,MAAM,WAAW,MAAY;AAC3B,IAAA,MAAA,CAAO,mBAAA,CAAoB,WAAW,SAAS,CAAA;AAC/C,IAAA,MAAA,CAAO,mBAAA,CAAoB,YAAY,UAAU,CAAA;AACjD,IAAA,MAAA,EAAQ,IAAA,EAAK;AACb,IAAA,MAAA,GAAS,IAAA;AACT,IAAA,iBAAA,EAAkB;AAClB,IAAA,IAAA,CAAK,EAAE,IAAA,EAAM,QAAA,EAAU,CAAA;AACvB,IAAA,KAAA,EAAO,QAAA,EAAS;AAChB,IAAA,KAAA,GAAQ,IAAA;AACR,IAAA,iBAAA,EAAkB;AAAA,EACpB,CAAA;AAGA,EAAA,IAAI,IAAI,KAAA,EAAO;AACb,IAAA,KAAA,GAAQ,kBAAA,CAAmB;AAAA,MACzB,eAAA;AAAA,MACA,KAAA;AAAA,MACA,SAAA,EAAW,OAAO,QAAA,CAAS,MAAA;AAAA,MAC3B,OAAO,GAAA,CAAI,KAAA;AAAA,MACX,WAAW,GAAA,CAAI,SAAA;AAAA,MACf,OAAA,EAAS,MAAM,QAAA;AAAS,KACzB,CAAA;AAAA,EACH,CAAA,MAAO;AACL,IAAA,YAAA,GAAe,aAAA,EAAc;AAC7B,IAAA,IAAI,CAAC,cAAc,OAAO,IAAA;AAAA,EAC5B;AAEA,EAAA,MAAM,WAAW,MAAY;AAC3B,IAAA,MAAA,CAAO,gBAAA,CAAiB,WAAW,SAAS,CAAA;AAC5C,IAAA,MAAA,CAAO,gBAAA,CAAiB,YAAY,UAAU,CAAA;AAG9C,IAAA,IAAI,CAAC,GAAA,CAAI,KAAA,OAAY,EAAE,IAAA,EAAM,SAAS,CAAA;AAAA,EACxC,CAAA;AAMA,EAAA,MAAM,MAAO,MAAA,CACV,YAAA;AACH,EAAA,IAAI,GAAA,EAAK,MAAA,IAAU,GAAA,EAAK,MAAA,EAAQ;AAC9B,IAAA,KAAK,kBAAA,CAAmB,IAAI,MAAA,EAAQ,GAAA,CAAI,QAAQ,KAAK,CAAA,CAAE,IAAA,CAAK,CAAC,EAAA,KAAO;AAClE,MAAA,IAAI,IAAI,QAAA,EAAS;AAAA,WAAA,IACR,MAAA,CAAO,OAAA,EAAS,OAAA,CAAQ,IAAA,CAAK,4DAAoD,CAAA;AAAA,IAC5F,CAAC,CAAA;AAAA,EACH,CAAA,MAAO;AACL,IAAA,QAAA,EAAS;AAAA,EACX;AAEA,EAAA,OAAO,EAAE,QAAA,EAAS;AACpB;AAQA,eAAe,kBAAA,CAAmB,MAAA,EAAgB,MAAA,EAAgB,KAAA,EAAiC;AACjG,EAAA,IAAI;AACF,IAAA,MAAM,MAAM,CAAA,EAAG,MAAA,CAAO,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAC,CAAA,kBAAA,CAAA;AACzC,IAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,MAC3B,MAAA,EAAQ,MAAA;AAAA,MACR,OAAA,EAAS,EAAE,cAAA,EAAgB,kBAAA,EAAoB,aAAa,MAAA,EAAO;AAAA,MACnE,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,OAAO;AAAA,KAC/B,CAAA;AACD,IAAA,IAAI,CAAC,GAAA,CAAI,EAAA,EAAI,OAAO,IAAA;AACpB,IAAA,MAAM,OAAQ,MAAM,GAAA,CAAI,MAAK,CAAE,KAAA,CAAM,MAAM,IAAI,CAAA;AAC/C,IAAA,OAAO,MAAM,KAAA,KAAU,KAAA;AAAA,EACzB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAGA,SAAS,aAAA,GAA+B;AACtC,EAAA,IAAI,OAAO,MAAA,IAAU,MAAA,CAAO,MAAA,KAAW,MAAA,SAAe,MAAA,CAAO,MAAA;AAC7D,EAAA,IAAI,OAAO,MAAA,IAAU,MAAA,CAAO,MAAA,KAAW,MAAA,SAAe,MAAA,CAAO,MAAA;AAC7D,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,uBAAuB,UAAA,EAA0C;AAExE,EAAA,IAAI,UAAA,EAAY;AACd,IAAA,IAAI;AACF,MAAA,OAAO,IAAI,GAAA,CAAI,UAAU,CAAA,CAAE,MAAA;AAAA,IAC7B,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAGA,EAAA,IAAI,WAAA,EAAY,IAAK,QAAA,CAAS,QAAA,EAAU;AACtC,IAAA,IAAI;AACF,MAAA,OAAO,IAAI,GAAA,CAAI,QAAA,CAAS,QAAQ,CAAA,CAAE,MAAA;AAAA,IACpC,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;;;ACjJA,IAAM,gBAAA,GAAmB,6BAAA;AACzB,IAAM,aAAA,GAAgB,GAAA;AAEf,SAAS,qBAAqB,OAAA,EAAgD;AACnF,EAAA,IAAI,CAAC,SAAA,EAAU,EAAG,OAAO,WAAA,EAAY;AAErC,EAAA,MAAM,eAAA,GAAkB,OAAA,CAAQ,eAAA,IAAmB,MAAA,CAAO,QAAA,CAAS,MAAA;AACnE,EAAA,MAAM,SAAA,GAAY,UAAA,CAAW,OAAA,CAAQ,MAAM,CAAA;AAC3C,EAAA,MAAM,MAAM,WAAA,CAAY,OAAA,CAAQ,MAAA,EAAQ,OAAA,CAAQ,OAAO,eAAe,CAAA;AAEtE,EAAA,MAAM,KAAA,GAAQ,QAAQ,KAAA,IAAS,IAAA;AAC/B,EAAA,MAAM,WAAW,KAAA,KAAU,IAAA;AAE3B,EAAA,IAAI,KAAA,GAAuB,IAAA;AAC3B,EAAA,IAAI,QAAA,EAAU;AAEZ,IAAA,KAAA,CAAO,GAAA,GAAM,GAAA;AAAA,EACf,CAAA,MAAO;AACL,IAAA,KAAA,GAAQ,MAAA,CAAO,IAAA;AAAA,MACb,GAAA;AAAA,MACA,QAAQ,UAAA,IAAc,aAAA;AAAA,MACtB,QAAQ,cAAA,IAAkB;AAAA,KAC5B;AAAA,EACF;AAGA,EAAA,MAAM,YAAA,GAAe,MAAsB,QAAA,GAAY,KAAA,EAAO,iBAAiB,IAAA,GAAQ,KAAA;AAEvF,EAAA,MAAM,IAAA,GAAO,CAAC,OAAA,KAAkC;AAC9C,IAAA,MAAM,IAAI,YAAA,EAAa;AACvB,IAAA,IAAI,CAAC,CAAA,EAAG;AACR,IAAA,IAAI,CAAC,QAAA,IAAY,KAAA,EAAO,MAAA,EAAQ;AAChC,IAAA,CAAA,CAAE,WAAA;AAAA,MACA,EAAE,MAAA,EAAQ,kBAAA,EAAoB,OAAO,OAAA,CAAQ,KAAA,EAAO,GAAG,OAAA,EAAQ;AAAA,MAC/D,SAAA,IAAa;AAAA,KACf;AAAA,EACF,CAAA;AAEA,EAAA,IAAI,SAAA;AAEJ,EAAA,MAAM,UAAU,MAAY;AAC1B,IAAA,MAAA,CAAO,mBAAA,CAAoB,WAAW,SAAS,CAAA;AAC/C,IAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,MAAA,aAAA,CAAc,SAAS,CAAA;AACvB,MAAA,SAAA,GAAY,MAAA;AAAA,IACd;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,SAAA,GAAY,CAAC,KAAA,KAA8B;AAC/C,IAAA,IAAI,SAAA,IAAa,KAAA,CAAM,MAAA,KAAW,SAAA,EAAW;AAC7C,IAAA,MAAM,OAAO,KAAA,CAAM,IAAA;AAMnB,IAAA,IAAI,CAAC,QAAQ,IAAA,CAAK,MAAA,KAAW,sBAAsB,IAAA,CAAK,KAAA,KAAU,QAAQ,KAAA,EAAO;AAEjF,IAAA,QAAQ,KAAK,IAAA;AAAM,MACjB,KAAK,OAAA;AACH,QAAA,OAAA,CAAQ,OAAA,IAAU;AAClB,QAAA;AAAA,MACF,KAAK,QAAA;AACH,QAAA,IAAI,IAAA,CAAK,OAAA,EAAS,OAAA,CAAQ,QAAA,GAAW,KAAK,OAAwB,CAAA;AAClE,QAAA;AAAA,MACF,KAAK,gBAAA;AACH,QAAA,OAAA,CAAQ,WAAA,IAAc;AACtB,QAAA;AAAA,MACF,KAAK,QAAA;AACH,QAAA,OAAA,EAAQ;AACR,QAAA,OAAA,CAAQ,QAAA,IAAW;AACnB,QAAA;AAAA;AACJ,EACF,CAAA;AAEA,EAAA,MAAA,CAAO,gBAAA,CAAiB,WAAW,SAAS,CAAA;AAI5C,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,SAAA,GAAY,YAAY,MAAM;AAC5B,MAAA,IAAI,OAAO,MAAA,EAAQ;AACjB,QAAA,OAAA,EAAQ;AACR,QAAA,OAAA,CAAQ,QAAA,IAAW;AAAA,MACrB;AAAA,IACF,GAAG,aAAa,CAAA;AAAA,EAClB;AAEA,EAAA,OAAO;AAAA,IACL,WAAA,EAAa,CAAC,CAAA,KACZ,IAAA,CAAK;AAAA,MACH,IAAA,EAAM,cAAA;AAAA,MACN,GAAI,GAAG,YAAA,KAAiB,MAAA,GAAY,EAAE,YAAA,EAAc,CAAA,CAAE,YAAA,EAAa,GAAI,EAAC;AAAA,MACxE,GAAI,GAAG,IAAA,KAAS,MAAA,GAAY,EAAE,IAAA,EAAM,CAAA,CAAE,IAAA,EAAK,GAAI;AAAC,KACjD,CAAA;AAAA,IACH,YAAY,MAAM,IAAA,CAAK,EAAE,IAAA,EAAM,eAAe,CAAA;AAAA,IAC9C,OAAA,EAAS,CAAC,KAAA,KAAU,IAAA,CAAK,EAAE,IAAA,EAAM,SAAA,EAAW,OAAO,CAAA;AAAA,IACnD,cAAc,MAAM,IAAA,CAAK,EAAE,IAAA,EAAM,iBAAiB,CAAA;AAAA,IAClD,OAAO,MAAM;AACX,MAAA,IAAA,CAAK,EAAE,IAAA,EAAM,UAAA,EAAY,CAAA;AACzB,MAAA,IAAI,QAAA,EAAU;AACZ,QAAA,IAAI,KAAA,QAAa,GAAA,GAAM,aAAA;AAAA,MACzB,CAAA,MAAA,IAAW,KAAA,IAAS,CAAC,KAAA,CAAM,MAAA,EAAQ;AACjC,QAAA,KAAA,CAAM,KAAA,EAAM;AAAA,MACd;AACA,MAAA,OAAA,EAAQ;AAAA,IACV;AAAA,GACF;AACF;AAEA,SAAS,WAAA,CAAY,MAAA,EAAgB,KAAA,EAAe,eAAA,EAAiC;AACnF,EAAA,IAAI;AACF,IAAA,MAAM,IAAI,IAAI,GAAA,CAAI,MAAA,EAAQ,MAAA,CAAO,SAAS,IAAI,CAAA;AAC9C,IAAA,CAAA,CAAE,YAAA,CAAa,GAAA,CAAI,mBAAA,EAAqB,KAAK,CAAA;AAC7C,IAAA,CAAA,CAAE,YAAA,CAAa,GAAA,CAAI,oBAAA,EAAsB,eAAe,CAAA;AACxD,IAAA,OAAO,EAAE,QAAA,EAAS;AAAA,EACpB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAEA,SAAS,WAAW,GAAA,EAA4B;AAC9C,EAAA,IAAI;AACF,IAAA,OAAO,IAAI,GAAA,CAAI,GAAA,EAAK,MAAA,CAAO,QAAA,CAAS,IAAI,CAAA,CAAE,MAAA;AAAA,EAC5C,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAEA,SAAS,WAAA,GAA8B;AACrC,EAAA,OAAO;AAAA,IACL,aAAa,MAAM;AAAA,IAAC,CAAA;AAAA,IACpB,YAAY,MAAM;AAAA,IAAC,CAAA;AAAA,IACnB,SAAS,MAAM;AAAA,IAAC,CAAA;AAAA,IAChB,cAAc,MAAM;AAAA,IAAC,CAAA;AAAA,IACrB,OAAO,MAAM;AAAA,IAAC;AAAA,GAChB;AACF","file":"chunk-IKFTO7MX.mjs","sourcesContent":["/**\n * Contrato de mensajes del puente builder (app del cliente ↔ dashboard).\n * Ambos lados validan `event.origin` y que `token` coincida antes de actuar.\n *\n * Flujo:\n * 1. El dashboard abre la app con `?veoBuilder=<token>&veoBuilderOrigin=<origen>`.\n * 2. La app (veo-builder.js) postea `ready` a la ventana que la abrió.\n * 3. El dashboard manda comandos (`start-picker`, `preview`, …).\n * 4. La app responde con eventos (`picked`, `pick-cancelled`, …).\n */\nimport type { PreviewGuideInput } from '../guides/guide-preview';\nimport type { PickedElement } from './element-picker';\n\nexport const VEO_BUILDER_SOURCE = 'veo-builder';\n// Los nombres de los query params viven en el core (`builder-token.ts`), única\n// fuente de verdad compartida con el loader y el gate del runtime de guías.\nexport { BUILDER_ORIGIN_PARAM, BUILDER_TOKEN_PARAM } from '../../core/builder-token';\n\n/** Eventos que la app del cliente envía al dashboard. */\nexport type BuilderEvent =\n | { type: 'ready' }\n | { type: 'picked'; payload: PickedElement }\n | { type: 'pick-cancelled' }\n | { type: 'closed' };\n\n/** Comandos que el dashboard/panel envía a la app del cliente. */\nexport type BuilderCommand =\n | { type: 'start-picker'; maxAncestors?: number; hint?: string }\n | { type: 'stop-picker' }\n | { type: 'preview'; guide: PreviewGuideInput }\n | { type: 'close-preview' }\n | { type: 'teardown' }\n // Modo panel inyectado: el panel avisa que cargó y está listo para recibir\n // eventos; la app responde con `ready`. Resuelve la carrera de que el iframe\n // del panel todavía no tenga su listener cuando la app postea `ready`.\n | { type: 'panel-ready' };\n\n/** Sobre común: todo mensaje del puente lleva `source` + `token`. */\nexport interface BuilderEnvelope {\n source: typeof VEO_BUILDER_SOURCE;\n token: string;\n}\n\nexport type BuilderEventMessage = BuilderEnvelope & BuilderEvent;\nexport type BuilderCommandMessage = BuilderEnvelope & BuilderCommand;\n","/**\n * Modo \"panel inyectado\" (editor en la pestaña de la app).\n *\n * La app es la pestaña top-level (login real) y el editor de Veo se inyecta\n * ENCIMA como una tarjeta flotante **arrastrable y redimensionable** (un iframe\n * al dashboard). Además se puede **sacar a una ventana independiente** del\n * navegador (\"pop-out\").\n *\n * El panel corre en el origen del dashboard (sesión de Veo para guardar guías) y\n * habla con la app (`window.parent` si está anclado, `window.opener` si está en\n * ventana aparte) por el puente postMessage. Este módulo inyecta/gestiona el\n * panel y expone su ventana destino.\n */\nimport { hasDocument, hasWindow } from '../../utils/safe-env';\n\nconst DEFAULT_PANEL_PATH = '/guides/design';\nconst PANEL_W = 400;\nconst PANEL_H = 640;\nconst MIN_W = 320;\nconst MIN_H = 320;\nconst MARGIN = 16;\n\nexport interface BuilderPanelOptions {\n dashboardOrigin: string;\n token: string;\n appOrigin: string;\n guide: string | null;\n panelPath: string | null;\n onClose: () => void;\n}\n\nexport interface BuilderPanelHandle {\n /** Ventana destino de los mensajes: el iframe anclado o la ventana pop-out. */\n target(): Window | null;\n /** Quita el panel del DOM (y cierra la ventana pop-out si hay). */\n teardown(): void;\n}\n\n/** Inyecta el panel del editor (arrastrable, redimensionable, pop-out). */\nexport function injectBuilderPanel(opts: BuilderPanelOptions): BuilderPanelHandle {\n if (!hasWindow() || !hasDocument()) {\n return { target: () => null, teardown: () => {} };\n }\n\n const panelUrl = buildPanelUrl(opts);\n\n const host = document.createElement('div');\n host.setAttribute('data-veo-builder-panel', '');\n const shadow = host.attachShadow({ mode: 'open' });\n\n const style = document.createElement('style');\n style.textContent = PANEL_CSS;\n\n const card = document.createElement('div');\n card.className = 'veo-panel';\n let left = Math.max(MARGIN, window.innerWidth - PANEL_W - MARGIN);\n let top = MARGIN;\n card.style.left = `${left}px`;\n card.style.top = `${top}px`;\n card.style.width = `${PANEL_W}px`;\n card.style.height = `${PANEL_H}px`;\n\n // Header: título + pop-out + cerrar.\n const header = document.createElement('div');\n header.className = 'veo-panel-header';\n const title = document.createElement('span');\n title.className = 'veo-panel-title';\n title.textContent = 'Veo · Editor';\n const actions = document.createElement('div');\n actions.className = 'veo-panel-actions';\n const popout = document.createElement('button');\n popout.className = 'veo-panel-btn';\n popout.type = 'button';\n popout.title = 'Abrir en ventana aparte';\n popout.setAttribute('aria-label', 'Abrir en ventana aparte');\n popout.textContent = '⧉';\n const close = document.createElement('button');\n close.className = 'veo-panel-btn veo-panel-close';\n close.type = 'button';\n close.title = 'Cerrar';\n close.setAttribute('aria-label', 'Cerrar');\n close.textContent = '✕';\n actions.append(popout, close);\n header.append(title, actions);\n\n const iframe = document.createElement('iframe');\n iframe.className = 'veo-panel-frame';\n iframe.title = 'Editor de Veo';\n iframe.src = panelUrl;\n\n const grip = document.createElement('div');\n grip.className = 'veo-panel-resize';\n grip.setAttribute('aria-hidden', 'true');\n\n card.append(header, iframe, grip);\n shadow.append(style, card);\n document.body.appendChild(host);\n\n // ── Pop-out: sacar el editor a una ventana independiente ────────────────\n let popped: Window | null = null;\n let pollTimer: ReturnType<typeof setInterval> | undefined;\n\n const stopPoll = (): void => {\n if (pollTimer !== undefined) {\n clearInterval(pollTimer);\n pollTimer = undefined;\n }\n };\n\n close.addEventListener('click', () => opts.onClose());\n popout.addEventListener('click', () => {\n const win = window.open(\n panelUrl,\n 'veo-editor',\n `popup,width=${Math.round(card.offsetWidth)},height=${Math.round(card.offsetHeight) + 60}`,\n );\n if (!win) return; // bloqueado por el navegador\n popped = win;\n card.style.display = 'none'; // el editor ahora vive en la ventana aparte\n pollTimer = setInterval(() => {\n if (popped?.closed) {\n stopPoll();\n opts.onClose(); // cerrar la ventana = salir del modo editor\n }\n }, 600);\n });\n\n // ── Arrastre por el header ──────────────────────────────────────────────\n header.addEventListener('mousedown', (e) => {\n if ((e.target as HTMLElement)?.classList.contains('veo-panel-btn')) return;\n e.preventDefault();\n const sx = e.clientX;\n const sy = e.clientY;\n const ol = left;\n const ot = top;\n iframe.style.pointerEvents = 'none';\n const move = (ev: MouseEvent): void => {\n left = clamp(ol + (ev.clientX - sx), 0, Math.max(0, window.innerWidth - card.offsetWidth));\n top = clamp(ot + (ev.clientY - sy), 0, Math.max(0, window.innerHeight - 40));\n card.style.left = `${left}px`;\n card.style.top = `${top}px`;\n };\n const up = (): void => {\n window.removeEventListener('mousemove', move);\n window.removeEventListener('mouseup', up);\n iframe.style.pointerEvents = '';\n };\n window.addEventListener('mousemove', move);\n window.addEventListener('mouseup', up);\n });\n\n // ── Redimensionar por el grip (esquina inferior derecha) ────────────────\n grip.addEventListener('mousedown', (e) => {\n e.preventDefault();\n e.stopPropagation();\n const sx = e.clientX;\n const sy = e.clientY;\n const sw = card.offsetWidth;\n const sh = card.offsetHeight;\n iframe.style.pointerEvents = 'none';\n const move = (ev: MouseEvent): void => {\n card.style.width = `${clamp(sw + (ev.clientX - sx), MIN_W, window.innerWidth)}px`;\n card.style.height = `${clamp(sh + (ev.clientY - sy), MIN_H, window.innerHeight)}px`;\n };\n const up = (): void => {\n window.removeEventListener('mousemove', move);\n window.removeEventListener('mouseup', up);\n iframe.style.pointerEvents = '';\n };\n window.addEventListener('mousemove', move);\n window.addEventListener('mouseup', up);\n });\n\n return {\n target: () => (popped && !popped.closed ? popped : iframe.contentWindow),\n teardown: () => {\n stopPoll();\n if (popped && !popped.closed) popped.close();\n host.remove();\n },\n };\n}\n\nfunction clamp(v: number, min: number, max: number): number {\n return Math.min(Math.max(v, min), max);\n}\n\nfunction buildPanelUrl(opts: BuilderPanelOptions): string {\n const path = opts.panelPath ?? DEFAULT_PANEL_PATH;\n const url = new URL(path, opts.dashboardOrigin);\n url.searchParams.set('veoToken', opts.token);\n url.searchParams.set('veoApp', opts.appOrigin);\n if (opts.guide) url.searchParams.set('veoGuide', opts.guide);\n return url.toString();\n}\n\nconst PANEL_CSS = `\n:host { all: initial; }\n.veo-panel {\n position: fixed;\n min-width: ${MIN_W}px; min-height: ${MIN_H}px;\n max-width: 96vw; max-height: 94vh;\n display: flex; flex-direction: column;\n background: #fff;\n border-radius: 12px;\n box-shadow: 0 12px 40px rgba(0,0,0,0.28);\n overflow: hidden;\n z-index: 2147483647;\n font-family: system-ui, -apple-system, sans-serif;\n}\n.veo-panel-header {\n flex: 0 0 auto;\n display: flex; align-items: center; justify-content: space-between;\n padding: 8px 10px 8px 12px;\n background: #0f172a; color: #fff;\n font-size: 13px; font-weight: 600;\n cursor: grab;\n}\n.veo-panel-header:active { cursor: grabbing; }\n.veo-panel-actions { display: flex; gap: 2px; }\n.veo-panel-btn {\n border: 0; background: transparent; color: #fff;\n font-size: 14px; cursor: pointer; line-height: 1;\n padding: 4px 7px; border-radius: 6px;\n}\n.veo-panel-btn:hover { background: rgba(255,255,255,0.15); }\n.veo-panel-frame { flex: 1 1 auto; width: 100%; border: 0; background: #fff; }\n.veo-panel-resize {\n position: absolute; right: 0; bottom: 0;\n width: 16px; height: 16px;\n cursor: nwse-resize;\n background:\n linear-gradient(135deg, transparent 50%, rgba(0,0,0,0.25) 50%, rgba(0,0,0,0.25) 60%,\n transparent 60%, transparent 72%, rgba(0,0,0,0.25) 72%, rgba(0,0,0,0.25) 82%, transparent 82%);\n}\n`;\n","/**\n * Element picker — el \"inspeccionar\" del navegador, pero del SDK. Corre\n * DENTRO de la app del cliente (no en el dashboard: son orígenes distintos\n * y el dashboard no puede leer el DOM de la app). Resalta el elemento bajo\n * el cursor, muestra su selector + dimensiones, y al hacer click captura un\n * selector CSS estable reutilizando `buildSelectorPath` del autocapture.\n *\n * Es la base del builder no-code: el dashboard abre la app del cliente en\n * modo builder, el usuario \"pincha\" un elemento y el selector resultante se\n * usa como ancla de un tooltip/walkthrough. El puente con el dashboard\n * (postMessage) es la fase siguiente; aquí exponemos el primitivo\n * `startElementPicker(onPick)`.\n *\n * No usa `innerHTML` — todo por `textContent`/DOM, igual que los renderers.\n */\n\nimport { hasDocument } from '../../utils/safe-env';\nimport { buildSelectorPath, filterHumanClasses } from '../autocapture/selector-builder';\n\n/** z-index por encima de las guías (2147483640) para tapar también una preview. */\nconst PICKER_Z = 2147483646;\nconst PICKER_HOST_ATTR = 'data-veo-picker';\nconst DEFAULT_MAX_ANCESTORS = 5;\n\n/** Datos del elemento elegido que se entregan al caller. */\nexport interface PickedElement {\n /** Selector CSS estable con ancestros (lo que se guarda como ancla). */\n selector: string;\n /** Selector corto solo del elemento (tag + id/atributo/clases). */\n shortSelector: string;\n tag: string;\n id: string | null;\n classes: string[];\n text: string;\n rect: { x: number; y: number; width: number; height: number };\n}\n\nexport interface ElementPickerOptions {\n /** Llamado al hacer click en un elemento. El picker se cierra tras esto. */\n onPick: (picked: PickedElement) => void;\n /** Llamado al cancelar (Esc). El picker se cierra. */\n onCancel?: () => void;\n /** Niveles de ancestros del selector. Default 5 (igual que autocapture). */\n maxAncestors?: number;\n /** Texto del banner superior. Default en español. */\n hint?: string;\n}\n\nexport interface ElementPickerHandle {\n /** Cierra el picker sin elegir nada. Idempotente. */\n stop(): void;\n}\n\nconst PICKER_STYLES = `\n:host { all: initial; }\n.veo-pick-box {\n position: fixed;\n z-index: ${PICKER_Z};\n pointer-events: none;\n box-sizing: border-box;\n background: rgba(99, 102, 241, 0.22);\n border: 1px dashed rgba(99, 102, 241, 0.95);\n border-radius: 2px;\n transition: top 60ms ease-out, left 60ms ease-out, width 60ms ease-out, height 60ms ease-out;\n}\n.veo-pick-label {\n position: fixed;\n z-index: ${PICKER_Z};\n pointer-events: none;\n max-width: 360px;\n background: #1e1b4b;\n color: #e0e7ff;\n font: 12px/1.45 ui-monospace, SFMono-Regular, Menlo, monospace;\n padding: 6px 9px;\n border-radius: 6px;\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.35);\n}\n.veo-pick-label .veo-pick-sel { color: #c7d2fe; word-break: break-all; }\n.veo-pick-label .veo-pick-dim { color: #a5b4fc; margin-top: 3px; }\n.veo-pick-hint {\n position: fixed;\n top: 12px;\n left: 50%;\n transform: translateX(-50%);\n z-index: ${PICKER_Z};\n pointer-events: none;\n background: #4338ca;\n color: #fff;\n font: 13px/1 -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n padding: 8px 14px;\n border-radius: 999px;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);\n}\n`;\n\n/**\n * Controla un picker activo. Singleton a nivel de módulo: empezar otro\n * cierra el anterior. Los listeners van en fase de captura para poder\n * cancelar el click ANTES de que la app del cliente reaccione.\n */\nclass ElementPicker {\n private host: HTMLElement | null = null;\n private box: HTMLElement | null = null;\n private label: HTMLElement | null = null;\n private current: Element | null = null;\n private maxAncestors = DEFAULT_MAX_ANCESTORS;\n private onPick: ((p: PickedElement) => void) | null = null;\n private onCancel: (() => void) | null = null;\n\n start(options: ElementPickerOptions): void {\n this.stop(); // solo un picker a la vez\n\n this.maxAncestors = options.maxAncestors ?? DEFAULT_MAX_ANCESTORS;\n this.onPick = options.onPick;\n this.onCancel = options.onCancel ?? null;\n\n const host = document.createElement('div');\n host.setAttribute(PICKER_HOST_ATTR, '');\n const shadow = host.attachShadow({ mode: 'open' });\n\n const style = document.createElement('style');\n style.textContent = PICKER_STYLES;\n\n this.box = document.createElement('div');\n this.box.className = 'veo-pick-box';\n this.box.style.display = 'none';\n\n this.label = document.createElement('div');\n this.label.className = 'veo-pick-label';\n this.label.style.display = 'none';\n\n const hint = document.createElement('div');\n hint.className = 'veo-pick-hint';\n hint.textContent = options.hint ?? 'Seleccioná un elemento · Esc para cancelar';\n\n shadow.append(style, this.box, this.label, hint);\n document.body.appendChild(host);\n this.host = host;\n\n document.addEventListener('mousemove', this.onMove, true);\n document.addEventListener('click', this.onClick, true);\n document.addEventListener('mousedown', this.swallow, true);\n document.addEventListener('mouseup', this.swallow, true);\n document.addEventListener('keydown', this.onKey, true);\n window.addEventListener('scroll', this.reposition, true);\n window.addEventListener('resize', this.reposition);\n }\n\n stop(): void {\n document.removeEventListener('mousemove', this.onMove, true);\n document.removeEventListener('click', this.onClick, true);\n document.removeEventListener('mousedown', this.swallow, true);\n document.removeEventListener('mouseup', this.swallow, true);\n document.removeEventListener('keydown', this.onKey, true);\n window.removeEventListener('scroll', this.reposition, true);\n window.removeEventListener('resize', this.reposition);\n\n if (this.host?.parentNode) this.host.parentNode.removeChild(this.host);\n this.host = null;\n this.box = null;\n this.label = null;\n this.current = null;\n this.onPick = null;\n this.onCancel = null;\n }\n\n /** ¿Es un nodo de nuestro propio overlay? (no debe ser seleccionable). */\n private isOwn(target: EventTarget | null): boolean {\n return target instanceof Node && this.host !== null && this.host.contains(target);\n }\n\n private onMove = (event: MouseEvent): void => {\n const target = event.target;\n if (!(target instanceof Element) || this.isOwn(target)) return;\n this.current = target;\n this.draw(target);\n };\n\n private onClick = (event: MouseEvent): void => {\n const target = this.current ?? (event.target instanceof Element ? event.target : null);\n if (!target || this.isOwn(target)) return;\n\n // Evitar que la app reaccione al click de selección.\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n\n const picked = this.describe(target);\n const cb = this.onPick;\n this.stop();\n cb?.(picked);\n };\n\n private onKey = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape') return;\n event.preventDefault();\n event.stopPropagation();\n const cb = this.onCancel;\n this.stop();\n cb?.();\n };\n\n /** Traga mousedown/mouseup durante el picking (evita focus/active de la app). */\n private swallow = (event: MouseEvent): void => {\n if (this.isOwn(event.target)) return;\n event.preventDefault();\n event.stopPropagation();\n };\n\n private reposition = (): void => {\n if (this.current) this.draw(this.current);\n };\n\n /** Dibuja el recuadro de resalte y la etiqueta sobre el elemento dado. */\n private draw(element: Element): void {\n if (!this.box || !this.label) return;\n const rect = element.getBoundingClientRect();\n\n this.box.style.display = 'block';\n this.box.style.top = `${rect.top}px`;\n this.box.style.left = `${rect.left}px`;\n this.box.style.width = `${rect.width}px`;\n this.box.style.height = `${rect.height}px`;\n\n const shortSel = buildSelectorPath(element, 0);\n this.label.textContent = '';\n const sel = document.createElement('div');\n sel.className = 'veo-pick-sel';\n sel.textContent = shortSel;\n const dim = document.createElement('div');\n dim.className = 'veo-pick-dim';\n dim.textContent = `${Math.round(rect.width)} × ${Math.round(rect.height)}`;\n this.label.append(sel, dim);\n\n // Etiqueta debajo del recuadro; si no hay espacio, arriba.\n this.label.style.display = 'block';\n const LABEL_H = 48;\n const placeAbove = rect.bottom + 8 + LABEL_H > window.innerHeight;\n this.label.style.top = placeAbove\n ? `${Math.max(8, rect.top - LABEL_H - 8)}px`\n : `${rect.bottom + 8}px`;\n this.label.style.left = `${Math.max(8, rect.left)}px`;\n }\n\n private describe(element: Element): PickedElement {\n const rect = element.getBoundingClientRect();\n return {\n selector: buildSelectorPath(element, this.maxAncestors),\n shortSelector: buildSelectorPath(element, 0),\n tag: element.tagName.toLowerCase(),\n id: element.id || null,\n classes: filterHumanClasses(element),\n text: (element.textContent ?? '').trim().slice(0, 120),\n rect: {\n x: Math.round(rect.left),\n y: Math.round(rect.top),\n width: Math.round(rect.width),\n height: Math.round(rect.height),\n },\n };\n }\n}\n\nlet activePicker: ElementPicker | null = null;\n\n/**\n * Inicia el modo de selección de elementos (inspector). Resalta lo que está\n * bajo el cursor y, al hacer click, entrega un selector CSS estable.\n * Devuelve un handle con `stop()`. Iniciar otro picker cierra el anterior.\n *\n * @example\n * ```ts\n * import { startElementPicker } from '@veo/sdk';\n *\n * const picker = startElementPicker({\n * onPick: ({ selector }) => console.log('elegido:', selector),\n * onCancel: () => console.log('cancelado'),\n * });\n * // picker.stop() para abortar manualmente.\n * ```\n */\nexport function startElementPicker(options: ElementPickerOptions): ElementPickerHandle {\n if (!hasDocument()) {\n return { stop: () => {} };\n }\n if (!activePicker) activePicker = new ElementPicker();\n activePicker.start(options);\n return { stop: () => activePicker?.stop() };\n}\n\n/** Cierra el picker activo, si lo hay. Idempotente. */\nexport function stopElementPicker(): void {\n activePicker?.stop();\n}\n","/**\n * Lado APP del puente builder. Corre dentro de la app del cliente (vía\n * veo-builder.js). Si el contexto trae `?veoBuilder=<token>`, se conecta con el\n * editor de Veo, atiende comandos y devuelve el elemento elegido.\n *\n * Dos transportes:\n * - **iframe/popup** (`resolveTarget` = opener/parent): el dashboard es la\n * ventana principal y embebe/abre la app; le hablamos a esa ventana.\n * - **panel inyectado** (`ctx.panel`): la app es top-level (login real) y NOSOTROS\n * inyectamos el panel del editor encima (iframe al dashboard); le hablamos a\n * ese iframe. Es el modo sin adaptación por app.\n *\n * Seguridad: solo acepta mensajes cuyo `origin` coincida con el del dashboard\n * (`veoBuilderOrigin` / `document.referrer`) y cuyo `token` coincida.\n */\nimport {\n type BuilderClientContext,\n clearBuilderToken,\n resolveBuilderContext,\n} from '../../core/builder-token';\nimport { hasDocument, hasWindow } from '../../utils/safe-env';\nimport { closeGuidePreview, previewGuide } from '../guides/guide-preview';\nimport { type BuilderCommand, type BuilderEvent, VEO_BUILDER_SOURCE } from './bridge-protocol';\nimport { type BuilderPanelHandle, injectBuilderPanel } from './builder-panel';\nimport { type ElementPickerHandle, startElementPicker } from './element-picker';\n\nexport interface BuilderModeHandle {\n /** Desconecta el puente y limpia picker/preview/panel. */\n teardown(): void;\n}\n\n/**\n * Inicializa el modo builder si hay contexto (URL o persistido). Devuelve un\n * handle, o `null` si no estamos en modo builder o no hay canal con el editor.\n * Es seguro llamarla siempre.\n */\nexport function initBuilderMode(): BuilderModeHandle | null {\n if (!hasWindow() || !hasDocument()) return null;\n\n // Contexto de la URL o de sessionStorage: sobrevive al redirect del guard de\n // auth (que suele tirar el query string) y a un login en la misma pestaña.\n const ctx = resolveBuilderContext();\n if (!ctx) return null;\n\n const token = ctx.token;\n const dashboardOrigin = resolveDashboardOrigin(ctx.origin);\n if (!dashboardOrigin) return null;\n\n let picker: ElementPickerHandle | null = null;\n let panel: BuilderPanelHandle | null = null;\n let staticTarget: Window | null = null;\n const getTarget = (): Window | null => (panel ? panel.target() : staticTarget);\n\n const post = (event: BuilderEvent): void => {\n getTarget()?.postMessage({ source: VEO_BUILDER_SOURCE, token, ...event }, dashboardOrigin);\n };\n\n const handleCommand = (cmd: BuilderCommand): void => {\n switch (cmd.type) {\n case 'panel-ready':\n // El panel cargó y ya escucha → recién ahora le mandamos `ready`.\n post({ type: 'ready' });\n break;\n case 'start-picker':\n picker?.stop();\n picker = startElementPicker({\n onPick: (payload) => {\n picker = null;\n post({ type: 'picked', payload });\n },\n onCancel: () => {\n picker = null;\n post({ type: 'pick-cancelled' });\n },\n ...(cmd.maxAncestors !== undefined ? { maxAncestors: cmd.maxAncestors } : {}),\n ...(cmd.hint !== undefined ? { hint: cmd.hint } : {}),\n });\n break;\n case 'stop-picker':\n picker?.stop();\n picker = null;\n break;\n case 'preview':\n if (cmd.guide) void previewGuide(cmd.guide).ready;\n break;\n case 'close-preview':\n closeGuidePreview();\n break;\n case 'teardown':\n teardown();\n break;\n }\n };\n\n const onMessage = (event: MessageEvent): void => {\n if (event.origin !== dashboardOrigin) return;\n const data = event.data as { source?: unknown; token?: unknown } | null;\n if (!data || data.source !== VEO_BUILDER_SOURCE || data.token !== token) return;\n handleCommand(data as BuilderCommand);\n };\n\n const onPageHide = (): void => post({ type: 'closed' });\n\n const teardown = (): void => {\n window.removeEventListener('message', onMessage);\n window.removeEventListener('pagehide', onPageHide);\n picker?.stop();\n picker = null;\n closeGuidePreview();\n post({ type: 'closed' }); // avisar al editor ANTES de sacar el panel\n panel?.teardown();\n panel = null;\n clearBuilderToken(); // salir del modo builder: no re-activar en la próxima carga\n };\n\n // Transporte: panel inyectado (app top-level) o iframe/popup (embebida).\n if (ctx.panel) {\n panel = injectBuilderPanel({\n dashboardOrigin,\n token,\n appOrigin: window.location.origin,\n guide: ctx.guide,\n panelPath: ctx.panelPath,\n onClose: () => teardown(),\n });\n } else {\n staticTarget = resolveTarget();\n if (!staticTarget) return null;\n }\n\n const activate = (): void => {\n window.addEventListener('message', onMessage);\n window.addEventListener('pagehide', onPageHide);\n // Panel: esperamos el `panel-ready` del iframe para postear `ready` (todavía\n // puede no tener su listener). iframe/popup: el opener ya escucha → posteamos ya.\n if (!ctx.panel) post({ type: 'ready' });\n };\n\n // Verificación del token contra el backend (firmado + scopeado por workspace)\n // ANTES de activar. Si `init()` dejó la config (integración real) verificamos;\n // si el backend dice explícitamente que NO es válido, no activamos. Si no hay\n // config (demo) o el backend no responde, activamos best-effort.\n const cfg = (window as unknown as { __veoBuilder?: { apiKey?: string; apiUrl?: string } })\n .__veoBuilder;\n if (cfg?.apiKey && cfg?.apiUrl) {\n void verifyBuilderToken(cfg.apiUrl, cfg.apiKey, token).then((ok) => {\n if (ok) activate();\n else if (window.console) console.warn('[veo] token de builder inválido — modo no activado');\n });\n } else {\n activate();\n }\n\n return { teardown };\n}\n\n/**\n * Verifica el token con el backend. Solo devuelve `false` (no activar) cuando el\n * backend responde explícitamente `{valid:false}` (token forjado/expirado/de\n * otro workspace). Ante 404/red caída/errores transitorios devuelve `true`\n * (best-effort) para no brickear el modo builder.\n */\nasync function verifyBuilderToken(apiUrl: string, apiKey: string, token: string): Promise<boolean> {\n try {\n const url = `${apiUrl.replace(/\\/+$/, '')}/v1/builder/verify`;\n const res = await fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'X-Api-Key': apiKey },\n body: JSON.stringify({ token }),\n });\n if (!res.ok) return true; // no pudimos verificar → best-effort\n const data = (await res.json().catch(() => null)) as { valid?: unknown } | null;\n return data?.valid !== false;\n } catch {\n return true; // red caída / sin backend → best-effort\n }\n}\n\n/** Ventana con la que hablar en modo iframe/popup: el opener o el parent. */\nfunction resolveTarget(): Window | null {\n if (window.opener && window.opener !== window) return window.opener as Window;\n if (window.parent && window.parent !== window) return window.parent;\n return null;\n}\n\nfunction resolveDashboardOrigin(originHint: string | null): string | null {\n // Origen de la URL o persistido en el primer arranque (antes del redirect).\n if (originHint) {\n try {\n return new URL(originHint).origin;\n } catch {\n return null;\n }\n }\n // Fallback: el referrer. Poco fiable tras un redirect same-origin (apunta a la\n // propia app), por eso el origen persistido va primero.\n if (hasDocument() && document.referrer) {\n try {\n return new URL(document.referrer).origin;\n } catch {\n return null;\n }\n }\n return null;\n}\n\n// Tipo re-exportado para consumidores que tipan el contexto.\nexport type { BuilderClientContext };\n","/**\n * Lado DASHBOARD del puente builder. Abre la app del cliente en un popup,\n * en modo builder, y expone una API para pedirle que seleccione un elemento\n * o previsualice una guía. Pensado para importarse en el dashboard\n * (`import { createBuilderSession } from '@veo/sdk/builder'`).\n *\n * Seguridad: solo procesa mensajes cuyo `origin` sea el de la app y cuyo\n * `token` coincida con el de esta sesión.\n */\nimport { hasWindow } from '../../utils/safe-env';\nimport type { PreviewGuideInput } from '../guides/guide-preview';\nimport {\n BUILDER_ORIGIN_PARAM,\n BUILDER_TOKEN_PARAM,\n type BuilderCommand,\n VEO_BUILDER_SOURCE,\n} from './bridge-protocol';\nimport type { PickedElement } from './element-picker';\n\nexport interface BuilderSessionOptions {\n /** URL de la app del cliente a abrir en modo builder. */\n appUrl: string;\n /** Token de la sesión (idealmente emitido/firmado por el backend). */\n token: string;\n /** Origen al que la app debe responder. Default: `location.origin`. */\n dashboardOrigin?: string;\n /** La app está lista y escuchando comandos. */\n onReady?: () => void;\n /** El usuario eligió un elemento. */\n onPicked?: (picked: PickedElement) => void;\n /** El usuario canceló la selección (Esc). */\n onCancelled?: () => void;\n /** La app cerró el modo builder (o el popup se cerró). */\n onClosed?: () => void;\n /**\n * Si se pasa, la app se embebe en este `<iframe>` (modo estudio in-app) en\n * lugar de abrirse en un popup. El lado app ya habla con `window.parent`,\n * así que el puente funciona igual. La sesión setea el `src` del iframe.\n */\n frame?: HTMLIFrameElement;\n /** Nombre de la ventana popup. Default: `veo-builder`. */\n windowName?: string;\n /** Features del popup. Default: ventana de ~1280×860. */\n windowFeatures?: string;\n}\n\nexport interface BuilderSession {\n /** Pide a la app que entre en modo selección de elemento. */\n startPicker(options?: { maxAncestors?: number; hint?: string }): void;\n /** Cancela la selección en curso. */\n stopPicker(): void;\n /** Pide a la app que previsualice una guía. */\n preview(guide: PreviewGuideInput): void;\n /** Cierra la preview activa en la app. */\n closePreview(): void;\n /** Cierra el popup y desconecta el puente. */\n close(): void;\n}\n\nconst DEFAULT_FEATURES = 'popup,width=1280,height=860';\nconst POPUP_POLL_MS = 600;\n\nexport function createBuilderSession(options: BuilderSessionOptions): BuilderSession {\n if (!hasWindow()) return noopSession();\n\n const dashboardOrigin = options.dashboardOrigin ?? window.location.origin;\n const appOrigin = safeOrigin(options.appUrl);\n const url = buildAppUrl(options.appUrl, options.token, dashboardOrigin);\n\n const frame = options.frame ?? null;\n const useFrame = frame !== null;\n\n let popup: Window | null = null;\n if (useFrame) {\n // biome-ignore lint/style/noNonNullAssertion: useFrame garantiza frame\n frame!.src = url;\n } else {\n popup = window.open(\n url,\n options.windowName ?? 'veo-builder',\n options.windowFeatures ?? DEFAULT_FEATURES,\n );\n }\n\n /** Ventana destino de los comandos: el popup o el contentWindow del iframe. */\n const targetWindow = (): Window | null => (useFrame ? (frame?.contentWindow ?? null) : popup);\n\n const post = (command: BuilderCommand): void => {\n const w = targetWindow();\n if (!w) return;\n if (!useFrame && popup?.closed) return;\n w.postMessage(\n { source: VEO_BUILDER_SOURCE, token: options.token, ...command },\n appOrigin ?? '*',\n );\n };\n\n let pollTimer: ReturnType<typeof setInterval> | undefined;\n\n const cleanup = (): void => {\n window.removeEventListener('message', onMessage);\n if (pollTimer !== undefined) {\n clearInterval(pollTimer);\n pollTimer = undefined;\n }\n };\n\n const onMessage = (event: MessageEvent): void => {\n if (appOrigin && event.origin !== appOrigin) return;\n const data = event.data as {\n source?: unknown;\n token?: unknown;\n type?: unknown;\n payload?: unknown;\n } | null;\n if (!data || data.source !== VEO_BUILDER_SOURCE || data.token !== options.token) return;\n\n switch (data.type) {\n case 'ready':\n options.onReady?.();\n break;\n case 'picked':\n if (data.payload) options.onPicked?.(data.payload as PickedElement);\n break;\n case 'pick-cancelled':\n options.onCancelled?.();\n break;\n case 'closed':\n cleanup();\n options.onClosed?.();\n break;\n }\n };\n\n window.addEventListener('message', onMessage);\n\n // Detectar cierre manual del popup (el usuario cierra la ventana). En modo\n // iframe el ciclo de vida lo controla el dashboard (no hay nada que pollear).\n if (!useFrame) {\n pollTimer = setInterval(() => {\n if (popup?.closed) {\n cleanup();\n options.onClosed?.();\n }\n }, POPUP_POLL_MS);\n }\n\n return {\n startPicker: (o) =>\n post({\n type: 'start-picker',\n ...(o?.maxAncestors !== undefined ? { maxAncestors: o.maxAncestors } : {}),\n ...(o?.hint !== undefined ? { hint: o.hint } : {}),\n }),\n stopPicker: () => post({ type: 'stop-picker' }),\n preview: (guide) => post({ type: 'preview', guide }),\n closePreview: () => post({ type: 'close-preview' }),\n close: () => {\n post({ type: 'teardown' });\n if (useFrame) {\n if (frame) frame.src = 'about:blank';\n } else if (popup && !popup.closed) {\n popup.close();\n }\n cleanup();\n },\n };\n}\n\nfunction buildAppUrl(appUrl: string, token: string, dashboardOrigin: string): string {\n try {\n const u = new URL(appUrl, window.location.href);\n u.searchParams.set(BUILDER_TOKEN_PARAM, token);\n u.searchParams.set(BUILDER_ORIGIN_PARAM, dashboardOrigin);\n return u.toString();\n } catch {\n return appUrl;\n }\n}\n\nfunction safeOrigin(url: string): string | null {\n try {\n return new URL(url, window.location.href).origin;\n } catch {\n return null;\n }\n}\n\nfunction noopSession(): BuilderSession {\n return {\n startPicker: () => {},\n stopPicker: () => {},\n preview: () => {},\n closePreview: () => {},\n close: () => {},\n };\n}\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -1944,6 +1944,7 @@ function injectBuilderPanel(opts) {
|
|
|
1944
1944
|
return { target: () => null, teardown: () => {
|
|
1945
1945
|
} };
|
|
1946
1946
|
}
|
|
1947
|
+
const panelUrl = buildPanelUrl(opts);
|
|
1947
1948
|
const host = document.createElement("div");
|
|
1948
1949
|
host.setAttribute("data-veo-builder-panel", "");
|
|
1949
1950
|
const shadow = host.attachShadow({ mode: "open" });
|
|
@@ -1955,55 +1956,113 @@ function injectBuilderPanel(opts) {
|
|
|
1955
1956
|
let top = MARGIN;
|
|
1956
1957
|
card.style.left = `${left}px`;
|
|
1957
1958
|
card.style.top = `${top}px`;
|
|
1959
|
+
card.style.width = `${PANEL_W}px`;
|
|
1960
|
+
card.style.height = `${PANEL_H}px`;
|
|
1958
1961
|
const header = document.createElement("div");
|
|
1959
1962
|
header.className = "veo-panel-header";
|
|
1960
1963
|
const title = document.createElement("span");
|
|
1961
1964
|
title.className = "veo-panel-title";
|
|
1962
1965
|
title.textContent = "Veo \xB7 Editor";
|
|
1966
|
+
const actions = document.createElement("div");
|
|
1967
|
+
actions.className = "veo-panel-actions";
|
|
1968
|
+
const popout = document.createElement("button");
|
|
1969
|
+
popout.className = "veo-panel-btn";
|
|
1970
|
+
popout.type = "button";
|
|
1971
|
+
popout.title = "Abrir en ventana aparte";
|
|
1972
|
+
popout.setAttribute("aria-label", "Abrir en ventana aparte");
|
|
1973
|
+
popout.textContent = "\u29C9";
|
|
1963
1974
|
const close = document.createElement("button");
|
|
1964
|
-
close.className = "veo-panel-close";
|
|
1975
|
+
close.className = "veo-panel-btn veo-panel-close";
|
|
1965
1976
|
close.type = "button";
|
|
1977
|
+
close.title = "Cerrar";
|
|
1966
1978
|
close.setAttribute("aria-label", "Cerrar");
|
|
1967
1979
|
close.textContent = "\u2715";
|
|
1968
|
-
|
|
1969
|
-
header.append(title,
|
|
1980
|
+
actions.append(popout, close);
|
|
1981
|
+
header.append(title, actions);
|
|
1970
1982
|
const iframe = document.createElement("iframe");
|
|
1971
1983
|
iframe.className = "veo-panel-frame";
|
|
1972
1984
|
iframe.title = "Editor de Veo";
|
|
1973
|
-
iframe.src =
|
|
1974
|
-
|
|
1985
|
+
iframe.src = panelUrl;
|
|
1986
|
+
const grip = document.createElement("div");
|
|
1987
|
+
grip.className = "veo-panel-resize";
|
|
1988
|
+
grip.setAttribute("aria-hidden", "true");
|
|
1989
|
+
card.append(header, iframe, grip);
|
|
1975
1990
|
shadow.append(style, card);
|
|
1976
1991
|
document.body.appendChild(host);
|
|
1977
|
-
|
|
1978
|
-
|
|
1992
|
+
let popped = null;
|
|
1993
|
+
let pollTimer;
|
|
1994
|
+
const stopPoll = () => {
|
|
1995
|
+
if (pollTimer !== void 0) {
|
|
1996
|
+
clearInterval(pollTimer);
|
|
1997
|
+
pollTimer = void 0;
|
|
1998
|
+
}
|
|
1999
|
+
};
|
|
2000
|
+
close.addEventListener("click", () => opts.onClose());
|
|
2001
|
+
popout.addEventListener("click", () => {
|
|
2002
|
+
const win = window.open(
|
|
2003
|
+
panelUrl,
|
|
2004
|
+
"veo-editor",
|
|
2005
|
+
`popup,width=${Math.round(card.offsetWidth)},height=${Math.round(card.offsetHeight) + 60}`
|
|
2006
|
+
);
|
|
2007
|
+
if (!win) return;
|
|
2008
|
+
popped = win;
|
|
2009
|
+
card.style.display = "none";
|
|
2010
|
+
pollTimer = setInterval(() => {
|
|
2011
|
+
if (popped?.closed) {
|
|
2012
|
+
stopPoll();
|
|
2013
|
+
opts.onClose();
|
|
2014
|
+
}
|
|
2015
|
+
}, 600);
|
|
2016
|
+
});
|
|
2017
|
+
header.addEventListener("mousedown", (e) => {
|
|
2018
|
+
if (e.target?.classList.contains("veo-panel-btn")) return;
|
|
1979
2019
|
e.preventDefault();
|
|
1980
|
-
const
|
|
1981
|
-
const
|
|
1982
|
-
const
|
|
1983
|
-
const
|
|
2020
|
+
const sx = e.clientX;
|
|
2021
|
+
const sy = e.clientY;
|
|
2022
|
+
const ol = left;
|
|
2023
|
+
const ot = top;
|
|
1984
2024
|
iframe.style.pointerEvents = "none";
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
const maxTop = window.innerHeight - 40;
|
|
1989
|
-
left = clamp2(origLeft + (ev.clientX - startX), 0, Math.max(0, maxLeft));
|
|
1990
|
-
top = clamp2(origTop + (ev.clientY - startY), 0, Math.max(0, maxTop));
|
|
2025
|
+
const move = (ev) => {
|
|
2026
|
+
left = clamp2(ol + (ev.clientX - sx), 0, Math.max(0, window.innerWidth - card.offsetWidth));
|
|
2027
|
+
top = clamp2(ot + (ev.clientY - sy), 0, Math.max(0, window.innerHeight - 40));
|
|
1991
2028
|
card.style.left = `${left}px`;
|
|
1992
2029
|
card.style.top = `${top}px`;
|
|
1993
2030
|
};
|
|
1994
|
-
const
|
|
1995
|
-
window.removeEventListener("mousemove",
|
|
1996
|
-
window.removeEventListener("mouseup",
|
|
2031
|
+
const up = () => {
|
|
2032
|
+
window.removeEventListener("mousemove", move);
|
|
2033
|
+
window.removeEventListener("mouseup", up);
|
|
1997
2034
|
iframe.style.pointerEvents = "";
|
|
1998
|
-
card.classList.remove("dragging");
|
|
1999
2035
|
};
|
|
2000
|
-
window.addEventListener("mousemove",
|
|
2001
|
-
window.addEventListener("mouseup",
|
|
2002
|
-
};
|
|
2003
|
-
|
|
2036
|
+
window.addEventListener("mousemove", move);
|
|
2037
|
+
window.addEventListener("mouseup", up);
|
|
2038
|
+
});
|
|
2039
|
+
grip.addEventListener("mousedown", (e) => {
|
|
2040
|
+
e.preventDefault();
|
|
2041
|
+
e.stopPropagation();
|
|
2042
|
+
const sx = e.clientX;
|
|
2043
|
+
const sy = e.clientY;
|
|
2044
|
+
const sw = card.offsetWidth;
|
|
2045
|
+
const sh = card.offsetHeight;
|
|
2046
|
+
iframe.style.pointerEvents = "none";
|
|
2047
|
+
const move = (ev) => {
|
|
2048
|
+
card.style.width = `${clamp2(sw + (ev.clientX - sx), MIN_W, window.innerWidth)}px`;
|
|
2049
|
+
card.style.height = `${clamp2(sh + (ev.clientY - sy), MIN_H, window.innerHeight)}px`;
|
|
2050
|
+
};
|
|
2051
|
+
const up = () => {
|
|
2052
|
+
window.removeEventListener("mousemove", move);
|
|
2053
|
+
window.removeEventListener("mouseup", up);
|
|
2054
|
+
iframe.style.pointerEvents = "";
|
|
2055
|
+
};
|
|
2056
|
+
window.addEventListener("mousemove", move);
|
|
2057
|
+
window.addEventListener("mouseup", up);
|
|
2058
|
+
});
|
|
2004
2059
|
return {
|
|
2005
|
-
target: () => iframe.contentWindow,
|
|
2006
|
-
teardown: () =>
|
|
2060
|
+
target: () => popped && !popped.closed ? popped : iframe.contentWindow,
|
|
2061
|
+
teardown: () => {
|
|
2062
|
+
stopPoll();
|
|
2063
|
+
if (popped && !popped.closed) popped.close();
|
|
2064
|
+
host.remove();
|
|
2065
|
+
}
|
|
2007
2066
|
};
|
|
2008
2067
|
}
|
|
2009
2068
|
function clamp2(v, min, max) {
|
|
@@ -2017,47 +2076,55 @@ function buildPanelUrl(opts) {
|
|
|
2017
2076
|
if (opts.guide) url.searchParams.set("veoGuide", opts.guide);
|
|
2018
2077
|
return url.toString();
|
|
2019
2078
|
}
|
|
2020
|
-
var DEFAULT_PANEL_PATH, PANEL_W, PANEL_H, MARGIN, PANEL_CSS;
|
|
2079
|
+
var DEFAULT_PANEL_PATH, PANEL_W, PANEL_H, MIN_W, MIN_H, MARGIN, PANEL_CSS;
|
|
2021
2080
|
var init_builder_panel = __esm({
|
|
2022
2081
|
"src/plugins/builder/builder-panel.ts"() {
|
|
2023
2082
|
init_safe_env();
|
|
2024
2083
|
DEFAULT_PANEL_PATH = "/guides/design";
|
|
2025
2084
|
PANEL_W = 400;
|
|
2026
2085
|
PANEL_H = 640;
|
|
2086
|
+
MIN_W = 320;
|
|
2087
|
+
MIN_H = 320;
|
|
2027
2088
|
MARGIN = 16;
|
|
2028
2089
|
PANEL_CSS = `
|
|
2029
2090
|
:host { all: initial; }
|
|
2030
2091
|
.veo-panel {
|
|
2031
2092
|
position: fixed;
|
|
2032
|
-
width: ${
|
|
2033
|
-
min-width: 320px; min-height: 320px;
|
|
2093
|
+
min-width: ${MIN_W}px; min-height: ${MIN_H}px;
|
|
2034
2094
|
max-width: 96vw; max-height: 94vh;
|
|
2035
2095
|
display: flex; flex-direction: column;
|
|
2036
2096
|
background: #fff;
|
|
2037
2097
|
border-radius: 12px;
|
|
2038
2098
|
box-shadow: 0 12px 40px rgba(0,0,0,0.28);
|
|
2039
2099
|
overflow: hidden;
|
|
2040
|
-
resize: both;
|
|
2041
2100
|
z-index: 2147483647;
|
|
2042
2101
|
font-family: system-ui, -apple-system, sans-serif;
|
|
2043
2102
|
}
|
|
2044
|
-
.veo-panel.dragging { user-select: none; }
|
|
2045
2103
|
.veo-panel-header {
|
|
2046
2104
|
flex: 0 0 auto;
|
|
2047
2105
|
display: flex; align-items: center; justify-content: space-between;
|
|
2048
|
-
padding: 8px 12px;
|
|
2106
|
+
padding: 8px 10px 8px 12px;
|
|
2049
2107
|
background: #0f172a; color: #fff;
|
|
2050
2108
|
font-size: 13px; font-weight: 600;
|
|
2051
2109
|
cursor: grab;
|
|
2052
2110
|
}
|
|
2053
2111
|
.veo-panel-header:active { cursor: grabbing; }
|
|
2054
|
-
.veo-panel-
|
|
2112
|
+
.veo-panel-actions { display: flex; gap: 2px; }
|
|
2113
|
+
.veo-panel-btn {
|
|
2055
2114
|
border: 0; background: transparent; color: #fff;
|
|
2056
|
-
font-size:
|
|
2057
|
-
padding: 4px
|
|
2115
|
+
font-size: 14px; cursor: pointer; line-height: 1;
|
|
2116
|
+
padding: 4px 7px; border-radius: 6px;
|
|
2058
2117
|
}
|
|
2059
|
-
.veo-panel-
|
|
2118
|
+
.veo-panel-btn:hover { background: rgba(255,255,255,0.15); }
|
|
2060
2119
|
.veo-panel-frame { flex: 1 1 auto; width: 100%; border: 0; background: #fff; }
|
|
2120
|
+
.veo-panel-resize {
|
|
2121
|
+
position: absolute; right: 0; bottom: 0;
|
|
2122
|
+
width: 16px; height: 16px;
|
|
2123
|
+
cursor: nwse-resize;
|
|
2124
|
+
background:
|
|
2125
|
+
linear-gradient(135deg, transparent 50%, rgba(0,0,0,0.25) 50%, rgba(0,0,0,0.25) 60%,
|
|
2126
|
+
transparent 60%, transparent 72%, rgba(0,0,0,0.25) 72%, rgba(0,0,0,0.25) 82%, transparent 82%);
|
|
2127
|
+
}
|
|
2061
2128
|
`;
|
|
2062
2129
|
}
|
|
2063
2130
|
});
|