veo-sdk 0.5.4 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/builder-AMCPHL4K.mjs +5 -0
- package/dist/{builder-MFTOJV6F.mjs.map → builder-AMCPHL4K.mjs.map} +1 -1
- package/dist/builder.cjs +294 -6
- package/dist/builder.cjs.map +1 -1
- package/dist/builder.d.cts +9 -2
- package/dist/builder.d.ts +9 -2
- package/dist/builder.mjs +4 -4
- package/dist/{chunk-JPA46JBS.mjs → chunk-764FSEHS.mjs} +221 -4
- package/dist/chunk-764FSEHS.mjs.map +1 -0
- package/dist/{chunk-SBNT464M.mjs → chunk-A4RHMCCM.mjs} +79 -8
- package/dist/chunk-A4RHMCCM.mjs.map +1 -0
- package/dist/{chunk-GKJW5TOZ.mjs → chunk-CPSHNLZG.mjs} +7 -3
- package/dist/chunk-CPSHNLZG.mjs.map +1 -0
- 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 +309 -6
- 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-MFTOJV6F.mjs +0 -5
- package/dist/chunk-GKJW5TOZ.mjs.map +0 -1
- package/dist/chunk-JPA46JBS.mjs.map +0 -1
- package/dist/chunk-SBNT464M.mjs.map +0 -1
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { VEO_BLOCK_MIME, attachBlockDropTarget, attachDesignManipulator, createBuilderSession, initBuilderMode, startElementPicker, stopElementPicker } from './chunk-A4RHMCCM.mjs';
|
|
2
|
+
import './chunk-764FSEHS.mjs';
|
|
3
|
+
import './chunk-PTG3BTJE.mjs';
|
|
4
|
+
//# sourceMappingURL=builder-AMCPHL4K.mjs.map
|
|
5
|
+
//# sourceMappingURL=builder-AMCPHL4K.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"builder-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"builder-AMCPHL4K.mjs"}
|
package/dist/builder.cjs
CHANGED
|
@@ -32,7 +32,8 @@ function attachBlockDropTarget(options) {
|
|
|
32
32
|
const types = event.dataTransfer?.types;
|
|
33
33
|
return !!types && Array.from(types).includes(VEO_BLOCK_MIME);
|
|
34
34
|
};
|
|
35
|
-
const
|
|
35
|
+
const NEAR_PX = 48;
|
|
36
|
+
const locate = (clientY) => {
|
|
36
37
|
const container = contentEl();
|
|
37
38
|
if (!container) return null;
|
|
38
39
|
const rect = container.getBoundingClientRect();
|
|
@@ -41,7 +42,7 @@ function attachBlockDropTarget(options) {
|
|
|
41
42
|
let y = kids.length === 0 ? rect.top + rect.height / 2 : 0;
|
|
42
43
|
for (const kid of kids) {
|
|
43
44
|
const r = kid.getBoundingClientRect();
|
|
44
|
-
if (
|
|
45
|
+
if (clientY < r.top + r.height / 2) {
|
|
45
46
|
const idx = Number(kid.dataset.veoIdx);
|
|
46
47
|
beforeIndex = Number.isFinite(idx) ? idx : null;
|
|
47
48
|
y = r.top;
|
|
@@ -51,9 +52,26 @@ function attachBlockDropTarget(options) {
|
|
|
51
52
|
}
|
|
52
53
|
return { beforeIndex, y, rect };
|
|
53
54
|
};
|
|
55
|
+
const overContent = (x, y, rect) => x >= rect.left - NEAR_PX && x <= rect.right + NEAR_PX && y >= rect.top - NEAR_PX && y <= rect.bottom + NEAR_PX;
|
|
56
|
+
const hoverAt = (x, y) => {
|
|
57
|
+
const at = locate(y);
|
|
58
|
+
if (!at || !overContent(x, y, at.rect)) {
|
|
59
|
+
hideLine();
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
spot = at;
|
|
63
|
+
showLine(at);
|
|
64
|
+
return true;
|
|
65
|
+
};
|
|
66
|
+
const dropAt = (x, y) => {
|
|
67
|
+
const at = locate(y);
|
|
68
|
+
hideLine();
|
|
69
|
+
if (!at || !overContent(x, y, at.rect)) return null;
|
|
70
|
+
return { beforeIndex: at.beforeIndex };
|
|
71
|
+
};
|
|
54
72
|
const onDragOver = (event) => {
|
|
55
73
|
if (!isBlockDrag(event)) return;
|
|
56
|
-
const at = locate(event);
|
|
74
|
+
const at = locate(event.clientY);
|
|
57
75
|
if (!at) return;
|
|
58
76
|
event.preventDefault();
|
|
59
77
|
if (event.dataTransfer) event.dataTransfer.dropEffect = "copy";
|
|
@@ -64,7 +82,7 @@ function attachBlockDropTarget(options) {
|
|
|
64
82
|
if (!isBlockDrag(event)) return;
|
|
65
83
|
event.preventDefault();
|
|
66
84
|
const blockType = event.dataTransfer?.getData(VEO_BLOCK_MIME) ?? "";
|
|
67
|
-
const at = spot ?? locate(event);
|
|
85
|
+
const at = spot ?? locate(event.clientY);
|
|
68
86
|
hideLine();
|
|
69
87
|
if (!blockType || !at) return;
|
|
70
88
|
onDrop({ stepIndex, blockType, beforeIndex: at.beforeIndex });
|
|
@@ -78,6 +96,9 @@ function attachBlockDropTarget(options) {
|
|
|
78
96
|
host.addEventListener("drop", onDropEvent);
|
|
79
97
|
host.addEventListener("dragleave", onDragLeave);
|
|
80
98
|
return {
|
|
99
|
+
hoverAt,
|
|
100
|
+
dropAt,
|
|
101
|
+
cancelHover: hideLine,
|
|
81
102
|
detach() {
|
|
82
103
|
host.removeEventListener("dragover", onDragOver);
|
|
83
104
|
host.removeEventListener("drop", onDropEvent);
|
|
@@ -501,7 +522,8 @@ function buildButtonBlock(block, doc, callbacks) {
|
|
|
501
522
|
btn.textContent = typeof block.text === "string" && block.text ? block.text : "OK";
|
|
502
523
|
applyBlockStyle(btn, block.style, "button");
|
|
503
524
|
btn.addEventListener("click", () => {
|
|
504
|
-
const
|
|
525
|
+
const raw = block.action ?? "dismiss";
|
|
526
|
+
const action = raw === "next" || raw === "url" || raw === "guide" ? raw : "dismiss";
|
|
505
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;
|
|
506
528
|
const meta = {
|
|
507
529
|
...typeof block.id === "string" && block.id ? { buttonId: block.id } : {},
|
|
@@ -897,6 +919,35 @@ var GUIDE_STYLES = `
|
|
|
897
919
|
animation: veo-fade-in 160ms ease-out;
|
|
898
920
|
}
|
|
899
921
|
|
|
922
|
+
/* \u2500\u2500 Modelo unificado (composite) \u2500\u2500 */
|
|
923
|
+
.veo-composite-overlay {
|
|
924
|
+
position: fixed; inset: 0;
|
|
925
|
+
z-index: ${GUIDE_Z_INDEX};
|
|
926
|
+
pointer-events: none;
|
|
927
|
+
}
|
|
928
|
+
/* Backdrop atenuado (solo centro con backdrop activo). */
|
|
929
|
+
.veo-composite-overlay--dim {
|
|
930
|
+
background: rgba(0, 0, 0, 0.5);
|
|
931
|
+
pointer-events: auto;
|
|
932
|
+
}
|
|
933
|
+
.veo-composite-anchored {
|
|
934
|
+
position: fixed;
|
|
935
|
+
z-index: ${GUIDE_Z_INDEX};
|
|
936
|
+
}
|
|
937
|
+
/* Card gen\xE9rica del modelo unificado. El dise\xF1o (bg/borde/padding/\u2026) lo aplica
|
|
938
|
+
el renderer como estilos inline desde step.design; ac\xE1 van los defaults. */
|
|
939
|
+
.veo-card {
|
|
940
|
+
pointer-events: auto;
|
|
941
|
+
background: var(--veo-bg, #ffffff);
|
|
942
|
+
color: var(--veo-text, #1f2937);
|
|
943
|
+
border-radius: var(--veo-radius, 12px);
|
|
944
|
+
padding: 20px;
|
|
945
|
+
max-width: 90vw;
|
|
946
|
+
box-shadow: var(--veo-shadow, 0 12px 40px rgba(0, 0, 0, 0.18));
|
|
947
|
+
animation: veo-fade-in 160ms ease-out;
|
|
948
|
+
}
|
|
949
|
+
.veo-composite-anchored .veo-card, .veo-composite-overlay .veo-card { position: relative; }
|
|
950
|
+
|
|
900
951
|
.veo-guide-content {
|
|
901
952
|
position: relative;
|
|
902
953
|
display: flex; flex-direction: column;
|
|
@@ -1703,6 +1754,182 @@ var BannerRenderer = class extends BaseRenderer {
|
|
|
1703
1754
|
function bannerClassOf(position, embedded) {
|
|
1704
1755
|
return embedded ? "veo-banner veo-banner-embedded" : `veo-banner veo-banner-${position}`;
|
|
1705
1756
|
}
|
|
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
|
+
}
|
|
1706
1933
|
|
|
1707
1934
|
// src/utils/uuid.ts
|
|
1708
1935
|
function uuidv7() {
|
|
@@ -2585,6 +2812,13 @@ var GuidePreviewController = class {
|
|
|
2585
2812
|
this.input = input;
|
|
2586
2813
|
const guide = normalize(input);
|
|
2587
2814
|
const start = typeof input.startStepIndex === "number" ? input.startStepIndex : 0;
|
|
2815
|
+
if (guide.guideType === "composite") {
|
|
2816
|
+
const s = Math.min(Math.max(0, start), guide.guideSteps.length - 1);
|
|
2817
|
+
const active = guide.guideSteps[s];
|
|
2818
|
+
if (active) guide.guideSteps = [active];
|
|
2819
|
+
const ready2 = this.renderSingleStep(guide);
|
|
2820
|
+
return { close: () => this.close(), ready: ready2, host: () => this.activeHost() };
|
|
2821
|
+
}
|
|
2588
2822
|
const ready = guide.guideType === "walkthrough" ? this.startWalkthrough(guide, start) : this.renderSingleStep(guide);
|
|
2589
2823
|
return { close: () => this.close(), ready, host: () => this.activeHost() };
|
|
2590
2824
|
}
|
|
@@ -2764,8 +2998,12 @@ function createSingleStepRenderer(type) {
|
|
|
2764
2998
|
return new InlineFormRenderer();
|
|
2765
2999
|
case "badge":
|
|
2766
3000
|
return new BadgeRenderer();
|
|
3001
|
+
case "composite":
|
|
3002
|
+
return new CompositeRenderer();
|
|
2767
3003
|
case "walkthrough":
|
|
2768
3004
|
return null;
|
|
3005
|
+
default:
|
|
3006
|
+
return null;
|
|
2769
3007
|
}
|
|
2770
3008
|
}
|
|
2771
3009
|
function safeDestroy(renderer) {
|
|
@@ -2787,7 +3025,7 @@ var MIN_H = 320;
|
|
|
2787
3025
|
var MARGIN = 16;
|
|
2788
3026
|
function injectBuilderPanel(opts) {
|
|
2789
3027
|
if (!hasWindow() || !hasDocument()) {
|
|
2790
|
-
return { target: () => null, teardown: () => {
|
|
3028
|
+
return { target: () => null, frameRect: () => null, teardown: () => {
|
|
2791
3029
|
} };
|
|
2792
3030
|
}
|
|
2793
3031
|
const panelUrl = buildPanelUrl(opts);
|
|
@@ -2904,6 +3142,7 @@ function injectBuilderPanel(opts) {
|
|
|
2904
3142
|
});
|
|
2905
3143
|
return {
|
|
2906
3144
|
target: () => popped && !popped.closed ? popped : iframe.contentWindow,
|
|
3145
|
+
frameRect: () => popped && !popped.closed ? null : iframe.getBoundingClientRect(),
|
|
2907
3146
|
teardown: () => {
|
|
2908
3147
|
stopPoll();
|
|
2909
3148
|
if (popped && !popped.closed) popped.close();
|
|
@@ -3488,6 +3727,8 @@ function initBuilderMode() {
|
|
|
3488
3727
|
let staticTarget = null;
|
|
3489
3728
|
let manipulator = null;
|
|
3490
3729
|
let dropTarget = null;
|
|
3730
|
+
let dragGhost = null;
|
|
3731
|
+
let previewStepIndex = 0;
|
|
3491
3732
|
let pendingPreview = null;
|
|
3492
3733
|
const getTarget = () => panel ? panel.target() : staticTarget;
|
|
3493
3734
|
const post = (event) => {
|
|
@@ -3498,6 +3739,7 @@ function initBuilderMode() {
|
|
|
3498
3739
|
manipulator = null;
|
|
3499
3740
|
dropTarget?.detach();
|
|
3500
3741
|
dropTarget = null;
|
|
3742
|
+
previewStepIndex = cmd.guide.startStepIndex ?? 0;
|
|
3501
3743
|
const handle = previewGuide(cmd.guide);
|
|
3502
3744
|
if (!cmd.editable) return;
|
|
3503
3745
|
void handle.ready.then((result) => {
|
|
@@ -3523,6 +3765,47 @@ function initBuilderMode() {
|
|
|
3523
3765
|
});
|
|
3524
3766
|
});
|
|
3525
3767
|
};
|
|
3768
|
+
const hideDragGhost = () => {
|
|
3769
|
+
dragGhost?.remove();
|
|
3770
|
+
dragGhost = null;
|
|
3771
|
+
};
|
|
3772
|
+
const moveDragGhost = (x, y, label) => {
|
|
3773
|
+
if (!dragGhost) {
|
|
3774
|
+
dragGhost = document.createElement("div");
|
|
3775
|
+
dragGhost.style.cssText = "position:fixed;padding:4px 10px;border-radius:999px;background:#1c1917;color:#fff;font:12px/1.4 system-ui,sans-serif;box-shadow:0 4px 14px rgba(0,0,0,0.35);border:1px solid rgba(255,255,255,0.25);pointer-events:none;z-index:2147483647;";
|
|
3776
|
+
document.body.appendChild(dragGhost);
|
|
3777
|
+
}
|
|
3778
|
+
dragGhost.textContent = label;
|
|
3779
|
+
dragGhost.style.left = `${x + 14}px`;
|
|
3780
|
+
dragGhost.style.top = `${y + 12}px`;
|
|
3781
|
+
};
|
|
3782
|
+
const handleBlockDrag = (cmd) => {
|
|
3783
|
+
const rect = panel?.frameRect();
|
|
3784
|
+
if (!rect || !dropTarget) {
|
|
3785
|
+
if (cmd.phase !== "move") hideDragGhost();
|
|
3786
|
+
dropTarget?.cancelHover();
|
|
3787
|
+
return;
|
|
3788
|
+
}
|
|
3789
|
+
const x = rect.left + cmd.x;
|
|
3790
|
+
const y = rect.top + cmd.y;
|
|
3791
|
+
if (cmd.phase === "move") {
|
|
3792
|
+
moveDragGhost(x, y, cmd.label || cmd.blockType);
|
|
3793
|
+
dropTarget.hoverAt(x, y);
|
|
3794
|
+
return;
|
|
3795
|
+
}
|
|
3796
|
+
hideDragGhost();
|
|
3797
|
+
if (cmd.phase === "cancel") {
|
|
3798
|
+
dropTarget.cancelHover();
|
|
3799
|
+
return;
|
|
3800
|
+
}
|
|
3801
|
+
const spotAt = dropTarget.dropAt(x, y);
|
|
3802
|
+
if (spotAt) {
|
|
3803
|
+
post({
|
|
3804
|
+
type: "block-dropped",
|
|
3805
|
+
payload: { stepIndex: previewStepIndex, blockType: cmd.blockType, ...spotAt }
|
|
3806
|
+
});
|
|
3807
|
+
}
|
|
3808
|
+
};
|
|
3526
3809
|
const handleCommand = (cmd) => {
|
|
3527
3810
|
switch (cmd.type) {
|
|
3528
3811
|
case "panel-ready":
|
|
@@ -3552,11 +3835,15 @@ function initBuilderMode() {
|
|
|
3552
3835
|
if (manipulator?.isDragging()) pendingPreview = cmd;
|
|
3553
3836
|
else applyPreview(cmd);
|
|
3554
3837
|
break;
|
|
3838
|
+
case "block-drag":
|
|
3839
|
+
handleBlockDrag(cmd);
|
|
3840
|
+
break;
|
|
3555
3841
|
case "close-preview":
|
|
3556
3842
|
manipulator?.detach();
|
|
3557
3843
|
manipulator = null;
|
|
3558
3844
|
dropTarget?.detach();
|
|
3559
3845
|
dropTarget = null;
|
|
3846
|
+
hideDragGhost();
|
|
3560
3847
|
pendingPreview = null;
|
|
3561
3848
|
closeGuidePreview();
|
|
3562
3849
|
break;
|
|
@@ -3581,6 +3868,7 @@ function initBuilderMode() {
|
|
|
3581
3868
|
manipulator = null;
|
|
3582
3869
|
dropTarget?.detach();
|
|
3583
3870
|
dropTarget = null;
|
|
3871
|
+
hideDragGhost();
|
|
3584
3872
|
pendingPreview = null;
|
|
3585
3873
|
closeGuidePreview();
|
|
3586
3874
|
post({ type: "closed" });
|