@ship-it-ui/graph-editor
v0.0.4
Published
Graph-editing canvas for the Ship-It design system. React Flow under the hood; same `elements[]` shape as `@ship-it-ui/cytoscape` so consumers can swap viewer ↔ editor without reshaping data.
Downloads
349
Maintainers
Readme
@ship-it-ui/graph-editor
<GraphEditorCanvas> — the editing analog of <GraphCanvas> (from @ship-it-ui/cytoscape). React Flow under the hood; same elements[] shape on the input so consumers can swap viewer ↔ editor without reshaping data.
How this fits in
Part of the Ship-It Design System. Sibling to @ship-it-ui/cytoscape (read-only graph viewer). Both packages consume @ship-it-ui/graph-tokens for theme-token resolution; neither imports the other at runtime — tree-shaking is enforced by package boundary.
Install + import the stylesheet
pnpm add @ship-it-ui/graph-editorThen once at your app entry (app/layout.tsx for Next.js, main.tsx for Vite, etc.):
import '@ship-it-ui/graph-editor/styles.css';The component intentionally does not import its own CSS. Next.js's App Router rejects library-internal global CSS, and explicit consumer imports let you control load order against your own theme. The stylesheet pulls in @xyflow/react/dist/style.css and layers Ship-It overrides on top.
Quick start
'use client';
import '@ship-it-ui/graph-editor/styles.css';
import { GraphEditorCanvas, type GraphElement } from '@ship-it-ui/graph-editor';
import { useState } from 'react';
const INITIAL: GraphElement[] = [
{ data: { id: 'a', label: 'Alpha', entityType: 'service' }, position: { x: 0, y: 0 } },
{ data: { id: 'b', label: 'Beta', entityType: 'service' }, position: { x: 200, y: 0 } },
{ data: { id: 'e-ab', source: 'a', target: 'b' } },
];
export default function Editor() {
const [elements, setElements] = useState(INITIAL);
return (
<div style={{ width: '100%', height: 480 }}>
<GraphEditorCanvas
elements={elements}
onConnect={({ id, source, target }) =>
setElements((prev) => [...prev, { data: { id, source, target } }])
}
onNodeMove={(id, position) =>
setElements((prev) => prev.map((el) => (el.data.id === id ? { ...el, position } : el)))
}
/>
</div>
);
}See the docs site for the full API and live examples (toolbar slot, custom-node renderer, keyboard, undo/redo).
Built-in behaviors
- Pan + zoom + mini-map (wraps
@ship-it-ui/shipit's<GraphMinimap>so the editor looks identical to the viewer). - Click-to-select; pane-click to clear.
- Drag-to-connect; drag-to-move (
onNodeMove). Delete/Backspaceremoves selection; arrow keys nudge (Shift = 32px);Escapeclears;⌘Z/⌘⇧Zundo / redo.- Theme-token sync via
@ship-it-ui/graph-tokens. - Built-in keyboard-accessible "+ Add" button when no
toolbaris supplied. role="application"on the canvas root.
Engine
React Flow (@xyflow/react@^12). The viewer (<GraphCanvas>) uses Cytoscape.js — same elements[] shape passes through via the round-trip-tested adapter (toFlowElements / toCytoscapeElements).
