@pixxl-tools/cangraph
v0.1.0
Published
Canvas-first graph editing and React components for Pixxl tools.
Readme
@pixxl-tools/cangraph
Canvas-first graph editor.
@pixxl-tools/cangraph owns graph data helpers, node/edge interaction, viewport state, custom node bridge, canvas rendering, selection adapters, and graph-specific CanvasDocument persona helpers. Shared product chrome lives in @pixxl-tools/canvas/react.
Package status: pre-1.0 public package. APIs may change before 1.0.
Quick Start
import { useCallback } from "react";
import {
Position,
addEdge,
} from "@pixxl-tools/cangraph";
import {
Background,
Controls,
GraphCanvas,
Handle,
MiniMap,
useEdgesState,
useNodesState,
} from "@pixxl-tools/cangraph/react";
const initialNodes = [
{ id: "a", type: "task", position: { x: 0, y: 0 }, data: { label: "A" } },
{ id: "b", type: "task", position: { x: 240, y: 0 }, data: { label: "B" } },
];
const initialEdges = [{ id: "a-b", source: "a", target: "b" }];
function TaskNode({ data }) {
return (
<div style={{ position: "relative", padding: 16 }}>
<Handle type="target" position={Position.Left} />
{data.label}
<Handle type="source" position={Position.Right} />
</div>
);
}
export function Flow() {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const onConnect = useCallback(
(connection) => setEdges((current) => addEdge(connection, current)),
[setEdges],
);
return (
<GraphCanvas
nodes={nodes}
edges={edges}
nodeTypes={{ task: TaskNode }}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
fitView
>
<Background />
<Controls />
<MiniMap />
</GraphCanvas>
);
}Install/CSS
Install the package with shared canvas and React peers:
pnpm add @pixxl-tools/cangraph @pixxl-tools/canvas react react-domReact graph surfaces need package imports plus shared canvas chrome styles in the host app:
import "@pixxl-tools/canvas/styles.css";Use @pixxl-tools/cangraph/core for non-React utilities and @pixxl-tools/cangraph/react for UI bindings.
Public API
@pixxl-tools/cangraph: root export for core, selection, workspace, and CanvasDocument persona helpers.@pixxl-tools/cangraph/core: graph types, changes, hit-test helpers, path helpers, and utilities.@pixxl-tools/cangraph/document:graphDataToCanvasDocumentandcanvasDocumentToGraphData.@pixxl-tools/cangraph/react:GraphCanvas, handles, panels, controls, minimap, edge labels, node resize controls, provider, store hooks, viewport hooks, and theme.@pixxl-tools/cangraph/examples: documented example fixtures used by docs and tests.
Controlled And Uncontrolled
- Controlled: pass
nodes,edges,onNodesChange, andonEdgesChange. - Uncontrolled: pass
defaultNodesanddefaultEdges; cangraph owns state. GraphCanvasProvider,useGraphCanvas,useStore, and state hooks mirror familiar graph editor names.
Custom Nodes
Custom nodes are normal React components. They receive NodeProps, can render local UI, and can include handles, toolbars, and resize controls.
Examples:
examples/cangraph/custom-workflow.tsxexamples/cangraph/canvas-bridge-showcase.tsxexamples/cangraph/component-gallery.tsxexamples/cangraph/custom-edge-components.tsxexamples/cangraph/large-custom-workflow.tsxcangraph/docs/api-reference.md
Model/Persistence
Cross-product storage uses CanvasDocument from @pixxl-tools/canvas. cangraph exposes cangraph persona helpers from the root export.
Graph data is not a separate root format. Nodes are normal scene elements; edges are connector elements using anchors. Unknown canvas element kinds must round-trip unchanged.
Adapter usage:
import {
canvasDocumentToGraphData,
graphDataToCanvasDocument,
} from "@pixxl-tools/cangraph/document";
const document = graphDataToCanvasDocument({ nodes, edges, viewport });
const graph = canvasDocumentToGraphData(document);Renderer And Bridge Notes
- Canvas owns graph state, viewport work, background, minimap, hit testing, and edge rendering.
- Live custom nodes render through a DOM overlay bridge because canvas cannot host live inputs, focus, portals, or component lifecycle.
- Use
onlyRenderVisibleElementsfor large graphs so offscreen custom nodes are culled while edges keep rendering from cached measurements.
Examples
Runnable examples:
examples/cangraph/quickstart.ts: controlled nodes/edges plus CanvasDocument persistence.examples/cangraph/custom-workflow.tsxexamples/cangraph/canvas-bridge-showcase.tsxexamples/cangraph/component-gallery.tsxcangraph/docs/api-reference.md
Testing
Relevant checks:
pnpm testLimits
- Canvas renders graph chrome and edges; live custom node DOM stays in overlay bridge.
- Interaction lock controls are compatibility UI until broader interaction parity lands.
- Layout algorithms are product-owned; shared canvas chrome should not absorb graph layout internals.
Troubleshooting
- If edges route from stale sizes, check custom node measurement and visibility culling.
- If controlled graphs do not update, verify
nodes,edges, and change handlers are passed together. - If app chrome differs from chart/text/draw, inspect shared canvas shell usage before local CSS changes.
Migration/Versioning
Keep graph model changes additive before 1.0. Prefer @pixxl-tools/cangraph/document for CanvasDocument adapters and avoid depending on internal store shapes.
