Split wiring, drags and the frame layer out of GraphCanvas (#215)

GraphCanvas had grown to 1406 lines. Wiring, dragging and the frame
views each carry their own state, so they now live in their own
classes behind a narrow host interface. Behaviour is unchanged.

- GraphCanvasHost is what the new classes see of the canvas.
- Wiring owns dragging a pin, the palette on a drop into empty space
  and "Make transition".
- GraphDrags owns moving nodes and frames, including snapping.
- AnnotationLayer holds the frame views. The test hooks stay on the
  canvas and read the views through the layer.
- BeadClock moves into beads.ts and can now be tested without a
  browser.
- The canvas builds host, wiring and drags in its constructor because
  state is a parameter property and not set during field init.
- GraphCanvas is down to 1019 lines.

Tests:
- ./check.sh: 145 files, 2192 tests, CHECK EXIT 0 (+2 for BeadClock)
- e2e 1-28,31,36: ALL PASSED, 932 checks
- New e2e check in 36k: a frame caught by the rubber band is also
  drawn as selected. No check covered that before. Against a bent
  build it fails with selected: false.
- Counter-checks for drop target, snapping and beads fail exactly
  the expected checks.
- Editor check sum is now 1314 (CI measured 1313 at 487b3aa).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Opus 5.5 committed 2026-09-23 10:20:05 +02:00
1 parent e31db3df1d
commit b830f9c747
9 files changed
+631 -454

No files matched your search

+6
View File
@@ -270,6 +270,12 @@ export async function graphGroups(t) {
caught.nodeIds.includes('gg-start'),
JSON.stringify(caught),
);
const drawnCaught = (await boxes()).find((box) => box.id === away.id);
check(
'the comment the band caught is drawn as selected',
drawnCaught?.selected === true,
JSON.stringify(drawnCaught),
);
// 36l. But a band that merely crosses a box leaves it alone – the rule that keeps a group, which
// wraps the nodes it holds, from joining every band drawn over any of them. It starts to the