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

+6 -2
View File
@@ -128,9 +128,13 @@ export async function graph(t) {
);
const dataPort = await json(`__gm.graph.portAt(${JSON.stringify(newNode.id)}, 'message', false)`);
await drag(fromPort.x, fromPort.y, dataPort.x, dataPort.y, 16);
// Released on the port itself, which sits at the node's very edge: that is a drop on the node, not
// on empty canvas. An open palette here swallows every later click – it did, for four checks.
check(
'incompatible ports are rejected',
(await graphCounts()).edges === before13.edges + 1 && s.mode === 'edit',
'incompatible ports are rejected without taking the drop for empty canvas',
(await graphCounts()).edges === before13.edges + 1 &&
(await state()).mode === 'edit' &&
!(await evaluate(`__gm.locate('Search nodes…')`)),
);
await shot('18-connected');