A drop asks the area the pointer already uses, so a port at the very edge is still the node

`nodeUnder()` recomputed the node's face as `0 <= x <= w`, while the pointer events follow the
`hitArea`, which reaches `PORT_HIT_RADIUS` past the edge. An input port sits at exactly x = 0, so the
global point rounded back landed a hair outside: the drop counted as one on empty canvas, the node
palette opened and swallowed every later click – four checks of step 6 at once. `NodeView` now
answers from that same `hitArea`, and the step also checks that no palette is open.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5 committed 2026-09-14 19:14:57 +02:00
1 parent 8143130ed2
commit 98fa9907fd
3 files changed
+16 -3

No files matched your search

+9
View File
@@ -137,6 +137,15 @@ export class NodeView extends Widget {
this.hitArea = new Rectangle(-PORT_HIT_RADIUS, 0, w + PORT_HIT_RADIUS * 2, h);
}
/**
* Whether a local point is on this node, by the same area its pointer events use. An input port
* sits at exactly x = 0, and rounding a global point back can land a hair outside it – which made
* a drop on such a port count as a drop on empty canvas and opened the palette.
*/
containsLocal(x: number, y: number): boolean {
return this.hitArea?.contains(x, y) ?? false;
}
/** `project` resolves asset references (Spawn, Is asset). */
sync(
node: GraphNode,