rspace-online/shared/draggable.ts

65 lines
2.0 KiB
TypeScript

/**
* Shared drag-and-drop utilities for cross-module item dragging.
*
* Any module card/list-item can become draggable by calling
* `makeDraggable(el, payload)` — the calendar and reminders widget
* will accept the drop via `application/rspace-item`.
*/
export interface RSpaceItemPayload {
title: string;
module: string; // e.g. "rnotes", "rtasks", "rfiles"
entityId: string;
label?: string; // human-readable source, e.g. "Note", "Task"
color?: string; // module accent color
}
/** Module accent colors for drag ghost + calendar indicators */
export const MODULE_COLORS: Record<string, string> = {
rnotes: "#f59e0b", // amber
rtasks: "#3b82f6", // blue
rfiles: "#10b981", // emerald
rsplat: "#818cf8", // indigo
rphotos: "#ec4899", // pink
rbooks: "#f97316", // orange
rforum: "#8b5cf6", // violet
rinbox: "#06b6d4", // cyan
rvote: "#ef4444", // red
rtube: "#a855f7", // purple
};
/**
* Make an element draggable with the rspace-item protocol.
* Adds draggable attribute and dragstart handler.
*/
export function makeDraggable(el: HTMLElement, payload: RSpaceItemPayload) {
el.draggable = true;
el.style.cursor = "grab";
el.addEventListener("dragstart", (e) => {
if (!e.dataTransfer) return;
e.dataTransfer.setData("application/rspace-item", JSON.stringify(payload));
e.dataTransfer.setData("text/plain", payload.title);
e.dataTransfer.effectAllowed = "copyMove";
el.style.opacity = "0.6";
});
el.addEventListener("dragend", () => {
el.style.opacity = "";
});
}
/**
* Attach drag handlers to all matching elements within a root.
* `selector` matches the card elements.
* `payloadFn` extracts the payload from each matched element.
*/
export function makeDraggableAll(
root: Element | ShadowRoot,
selector: string,
payloadFn: (el: HTMLElement) => RSpaceItemPayload | null,
) {
root.querySelectorAll<HTMLElement>(selector).forEach((el) => {
const payload = payloadFn(el);
if (payload) makeDraggable(el, payload);
});
}