flow-to-graph.ts1.8 KBView on GitHub /**
* React Flow → domain. The inverse of `graphToFlow`, and deliberately much smaller than it.
*
* Only TWO gestures on the canvas change the document, and each maps to exactly one operation:
*
* a drag → `moveNode`, ONE `graphLayout` key
* a connection → `connect`, with the currently selected edge kind
*
* Everything else the canvas shows — the layout it computed, the lint rings, the hydrated
* values, the selection — is an OVERLAY and is never written back. That is why there is no
* `flowToGraph(nodes, edges)` that serializes the whole canvas: a whole-canvas save is how a
* derived annotation becomes a persisted field, and how one person's open tab overwrites
* another's concurrent edit.
*/
import type { Connection } from '@xyflow/react';
import type { GraphFlowNode } from './graph-flow-types';
import type { GraphPosition } from '@zero/server/graph';
/** A drag, as the one `moveNode` call it is. */
export function dragToMove(node: Pick<GraphFlowNode, 'id' | 'position'>): {
node: string;
position: GraphPosition;
} {
return { node: node.id, position: { x: node.position.x, y: node.position.y } };
}
/**
* A drawn connection, as the `connect` call it is.
*
* Returns `null` for a connection React Flow can produce but a graph cannot hold: a missing
* endpoint, or a self-connection. Refusing here rather than at the server keeps the canvas from
* showing an edge for the moment it takes the write to come back and fail.
*/
export function connectionToEdge(
connection: Connection,
kind: string,
): { source: string; target: string; kind: string } | null {
if (!connection.source || !connection.target) return null;
if (connection.source === connection.target) return null;
if (!kind) return null;
return { source: connection.source, target: connection.target, kind };
}