veo-sdk 0.5.5 → 0.5.10
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-2TBF3NZF.mjs +5 -0
- package/dist/{builder-O2QHV2DV.mjs.map → builder-2TBF3NZF.mjs.map} +1 -1
- package/dist/builder.cjs +544 -75
- package/dist/builder.cjs.map +1 -1
- package/dist/builder.d.cts +2 -2
- package/dist/builder.d.ts +2 -2
- package/dist/builder.mjs +4 -4
- package/dist/{chunk-JPA46JBS.mjs → chunk-END325ZM.mjs} +547 -78
- package/dist/chunk-END325ZM.mjs.map +1 -0
- package/dist/{chunk-GKJW5TOZ.mjs → chunk-RO5IHBTJ.mjs} +123 -3
- package/dist/chunk-RO5IHBTJ.mjs.map +1 -0
- package/dist/{chunk-XPB4DL2Y.mjs → chunk-S2CLUAAC.mjs} +3 -3
- package/dist/{chunk-XPB4DL2Y.mjs.map → chunk-S2CLUAAC.mjs.map} +1 -1
- package/dist/{guide-preview-B912Y6UY.d.cts → guide-preview-XUnTmzUO.d.cts} +22 -4
- package/dist/{guide-preview-B912Y6UY.d.ts → guide-preview-XUnTmzUO.d.ts} +22 -4
- package/dist/index.cjs +691 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +5 -5
- package/dist/veo-builder.js +39 -10
- package/dist/veo-builder.js.map +1 -1
- package/dist/veo-guides.js +34 -5
- package/dist/veo-guides.js.map +1 -1
- package/package.json +1 -1
- package/dist/builder-O2QHV2DV.mjs +0 -5
- package/dist/chunk-GKJW5TOZ.mjs.map +0 -1
- package/dist/chunk-JPA46JBS.mjs.map +0 -1
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { VEO_BLOCK_MIME, attachBlockDropTarget, attachDesignManipulator, createBuilderSession, initBuilderMode, startElementPicker, stopElementPicker } from './chunk-S2CLUAAC.mjs';
|
|
2
|
+
import './chunk-END325ZM.mjs';
|
|
3
|
+
import './chunk-PTG3BTJE.mjs';
|
|
4
|
+
//# sourceMappingURL=builder-2TBF3NZF.mjs.map
|
|
5
|
+
//# sourceMappingURL=builder-2TBF3NZF.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"builder-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"builder-2TBF3NZF.mjs"}
|
package/dist/builder.cjs
CHANGED
|
@@ -522,7 +522,8 @@ function buildButtonBlock(block, doc, callbacks) {
|
|
|
522
522
|
btn.textContent = typeof block.text === "string" && block.text ? block.text : "OK";
|
|
523
523
|
applyBlockStyle(btn, block.style, "button");
|
|
524
524
|
btn.addEventListener("click", () => {
|
|
525
|
-
const
|
|
525
|
+
const raw = block.action ?? "dismiss";
|
|
526
|
+
const action = raw === "next" || raw === "url" || raw === "guide" ? raw : "dismiss";
|
|
526
527
|
const target = action === "url" && typeof block.url === "string" && isSafeUrl(block.url) ? block.url : action === "guide" && typeof block.targetGuideId === "string" && block.targetGuideId ? block.targetGuideId : void 0;
|
|
527
528
|
const meta = {
|
|
528
529
|
...typeof block.id === "string" && block.id ? { buttonId: block.id } : {},
|
|
@@ -568,6 +569,42 @@ function applyBlockStyle(el, style, kind) {
|
|
|
568
569
|
if (typeof s.marginBottom === "number" && Number.isFinite(s.marginBottom)) {
|
|
569
570
|
el.style.marginBottom = `${clampNum(s.marginBottom, 0, 64)}px`;
|
|
570
571
|
}
|
|
572
|
+
if (kind !== "image") {
|
|
573
|
+
if (typeof s.fontSize === "number" && Number.isFinite(s.fontSize)) {
|
|
574
|
+
el.style.fontSize = `${clampNum(s.fontSize, 8, 96)}px`;
|
|
575
|
+
}
|
|
576
|
+
if (typeof s.fontFamily === "string" && s.fontFamily && s.fontFamily !== "inherit") {
|
|
577
|
+
el.style.fontFamily = s.fontFamily;
|
|
578
|
+
}
|
|
579
|
+
if (typeof s.fontWeight === "string" && s.fontWeight) el.style.fontWeight = s.fontWeight;
|
|
580
|
+
if (typeof s.textTransform === "string" && s.textTransform && s.textTransform !== "none") {
|
|
581
|
+
el.style.textTransform = s.textTransform;
|
|
582
|
+
}
|
|
583
|
+
if (typeof s.lineHeight === "number" && Number.isFinite(s.lineHeight)) {
|
|
584
|
+
el.style.lineHeight = `${clampNum(s.lineHeight, 50, 300)}%`;
|
|
585
|
+
}
|
|
586
|
+
if (typeof s.letterSpacing === "number" && Number.isFinite(s.letterSpacing)) {
|
|
587
|
+
el.style.letterSpacing = `${clampNum(s.letterSpacing, -5, 20)}px`;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
if (typeof s.background === "string" && s.background) el.style.background = s.background;
|
|
591
|
+
if (typeof s.borderWidth === "number" && s.borderWidth > 0) {
|
|
592
|
+
const bc = typeof s.borderColor === "string" && s.borderColor ? s.borderColor : "#bbbbbb";
|
|
593
|
+
el.style.border = `${clampNum(s.borderWidth, 0, 20)}px solid ${bc}`;
|
|
594
|
+
}
|
|
595
|
+
if (kind !== "image" && typeof s.radius === "number" && Number.isFinite(s.radius)) {
|
|
596
|
+
el.style.borderRadius = `${clampNum(s.radius, 0, 64)}px`;
|
|
597
|
+
}
|
|
598
|
+
for (const side of ["Top", "Right", "Bottom", "Left"]) {
|
|
599
|
+
const p = s[`padding${side}`];
|
|
600
|
+
if (typeof p === "number" && Number.isFinite(p)) {
|
|
601
|
+
el.style.setProperty(`padding-${side.toLowerCase()}`, `${clampNum(p, 0, 128)}px`);
|
|
602
|
+
}
|
|
603
|
+
const m = s[`margin${side}`];
|
|
604
|
+
if (typeof m === "number" && Number.isFinite(m)) {
|
|
605
|
+
el.style.setProperty(`margin-${side.toLowerCase()}`, `${clampNum(m, 0, 128)}px`);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
571
608
|
}
|
|
572
609
|
function createCloseButton(doc, onClose, className = "veo-guide-close") {
|
|
573
610
|
const closeBtn = doc.createElement("button");
|
|
@@ -918,6 +955,35 @@ var GUIDE_STYLES = `
|
|
|
918
955
|
animation: veo-fade-in 160ms ease-out;
|
|
919
956
|
}
|
|
920
957
|
|
|
958
|
+
/* \u2500\u2500 Modelo unificado (composite) \u2500\u2500 */
|
|
959
|
+
.veo-composite-overlay {
|
|
960
|
+
position: fixed; inset: 0;
|
|
961
|
+
z-index: ${GUIDE_Z_INDEX};
|
|
962
|
+
pointer-events: none;
|
|
963
|
+
}
|
|
964
|
+
/* Backdrop atenuado (solo centro con backdrop activo). */
|
|
965
|
+
.veo-composite-overlay--dim {
|
|
966
|
+
background: rgba(0, 0, 0, 0.5);
|
|
967
|
+
pointer-events: auto;
|
|
968
|
+
}
|
|
969
|
+
.veo-composite-anchored {
|
|
970
|
+
position: fixed;
|
|
971
|
+
z-index: ${GUIDE_Z_INDEX};
|
|
972
|
+
}
|
|
973
|
+
/* Card gen\xE9rica del modelo unificado. El dise\xF1o (bg/borde/padding/\u2026) lo aplica
|
|
974
|
+
el renderer como estilos inline desde step.design; ac\xE1 van los defaults. */
|
|
975
|
+
.veo-card {
|
|
976
|
+
pointer-events: auto;
|
|
977
|
+
background: var(--veo-bg, #ffffff);
|
|
978
|
+
color: var(--veo-text, #1f2937);
|
|
979
|
+
border-radius: var(--veo-radius, 12px);
|
|
980
|
+
padding: 20px;
|
|
981
|
+
max-width: 90vw;
|
|
982
|
+
box-shadow: var(--veo-shadow, 0 12px 40px rgba(0, 0, 0, 0.18));
|
|
983
|
+
animation: veo-fade-in 160ms ease-out;
|
|
984
|
+
}
|
|
985
|
+
.veo-composite-anchored .veo-card, .veo-composite-overlay .veo-card { position: relative; }
|
|
986
|
+
|
|
921
987
|
.veo-guide-content {
|
|
922
988
|
position: relative;
|
|
923
989
|
display: flex; flex-direction: column;
|
|
@@ -1880,85 +1946,53 @@ function escapeClosing(code, tag) {
|
|
|
1880
1946
|
return code.replace(rx, `<\\/${tag}`);
|
|
1881
1947
|
}
|
|
1882
1948
|
|
|
1883
|
-
// src/plugins/guides/
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
async render(context) {
|
|
1889
|
-
const step = context.guide.guideSteps[0];
|
|
1890
|
-
if (!step || typeof step.html !== "string" || step.html.length === 0) return;
|
|
1891
|
-
const placement = step.placement ?? DEFAULT_PLACEMENT;
|
|
1892
|
-
let anchor = null;
|
|
1893
|
-
if (placement.mode === "anchored") {
|
|
1894
|
-
const selector = placement.selector ?? step.selector ?? context.guide.activationRules.selector;
|
|
1895
|
-
if (typeof selector !== "string" || selector.length === 0) return;
|
|
1896
|
-
anchor = await waitForElement(selector);
|
|
1897
|
-
if (!anchor) return;
|
|
1898
|
-
}
|
|
1899
|
-
const { root } = this.createHost();
|
|
1900
|
-
const doc = root.ownerDocument ?? document;
|
|
1949
|
+
// src/plugins/guides/code-block.ts
|
|
1950
|
+
function mountCodeBlock(block, doc, context) {
|
|
1951
|
+
if (block.sandboxed) {
|
|
1952
|
+
const step = { html: block.html ?? "", css: block.css, js: block.js };
|
|
1953
|
+
const { iframe, cleanup } = mountCustomFrame(doc, step, context, { width: "100%" });
|
|
1901
1954
|
const wrapper = doc.createElement("div");
|
|
1902
|
-
wrapper.className =
|
|
1903
|
-
const { iframe, cleanup } = mountCustomFrame(doc, step, context, {
|
|
1904
|
-
width: toCssSize(placement.width ?? DEFAULT_WIDTH),
|
|
1905
|
-
fixedHeight: placement.height ?? null
|
|
1906
|
-
});
|
|
1907
|
-
this.registerCleanup(cleanup);
|
|
1955
|
+
wrapper.className = "veo-code-sandbox";
|
|
1908
1956
|
wrapper.appendChild(iframe);
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1957
|
+
return { node: wrapper, cleanup };
|
|
1958
|
+
}
|
|
1959
|
+
const hostDoc = doc;
|
|
1960
|
+
const injected = [];
|
|
1961
|
+
if (typeof block.css === "string" && block.css.trim()) {
|
|
1962
|
+
const style = hostDoc.createElement("style");
|
|
1963
|
+
style.textContent = block.css;
|
|
1964
|
+
hostDoc.head.appendChild(style);
|
|
1965
|
+
injected.push(style);
|
|
1966
|
+
}
|
|
1967
|
+
let node = null;
|
|
1968
|
+
if (typeof block.html === "string" && block.html.trim()) {
|
|
1969
|
+
node = doc.createElement("div");
|
|
1970
|
+
node.className = "veo-code-html";
|
|
1971
|
+
node.innerHTML = block.html;
|
|
1972
|
+
for (const old of Array.from(node.querySelectorAll("script"))) {
|
|
1973
|
+
injected.push(runScript(old, hostDoc));
|
|
1974
|
+
old.remove();
|
|
1914
1975
|
}
|
|
1915
|
-
context.onInteraction({ guideId: context.guide.guideId, stepIndex: 0, action: "shown" });
|
|
1916
|
-
}
|
|
1917
|
-
async setupAnchoredPosition(anchor, wrapper, placement) {
|
|
1918
|
-
const side = placement.side ?? "bottom";
|
|
1919
|
-
const update = async () => {
|
|
1920
|
-
const { x, y } = await dom.computePosition(anchor, wrapper, {
|
|
1921
|
-
placement: side,
|
|
1922
|
-
strategy: "fixed",
|
|
1923
|
-
middleware: [dom.offset(placement.offsetY ?? 8), dom.flip(), dom.shift({ padding: 8 })]
|
|
1924
|
-
});
|
|
1925
|
-
wrapper.style.left = `${x}px`;
|
|
1926
|
-
wrapper.style.top = `${y}px`;
|
|
1927
|
-
};
|
|
1928
|
-
await update();
|
|
1929
|
-
const reposition = () => {
|
|
1930
|
-
void update();
|
|
1931
|
-
};
|
|
1932
|
-
window.addEventListener("scroll", reposition, true);
|
|
1933
|
-
window.addEventListener("resize", reposition);
|
|
1934
|
-
return () => {
|
|
1935
|
-
window.removeEventListener("scroll", reposition, true);
|
|
1936
|
-
window.removeEventListener("resize", reposition);
|
|
1937
|
-
};
|
|
1938
|
-
}
|
|
1939
|
-
};
|
|
1940
|
-
function applyFloatingPosition(wrapper, placement) {
|
|
1941
|
-
const position = placement.position ?? "bottom-right";
|
|
1942
|
-
const ox = `${placement.offsetX ?? DEFAULT_OFFSET}px`;
|
|
1943
|
-
const oy = `${placement.offsetY ?? DEFAULT_OFFSET}px`;
|
|
1944
|
-
const s = wrapper.style;
|
|
1945
|
-
if (position === "center") {
|
|
1946
|
-
s.top = "50%";
|
|
1947
|
-
s.left = "50%";
|
|
1948
|
-
s.transform = "translate(-50%, -50%)";
|
|
1949
|
-
return;
|
|
1950
1976
|
}
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
s
|
|
1956
|
-
} else if (horizontal === "right") {
|
|
1957
|
-
s.right = ox;
|
|
1958
|
-
} else {
|
|
1959
|
-
s.left = "50%";
|
|
1960
|
-
s.transform = "translateX(-50%)";
|
|
1977
|
+
if (typeof block.js === "string" && block.js.trim()) {
|
|
1978
|
+
const s = hostDoc.createElement("script");
|
|
1979
|
+
s.textContent = block.js;
|
|
1980
|
+
hostDoc.body.appendChild(s);
|
|
1981
|
+
injected.push(s);
|
|
1961
1982
|
}
|
|
1983
|
+
return {
|
|
1984
|
+
node,
|
|
1985
|
+
cleanup: () => {
|
|
1986
|
+
for (const n of injected) n.parentNode?.removeChild(n);
|
|
1987
|
+
}
|
|
1988
|
+
};
|
|
1989
|
+
}
|
|
1990
|
+
function runScript(old, hostDoc) {
|
|
1991
|
+
const s = hostDoc.createElement("script");
|
|
1992
|
+
for (const attr of Array.from(old.attributes)) s.setAttribute(attr.name, attr.value);
|
|
1993
|
+
if (!old.src) s.textContent = old.textContent;
|
|
1994
|
+
hostDoc.body.appendChild(s);
|
|
1995
|
+
return s;
|
|
1962
1996
|
}
|
|
1963
1997
|
|
|
1964
1998
|
// src/plugins/guides/form-content.ts
|
|
@@ -2226,6 +2260,430 @@ function buildScale(wrapper, doc, min, max, btnClass, symbol) {
|
|
|
2226
2260
|
return { wrapper, read: () => selected };
|
|
2227
2261
|
}
|
|
2228
2262
|
|
|
2263
|
+
// src/plugins/guides/renderers/composite-renderer.ts
|
|
2264
|
+
var CompositeRenderer = class extends BaseRenderer {
|
|
2265
|
+
async render(context) {
|
|
2266
|
+
const idx = context.nav?.stepIndex ?? 0;
|
|
2267
|
+
const step = context.guide.guideSteps[idx];
|
|
2268
|
+
if (!step) return;
|
|
2269
|
+
const anchorSelector = step.position === "relative-to-element" || step.presentation === "inline" ? step.anchorSelector?.trim() || void 0 : void 0;
|
|
2270
|
+
let anchor = null;
|
|
2271
|
+
if (anchorSelector) {
|
|
2272
|
+
anchor = await waitForElement(anchorSelector);
|
|
2273
|
+
if (!anchor) return;
|
|
2274
|
+
}
|
|
2275
|
+
const { host, root } = this.createHost();
|
|
2276
|
+
const doc = root.ownerDocument ?? document;
|
|
2277
|
+
const design = step.design ?? {};
|
|
2278
|
+
if (typeof design.zIndex === "number") host.style.zIndex = String(design.zIndex);
|
|
2279
|
+
const card = doc.createElement("div");
|
|
2280
|
+
card.className = "veo-card";
|
|
2281
|
+
applyCompositeDesign(card, design);
|
|
2282
|
+
const dismiss = (action, meta) => {
|
|
2283
|
+
context.onInteraction({
|
|
2284
|
+
guideId: context.guide.guideId,
|
|
2285
|
+
stepIndex: idx,
|
|
2286
|
+
action,
|
|
2287
|
+
...{}
|
|
2288
|
+
});
|
|
2289
|
+
};
|
|
2290
|
+
const readers = [];
|
|
2291
|
+
this.buildContent(card, step.blocks ?? [], doc, context, idx, readers);
|
|
2292
|
+
if (design.closeButton !== false) {
|
|
2293
|
+
const closeBtn = createCloseButton(doc, () => {
|
|
2294
|
+
dismiss("dismissed");
|
|
2295
|
+
this.closeOrSkip(context);
|
|
2296
|
+
});
|
|
2297
|
+
const closeColor = typeof design.closeColor === "string" ? design.closeColor : null;
|
|
2298
|
+
const hoverColor = typeof design.closeHoverColor === "string" ? design.closeHoverColor : null;
|
|
2299
|
+
if (closeColor) closeBtn.style.color = closeColor;
|
|
2300
|
+
if (hoverColor) {
|
|
2301
|
+
closeBtn.addEventListener("mouseenter", () => {
|
|
2302
|
+
closeBtn.style.color = hoverColor;
|
|
2303
|
+
});
|
|
2304
|
+
closeBtn.addEventListener("mouseleave", () => {
|
|
2305
|
+
closeBtn.style.color = closeColor ?? "";
|
|
2306
|
+
});
|
|
2307
|
+
}
|
|
2308
|
+
card.appendChild(closeBtn);
|
|
2309
|
+
}
|
|
2310
|
+
if (step.presentation === "inline" && anchor) {
|
|
2311
|
+
host.style.display = "block";
|
|
2312
|
+
const pos = inlinePosOf(step.inlinePosition);
|
|
2313
|
+
root.appendChild(card);
|
|
2314
|
+
insertHost(anchor, host, pos);
|
|
2315
|
+
this.registerCleanup(keepHostAttached(host, anchorSelector, pos));
|
|
2316
|
+
} else if (step.position === "relative-to-element" && anchor) {
|
|
2317
|
+
if (design.backdrop === true) {
|
|
2318
|
+
const bg = doc.createElement("div");
|
|
2319
|
+
bg.className = "veo-composite-overlay veo-composite-overlay--dim";
|
|
2320
|
+
if (typeof design.backdropColor === "string") bg.style.background = design.backdropColor;
|
|
2321
|
+
const bz = typeof design.backdropZIndex === "number" ? design.backdropZIndex : 2e5;
|
|
2322
|
+
bg.style.zIndex = String(bz);
|
|
2323
|
+
root.appendChild(bg);
|
|
2324
|
+
if (design.targetAbove === true) this.registerCleanup(liftTarget(anchor, bz + 1));
|
|
2325
|
+
}
|
|
2326
|
+
const wrapper = doc.createElement("div");
|
|
2327
|
+
wrapper.className = "veo-composite-anchored";
|
|
2328
|
+
const caretEl = design.caret === false ? null : makeCaret(doc, design);
|
|
2329
|
+
if (caretEl) wrapper.appendChild(caretEl);
|
|
2330
|
+
wrapper.appendChild(card);
|
|
2331
|
+
root.appendChild(wrapper);
|
|
2332
|
+
this.registerCleanup(await anchorPosition(anchor, wrapper, caretEl));
|
|
2333
|
+
} else {
|
|
2334
|
+
const overlay = doc.createElement("div");
|
|
2335
|
+
overlay.className = "veo-composite-overlay";
|
|
2336
|
+
if (step.position === "center" && design.backdrop !== false) {
|
|
2337
|
+
overlay.classList.add("veo-composite-overlay--dim");
|
|
2338
|
+
if (typeof design.backdropColor === "string") {
|
|
2339
|
+
overlay.style.background = design.backdropColor;
|
|
2340
|
+
}
|
|
2341
|
+
if (typeof design.backdropZIndex === "number") {
|
|
2342
|
+
overlay.style.zIndex = String(design.backdropZIndex);
|
|
2343
|
+
}
|
|
2344
|
+
overlay.addEventListener("click", (e) => {
|
|
2345
|
+
if (e.target === overlay) {
|
|
2346
|
+
dismiss("dismissed");
|
|
2347
|
+
this.closeOrSkip(context);
|
|
2348
|
+
}
|
|
2349
|
+
});
|
|
2350
|
+
}
|
|
2351
|
+
applyViewportPosition(card, step.position, design);
|
|
2352
|
+
overlay.appendChild(card);
|
|
2353
|
+
root.appendChild(overlay);
|
|
2354
|
+
}
|
|
2355
|
+
context.onInteraction({ guideId: context.guide.guideId, stepIndex: idx, action: "shown" });
|
|
2356
|
+
}
|
|
2357
|
+
/** Recorre los bloques en orden y los pinta en la card. */
|
|
2358
|
+
buildContent(card, blocks, doc, context, idx, readers) {
|
|
2359
|
+
const emit = (block) => {
|
|
2360
|
+
context.onInteraction({
|
|
2361
|
+
guideId: context.guide.guideId,
|
|
2362
|
+
stepIndex: idx,
|
|
2363
|
+
action: "cta_clicked",
|
|
2364
|
+
...block.id ? { metadata: { buttonId: block.id } } : {}
|
|
2365
|
+
});
|
|
2366
|
+
};
|
|
2367
|
+
let i = 0;
|
|
2368
|
+
while (i < blocks.length) {
|
|
2369
|
+
const b = blocks[i];
|
|
2370
|
+
if (!b) {
|
|
2371
|
+
i++;
|
|
2372
|
+
continue;
|
|
2373
|
+
}
|
|
2374
|
+
if (b.type === "button") {
|
|
2375
|
+
const row = doc.createElement("div");
|
|
2376
|
+
row.className = "veo-guide-actions";
|
|
2377
|
+
while (i < blocks.length && blocks[i]?.type === "button") {
|
|
2378
|
+
row.appendChild(
|
|
2379
|
+
this.buildButton(blocks[i], doc, context, idx, readers, emit)
|
|
2380
|
+
);
|
|
2381
|
+
i++;
|
|
2382
|
+
}
|
|
2383
|
+
card.appendChild(row);
|
|
2384
|
+
continue;
|
|
2385
|
+
}
|
|
2386
|
+
if (b.type === "code") {
|
|
2387
|
+
const { node: node2, cleanup } = mountCodeBlock(b, doc, context);
|
|
2388
|
+
if (node2) card.appendChild(node2);
|
|
2389
|
+
this.registerCleanup(cleanup);
|
|
2390
|
+
i++;
|
|
2391
|
+
continue;
|
|
2392
|
+
}
|
|
2393
|
+
if (b.type === "form") {
|
|
2394
|
+
const form = doc.createElement("div");
|
|
2395
|
+
form.className = "veo-form";
|
|
2396
|
+
for (const field of b.fields ?? []) {
|
|
2397
|
+
const { wrapper, read } = buildField(field, doc);
|
|
2398
|
+
readers.push({ field, read });
|
|
2399
|
+
form.appendChild(wrapper);
|
|
2400
|
+
}
|
|
2401
|
+
card.appendChild(form);
|
|
2402
|
+
i++;
|
|
2403
|
+
continue;
|
|
2404
|
+
}
|
|
2405
|
+
const node = buildContentBlock(b, doc);
|
|
2406
|
+
if (node) card.appendChild(node);
|
|
2407
|
+
i++;
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
/** Botón con enrutado de acción (navegación / cierre / url / guía / envío de forms). */
|
|
2411
|
+
buildButton(block, doc, context, idx, readers, emit) {
|
|
2412
|
+
const btn = doc.createElement("button");
|
|
2413
|
+
btn.type = "button";
|
|
2414
|
+
btn.className = "veo-guide-cta";
|
|
2415
|
+
btn.textContent = block.text?.trim() || "OK";
|
|
2416
|
+
const nav = context.nav?.callbacks;
|
|
2417
|
+
btn.addEventListener("click", () => {
|
|
2418
|
+
switch (block.action) {
|
|
2419
|
+
case "next":
|
|
2420
|
+
emit(block);
|
|
2421
|
+
if (nav) nav.onNext();
|
|
2422
|
+
else context.onClose();
|
|
2423
|
+
break;
|
|
2424
|
+
case "prev":
|
|
2425
|
+
emit(block);
|
|
2426
|
+
nav?.onBack();
|
|
2427
|
+
break;
|
|
2428
|
+
case "url":
|
|
2429
|
+
emit(block);
|
|
2430
|
+
if (typeof block.url === "string" && isSafeUrl(block.url)) {
|
|
2431
|
+
window.open(block.url, "_blank", "noopener,noreferrer");
|
|
2432
|
+
}
|
|
2433
|
+
break;
|
|
2434
|
+
case "guide":
|
|
2435
|
+
emit(block);
|
|
2436
|
+
if (block.targetGuideId) context.onOpenGuide?.(block.targetGuideId);
|
|
2437
|
+
this.closeOrSkip(context);
|
|
2438
|
+
break;
|
|
2439
|
+
case "submit-forms":
|
|
2440
|
+
case "submit-forms-advance":
|
|
2441
|
+
case "submit-forms-goto":
|
|
2442
|
+
this.submitForms(readers, context, idx, btn, () => {
|
|
2443
|
+
emit(block);
|
|
2444
|
+
if (block.action === "submit-forms" || !nav) {
|
|
2445
|
+
context.onClose();
|
|
2446
|
+
} else if (block.action === "submit-forms-goto" && typeof block.targetStep === "number" && nav.onGoto) {
|
|
2447
|
+
nav.onGoto(block.targetStep);
|
|
2448
|
+
} else {
|
|
2449
|
+
nav.onNext();
|
|
2450
|
+
}
|
|
2451
|
+
});
|
|
2452
|
+
break;
|
|
2453
|
+
default:
|
|
2454
|
+
emit(block);
|
|
2455
|
+
this.closeOrSkip(context);
|
|
2456
|
+
}
|
|
2457
|
+
});
|
|
2458
|
+
return btn;
|
|
2459
|
+
}
|
|
2460
|
+
/** Recoge respuestas de todos los form-blocks del paso, valida y envía. */
|
|
2461
|
+
submitForms(readers, context, idx, btn, onDone) {
|
|
2462
|
+
const answers = {};
|
|
2463
|
+
for (const { field, read } of readers) {
|
|
2464
|
+
const value = read();
|
|
2465
|
+
const empty = value === void 0 || value === null || value === "";
|
|
2466
|
+
if (empty) {
|
|
2467
|
+
if (field.required) {
|
|
2468
|
+
btn.textContent = `Completa "${field.label}"`;
|
|
2469
|
+
return;
|
|
2470
|
+
}
|
|
2471
|
+
continue;
|
|
2472
|
+
}
|
|
2473
|
+
answers[field.key] = value;
|
|
2474
|
+
}
|
|
2475
|
+
if (readers.length > 0 && Object.keys(answers).length === 0) return;
|
|
2476
|
+
btn.disabled = true;
|
|
2477
|
+
const submitFn = context.onFormSubmit ?? (() => Promise.resolve(true));
|
|
2478
|
+
void submitFn(answers).then((ok) => {
|
|
2479
|
+
btn.disabled = false;
|
|
2480
|
+
if (!ok) return;
|
|
2481
|
+
context.onInteraction({
|
|
2482
|
+
guideId: context.guide.guideId,
|
|
2483
|
+
stepIndex: idx,
|
|
2484
|
+
action: "completed"
|
|
2485
|
+
});
|
|
2486
|
+
onDone();
|
|
2487
|
+
});
|
|
2488
|
+
}
|
|
2489
|
+
closeOrSkip(context) {
|
|
2490
|
+
if (context.nav?.callbacks) context.nav.callbacks.onSkip();
|
|
2491
|
+
else context.onClose();
|
|
2492
|
+
}
|
|
2493
|
+
};
|
|
2494
|
+
function inlinePosOf(p) {
|
|
2495
|
+
return p === "before" || p === "prepend" || p === "append" ? p : "after";
|
|
2496
|
+
}
|
|
2497
|
+
function applyViewportPosition(card, position, design) {
|
|
2498
|
+
const s = card.style;
|
|
2499
|
+
s.position = "fixed";
|
|
2500
|
+
const M = "16px";
|
|
2501
|
+
const hAlign = design.hAlign === "left" ? "left" : design.hAlign === "right" ? "right" : null;
|
|
2502
|
+
const v = position.includes("top") ? "top" : position.includes("bottom") ? "bottom" : "middle";
|
|
2503
|
+
const h = hAlign ?? (position.includes("left") ? "left" : position.includes("right") ? "right" : "middle");
|
|
2504
|
+
if (v === "top") s.top = M;
|
|
2505
|
+
else if (v === "bottom") s.bottom = M;
|
|
2506
|
+
else s.top = "50%";
|
|
2507
|
+
if (h === "left") s.left = M;
|
|
2508
|
+
else if (h === "right") s.right = M;
|
|
2509
|
+
else s.left = "50%";
|
|
2510
|
+
const tx = h === "middle" ? "-50%" : "0";
|
|
2511
|
+
const ty = v === "middle" ? "-50%" : "0";
|
|
2512
|
+
s.transform = tx === "0" && ty === "0" ? "" : `translate(${tx}, ${ty})`;
|
|
2513
|
+
}
|
|
2514
|
+
function makeCaret(doc, design) {
|
|
2515
|
+
const caret = doc.createElement("div");
|
|
2516
|
+
caret.className = "veo-composite-caret";
|
|
2517
|
+
const w = typeof design.caretWidth === "number" ? design.caretWidth : 12;
|
|
2518
|
+
const h = typeof design.caretHeight === "number" ? design.caretHeight : 12;
|
|
2519
|
+
const s = caret.style;
|
|
2520
|
+
s.position = "absolute";
|
|
2521
|
+
s.width = `${w}px`;
|
|
2522
|
+
s.height = `${h}px`;
|
|
2523
|
+
s.transform = "rotate(45deg)";
|
|
2524
|
+
s.background = typeof design.background === "string" ? design.background : "#ffffff";
|
|
2525
|
+
if (typeof design.borderWidth === "number" && design.borderWidth > 0) {
|
|
2526
|
+
const bc = typeof design.borderColor === "string" ? design.borderColor : "#bbbbbb";
|
|
2527
|
+
s.border = `${design.borderWidth}px solid ${bc}`;
|
|
2528
|
+
}
|
|
2529
|
+
return caret;
|
|
2530
|
+
}
|
|
2531
|
+
function liftTarget(anchor, zIndex) {
|
|
2532
|
+
const el = anchor;
|
|
2533
|
+
const prevPosition = el.style.position;
|
|
2534
|
+
const prevZ = el.style.zIndex;
|
|
2535
|
+
if (getComputedStyle(el).position === "static") el.style.position = "relative";
|
|
2536
|
+
el.style.zIndex = String(zIndex);
|
|
2537
|
+
return () => {
|
|
2538
|
+
el.style.position = prevPosition;
|
|
2539
|
+
el.style.zIndex = prevZ;
|
|
2540
|
+
};
|
|
2541
|
+
}
|
|
2542
|
+
async function anchorPosition(anchor, wrapper, caret) {
|
|
2543
|
+
const update = async () => {
|
|
2544
|
+
const { x, y, placement, middlewareData } = await dom.computePosition(anchor, wrapper, {
|
|
2545
|
+
placement: "bottom",
|
|
2546
|
+
strategy: "fixed",
|
|
2547
|
+
middleware: [
|
|
2548
|
+
dom.offset(caret ? 10 : 8),
|
|
2549
|
+
dom.flip(),
|
|
2550
|
+
dom.shift({ padding: 8 }),
|
|
2551
|
+
...caret ? [dom.arrow({ element: caret })] : []
|
|
2552
|
+
]
|
|
2553
|
+
});
|
|
2554
|
+
wrapper.style.left = `${x}px`;
|
|
2555
|
+
wrapper.style.top = `${y}px`;
|
|
2556
|
+
if (caret) positionArrow(caret, placement, middlewareData.arrow);
|
|
2557
|
+
};
|
|
2558
|
+
await update();
|
|
2559
|
+
const reposition = () => void update();
|
|
2560
|
+
window.addEventListener("scroll", reposition, true);
|
|
2561
|
+
window.addEventListener("resize", reposition);
|
|
2562
|
+
return () => {
|
|
2563
|
+
window.removeEventListener("scroll", reposition, true);
|
|
2564
|
+
window.removeEventListener("resize", reposition);
|
|
2565
|
+
};
|
|
2566
|
+
}
|
|
2567
|
+
function applyCompositeDesign(card, design) {
|
|
2568
|
+
const s = card.style;
|
|
2569
|
+
const px = (v) => typeof v === "number" && Number.isFinite(v) ? `${v}px` : null;
|
|
2570
|
+
const strv = (v) => typeof v === "string" && v ? v : null;
|
|
2571
|
+
if (strv(design.background)) s.background = design.background;
|
|
2572
|
+
const textColor = strv(design.color) ?? strv(design.textColor);
|
|
2573
|
+
if (textColor) s.color = textColor;
|
|
2574
|
+
if (px(design.fontSize)) s.fontSize = px(design.fontSize);
|
|
2575
|
+
if (strv(design.fontWeight)) s.fontWeight = design.fontWeight;
|
|
2576
|
+
if (strv(design.fontFamily) && design.fontFamily !== "inherit") {
|
|
2577
|
+
s.fontFamily = design.fontFamily;
|
|
2578
|
+
}
|
|
2579
|
+
if (strv(design.textTransform) && design.textTransform !== "none") {
|
|
2580
|
+
s.textTransform = design.textTransform;
|
|
2581
|
+
}
|
|
2582
|
+
if (typeof design.letterSpacing === "number") s.letterSpacing = `${design.letterSpacing}px`;
|
|
2583
|
+
if (strv(design.align)) s.textAlign = design.align;
|
|
2584
|
+
if (typeof design.lineHeight === "number") s.lineHeight = `${design.lineHeight}%`;
|
|
2585
|
+
if (px(design.radius)) s.borderRadius = px(design.radius);
|
|
2586
|
+
const bw = px(design.borderWidth);
|
|
2587
|
+
if (bw) s.border = `${bw} solid ${strv(design.borderColor) ?? "#e5e5e5"}`;
|
|
2588
|
+
if (strv(design.shadowColor) || typeof design.shadowBlur === "number") {
|
|
2589
|
+
const n = (k) => typeof design[k] === "number" ? design[k] : 0;
|
|
2590
|
+
s.boxShadow = `${n("shadowX")}px ${n("shadowY")}px ${n("shadowBlur")}px ${n("shadowSpread")}px ${strv(design.shadowColor) ?? "rgba(0,0,0,0.2)"}`;
|
|
2591
|
+
}
|
|
2592
|
+
if (design.fullWidth === true) {
|
|
2593
|
+
s.width = "100%";
|
|
2594
|
+
} else if (design.widthType === "fluid") {
|
|
2595
|
+
s.width = "auto";
|
|
2596
|
+
if (px(design.width)) s.maxWidth = px(design.width);
|
|
2597
|
+
} else if (px(design.width)) {
|
|
2598
|
+
s.width = px(design.width);
|
|
2599
|
+
}
|
|
2600
|
+
for (const side of ["Top", "Right", "Bottom", "Left"]) {
|
|
2601
|
+
const p = px(design[`padding${side}`]);
|
|
2602
|
+
if (p) s.setProperty(`padding-${side.toLowerCase()}`, p);
|
|
2603
|
+
const m = px(design[`margin${side}`]);
|
|
2604
|
+
if (m) s.setProperty(`margin-${side.toLowerCase()}`, m);
|
|
2605
|
+
}
|
|
2606
|
+
}
|
|
2607
|
+
var DEFAULT_PLACEMENT = { mode: "floating", position: "bottom-right" };
|
|
2608
|
+
var DEFAULT_OFFSET = 16;
|
|
2609
|
+
var DEFAULT_WIDTH = 360;
|
|
2610
|
+
var CustomRenderer = class extends BaseRenderer {
|
|
2611
|
+
async render(context) {
|
|
2612
|
+
const step = context.guide.guideSteps[0];
|
|
2613
|
+
if (!step || typeof step.html !== "string" || step.html.length === 0) return;
|
|
2614
|
+
const placement = step.placement ?? DEFAULT_PLACEMENT;
|
|
2615
|
+
let anchor = null;
|
|
2616
|
+
if (placement.mode === "anchored") {
|
|
2617
|
+
const selector = placement.selector ?? step.selector ?? context.guide.activationRules.selector;
|
|
2618
|
+
if (typeof selector !== "string" || selector.length === 0) return;
|
|
2619
|
+
anchor = await waitForElement(selector);
|
|
2620
|
+
if (!anchor) return;
|
|
2621
|
+
}
|
|
2622
|
+
const { root } = this.createHost();
|
|
2623
|
+
const doc = root.ownerDocument ?? document;
|
|
2624
|
+
const wrapper = doc.createElement("div");
|
|
2625
|
+
wrapper.className = placement.mode === "anchored" ? "veo-custom-anchored" : "veo-custom-floating";
|
|
2626
|
+
const { iframe, cleanup } = mountCustomFrame(doc, step, context, {
|
|
2627
|
+
width: toCssSize(placement.width ?? DEFAULT_WIDTH),
|
|
2628
|
+
fixedHeight: placement.height ?? null
|
|
2629
|
+
});
|
|
2630
|
+
this.registerCleanup(cleanup);
|
|
2631
|
+
wrapper.appendChild(iframe);
|
|
2632
|
+
root.appendChild(wrapper);
|
|
2633
|
+
if (placement.mode === "floating") {
|
|
2634
|
+
applyFloatingPosition(wrapper, placement);
|
|
2635
|
+
} else if (anchor) {
|
|
2636
|
+
this.registerCleanup(await this.setupAnchoredPosition(anchor, wrapper, placement));
|
|
2637
|
+
}
|
|
2638
|
+
context.onInteraction({ guideId: context.guide.guideId, stepIndex: 0, action: "shown" });
|
|
2639
|
+
}
|
|
2640
|
+
async setupAnchoredPosition(anchor, wrapper, placement) {
|
|
2641
|
+
const side = placement.side ?? "bottom";
|
|
2642
|
+
const update = async () => {
|
|
2643
|
+
const { x, y } = await dom.computePosition(anchor, wrapper, {
|
|
2644
|
+
placement: side,
|
|
2645
|
+
strategy: "fixed",
|
|
2646
|
+
middleware: [dom.offset(placement.offsetY ?? 8), dom.flip(), dom.shift({ padding: 8 })]
|
|
2647
|
+
});
|
|
2648
|
+
wrapper.style.left = `${x}px`;
|
|
2649
|
+
wrapper.style.top = `${y}px`;
|
|
2650
|
+
};
|
|
2651
|
+
await update();
|
|
2652
|
+
const reposition = () => {
|
|
2653
|
+
void update();
|
|
2654
|
+
};
|
|
2655
|
+
window.addEventListener("scroll", reposition, true);
|
|
2656
|
+
window.addEventListener("resize", reposition);
|
|
2657
|
+
return () => {
|
|
2658
|
+
window.removeEventListener("scroll", reposition, true);
|
|
2659
|
+
window.removeEventListener("resize", reposition);
|
|
2660
|
+
};
|
|
2661
|
+
}
|
|
2662
|
+
};
|
|
2663
|
+
function applyFloatingPosition(wrapper, placement) {
|
|
2664
|
+
const position = placement.position ?? "bottom-right";
|
|
2665
|
+
const ox = `${placement.offsetX ?? DEFAULT_OFFSET}px`;
|
|
2666
|
+
const oy = `${placement.offsetY ?? DEFAULT_OFFSET}px`;
|
|
2667
|
+
const s = wrapper.style;
|
|
2668
|
+
if (position === "center") {
|
|
2669
|
+
s.top = "50%";
|
|
2670
|
+
s.left = "50%";
|
|
2671
|
+
s.transform = "translate(-50%, -50%)";
|
|
2672
|
+
return;
|
|
2673
|
+
}
|
|
2674
|
+
const [vertical, horizontal] = position.split("-");
|
|
2675
|
+
if (vertical === "top") s.top = oy;
|
|
2676
|
+
else s.bottom = oy;
|
|
2677
|
+
if (horizontal === "left") {
|
|
2678
|
+
s.left = ox;
|
|
2679
|
+
} else if (horizontal === "right") {
|
|
2680
|
+
s.right = ox;
|
|
2681
|
+
} else {
|
|
2682
|
+
s.left = "50%";
|
|
2683
|
+
s.transform = "translateX(-50%)";
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
|
|
2229
2687
|
// src/plugins/guides/renderers/form-renderer.ts
|
|
2230
2688
|
var FormRenderer = class extends BaseRenderer {
|
|
2231
2689
|
render(context) {
|
|
@@ -2606,6 +3064,13 @@ var GuidePreviewController = class {
|
|
|
2606
3064
|
this.input = input;
|
|
2607
3065
|
const guide = normalize(input);
|
|
2608
3066
|
const start = typeof input.startStepIndex === "number" ? input.startStepIndex : 0;
|
|
3067
|
+
if (guide.guideType === "composite") {
|
|
3068
|
+
const s = Math.min(Math.max(0, start), guide.guideSteps.length - 1);
|
|
3069
|
+
const active = guide.guideSteps[s];
|
|
3070
|
+
if (active) guide.guideSteps = [active];
|
|
3071
|
+
const ready2 = this.renderSingleStep(guide);
|
|
3072
|
+
return { close: () => this.close(), ready: ready2, host: () => this.activeHost() };
|
|
3073
|
+
}
|
|
2609
3074
|
const ready = guide.guideType === "walkthrough" ? this.startWalkthrough(guide, start) : this.renderSingleStep(guide);
|
|
2610
3075
|
return { close: () => this.close(), ready, host: () => this.activeHost() };
|
|
2611
3076
|
}
|
|
@@ -2785,8 +3250,12 @@ function createSingleStepRenderer(type) {
|
|
|
2785
3250
|
return new InlineFormRenderer();
|
|
2786
3251
|
case "badge":
|
|
2787
3252
|
return new BadgeRenderer();
|
|
3253
|
+
case "composite":
|
|
3254
|
+
return new CompositeRenderer();
|
|
2788
3255
|
case "walkthrough":
|
|
2789
3256
|
return null;
|
|
3257
|
+
default:
|
|
3258
|
+
return null;
|
|
2790
3259
|
}
|
|
2791
3260
|
}
|
|
2792
3261
|
function safeDestroy(renderer) {
|