veo-sdk 0.5.6 → 0.5.11
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-324AW5Z7.mjs +5 -0
- package/dist/{builder-AMCPHL4K.mjs.map → builder-324AW5Z7.mjs.map} +1 -1
- package/dist/builder.cjs +534 -250
- package/dist/builder.cjs.map +1 -1
- package/dist/builder.mjs +4 -4
- package/dist/{chunk-A4RHMCCM.mjs → chunk-JXRYBP77.mjs} +3 -3
- package/dist/{chunk-A4RHMCCM.mjs.map → chunk-JXRYBP77.mjs.map} +1 -1
- package/dist/{chunk-CPSHNLZG.mjs → chunk-OTZH2CV2.mjs} +119 -3
- package/dist/chunk-OTZH2CV2.mjs.map +1 -0
- package/dist/{chunk-764FSEHS.mjs → chunk-Z5EBMOZJ.mjs} +536 -252
- package/dist/chunk-Z5EBMOZJ.mjs.map +1 -0
- package/dist/index.cjs +758 -349
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +5 -5
- package/dist/veo-builder.js +10 -10
- package/dist/veo-builder.js.map +1 -1
- package/dist/veo-guides.js +5 -5
- package/dist/veo-guides.js.map +1 -1
- package/package.json +1 -1
- package/dist/builder-AMCPHL4K.mjs +0 -5
- package/dist/chunk-764FSEHS.mjs.map +0 -1
- package/dist/chunk-CPSHNLZG.mjs.map +0 -1
package/dist/builder.cjs
CHANGED
|
@@ -569,6 +569,42 @@ function applyBlockStyle(el, style, kind) {
|
|
|
569
569
|
if (typeof s.marginBottom === "number" && Number.isFinite(s.marginBottom)) {
|
|
570
570
|
el.style.marginBottom = `${clampNum(s.marginBottom, 0, 64)}px`;
|
|
571
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
|
+
}
|
|
572
608
|
}
|
|
573
609
|
function createCloseButton(doc, onClose, className = "veo-guide-close") {
|
|
574
610
|
const closeBtn = doc.createElement("button");
|
|
@@ -1754,182 +1790,6 @@ var BannerRenderer = class extends BaseRenderer {
|
|
|
1754
1790
|
function bannerClassOf(position, embedded) {
|
|
1755
1791
|
return embedded ? "veo-banner veo-banner-embedded" : `veo-banner veo-banner-${position}`;
|
|
1756
1792
|
}
|
|
1757
|
-
var CompositeRenderer = class extends BaseRenderer {
|
|
1758
|
-
async render(context) {
|
|
1759
|
-
const idx = context.nav?.stepIndex ?? 0;
|
|
1760
|
-
const step = context.guide.guideSteps[idx];
|
|
1761
|
-
if (!step) return;
|
|
1762
|
-
const anchorSelector = step.position === "relative-to-element" || step.presentation === "inline" ? step.anchorSelector?.trim() || void 0 : void 0;
|
|
1763
|
-
let anchor = null;
|
|
1764
|
-
if (anchorSelector) {
|
|
1765
|
-
anchor = await waitForElement(anchorSelector);
|
|
1766
|
-
if (!anchor) return;
|
|
1767
|
-
}
|
|
1768
|
-
const { host, root } = this.createHost();
|
|
1769
|
-
const doc = root.ownerDocument ?? document;
|
|
1770
|
-
const card = doc.createElement("div");
|
|
1771
|
-
card.className = "veo-card";
|
|
1772
|
-
applyCompositeDesign(card, step.design ?? {});
|
|
1773
|
-
const dismiss = (action, meta) => {
|
|
1774
|
-
context.onInteraction({
|
|
1775
|
-
guideId: context.guide.guideId,
|
|
1776
|
-
stepIndex: idx,
|
|
1777
|
-
action,
|
|
1778
|
-
...meta?.id ? { metadata: { buttonId: meta.id } } : {}
|
|
1779
|
-
});
|
|
1780
|
-
};
|
|
1781
|
-
const synthetic = { blocks: step.blocks ?? [] };
|
|
1782
|
-
for (const node of buildContentNodes(synthetic, doc)) card.appendChild(node);
|
|
1783
|
-
const buttons = (step.blocks ?? []).filter((b) => b.type === "button");
|
|
1784
|
-
if (buttons.length) {
|
|
1785
|
-
const row = doc.createElement("div");
|
|
1786
|
-
row.className = "veo-guide-actions";
|
|
1787
|
-
for (const b of buttons) row.appendChild(this.buildButton(b, doc, context, dismiss));
|
|
1788
|
-
card.appendChild(row);
|
|
1789
|
-
}
|
|
1790
|
-
card.appendChild(
|
|
1791
|
-
createCloseButton(doc, () => {
|
|
1792
|
-
dismiss("dismissed");
|
|
1793
|
-
this.closeOrSkip(context);
|
|
1794
|
-
})
|
|
1795
|
-
);
|
|
1796
|
-
if (step.presentation === "inline" && anchor) {
|
|
1797
|
-
host.style.display = "block";
|
|
1798
|
-
const pos = inlinePosOf(step.inlinePosition);
|
|
1799
|
-
root.appendChild(card);
|
|
1800
|
-
insertHost(anchor, host, pos);
|
|
1801
|
-
this.registerCleanup(keepHostAttached(host, anchorSelector, pos));
|
|
1802
|
-
} else if (step.position === "relative-to-element" && anchor) {
|
|
1803
|
-
const wrapper = doc.createElement("div");
|
|
1804
|
-
wrapper.className = "veo-composite-anchored";
|
|
1805
|
-
wrapper.appendChild(card);
|
|
1806
|
-
root.appendChild(wrapper);
|
|
1807
|
-
this.registerCleanup(await anchorPosition(anchor, wrapper));
|
|
1808
|
-
} else {
|
|
1809
|
-
const overlay = doc.createElement("div");
|
|
1810
|
-
overlay.className = "veo-composite-overlay";
|
|
1811
|
-
if (step.position === "center" && step.design?.backdrop !== false) {
|
|
1812
|
-
overlay.classList.add("veo-composite-overlay--dim");
|
|
1813
|
-
overlay.addEventListener("click", (e) => {
|
|
1814
|
-
if (e.target === overlay) {
|
|
1815
|
-
dismiss("dismissed");
|
|
1816
|
-
this.closeOrSkip(context);
|
|
1817
|
-
}
|
|
1818
|
-
});
|
|
1819
|
-
}
|
|
1820
|
-
applyViewportPosition(card, step.position);
|
|
1821
|
-
overlay.appendChild(card);
|
|
1822
|
-
root.appendChild(overlay);
|
|
1823
|
-
}
|
|
1824
|
-
context.onInteraction({ guideId: context.guide.guideId, stepIndex: idx, action: "shown" });
|
|
1825
|
-
}
|
|
1826
|
-
/** Botón con enrutado de acción (navegación / cierre / url / guía). */
|
|
1827
|
-
buildButton(block, doc, context, emit) {
|
|
1828
|
-
const btn = doc.createElement("button");
|
|
1829
|
-
btn.type = "button";
|
|
1830
|
-
btn.className = "veo-guide-cta";
|
|
1831
|
-
btn.textContent = block.text?.trim() || "OK";
|
|
1832
|
-
btn.addEventListener("click", () => {
|
|
1833
|
-
emit("cta_clicked", block);
|
|
1834
|
-
const nav = context.nav?.callbacks;
|
|
1835
|
-
switch (block.action) {
|
|
1836
|
-
case "next":
|
|
1837
|
-
case "submit-forms":
|
|
1838
|
-
case "submit-forms-advance":
|
|
1839
|
-
if (nav) nav.onNext();
|
|
1840
|
-
else context.onClose();
|
|
1841
|
-
break;
|
|
1842
|
-
case "prev":
|
|
1843
|
-
nav?.onBack();
|
|
1844
|
-
break;
|
|
1845
|
-
case "url":
|
|
1846
|
-
if (typeof block.url === "string" && isSafeUrl(block.url)) {
|
|
1847
|
-
window.open(block.url, "_blank", "noopener,noreferrer");
|
|
1848
|
-
}
|
|
1849
|
-
break;
|
|
1850
|
-
case "guide":
|
|
1851
|
-
if (block.targetGuideId) context.onOpenGuide?.(block.targetGuideId);
|
|
1852
|
-
this.closeOrSkip(context);
|
|
1853
|
-
break;
|
|
1854
|
-
default:
|
|
1855
|
-
this.closeOrSkip(context);
|
|
1856
|
-
}
|
|
1857
|
-
});
|
|
1858
|
-
return btn;
|
|
1859
|
-
}
|
|
1860
|
-
closeOrSkip(context) {
|
|
1861
|
-
if (context.nav?.callbacks) context.nav.callbacks.onSkip();
|
|
1862
|
-
else context.onClose();
|
|
1863
|
-
}
|
|
1864
|
-
};
|
|
1865
|
-
function inlinePosOf(p) {
|
|
1866
|
-
return p === "before" || p === "prepend" || p === "append" ? p : "after";
|
|
1867
|
-
}
|
|
1868
|
-
function applyViewportPosition(card, position) {
|
|
1869
|
-
const s = card.style;
|
|
1870
|
-
s.position = "fixed";
|
|
1871
|
-
const M = "16px";
|
|
1872
|
-
const v = position.includes("top") ? "top" : position.includes("bottom") ? "bottom" : "middle";
|
|
1873
|
-
const h = position.includes("left") ? "left" : position.includes("right") ? "right" : "middle";
|
|
1874
|
-
if (position === "center") {
|
|
1875
|
-
s.top = "50%";
|
|
1876
|
-
s.left = "50%";
|
|
1877
|
-
s.transform = "translate(-50%, -50%)";
|
|
1878
|
-
return;
|
|
1879
|
-
}
|
|
1880
|
-
if (v === "top") s.top = M;
|
|
1881
|
-
else if (v === "bottom") s.bottom = M;
|
|
1882
|
-
else {
|
|
1883
|
-
s.top = "50%";
|
|
1884
|
-
s.transform = "translateY(-50%)";
|
|
1885
|
-
}
|
|
1886
|
-
if (h === "left") s.left = M;
|
|
1887
|
-
else if (h === "right") s.right = M;
|
|
1888
|
-
else {
|
|
1889
|
-
s.left = "50%";
|
|
1890
|
-
s.transform = `${s.transform} translateX(-50%)`.trim();
|
|
1891
|
-
}
|
|
1892
|
-
}
|
|
1893
|
-
async function anchorPosition(anchor, wrapper) {
|
|
1894
|
-
const update = async () => {
|
|
1895
|
-
const { x, y } = await dom.computePosition(anchor, wrapper, {
|
|
1896
|
-
placement: "bottom",
|
|
1897
|
-
strategy: "fixed",
|
|
1898
|
-
middleware: [dom.offset(8), dom.flip(), dom.shift({ padding: 8 })]
|
|
1899
|
-
});
|
|
1900
|
-
wrapper.style.left = `${x}px`;
|
|
1901
|
-
wrapper.style.top = `${y}px`;
|
|
1902
|
-
};
|
|
1903
|
-
await update();
|
|
1904
|
-
const reposition = () => void update();
|
|
1905
|
-
window.addEventListener("scroll", reposition, true);
|
|
1906
|
-
window.addEventListener("resize", reposition);
|
|
1907
|
-
return () => {
|
|
1908
|
-
window.removeEventListener("scroll", reposition, true);
|
|
1909
|
-
window.removeEventListener("resize", reposition);
|
|
1910
|
-
};
|
|
1911
|
-
}
|
|
1912
|
-
function applyCompositeDesign(card, design) {
|
|
1913
|
-
const s = card.style;
|
|
1914
|
-
const px = (v) => typeof v === "number" && Number.isFinite(v) ? `${v}px` : null;
|
|
1915
|
-
const strv = (v) => typeof v === "string" && v ? v : null;
|
|
1916
|
-
if (strv(design.background)) s.background = design.background;
|
|
1917
|
-
if (strv(design.textColor)) s.color = design.textColor;
|
|
1918
|
-
if (px(design.fontSize)) s.fontSize = px(design.fontSize);
|
|
1919
|
-
if (strv(design.fontWeight)) s.fontWeight = design.fontWeight;
|
|
1920
|
-
if (strv(design.align)) s.textAlign = design.align;
|
|
1921
|
-
if (typeof design.lineHeight === "number") s.lineHeight = `${design.lineHeight}%`;
|
|
1922
|
-
if (px(design.radius)) s.borderRadius = px(design.radius);
|
|
1923
|
-
if (px(design.width)) s.width = px(design.width);
|
|
1924
|
-
const bw = px(design.borderWidth);
|
|
1925
|
-
if (bw) s.border = `${bw} solid ${strv(design.borderColor) ?? "#e5e5e5"}`;
|
|
1926
|
-
for (const side of ["Top", "Right", "Bottom", "Left"]) {
|
|
1927
|
-
const p = px(design[`padding${side}`]);
|
|
1928
|
-
if (p) s.setProperty(`padding-${side.toLowerCase()}`, p);
|
|
1929
|
-
const m = px(design[`margin${side}`]);
|
|
1930
|
-
if (m) s.setProperty(`margin-${side.toLowerCase()}`, m);
|
|
1931
|
-
}
|
|
1932
|
-
}
|
|
1933
1793
|
|
|
1934
1794
|
// src/utils/uuid.ts
|
|
1935
1795
|
function uuidv7() {
|
|
@@ -2086,85 +1946,53 @@ function escapeClosing(code, tag) {
|
|
|
2086
1946
|
return code.replace(rx, `<\\/${tag}`);
|
|
2087
1947
|
}
|
|
2088
1948
|
|
|
2089
|
-
// src/plugins/guides/
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
async render(context) {
|
|
2095
|
-
const step = context.guide.guideSteps[0];
|
|
2096
|
-
if (!step || typeof step.html !== "string" || step.html.length === 0) return;
|
|
2097
|
-
const placement = step.placement ?? DEFAULT_PLACEMENT;
|
|
2098
|
-
let anchor = null;
|
|
2099
|
-
if (placement.mode === "anchored") {
|
|
2100
|
-
const selector = placement.selector ?? step.selector ?? context.guide.activationRules.selector;
|
|
2101
|
-
if (typeof selector !== "string" || selector.length === 0) return;
|
|
2102
|
-
anchor = await waitForElement(selector);
|
|
2103
|
-
if (!anchor) return;
|
|
2104
|
-
}
|
|
2105
|
-
const { root } = this.createHost();
|
|
2106
|
-
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%" });
|
|
2107
1954
|
const wrapper = doc.createElement("div");
|
|
2108
|
-
wrapper.className =
|
|
2109
|
-
const { iframe, cleanup } = mountCustomFrame(doc, step, context, {
|
|
2110
|
-
width: toCssSize(placement.width ?? DEFAULT_WIDTH),
|
|
2111
|
-
fixedHeight: placement.height ?? null
|
|
2112
|
-
});
|
|
2113
|
-
this.registerCleanup(cleanup);
|
|
1955
|
+
wrapper.className = "veo-code-sandbox";
|
|
2114
1956
|
wrapper.appendChild(iframe);
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
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();
|
|
2120
1975
|
}
|
|
2121
|
-
context.onInteraction({ guideId: context.guide.guideId, stepIndex: 0, action: "shown" });
|
|
2122
|
-
}
|
|
2123
|
-
async setupAnchoredPosition(anchor, wrapper, placement) {
|
|
2124
|
-
const side = placement.side ?? "bottom";
|
|
2125
|
-
const update = async () => {
|
|
2126
|
-
const { x, y } = await dom.computePosition(anchor, wrapper, {
|
|
2127
|
-
placement: side,
|
|
2128
|
-
strategy: "fixed",
|
|
2129
|
-
middleware: [dom.offset(placement.offsetY ?? 8), dom.flip(), dom.shift({ padding: 8 })]
|
|
2130
|
-
});
|
|
2131
|
-
wrapper.style.left = `${x}px`;
|
|
2132
|
-
wrapper.style.top = `${y}px`;
|
|
2133
|
-
};
|
|
2134
|
-
await update();
|
|
2135
|
-
const reposition = () => {
|
|
2136
|
-
void update();
|
|
2137
|
-
};
|
|
2138
|
-
window.addEventListener("scroll", reposition, true);
|
|
2139
|
-
window.addEventListener("resize", reposition);
|
|
2140
|
-
return () => {
|
|
2141
|
-
window.removeEventListener("scroll", reposition, true);
|
|
2142
|
-
window.removeEventListener("resize", reposition);
|
|
2143
|
-
};
|
|
2144
1976
|
}
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
const s = wrapper.style;
|
|
2151
|
-
if (position === "center") {
|
|
2152
|
-
s.top = "50%";
|
|
2153
|
-
s.left = "50%";
|
|
2154
|
-
s.transform = "translate(-50%, -50%)";
|
|
2155
|
-
return;
|
|
2156
|
-
}
|
|
2157
|
-
const [vertical, horizontal] = position.split("-");
|
|
2158
|
-
if (vertical === "top") s.top = oy;
|
|
2159
|
-
else s.bottom = oy;
|
|
2160
|
-
if (horizontal === "left") {
|
|
2161
|
-
s.left = ox;
|
|
2162
|
-
} else if (horizontal === "right") {
|
|
2163
|
-
s.right = ox;
|
|
2164
|
-
} else {
|
|
2165
|
-
s.left = "50%";
|
|
2166
|
-
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);
|
|
2167
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;
|
|
2168
1996
|
}
|
|
2169
1997
|
|
|
2170
1998
|
// src/plugins/guides/form-content.ts
|
|
@@ -2432,6 +2260,462 @@ function buildScale(wrapper, doc, min, max, btnClass, symbol) {
|
|
|
2432
2260
|
return { wrapper, read: () => selected };
|
|
2433
2261
|
}
|
|
2434
2262
|
|
|
2263
|
+
// src/plugins/guides/renderers/composite-renderer.ts
|
|
2264
|
+
var CompositeRenderer = class extends BaseRenderer {
|
|
2265
|
+
constructor() {
|
|
2266
|
+
super(...arguments);
|
|
2267
|
+
/** Delegado para pasos `badge` (reusa el BadgeRenderer con un step sintético). */
|
|
2268
|
+
this.badgeDelegate = null;
|
|
2269
|
+
}
|
|
2270
|
+
async render(context) {
|
|
2271
|
+
const idx = context.nav?.stepIndex ?? 0;
|
|
2272
|
+
const step = context.guide.guideSteps[idx];
|
|
2273
|
+
if (!step) return;
|
|
2274
|
+
if (step.presentation === "badge") {
|
|
2275
|
+
const syntheticStep = {
|
|
2276
|
+
title: "",
|
|
2277
|
+
content: "",
|
|
2278
|
+
selector: step.anchorSelector ?? void 0,
|
|
2279
|
+
blocks: step.blocks ?? [],
|
|
2280
|
+
style: {
|
|
2281
|
+
...step.design ?? {},
|
|
2282
|
+
...step.badge ? { badge: step.badge } : {},
|
|
2283
|
+
...step.badgeTrigger ? { badgeTrigger: step.badgeTrigger } : {}
|
|
2284
|
+
}
|
|
2285
|
+
};
|
|
2286
|
+
const syntheticGuide = {
|
|
2287
|
+
...context.guide,
|
|
2288
|
+
guideSteps: [syntheticStep]
|
|
2289
|
+
};
|
|
2290
|
+
const { nav: _nav, ...rest } = context;
|
|
2291
|
+
this.badgeDelegate = new BadgeRenderer();
|
|
2292
|
+
await this.badgeDelegate.render({ ...rest, guide: syntheticGuide });
|
|
2293
|
+
return;
|
|
2294
|
+
}
|
|
2295
|
+
const anchorSelector = step.position === "relative-to-element" || step.presentation === "inline" ? step.anchorSelector?.trim() || void 0 : void 0;
|
|
2296
|
+
let anchor = null;
|
|
2297
|
+
if (anchorSelector) {
|
|
2298
|
+
anchor = await waitForElement(anchorSelector);
|
|
2299
|
+
if (!anchor) return;
|
|
2300
|
+
}
|
|
2301
|
+
const { host, root } = this.createHost();
|
|
2302
|
+
const doc = root.ownerDocument ?? document;
|
|
2303
|
+
const design = step.design ?? {};
|
|
2304
|
+
if (typeof design.zIndex === "number") host.style.zIndex = String(design.zIndex);
|
|
2305
|
+
const card = doc.createElement("div");
|
|
2306
|
+
card.className = "veo-card";
|
|
2307
|
+
applyCompositeDesign(card, design);
|
|
2308
|
+
const dismiss = (action, meta) => {
|
|
2309
|
+
context.onInteraction({
|
|
2310
|
+
guideId: context.guide.guideId,
|
|
2311
|
+
stepIndex: idx,
|
|
2312
|
+
action,
|
|
2313
|
+
...{}
|
|
2314
|
+
});
|
|
2315
|
+
};
|
|
2316
|
+
const readers = [];
|
|
2317
|
+
this.buildContent(card, step.blocks ?? [], doc, context, idx, readers);
|
|
2318
|
+
if (design.closeButton !== false) {
|
|
2319
|
+
const closeBtn = createCloseButton(doc, () => {
|
|
2320
|
+
dismiss("dismissed");
|
|
2321
|
+
this.closeOrSkip(context);
|
|
2322
|
+
});
|
|
2323
|
+
const closeColor = typeof design.closeColor === "string" ? design.closeColor : null;
|
|
2324
|
+
const hoverColor = typeof design.closeHoverColor === "string" ? design.closeHoverColor : null;
|
|
2325
|
+
if (closeColor) closeBtn.style.color = closeColor;
|
|
2326
|
+
if (hoverColor) {
|
|
2327
|
+
closeBtn.addEventListener("mouseenter", () => {
|
|
2328
|
+
closeBtn.style.color = hoverColor;
|
|
2329
|
+
});
|
|
2330
|
+
closeBtn.addEventListener("mouseleave", () => {
|
|
2331
|
+
closeBtn.style.color = closeColor ?? "";
|
|
2332
|
+
});
|
|
2333
|
+
}
|
|
2334
|
+
card.appendChild(closeBtn);
|
|
2335
|
+
}
|
|
2336
|
+
if (step.presentation === "inline" && anchor) {
|
|
2337
|
+
host.style.display = "block";
|
|
2338
|
+
const pos = inlinePosOf(step.inlinePosition);
|
|
2339
|
+
root.appendChild(card);
|
|
2340
|
+
insertHost(anchor, host, pos);
|
|
2341
|
+
this.registerCleanup(keepHostAttached(host, anchorSelector, pos));
|
|
2342
|
+
} else if (step.position === "relative-to-element" && anchor) {
|
|
2343
|
+
if (design.backdrop === true) {
|
|
2344
|
+
const bg = doc.createElement("div");
|
|
2345
|
+
bg.className = "veo-composite-overlay veo-composite-overlay--dim";
|
|
2346
|
+
if (typeof design.backdropColor === "string") bg.style.background = design.backdropColor;
|
|
2347
|
+
const bz = typeof design.backdropZIndex === "number" ? design.backdropZIndex : 2e5;
|
|
2348
|
+
bg.style.zIndex = String(bz);
|
|
2349
|
+
root.appendChild(bg);
|
|
2350
|
+
if (design.targetAbove === true) this.registerCleanup(liftTarget(anchor, bz + 1));
|
|
2351
|
+
}
|
|
2352
|
+
const wrapper = doc.createElement("div");
|
|
2353
|
+
wrapper.className = "veo-composite-anchored";
|
|
2354
|
+
const caretEl = design.caret === false ? null : makeCaret(doc, design);
|
|
2355
|
+
if (caretEl) wrapper.appendChild(caretEl);
|
|
2356
|
+
wrapper.appendChild(card);
|
|
2357
|
+
root.appendChild(wrapper);
|
|
2358
|
+
this.registerCleanup(await anchorPosition(anchor, wrapper, caretEl));
|
|
2359
|
+
} else {
|
|
2360
|
+
const overlay = doc.createElement("div");
|
|
2361
|
+
overlay.className = "veo-composite-overlay";
|
|
2362
|
+
if (step.position === "center" && design.backdrop !== false) {
|
|
2363
|
+
overlay.classList.add("veo-composite-overlay--dim");
|
|
2364
|
+
if (typeof design.backdropColor === "string") {
|
|
2365
|
+
overlay.style.background = design.backdropColor;
|
|
2366
|
+
}
|
|
2367
|
+
if (typeof design.backdropZIndex === "number") {
|
|
2368
|
+
overlay.style.zIndex = String(design.backdropZIndex);
|
|
2369
|
+
}
|
|
2370
|
+
overlay.addEventListener("click", (e) => {
|
|
2371
|
+
if (e.target === overlay) {
|
|
2372
|
+
dismiss("dismissed");
|
|
2373
|
+
this.closeOrSkip(context);
|
|
2374
|
+
}
|
|
2375
|
+
});
|
|
2376
|
+
}
|
|
2377
|
+
applyViewportPosition(card, step.position, design);
|
|
2378
|
+
overlay.appendChild(card);
|
|
2379
|
+
root.appendChild(overlay);
|
|
2380
|
+
}
|
|
2381
|
+
context.onInteraction({ guideId: context.guide.guideId, stepIndex: idx, action: "shown" });
|
|
2382
|
+
}
|
|
2383
|
+
/** Recorre los bloques en orden y los pinta en la card. */
|
|
2384
|
+
buildContent(card, blocks, doc, context, idx, readers) {
|
|
2385
|
+
const emit = (block) => {
|
|
2386
|
+
context.onInteraction({
|
|
2387
|
+
guideId: context.guide.guideId,
|
|
2388
|
+
stepIndex: idx,
|
|
2389
|
+
action: "cta_clicked",
|
|
2390
|
+
...block.id ? { metadata: { buttonId: block.id } } : {}
|
|
2391
|
+
});
|
|
2392
|
+
};
|
|
2393
|
+
let i = 0;
|
|
2394
|
+
while (i < blocks.length) {
|
|
2395
|
+
const b = blocks[i];
|
|
2396
|
+
if (!b) {
|
|
2397
|
+
i++;
|
|
2398
|
+
continue;
|
|
2399
|
+
}
|
|
2400
|
+
if (b.type === "button") {
|
|
2401
|
+
const row = doc.createElement("div");
|
|
2402
|
+
row.className = "veo-guide-actions";
|
|
2403
|
+
while (i < blocks.length && blocks[i]?.type === "button") {
|
|
2404
|
+
row.appendChild(
|
|
2405
|
+
this.buildButton(blocks[i], doc, context, idx, readers, emit)
|
|
2406
|
+
);
|
|
2407
|
+
i++;
|
|
2408
|
+
}
|
|
2409
|
+
card.appendChild(row);
|
|
2410
|
+
continue;
|
|
2411
|
+
}
|
|
2412
|
+
if (b.type === "code") {
|
|
2413
|
+
const { node: node2, cleanup } = mountCodeBlock(b, doc, context);
|
|
2414
|
+
if (node2) card.appendChild(node2);
|
|
2415
|
+
this.registerCleanup(cleanup);
|
|
2416
|
+
i++;
|
|
2417
|
+
continue;
|
|
2418
|
+
}
|
|
2419
|
+
if (b.type === "form") {
|
|
2420
|
+
const form = doc.createElement("div");
|
|
2421
|
+
form.className = "veo-form";
|
|
2422
|
+
for (const field of b.fields ?? []) {
|
|
2423
|
+
const { wrapper, read } = buildField(field, doc);
|
|
2424
|
+
readers.push({ field, read });
|
|
2425
|
+
form.appendChild(wrapper);
|
|
2426
|
+
}
|
|
2427
|
+
card.appendChild(form);
|
|
2428
|
+
i++;
|
|
2429
|
+
continue;
|
|
2430
|
+
}
|
|
2431
|
+
const node = buildContentBlock(b, doc);
|
|
2432
|
+
if (node) card.appendChild(node);
|
|
2433
|
+
i++;
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
/** Botón con enrutado de acción (navegación / cierre / url / guía / envío de forms). */
|
|
2437
|
+
buildButton(block, doc, context, idx, readers, emit) {
|
|
2438
|
+
const btn = doc.createElement("button");
|
|
2439
|
+
btn.type = "button";
|
|
2440
|
+
btn.className = "veo-guide-cta";
|
|
2441
|
+
btn.textContent = block.text?.trim() || "OK";
|
|
2442
|
+
const nav = context.nav?.callbacks;
|
|
2443
|
+
btn.addEventListener("click", () => {
|
|
2444
|
+
switch (block.action) {
|
|
2445
|
+
case "next":
|
|
2446
|
+
emit(block);
|
|
2447
|
+
if (nav) nav.onNext();
|
|
2448
|
+
else context.onClose();
|
|
2449
|
+
break;
|
|
2450
|
+
case "prev":
|
|
2451
|
+
emit(block);
|
|
2452
|
+
nav?.onBack();
|
|
2453
|
+
break;
|
|
2454
|
+
case "url":
|
|
2455
|
+
emit(block);
|
|
2456
|
+
if (typeof block.url === "string" && isSafeUrl(block.url)) {
|
|
2457
|
+
window.open(block.url, "_blank", "noopener,noreferrer");
|
|
2458
|
+
}
|
|
2459
|
+
break;
|
|
2460
|
+
case "guide":
|
|
2461
|
+
emit(block);
|
|
2462
|
+
if (block.targetGuideId) context.onOpenGuide?.(block.targetGuideId);
|
|
2463
|
+
this.closeOrSkip(context);
|
|
2464
|
+
break;
|
|
2465
|
+
case "submit-forms":
|
|
2466
|
+
case "submit-forms-advance":
|
|
2467
|
+
case "submit-forms-goto":
|
|
2468
|
+
this.submitForms(readers, context, idx, btn, () => {
|
|
2469
|
+
emit(block);
|
|
2470
|
+
if (block.action === "submit-forms" || !nav) {
|
|
2471
|
+
context.onClose();
|
|
2472
|
+
} else if (block.action === "submit-forms-goto" && typeof block.targetStep === "number" && nav.onGoto) {
|
|
2473
|
+
nav.onGoto(block.targetStep);
|
|
2474
|
+
} else {
|
|
2475
|
+
nav.onNext();
|
|
2476
|
+
}
|
|
2477
|
+
});
|
|
2478
|
+
break;
|
|
2479
|
+
default:
|
|
2480
|
+
emit(block);
|
|
2481
|
+
this.closeOrSkip(context);
|
|
2482
|
+
}
|
|
2483
|
+
});
|
|
2484
|
+
return btn;
|
|
2485
|
+
}
|
|
2486
|
+
/** Recoge respuestas de todos los form-blocks del paso, valida y envía. */
|
|
2487
|
+
submitForms(readers, context, idx, btn, onDone) {
|
|
2488
|
+
const answers = {};
|
|
2489
|
+
for (const { field, read } of readers) {
|
|
2490
|
+
const value = read();
|
|
2491
|
+
const empty = value === void 0 || value === null || value === "";
|
|
2492
|
+
if (empty) {
|
|
2493
|
+
if (field.required) {
|
|
2494
|
+
btn.textContent = `Completa "${field.label}"`;
|
|
2495
|
+
return;
|
|
2496
|
+
}
|
|
2497
|
+
continue;
|
|
2498
|
+
}
|
|
2499
|
+
answers[field.key] = value;
|
|
2500
|
+
}
|
|
2501
|
+
if (readers.length > 0 && Object.keys(answers).length === 0) return;
|
|
2502
|
+
btn.disabled = true;
|
|
2503
|
+
const submitFn = context.onFormSubmit ?? (() => Promise.resolve(true));
|
|
2504
|
+
void submitFn(answers).then((ok) => {
|
|
2505
|
+
btn.disabled = false;
|
|
2506
|
+
if (!ok) return;
|
|
2507
|
+
context.onInteraction({
|
|
2508
|
+
guideId: context.guide.guideId,
|
|
2509
|
+
stepIndex: idx,
|
|
2510
|
+
action: "completed"
|
|
2511
|
+
});
|
|
2512
|
+
onDone();
|
|
2513
|
+
});
|
|
2514
|
+
}
|
|
2515
|
+
closeOrSkip(context) {
|
|
2516
|
+
if (context.nav?.callbacks) context.nav.callbacks.onSkip();
|
|
2517
|
+
else context.onClose();
|
|
2518
|
+
}
|
|
2519
|
+
/** Además del host propio, destruye el delegado de badge si lo hubo. */
|
|
2520
|
+
destroy() {
|
|
2521
|
+
this.badgeDelegate?.destroy();
|
|
2522
|
+
this.badgeDelegate = null;
|
|
2523
|
+
super.destroy();
|
|
2524
|
+
}
|
|
2525
|
+
};
|
|
2526
|
+
function inlinePosOf(p) {
|
|
2527
|
+
return p === "before" || p === "prepend" || p === "append" ? p : "after";
|
|
2528
|
+
}
|
|
2529
|
+
function applyViewportPosition(card, position, design) {
|
|
2530
|
+
const s = card.style;
|
|
2531
|
+
s.position = "fixed";
|
|
2532
|
+
const M = "16px";
|
|
2533
|
+
const hAlign = design.hAlign === "left" ? "left" : design.hAlign === "right" ? "right" : null;
|
|
2534
|
+
const v = position.includes("top") ? "top" : position.includes("bottom") ? "bottom" : "middle";
|
|
2535
|
+
const h = hAlign ?? (position.includes("left") ? "left" : position.includes("right") ? "right" : "middle");
|
|
2536
|
+
if (v === "top") s.top = M;
|
|
2537
|
+
else if (v === "bottom") s.bottom = M;
|
|
2538
|
+
else s.top = "50%";
|
|
2539
|
+
if (h === "left") s.left = M;
|
|
2540
|
+
else if (h === "right") s.right = M;
|
|
2541
|
+
else s.left = "50%";
|
|
2542
|
+
const tx = h === "middle" ? "-50%" : "0";
|
|
2543
|
+
const ty = v === "middle" ? "-50%" : "0";
|
|
2544
|
+
s.transform = tx === "0" && ty === "0" ? "" : `translate(${tx}, ${ty})`;
|
|
2545
|
+
}
|
|
2546
|
+
function makeCaret(doc, design) {
|
|
2547
|
+
const caret = doc.createElement("div");
|
|
2548
|
+
caret.className = "veo-composite-caret";
|
|
2549
|
+
const w = typeof design.caretWidth === "number" ? design.caretWidth : 12;
|
|
2550
|
+
const h = typeof design.caretHeight === "number" ? design.caretHeight : 12;
|
|
2551
|
+
const s = caret.style;
|
|
2552
|
+
s.position = "absolute";
|
|
2553
|
+
s.width = `${w}px`;
|
|
2554
|
+
s.height = `${h}px`;
|
|
2555
|
+
s.transform = "rotate(45deg)";
|
|
2556
|
+
s.background = typeof design.background === "string" ? design.background : "#ffffff";
|
|
2557
|
+
if (typeof design.borderWidth === "number" && design.borderWidth > 0) {
|
|
2558
|
+
const bc = typeof design.borderColor === "string" ? design.borderColor : "#bbbbbb";
|
|
2559
|
+
s.border = `${design.borderWidth}px solid ${bc}`;
|
|
2560
|
+
}
|
|
2561
|
+
return caret;
|
|
2562
|
+
}
|
|
2563
|
+
function liftTarget(anchor, zIndex) {
|
|
2564
|
+
const el = anchor;
|
|
2565
|
+
const prevPosition = el.style.position;
|
|
2566
|
+
const prevZ = el.style.zIndex;
|
|
2567
|
+
if (getComputedStyle(el).position === "static") el.style.position = "relative";
|
|
2568
|
+
el.style.zIndex = String(zIndex);
|
|
2569
|
+
return () => {
|
|
2570
|
+
el.style.position = prevPosition;
|
|
2571
|
+
el.style.zIndex = prevZ;
|
|
2572
|
+
};
|
|
2573
|
+
}
|
|
2574
|
+
async function anchorPosition(anchor, wrapper, caret) {
|
|
2575
|
+
const update = async () => {
|
|
2576
|
+
const { x, y, placement, middlewareData } = await dom.computePosition(anchor, wrapper, {
|
|
2577
|
+
placement: "bottom",
|
|
2578
|
+
strategy: "fixed",
|
|
2579
|
+
middleware: [
|
|
2580
|
+
dom.offset(caret ? 10 : 8),
|
|
2581
|
+
dom.flip(),
|
|
2582
|
+
dom.shift({ padding: 8 }),
|
|
2583
|
+
...caret ? [dom.arrow({ element: caret })] : []
|
|
2584
|
+
]
|
|
2585
|
+
});
|
|
2586
|
+
wrapper.style.left = `${x}px`;
|
|
2587
|
+
wrapper.style.top = `${y}px`;
|
|
2588
|
+
if (caret) positionArrow(caret, placement, middlewareData.arrow);
|
|
2589
|
+
};
|
|
2590
|
+
await update();
|
|
2591
|
+
const reposition = () => void update();
|
|
2592
|
+
window.addEventListener("scroll", reposition, true);
|
|
2593
|
+
window.addEventListener("resize", reposition);
|
|
2594
|
+
return () => {
|
|
2595
|
+
window.removeEventListener("scroll", reposition, true);
|
|
2596
|
+
window.removeEventListener("resize", reposition);
|
|
2597
|
+
};
|
|
2598
|
+
}
|
|
2599
|
+
function applyCompositeDesign(card, design) {
|
|
2600
|
+
const s = card.style;
|
|
2601
|
+
const px = (v) => typeof v === "number" && Number.isFinite(v) ? `${v}px` : null;
|
|
2602
|
+
const strv = (v) => typeof v === "string" && v ? v : null;
|
|
2603
|
+
if (strv(design.background)) s.background = design.background;
|
|
2604
|
+
const textColor = strv(design.color) ?? strv(design.textColor);
|
|
2605
|
+
if (textColor) s.color = textColor;
|
|
2606
|
+
if (px(design.fontSize)) s.fontSize = px(design.fontSize);
|
|
2607
|
+
if (strv(design.fontWeight)) s.fontWeight = design.fontWeight;
|
|
2608
|
+
if (strv(design.fontFamily) && design.fontFamily !== "inherit") {
|
|
2609
|
+
s.fontFamily = design.fontFamily;
|
|
2610
|
+
}
|
|
2611
|
+
if (strv(design.textTransform) && design.textTransform !== "none") {
|
|
2612
|
+
s.textTransform = design.textTransform;
|
|
2613
|
+
}
|
|
2614
|
+
if (typeof design.letterSpacing === "number") s.letterSpacing = `${design.letterSpacing}px`;
|
|
2615
|
+
if (strv(design.align)) s.textAlign = design.align;
|
|
2616
|
+
if (typeof design.lineHeight === "number") s.lineHeight = `${design.lineHeight}%`;
|
|
2617
|
+
if (px(design.radius)) s.borderRadius = px(design.radius);
|
|
2618
|
+
const bw = px(design.borderWidth);
|
|
2619
|
+
if (bw) s.border = `${bw} solid ${strv(design.borderColor) ?? "#e5e5e5"}`;
|
|
2620
|
+
if (strv(design.shadowColor) || typeof design.shadowBlur === "number") {
|
|
2621
|
+
const n = (k) => typeof design[k] === "number" ? design[k] : 0;
|
|
2622
|
+
s.boxShadow = `${n("shadowX")}px ${n("shadowY")}px ${n("shadowBlur")}px ${n("shadowSpread")}px ${strv(design.shadowColor) ?? "rgba(0,0,0,0.2)"}`;
|
|
2623
|
+
}
|
|
2624
|
+
if (design.fullWidth === true) {
|
|
2625
|
+
s.width = "100%";
|
|
2626
|
+
} else if (design.widthType === "fluid") {
|
|
2627
|
+
s.width = "auto";
|
|
2628
|
+
if (px(design.width)) s.maxWidth = px(design.width);
|
|
2629
|
+
} else if (px(design.width)) {
|
|
2630
|
+
s.width = px(design.width);
|
|
2631
|
+
}
|
|
2632
|
+
for (const side of ["Top", "Right", "Bottom", "Left"]) {
|
|
2633
|
+
const p = px(design[`padding${side}`]);
|
|
2634
|
+
if (p) s.setProperty(`padding-${side.toLowerCase()}`, p);
|
|
2635
|
+
const m = px(design[`margin${side}`]);
|
|
2636
|
+
if (m) s.setProperty(`margin-${side.toLowerCase()}`, m);
|
|
2637
|
+
}
|
|
2638
|
+
}
|
|
2639
|
+
var DEFAULT_PLACEMENT = { mode: "floating", position: "bottom-right" };
|
|
2640
|
+
var DEFAULT_OFFSET = 16;
|
|
2641
|
+
var DEFAULT_WIDTH = 360;
|
|
2642
|
+
var CustomRenderer = class extends BaseRenderer {
|
|
2643
|
+
async render(context) {
|
|
2644
|
+
const step = context.guide.guideSteps[0];
|
|
2645
|
+
if (!step || typeof step.html !== "string" || step.html.length === 0) return;
|
|
2646
|
+
const placement = step.placement ?? DEFAULT_PLACEMENT;
|
|
2647
|
+
let anchor = null;
|
|
2648
|
+
if (placement.mode === "anchored") {
|
|
2649
|
+
const selector = placement.selector ?? step.selector ?? context.guide.activationRules.selector;
|
|
2650
|
+
if (typeof selector !== "string" || selector.length === 0) return;
|
|
2651
|
+
anchor = await waitForElement(selector);
|
|
2652
|
+
if (!anchor) return;
|
|
2653
|
+
}
|
|
2654
|
+
const { root } = this.createHost();
|
|
2655
|
+
const doc = root.ownerDocument ?? document;
|
|
2656
|
+
const wrapper = doc.createElement("div");
|
|
2657
|
+
wrapper.className = placement.mode === "anchored" ? "veo-custom-anchored" : "veo-custom-floating";
|
|
2658
|
+
const { iframe, cleanup } = mountCustomFrame(doc, step, context, {
|
|
2659
|
+
width: toCssSize(placement.width ?? DEFAULT_WIDTH),
|
|
2660
|
+
fixedHeight: placement.height ?? null
|
|
2661
|
+
});
|
|
2662
|
+
this.registerCleanup(cleanup);
|
|
2663
|
+
wrapper.appendChild(iframe);
|
|
2664
|
+
root.appendChild(wrapper);
|
|
2665
|
+
if (placement.mode === "floating") {
|
|
2666
|
+
applyFloatingPosition(wrapper, placement);
|
|
2667
|
+
} else if (anchor) {
|
|
2668
|
+
this.registerCleanup(await this.setupAnchoredPosition(anchor, wrapper, placement));
|
|
2669
|
+
}
|
|
2670
|
+
context.onInteraction({ guideId: context.guide.guideId, stepIndex: 0, action: "shown" });
|
|
2671
|
+
}
|
|
2672
|
+
async setupAnchoredPosition(anchor, wrapper, placement) {
|
|
2673
|
+
const side = placement.side ?? "bottom";
|
|
2674
|
+
const update = async () => {
|
|
2675
|
+
const { x, y } = await dom.computePosition(anchor, wrapper, {
|
|
2676
|
+
placement: side,
|
|
2677
|
+
strategy: "fixed",
|
|
2678
|
+
middleware: [dom.offset(placement.offsetY ?? 8), dom.flip(), dom.shift({ padding: 8 })]
|
|
2679
|
+
});
|
|
2680
|
+
wrapper.style.left = `${x}px`;
|
|
2681
|
+
wrapper.style.top = `${y}px`;
|
|
2682
|
+
};
|
|
2683
|
+
await update();
|
|
2684
|
+
const reposition = () => {
|
|
2685
|
+
void update();
|
|
2686
|
+
};
|
|
2687
|
+
window.addEventListener("scroll", reposition, true);
|
|
2688
|
+
window.addEventListener("resize", reposition);
|
|
2689
|
+
return () => {
|
|
2690
|
+
window.removeEventListener("scroll", reposition, true);
|
|
2691
|
+
window.removeEventListener("resize", reposition);
|
|
2692
|
+
};
|
|
2693
|
+
}
|
|
2694
|
+
};
|
|
2695
|
+
function applyFloatingPosition(wrapper, placement) {
|
|
2696
|
+
const position = placement.position ?? "bottom-right";
|
|
2697
|
+
const ox = `${placement.offsetX ?? DEFAULT_OFFSET}px`;
|
|
2698
|
+
const oy = `${placement.offsetY ?? DEFAULT_OFFSET}px`;
|
|
2699
|
+
const s = wrapper.style;
|
|
2700
|
+
if (position === "center") {
|
|
2701
|
+
s.top = "50%";
|
|
2702
|
+
s.left = "50%";
|
|
2703
|
+
s.transform = "translate(-50%, -50%)";
|
|
2704
|
+
return;
|
|
2705
|
+
}
|
|
2706
|
+
const [vertical, horizontal] = position.split("-");
|
|
2707
|
+
if (vertical === "top") s.top = oy;
|
|
2708
|
+
else s.bottom = oy;
|
|
2709
|
+
if (horizontal === "left") {
|
|
2710
|
+
s.left = ox;
|
|
2711
|
+
} else if (horizontal === "right") {
|
|
2712
|
+
s.right = ox;
|
|
2713
|
+
} else {
|
|
2714
|
+
s.left = "50%";
|
|
2715
|
+
s.transform = "translateX(-50%)";
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
|
|
2435
2719
|
// src/plugins/guides/renderers/form-renderer.ts
|
|
2436
2720
|
var FormRenderer = class extends BaseRenderer {
|
|
2437
2721
|
render(context) {
|