@renderx-plugins/library-component
Version:
Runtime for Library-Component drag/drop sequences (externalized).
246 lines (242 loc) • 7.76 kB
JavaScript
// src/symphonies/drag/drag.preview.stage-crew.ts
function ensurePayload(dt, component) {
dt?.setData("application/rx-component", JSON.stringify({ component }));
}
function computeGhostSize(e, component) {
const targetEl = e?.target || null;
const tplDim = component?.template?.dimensions;
let width;
let height;
if (tplDim) {
if (Number.isFinite(tplDim.width)) width = tplDim.width;
if (Number.isFinite(tplDim.height)) height = tplDim.height;
}
if ((!width || !height) && targetEl?.getBoundingClientRect) {
const rect = targetEl.getBoundingClientRect();
width = width ?? Math.round(rect.width);
height = height ?? Math.round(rect.height);
}
width = width ?? 120;
height = height ?? 40;
return { width, height, targetEl };
}
function createGhostContainer(width, height) {
const ghost = document.createElement("div");
ghost.style.width = `${width}px`;
ghost.style.height = `${height}px`;
ghost.style.boxSizing = "border-box";
ghost.style.padding = "0";
ghost.style.margin = "0";
ghost.style.position = "absolute";
ghost.style.left = "-9999px";
ghost.style.top = "-9999px";
ghost.style.pointerEvents = "none";
ghost.style.background = "transparent";
ghost.style.filter = "blur(2px)";
ghost.style.opacity = "0.9";
return ghost;
}
function renderTemplatePreview(ghost, template, width, height) {
if (!template || typeof template !== "object") return;
const tag = template?.tag || "div";
const isSvg = String(tag).toLowerCase() === "svg";
const child = isSvg ? document.createElementNS("http://www.w3.org/2000/svg", "svg") : document.createElement(tag);
try {
const classes = Array.isArray(template?.classes) ? template.classes : [];
classes.forEach((cls) => child.classList.add(cls));
} catch {
}
if (!isSvg && typeof template?.text === "string")
child.textContent = template.text;
child.style.width = `${width}px`;
child.style.height = `${height}px`;
child.style.display = "inline-block";
if (isSvg) {
child.setAttribute("width", "100%");
child.setAttribute("height", "100%");
child.setAttribute("viewBox", "0 0 100 100");
child.setAttribute("preserveAspectRatio", "none");
const ns = "http://www.w3.org/2000/svg";
const seg = document.createElementNS(ns, "line");
seg.setAttribute("class", "segment");
seg.setAttribute("x1", "0");
seg.setAttribute("y1", "50");
seg.setAttribute("x2", "100");
seg.setAttribute("y2", "50");
seg.setAttribute("vector-effect", "non-scaling-stroke");
child.appendChild(seg);
}
ghost.appendChild(child);
}
function applyTemplateStyles(ghost, template) {
if (!template || typeof template !== "object") return;
if (typeof template?.css === "string") {
const styleEl = document.createElement("style");
styleEl.textContent = template.css;
ghost.appendChild(styleEl);
}
const vars = template?.cssVariables;
if (vars && typeof vars === "object") {
for (const [k, v] of Object.entries(vars)) {
try {
const name = String(k).startsWith("--") ? String(k) : `--${k}`;
ghost.style.setProperty(name, String(v));
} catch {
}
}
}
}
function computeCursorOffsets(e, targetEl, width, height) {
let offsetX = Math.round(width / 2);
let offsetY = Math.round(height / 2);
if (targetEl && typeof e?.clientX === "number" && typeof e?.clientY === "number") {
try {
const rect = targetEl.getBoundingClientRect();
offsetX = Math.max(0, Math.round(e.clientX - rect.left));
offsetY = Math.max(0, Math.round(e.clientY - rect.top));
} catch {
}
}
return { offsetX, offsetY };
}
function installDragImage(dt, ghost, offsetX, offsetY) {
document.body.appendChild(ghost);
try {
dt.setDragImage(ghost, offsetX, offsetY);
} finally {
if (typeof requestAnimationFrame === "function") {
requestAnimationFrame(() => ghost.remove());
} else {
setTimeout(() => ghost.remove(), 0);
}
}
}
// src/symphonies/drag.symphony.ts
var handlers = {
onDragStart(data) {
const e = data?.domEvent;
const dt = e?.dataTransfer;
ensurePayload(dt, data?.component);
try {
if (dt?.setDragImage) {
const { width, height, targetEl } = computeGhostSize(
e,
data?.component
);
const ghost = createGhostContainer(width, height);
renderTemplatePreview(ghost, data?.component?.template, width, height);
applyTemplateStyles(ghost, data?.component?.template);
const { offsetX, offsetY } = computeCursorOffsets(
e,
targetEl,
width,
height
);
installDragImage(dt, ghost, offsetX, offsetY);
}
} catch {
}
return { started: true };
}
};
// src/symphonies/drop.symphony.ts
import { EventRouter } from "@renderx-plugins/host-sdk";
var handlers2 = {
async publishCreateRequested(data, ctx) {
const correlationId = data?.correlationId || crypto.randomUUID?.() || String(Date.now());
await EventRouter.publish(
"canvas.component.create.requested",
{
component: data.component,
position: data.position,
containerId: data.containerId,
correlationId
},
ctx.conductor
);
}
};
// src/symphonies/drop.container.symphony.ts
import { EventRouter as EventRouter2 } from "@renderx-plugins/host-sdk";
var handlers3 = {
async publishCreateRequested(data, ctx) {
const correlationId = data?.correlationId || crypto.randomUUID?.() || String(Date.now());
await EventRouter2.publish(
"canvas.component.create.requested",
{
component: data.component,
position: data.position,
containerId: data.containerId,
correlationId
},
ctx.conductor
);
}
};
// src/index.ts
var mergedHandlers = {
onDragStart: handlers.onDragStart,
publishCreateRequested: handlers2.publishCreateRequested
};
async function register(conductor) {
if (!conductor?.mount) return;
const dragSeq = {
pluginId: "LibraryComponentPlugin",
id: "library-component-drag-symphony",
name: "Library Component Drag",
movements: [
{
id: "drag",
name: "Drag",
beats: [
{ beat: 1, event: "library.component.drag.start.requested", handler: "onDragStart", kind: "pure", dynamics: "mf", timing: "immediate" }
]
}
]
};
const dropSeq = {
pluginId: "LibraryComponentPlugin",
id: "library-component-drop-symphony",
name: "Library Component Drop",
movements: [
{
id: "drop",
name: "Drop",
beats: [
{ beat: 1, event: "library:component:drop", handler: "publishCreateRequested", kind: "pure", dynamics: "mf", timing: "immediate" }
]
}
]
};
const containerDropSeq = {
pluginId: "LibraryComponentPlugin",
id: "library-component-container-drop-symphony",
name: "Library Component Container Drop",
movements: [
{
id: "drop",
name: "Drop",
beats: [
{ beat: 1, event: "library:container:drop", handler: "publishCreateRequested", kind: "pure", dynamics: "mf", timing: "immediate" }
]
}
]
};
const mark = (id) => {
const key = "_runtimeMountedSeqIds";
const set = conductor[key] || /* @__PURE__ */ new Set();
set.add(id);
conductor[key] = set;
};
await conductor.mount(dragSeq, handlers, dragSeq.pluginId);
mark(dragSeq.id);
await conductor.mount(dropSeq, handlers2, dropSeq.pluginId);
mark(dropSeq.id);
await conductor.mount(containerDropSeq, handlers3, containerDropSeq.pluginId);
mark(containerDropSeq.id);
}
export {
mergedHandlers as handlers,
register
};
//# sourceMappingURL=index.js.map