@infinit-canvas/react 0.1.19 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -61,13 +61,123 @@ function App() {
61
61
  | Rendering | DOM (React divs + SVG) | OffscreenCanvas + Web Worker |
62
62
  | Max nodes (60fps) | ~500 | 5,000+ |
63
63
  | Main thread | Blocked during render | Always free |
64
- | Custom nodes | React components | Hybrid: canvas + DOM overlay |
64
+ | Custom nodes | React components (all DOM) | Hybrid: canvas + spatial DOM |
65
65
  | API | React Flow API | Same API (drop-in compatible) |
66
66
 
67
+ ## Architecture
68
+
69
+ ```
70
+ ┌─────────────────────────────────┐
71
+ │ Your React App │
72
+ └──────────┬──────────────────────┘
73
+
74
+ ┌──────────▼──────────────────────┐
75
+ │ <InfiniteCanvas> │
76
+ │ │
77
+ │ ┌────────────┐ ┌────────────┐ │
78
+ │ │ Canvas │ │ DOM │ │
79
+ │ │ Worker │ │ Overlay │ │
80
+ │ │ │ │ │ │
81
+ │ │ All nodes │ │ Nearest 50 │ │
82
+ │ │ as styled │ │ nodes as │ │
83
+ │ │ canvas │ │ full React │ │
84
+ │ │ primitives │ │ components │ │
85
+ │ └────────────┘ └────────────┘ │
86
+ └──────────────────────────────────┘
87
+ ```
88
+
89
+ **The key insight:** Most nodes don't need to be DOM elements. Only the ones near your viewport get promoted to real React components. The rest render as styled canvas primitives via a Web Worker — zero DOM cost.
90
+
91
+ ## Spatial DOM Promotion
92
+
93
+ By default, up to **50 custom nodes** nearest to your viewport center are rendered as full React components. Everything else renders on canvas. This gives you rich interactivity where you need it and canvas performance everywhere else.
94
+
95
+ ```jsx
96
+ <InfiniteCanvas
97
+ nodes={nodes}
98
+ edges={edges}
99
+ nodeTypes={{ workflow: WorkflowNode }}
100
+ domNodeLimit={50} // Max DOM nodes (default: 50, 0 = pure canvas)
101
+ canvasNodeTypes={{ // How non-DOM nodes look on canvas
102
+ workflow: {
103
+ fill: '#f0f9ff',
104
+ stroke: '#c7d8f0',
105
+ radius: 10,
106
+ accent: { side: 'left', width: 5, color: '#3b82f6' },
107
+ icon: { dataField: 'icon', x: 20, size: 18 },
108
+ title: { dataField: 'label', x: 40, y: 16 },
109
+ subtitle: { dataField: 'description', x: 40, y: 36 },
110
+ badge: { dataField: 'badge', bg: '#3b82f6' },
111
+ }
112
+ }}
113
+ />
114
+ ```
115
+
116
+ ### Promotion rules (priority order):
117
+ 1. **Pinned nodes** — user clicked the pin button, stays DOM forever
118
+ 2. **Selected/dragging nodes** — always promoted while interacting
119
+ 3. **Nearest visible nodes** — fills remaining `domNodeLimit` slots by distance to viewport center
120
+
121
+ ### Pin nodes to DOM
122
+
123
+ Every DOM-promoted node shows a pin button on hover. Click it to keep that node as a full React component even when you scroll away. Useful for nodes with live data, inputs, or interactive content.
124
+
125
+ ## Canvas Node Types
126
+
127
+ Three ways to define how nodes look when rendered on canvas (non-DOM):
128
+
129
+ ### 1. Declarative Config (recommended)
130
+
131
+ Define node appearance with a config object. The worker draws shapes, text, icons, and badges per node — reading from `node.data` for dynamic content.
132
+
133
+ ```jsx
134
+ canvasNodeTypes={{
135
+ workflow: {
136
+ fill: '#f0f9ff',
137
+ stroke: '#c7d8f0',
138
+ strokeWidth: 1,
139
+ radius: 10,
140
+ accent: { side: 'left', width: 5, color: '#3b82f6' },
141
+ icon: { dataField: 'icon', x: 20, size: 18 },
142
+ title: { dataField: 'label', x: 40, y: 16, font: '600 13px system-ui', color: '#1e293b' },
143
+ subtitle: { dataField: 'description', x: 40, y: 36, font: '11px system-ui', color: '#64748b' },
144
+ badge: { dataField: 'badge', bg: '#3b82f6', color: '#fff' },
145
+ }
146
+ }}
147
+ ```
148
+
149
+ ### 2. SVG String
150
+
151
+ Provide an SVG string — converted to `ImageBitmap` and drawn via `drawImage`. Good for static visual shells (the worker still draws `node.data.label` on top).
152
+
153
+ ```jsx
154
+ canvasNodeTypes={{
155
+ workflow: `<svg xmlns="http://www.w3.org/2000/svg" width="160" height="70">
156
+ <rect x="1" y="1" width="158" height="68" rx="10" fill="#f0f9ff" stroke="#c7d8f0"/>
157
+ <rect x="1" y="1" width="6" height="68" rx="3" fill="#3b82f6"/>
158
+ </svg>`
159
+ }}
160
+ ```
161
+
162
+ ### 3. Function (per-node variation)
163
+
164
+ Provide a function `(data) => svgString` for per-node bitmaps. Results are deduplicated and cached — if 5000 nodes share 8 color variants, only 8 bitmaps are created.
165
+
166
+ ```jsx
167
+ canvasNodeTypes={{
168
+ workflow: (data) => `<svg xmlns="http://www.w3.org/2000/svg" width="160" height="70">
169
+ <rect x="1" y="1" width="158" height="68" rx="10" fill="${data.color}" stroke="#ccc"/>
170
+ </svg>`
171
+ }}
172
+ ```
173
+
67
174
  ## Features
68
175
 
69
176
  - **Full React Flow API** — nodes, edges, handles, connections, selection, drag, zoom, pan
70
177
  - **Custom node & edge types** — use any React component
178
+ - **Spatial DOM virtualization** — only nearest N nodes are real DOM elements
179
+ - **Canvas node rendering** — declarative config, SVG bitmap, or per-node functions
180
+ - **Node pinning** — keep specific nodes as DOM permanently
71
181
  - **Built-in components** — Controls, MiniMap, Background, Panel, Handle, NodeResizer, NodeToolbar, EdgeLabelRenderer, ViewportPortal
72
182
  - **All hooks** — useReactFlow, useNodes, useEdges, useViewport, useConnection, useNodesData, useOnViewportChange, useOnSelectionChange, useKeyPress, useStore, useStoreApi, + more
73
183
  - **Sub-flows** — parentId, extent: 'parent'
@@ -78,11 +188,10 @@ function App() {
78
188
  - **Snap to grid** — configurable grid snapping
79
189
  - **Undo/redo** — built-in history management
80
190
  - **Delete validation** — onBeforeDelete async callback
81
- - **Error handling** — onError callback
191
+ - **Frustum culling** — spatial grid index for O(visible) rendering
192
+ - **LOD rendering** — handles and text hidden at low zoom for performance
82
193
  - **noDragClassName / noPanClassName** — prevent drag/pan on specific elements
83
194
  - **Elevate on select** — bring nodes/edges to front on selection
84
- - **Node virtualization** — only visible custom nodes are mounted in DOM
85
- - **Frustum culling** — spatial grid index for O(visible) rendering
86
195
 
87
196
  ## Props
88
197
 
@@ -96,8 +205,10 @@ function App() {
96
205
  onConnect={onConnect}
97
206
 
98
207
  // Types
99
- nodeTypes={nodeTypes}
100
- edgeTypes={edgeTypes}
208
+ nodeTypes={nodeTypes} // React components for custom nodes
209
+ edgeTypes={edgeTypes} // React components for custom edges
210
+ canvasNodeTypes={configs} // Canvas rendering: config | SVG | function
211
+ domNodeLimit={50} // Max DOM nodes (0 = pure canvas)
101
212
 
102
213
  // Events
103
214
  onNodeClick onNodeDoubleClick onNodeContextMenu
@@ -118,6 +229,7 @@ function App() {
118
229
  noDragClassName="nodrag" noPanClassName="nopan"
119
230
  deleteKeyCode="Delete"
120
231
  isValidConnection={fn}
232
+ edgeRouting={true}
121
233
 
122
234
  // Viewport
123
235
  fitView initialCamera={{ x: 0, y: 0, zoom: 1 }}
@@ -150,6 +262,14 @@ function App() {
150
262
 
151
263
  `applyNodeChanges` · `applyEdgeChanges` · `addEdge` · `isNode` · `isEdge` · `getConnectedEdges` · `getIncomers` · `getOutgoers` · `getNodesBounds` · `getBezierPath` · `getSmoothStepPath` · `getStraightPath` · `getSimpleBezierPath` · `snapPosition` · `reconnectEdge`
152
264
 
265
+ ## Migration from React Flow
266
+
267
+ 1. Replace `reactflow` with `@infinit-canvas/react` in your imports
268
+ 2. Replace `reactflow/dist/style.css` with `@infinit-canvas/react/styles.css`
269
+ 3. That's it — same API, same hooks, same components
270
+
271
+ For large node counts, add `canvasNodeTypes` to define how nodes look on canvas and set `domNodeLimit` to control the DOM budget.
272
+
153
273
  ## Sponsor
154
274
 
155
275
  If this package saves you time, consider supporting its development: