|
1 | | -<p> |
2 | | - <img width="100%" src="https://assets.solidjs.com/banner?type=Ecosystem&background=tiles&project=solid-flow" alt="solid-flow"> |
| 1 | +<p align="center"> |
| 2 | + <img src="https://assets.solidjs.com/banner?project=solid-flow&type=Ecosystem&background=tiles" alt="@dschz/solid-flow banner" /> |
3 | 3 | </p> |
4 | 4 |
|
5 | | -# Solid Flow |
| 5 | +# @dschz/solid-flow |
6 | 6 |
|
7 | | -Solid Flow is a port of [Svelte Flow](https://svelteflow.dev/) for SolidJS. |
| 7 | +[](LICENSE) |
| 8 | +[](https://www.npmjs.com/package/@dschz/solid-flow) |
| 9 | +[](https://bundlephobia.com/package/@dschz/solid-flow) |
| 10 | +[](https://github.com/dsnchz/solid-flow/actions/workflows/ci.yaml) |
8 | 11 |
|
9 | | -It is a highly customizable component for building interactive graphs and node-based editors. |
| 12 | +> Solid Flow is a port of [React Flow](https://reactflow.dev/) and [Svelte Flow](https://svelteflow.dev/) for SolidJS. |
10 | 13 |
|
11 | 14 | ☣️ **Solid Flow is alpha and currently under development. The API intends to follow React/Svelte Flow closely but some things might change for the sake of SolidJS.** ☣️ |
12 | 15 |
|
13 | | -## Remaining TODOs for v0.1.0: |
| 16 | +## Current Unsupported Features: |
14 | 17 |
|
15 | | -- [x] Get node dragging working |
16 | | -- [x] Add core CSS styles from @xyflow/system and Svelte Flow |
17 | | -- [ ] Synchronize userland state with internal Solid Flow state |
18 | | -- [ ] Port Svelte Flow tests |
19 | | -- [ ] Add a playground app and smoketest library |
20 | | -- [ ] Add more examples |
21 | | -- [ ] Add a documentation site |
| 18 | +- `onlyRenderVisibleElements` prop: the ability to only render visible elements on screen. |
| 19 | +- Custom MiniMap nodes: the ability to render custom node visuals in the minimap |
| 20 | +- Edge Reconnect Anchors: the ability to re-connect already connected edges |
22 | 21 |
|
23 | 22 | ## Key Features |
24 | 23 |
|
25 | 24 | - **Easy to use:** Seamless zooming and panning, single- and multi selection of graph elements and keyboard shortcuts are supported out of the box |
26 | | -- **Customizable:** Different [node](https://svelteflow.dev/examples) and [edge types](https://svelteflow.dev/examples/edges/edge-types) and support for custom nodes with multiple handles and custom edges |
27 | | -- **Fast rendering:** Only nodes that have changed are re-rendered |
28 | | -- **Hooks and Utils:** [Hooks](https://svelteflow.dev/api-reference/hooks) for handling nodes, edges and the viewport and graph [helper functions](https://svelteflow.dev/api-reference/utils) |
29 | | -- **Plugin Components:** [Background](https://svelteflow.dev/api-reference/components/background), [MiniMap](https://svelteflow.dev/api-reference/components/minimap) and [Controls](https://svelteflow.dev/api-reference/components/controls) |
30 | | -- **Reliable**: Written in [Typescript](https://www.typescriptlang.org) |
| 25 | +- **Customizable:** Different node types (Input, Output, Default, Group) and edge types (Bezier, Straight, Step, SmoothStep) with full support for custom nodes and edges |
| 26 | +- **Fast rendering:** Only nodes that have changed are re-rendered using SolidJS's fine-grained reactivity |
| 27 | +- **Rich Plugin Ecosystem:** Background patterns, Interactive MiniMap, Zoom Controls, Node Toolbar, and Node Resizer components |
| 28 | +- **Powerful Hooks:** Comprehensive set of reactive hooks for nodes, edges, viewport, connections, and data management |
| 29 | +- **Full Accessibility:** Complete keyboard navigation, screen reader support, ARIA labels, and focus management |
| 30 | +- **Drag & Drop:** Built-in dragging for nodes, external drag-and-drop support, and customizable drag handles |
| 31 | +- **Advanced Features:** Node grouping, intersection detection, connection validation, and subflow support |
| 32 | +- **TypeScript First:** Fully typed API with generic type support and IntelliSense integration |
31 | 33 |
|
32 | 34 | ## Installation |
33 | 35 |
|
34 | 36 | The easiest way to get the latest version of Solid Flow is to install it via npm, yarn or pnpm: |
35 | 37 |
|
36 | 38 | ```sh |
37 | | -npm install @xyflow/system solid-flow |
| 39 | +npm install @dschz/solid-flow |
| 40 | +``` |
| 41 | + |
| 42 | +## Quick Start |
| 43 | + |
| 44 | +This is a basic example to get you started. For more advanced examples and full API documentation, explore the playground examples included in this repository. |
| 45 | + |
| 46 | +```tsx |
| 47 | +import { addEdge, type EdgeConnection, createEdgeStore, createNodeStore } from "@dschz/solid-flow"; |
| 48 | +import { SolidFlow, Controls, Background, MiniMap } from "@dschz/solid-flow"; |
| 49 | +import "@dschz/solid-flow/styles"; // Required styles |
| 50 | + |
| 51 | +export default function Flow() { |
| 52 | + // Use createNodeStore and createEdgeStore for reactive state management |
| 53 | + const [nodes, setNodes] = createNodeStore([ |
| 54 | + { |
| 55 | + id: "1", |
| 56 | + type: "input", |
| 57 | + data: { label: "Input Node" }, |
| 58 | + position: { x: 250, y: 0 }, |
| 59 | + }, |
| 60 | + { |
| 61 | + id: "2", |
| 62 | + type: "default", |
| 63 | + data: { label: "Default Node" }, |
| 64 | + position: { x: 100, y: 100 }, |
| 65 | + }, |
| 66 | + { |
| 67 | + id: "3", |
| 68 | + type: "output", |
| 69 | + data: { label: "Output Node" }, |
| 70 | + position: { x: 250, y: 200 }, |
| 71 | + }, |
| 72 | + ]); |
| 73 | + |
| 74 | + const [edges, setEdges] = createEdgeStore([ |
| 75 | + { id: "e1-2", source: "1", target: "2" }, |
| 76 | + { id: "e2-3", source: "2", target: "3" }, |
| 77 | + ]); |
| 78 | + |
| 79 | + const onConnect = (connection: EdgeConnection) => { |
| 80 | + /** |
| 81 | + * Solid Flow updates the node/edge stores internally. The user-land edge store will have the connection inserted by the time onConnect fires so we can just go ahead and update the state of it |
| 82 | + */ |
| 83 | + setEdges( |
| 84 | + (edge) => edge.id === connection.id, |
| 85 | + produce((edge) => { |
| 86 | + edge.animated = true; |
| 87 | + }), |
| 88 | + ); |
| 89 | + }; |
| 90 | + |
| 91 | + return ( |
| 92 | + <SolidFlow nodes={nodes} edges={edges} onConnect={onConnect} fitView> |
| 93 | + <Controls /> |
| 94 | + <MiniMap /> |
| 95 | + <Background variant="dots" /> |
| 96 | + </SolidFlow> |
| 97 | + ); |
| 98 | +} |
| 99 | +``` |
| 100 | + |
| 101 | +## Core Components |
| 102 | + |
| 103 | +### Built-in Node Types |
| 104 | + |
| 105 | +- **InputNode** - Nodes with source handles only (starting points) |
| 106 | +- **OutputNode** - Nodes with target handles only (ending points) |
| 107 | +- **DefaultNode** - Standard nodes with both source and target handles |
| 108 | +- **GroupNode** - Container nodes for organizing other nodes |
| 109 | + |
| 110 | +### Built-in Edge Types |
| 111 | + |
| 112 | +- **BezierEdge** - Smooth curved connections (default) |
| 113 | +- **StraightEdge** - Direct straight line connections |
| 114 | +- **StepEdge** - Right-angle step connections |
| 115 | +- **SmoothStepEdge** - Rounded step connections |
| 116 | + |
| 117 | +### Plugin Components |
| 118 | + |
| 119 | +- **Background** - Customizable canvas backgrounds (dots, lines, cross patterns) |
| 120 | +- **Controls** - Zoom in/out, fit view, lock/unlock interactions |
| 121 | +- **MiniMap** - Interactive overview with viewport indicator |
| 122 | +- **NodeToolbar** - Context-sensitive toolbars for nodes |
| 123 | +- **NodeResizer** - Real-time node resizing with handles |
| 124 | + |
| 125 | +## Hooks & Utilities |
| 126 | + |
| 127 | +### Essential Hooks |
| 128 | + |
| 129 | +```tsx |
| 130 | +// Main flow instance with full API |
| 131 | +const solidFlow = useSolidFlow(); |
| 132 | + |
| 133 | +// Reactive access to nodes and edges |
| 134 | +const nodes = useNodes(); |
| 135 | +const edges = useEdges(); |
| 136 | + |
| 137 | +// Viewport control and monitoring |
| 138 | +const viewport = useViewport(); |
| 139 | + |
| 140 | +// Connection state during drag operations |
| 141 | +const connection = useConnection(); |
| 142 | + |
| 143 | +// Reactive access to node data |
| 144 | +const nodeData = useNodesData(["node-1", "node-2"]); |
| 145 | + |
| 146 | +// Node connection information |
| 147 | +const connections = useNodeConnections("node-1"); |
| 148 | +``` |
| 149 | + |
| 150 | +### Utility Functions |
| 151 | + |
| 152 | +```tsx |
| 153 | +// Create reactive stores (replaces signals) |
| 154 | +const [nodes, setNodes] = createNodeStore(initialNodes); |
| 155 | +const [edges, setEdges] = createEdgeStore(initialEdges); |
| 156 | + |
| 157 | +// Update stores with SolidJS patterns |
| 158 | +import { produce } from "solid-js/store"; |
| 159 | +setNodes( |
| 160 | + (node) => node.id === "1", |
| 161 | + produce((node) => { |
| 162 | + node.position.x += 20; |
| 163 | + }), |
| 164 | +); |
| 165 | + |
| 166 | +// Add new connections |
| 167 | +setEdges(addEdge(connection, edges)); |
| 168 | + |
| 169 | +// Coordinate transformations (via useSolidFlow) |
| 170 | +const { screenToFlowPosition, flowToScreenPosition } = useSolidFlow(); |
| 171 | + |
| 172 | +// Node/edge utilities |
| 173 | +getNodesBounds(nodes); |
| 174 | +getIntersectingNodes(node, nodes); |
| 175 | +``` |
| 176 | + |
| 177 | +## Advanced Features |
| 178 | + |
| 179 | +### Custom Nodes and Edges |
| 180 | + |
| 181 | +Create fully customized components with multiple handles: |
| 182 | + |
| 183 | +```tsx |
| 184 | +import { Handle, type NodeProps } from "@dschz/solid-flow"; |
| 185 | + |
| 186 | +// Type-safe custom node component |
| 187 | +function CustomNode(props: NodeProps<{ label: string }, "custom">) { |
| 188 | + return ( |
| 189 | + <div class="custom-node" style={{ padding: "10px", background: "white" }}> |
| 190 | + <Handle type="target" position="top /> |
| 191 | + <div>{props.data.label}</div> |
| 192 | + <Handle type="source" position="bottom" id="output-a" /> |
| 193 | + <Handle type="source" position="bottom id="output-b" style={{ left: "80%" }} /> |
| 194 | + </div> |
| 195 | + ); |
| 196 | +} |
| 197 | + |
| 198 | +// Create type-safe node types |
| 199 | +const nodeTypes = { |
| 200 | + custom: CustomNode, |
| 201 | +} satisfies NodeTypes; |
| 202 | + |
| 203 | +// Use with typed store |
| 204 | +const [nodes] = createNodeStore<typeof nodeTypes>([...]); |
| 205 | + |
| 206 | +<SolidFlow nodeTypes={nodeTypes} nodes={nodes} ... /> |
| 207 | +``` |
| 208 | + |
| 209 | +### Connection Validation |
| 210 | + |
| 211 | +```tsx |
| 212 | +import { type Connection } from "@dschz/solid-flow"; |
| 213 | + |
| 214 | +const isValidConnection = (connection: Connection) => { |
| 215 | + // Custom validation logic |
| 216 | + return connection.source !== connection.target; |
| 217 | +}; |
| 218 | + |
| 219 | +const onConnect = (connection: Connection) => { |
| 220 | + console.log("New connection:", connection); |
| 221 | + setEdges(addEdge(connection, edges)); |
| 222 | +}; |
| 223 | + |
| 224 | +<SolidFlow |
| 225 | + isValidConnection={isValidConnection} |
| 226 | + onConnect={onConnect} |
| 227 | + ... |
| 228 | +/> |
| 229 | +``` |
| 230 | + |
| 231 | +### Event Handling |
| 232 | + |
| 233 | +```tsx |
| 234 | +<SolidFlow |
| 235 | + onNodeClick={(event, node) => console.log("Node clicked:", node)} |
| 236 | + onNodeDrag={(event, node) => console.log("Node dragged:", node)} |
| 237 | + onEdgeClick={(event, edge) => console.log("Edge clicked:", edge)} |
| 238 | + onPaneClick={(event) => console.log("Pane clicked")} |
| 239 | + onSelectionChange={(params) => console.log("Selection changed:", params)} |
| 240 | +/> |
| 241 | +``` |
| 242 | + |
| 243 | +## Accessibility |
| 244 | + |
| 245 | +Solid Flow includes comprehensive accessibility features: |
| 246 | + |
| 247 | +- Full keyboard navigation support |
| 248 | +- Screen reader compatibility with ARIA labels |
| 249 | +- Focus management and visual indicators |
| 250 | +- High contrast and color mode support |
| 251 | +- Customizable keyboard shortcuts |
| 252 | + |
| 253 | +## Performance |
| 254 | + |
| 255 | +- **Reactive Updates**: Only re-renders components when their specific data changes |
| 256 | +- **Viewport Optimization**: Option to render only visible elements (coming soon) |
| 257 | +- **Memory Efficient**: Optimized data structures for large graphs |
| 258 | +- **Stress Tested**: Handles hundreds of nodes smoothly |
| 259 | + |
| 260 | +## Examples |
| 261 | + |
| 262 | +The repository includes a comprehensive playground with 25+ examples: |
| 263 | + |
| 264 | +- **Basic Usage** - Simple flows and interactions |
| 265 | +- **Custom Nodes** - Creating specialized node types |
| 266 | +- **Edge Types** - Different connection styles |
| 267 | +- **Drag & Drop** - External elements and node creation |
| 268 | +- **Validation** - Connection rules and constraints |
| 269 | +- **Subflows** - Hierarchical node organization |
| 270 | +- **Performance** - Large dataset handling |
| 271 | +- **Accessibility** - Keyboard navigation and screen readers |
| 272 | + |
| 273 | +Run the examples locally: |
| 274 | + |
| 275 | +```bash |
| 276 | +bun start |
38 | 277 | ``` |
39 | 278 |
|
40 | 279 | ## Contributing: Getting Started |
|
0 commit comments