/**
* rgui HTML overlays — real DOM controls glued to nodes.
*
* Canvas cannot host interactive form controls, so rgui owns a positioned
* DOM layer above the canvas and keeps each registered element glued to its
* node's screen rect every frame (drag included). Size is screen-fixed
* (overlays do not scale with zoom); only position follows.
*
* Visibility reuses the native readability rule: an overlay hides (without
* being destroyed) whenever its node is collapsed into a pseudo-node,
* fully off-screen, or too small to read — so collapsed stacks show only
* boundary ports + the pseudo summary, never per-node config.
*/
import { type Graph, type GraphNode } from "../core/graph.js";
import type { ViewTransform } from "../core/grid.js";
import type { RgRule } from "../core/rule.js";
export interface NodeHtmlOverlay {
el: HTMLElement;
/** where to glue relative to the node rect (default "right") */
anchor?: "right" | "below" | "over";
/**
* offset from the anchor point — screen px in "fixed" mode, WORLD units
* in "zoom" mode (it belongs to the node's local layout, so it scales)
*/
offset?: {
x: number;
y: number;
};
/**
* "fixed" (default): screen-constant size, position glued to the node.
* "zoom": scales with view.k like part of the node (lay out for k=1).
* "fit": rgui measures the element's natural size and applies
* scale = min(maxScale, node screen area / natural size) — the control fits
* the node's on-screen area, whatever the node type's size.
* In zoom/fit modes, when the applied scale drops below `minScale` the
* overlay hides and the native/summarized content takes over.
*/
scale?: "fixed" | "zoom" | "fit";
/**
* zoom/fit modes: hide when the applied scale drops below this
* (default 0.75) — an unreadable control yields to the summary.
* Hide always wins over scaling.
*/
minScale?: number;
/**
* fit mode: cap on the applied scale (default 1 — never upscale past the
* element's natural size, keeping it crisp). Raise above 1 to let a small
* overlay UPSCALE to fill a larger node (it grows past natural size, so it
* fills the node's screen rect instead of sitting at native size with the
* node showing around it — at the cost of some blur on a bitmap/canvas child).
*/
maxScale?: number;
/**
* "node": constrain the overlay to the node's screen rect (never larger
* than the node); overflowing content scrolls ("auto", default) or is
* cut ("hidden"). "viewport" (default): clipped by the viewport only.
*/
clip?: "node" | "viewport" | "none";
overflow?: "hidden" | "auto";
/**
* pointer-events mode (default true). When true, only actual CONTROLS
* inside the element receive pointer events (inputs, selects, buttons,
* links, [contenteditable], [data-rgui-interactive]) — the background is
* click-through so node drag / canvas pan keep working underneath.
* Mark custom widgets with data-rgui-interactive.
*/
interactive?: boolean;
/** called when the overlay is unmounted (replaced, node gone, destroy) */
destroy?: () => void;
}
export interface OverlayManager {
/** glue/refresh all overlays for the current frame */
sync(graph: Graph, visibleNodes: GraphNode[] | null, view: ViewTransform, rule: RgRule,
/**
* screen rects (CSS px) cut OUT of the overlay layer — canvas-native
* chrome (panels) that must stay visible and clickable above HTML
* overlays. Clipping also removes pointer hits, so presses over a
* cutout reach the canvas.
*/
cutouts?: Array<{
x: number;
y: number;
w: number;
h: number;
}>): void;
destroy(): void;
}
export declare function createOverlayManager(canvas: HTMLCanvasElement, opts?: {
/**
* re-dispatch wheel events here (usually the rgui canvas) so pan/zoom
* keeps working over overlays instead of scrolling the page. A wheel is
* NOT forwarded when an ENGAGED overlay's inner scrollable can consume it.
*/
forwardWheelTo?: HTMLElement;
/**
* is this node engaged (selected)? An overlay only captures the wheel for
* its own scrolling once engaged — selected, or holding DOM focus. Merely
* hovering it must not steal the wheel, or a pan that sweeps the cursor
* across a node stalls mid-gesture.
*/
isNodeEngaged?: (nodeId: string) => boolean;
/** map view-space anchor points to raw screen (viewport rotation) */
transformPoint?: (x: number, y: number) => readonly [number, number];
}): OverlayManager;
//# sourceMappingURL=overlayLayer.d.ts.map