Make an edge drag say where it will land, and offer nodes when it lands nowhere

Dragging an edge now rings the port it would connect to and snaps the line
there. A drop on a node's body takes that node's first free compatible port,
or the last compatible one when none is free, replacing its link. A drop into
empty space opens the palette filtered to the node types the edge could reach
at all, and the picked node arrives wired - node and link as one undo step,
so a single undo takes back the whole gesture.

The decision of what fits what lives in core/graph/dropTarget.ts as pure
functions, tested directly; the canvas only draws the answer. The palette
takes an optional filter rather than knowing about drags.

Verified remote on the Windows box (GPU): ALL PASSED, 284 checks.
This commit is contained in:
root committed 2026-09-09 12:29:57 +02:00
1 parent 633f01cc46
commit ebad3fd530
12 files changed
+453 -28

No files matched your search

+8 -1
View File
@@ -76,6 +76,8 @@ export class NodeView extends Widget {
private paramLines: string[] = [];
selected = false;
hot = false;
/** Port a running edge drag would connect to, drawn with a ring so the drop is predictable. */
targetPort: { port: string; isOutput: boolean } | null = null;
/** Data inputs that currently have a connection (their inline value is hidden). */
private connected = new Set<string>();
@@ -215,7 +217,12 @@ export class NodeView extends Widget {
this.ports.clear();
const r = PORT_RADIUS;
for (const { port, x, y } of this.portCentres()) {
for (const { port, isOutput, x, y } of this.portCentres()) {
if (this.targetPort?.port === port.key && this.targetPort.isOutput === isOutput) {
// A gap in the node colour first, so the ring stays visible on the white exec pin too.
this.ports.circle(x, y, r + 2).stroke({ width: 2, color: c.node });
this.ports.circle(x, y, r + 4).stroke({ width: 2, color: c.portTarget });
}
if (port.type === 'exec') {
// A pentagon pointing right: the Blueprint-style exec pin.
this.ports