@3plate/graph 0.1.6 → 0.1.9

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.
Files changed (2) hide show
  1. package/README.md +260 -99
  2. package/package.json +5 -5
package/README.md CHANGED
@@ -1,110 +1,273 @@
1
1
  # @3plate/graph
2
2
 
3
- Graph library with stable layout and incremental updates
3
+ A graph visualization library with **stable layouts** and **incremental updates**. Build interactive directed graphs that maintain their structure as data changes—perfect for visualizing pipelines, workflows, dependency trees, and state machines.
4
4
 
5
- ## Inspiration
5
+ ## Why @3plate/graph?
6
6
 
7
- This component is inspired by [IonGraph Web](https://spidermonkey.dev/blog/2025/10/28/iongraph-web.html) from the SpiderMonkey team.
7
+ Most graph libraries re-layout the entire graph when data changes, causing nodes to jump around unpredictably. @3plate/graph solves this with:
8
8
 
9
- ## Features
9
+ - **Stable layouts** — Nodes stay in predictable positions as the graph evolves
10
+ - **Incremental updates** — Add, remove, or modify nodes without full re-renders
11
+ - **Railroad-style edges** — Clean, orthogonal routing that avoids crossing nodes
12
+ - **Real-time ingestion** — Stream graph updates from WebSockets or files
10
13
 
11
- - Custom node rendering
12
- - Automatic graph layout
13
- - Stable layouts
14
- - Multiple orientations
15
- - Interactive features
16
- - Cycle detection
17
- - Edge styling
18
- - Pan and zoom
19
- - Mini-map
20
- - Animations
21
- - SVG for crisp details
22
- - Fast rendering
23
- - Builder mode
24
- - Incremental updates
25
- - Railroad-style edges
26
- - Configurable layout
27
- - React/Vue/Angular support
28
-
29
- ## Project Structure
30
-
31
- `@3plate/graph` can be used as a library with no framework dependencies, or you can use the
32
- components in `@3plate/graph-react`, `@3plate/graph-vue`, or `@3plate/graph-angular` which wrap
33
- the core library.
14
+ ## Quick Start
34
15
 
35
- ```
36
- graph/
37
- ├── packages/
38
- │ ├── core/
39
- │ │ ├── src/
40
- │ │ ├── package.json
41
- │ │ ├── tsconfig.json
42
- │ │ └── README.md
43
- │ │
44
- │ ├── react/
45
- │ │ ├── src/
46
- │ │ ├── package.json
47
- │ │ └── README.md
48
- │ │
49
- │ ├── vue/
50
- │ │ └── ...
51
- │ │
52
- │ └── angular/
53
- │ └── ...
54
-
55
- ├── apps/
56
- │ └── site/
57
- │ ├── src/
58
- │ ├── public/
59
- │ ├── astro.config.mjs
60
- │ └── package.json
61
-
62
- ├── .github/
63
- │ └── workflows/
64
- │ ├── publish-npm.yml
65
- │ └── deploy-pages.yml
66
-
67
- ├── pnpm-workspace.yaml
68
- ├── package.json
69
- ├── .npmrc
70
- ├── turbo.json
71
- └── README.md
72
- ```
73
-
74
- ## Installation
75
-
76
- ### Core Library
16
+ ### Vanilla JavaScript
77
17
 
78
18
  ```bash
79
19
  npm install @3plate/graph-core
80
20
  ```
81
21
 
82
- ### Framework Wrappers
22
+ ```typescript
23
+ import { graph } from '@3plate/graph-core'
24
+
25
+ const api = await graph({
26
+ root: 'my-graph',
27
+ nodes: [
28
+ { id: 'a', title: 'Start' },
29
+ { id: 'b', title: 'Process' },
30
+ { id: 'c', title: 'End' },
31
+ ],
32
+ edges: [
33
+ { source: 'a', target: 'b' },
34
+ { source: 'b', target: 'c' },
35
+ ],
36
+ })
37
+
38
+ // Update the graph incrementally
39
+ api.update(u => {
40
+ u.addNodes({ id: 'd', title: 'New Step' })
41
+ u.addEdges({ source: 'b', target: 'd' })
42
+ })
43
+ ```
44
+
45
+ ### React
83
46
 
84
47
  ```bash
85
- # React
86
48
  npm install @3plate/graph-react
49
+ ```
87
50
 
88
- # Vue
89
- npm install @3plate/graph-vue
90
-
91
- # Angular
92
- npm install @3plate/graph-angular
51
+ ```tsx
52
+ import { Graph } from '@3plate/graph-react'
53
+
54
+ function App() {
55
+ return (
56
+ <Graph
57
+ nodes={[
58
+ { id: 'a', title: 'Start' },
59
+ { id: 'b', title: 'Process' },
60
+ { id: 'c', title: 'End' },
61
+ ]}
62
+ edges={[
63
+ { source: 'a', target: 'b' },
64
+ { source: 'b', target: 'c' },
65
+ ]}
66
+ />
67
+ )
68
+ }
93
69
  ```
94
70
 
95
- ## Usage
71
+ ## Features
96
72
 
97
- ### Core (Framework-agnostic)
73
+ ### Layout & Rendering
74
+
75
+ - **Automatic layered layout** — Nodes are positioned in layers based on their connections
76
+ - **Multiple orientations** — Top-to-bottom, bottom-to-top, left-to-right, or right-to-left
77
+ - **SVG rendering** — Crisp graphics at any zoom level
78
+ - **Pan and zoom** — Navigate large graphs with mouse/touch controls
79
+ - **Custom node rendering** — Render any HTML content inside nodes
80
+
81
+ ### Interactivity
82
+
83
+ - **Edit mode** — Add, remove, and connect nodes with mouse interactions
84
+ - **Click handlers** — Respond to node and edge clicks
85
+ - **Keyboard navigation** — Step through graph history with arrow keys
86
+ - **Selection** — Visual feedback for selected nodes and edges
87
+
88
+ ### Theming
89
+
90
+ - **Light/dark mode** — Built-in themes with system preference detection
91
+ - **Node types** — Define custom styles per node type
92
+ - **Edge types** — Style edges by category (error, success, etc.)
93
+ - **CSS variables** — Full control over colors, borders, and shadows
94
+
95
+ ### Data Handling
96
+
97
+ - **History & time-travel** — Navigate through graph states with undo/redo
98
+ - **Real-time ingestion** — Connect to WebSocket or file sources for live updates
99
+ - **Snapshot & update modes** — Replace entire graph or apply incremental changes
100
+ - **Ports** — Define named input/output ports on nodes for precise edge routing
101
+
102
+ ### Graph Features
103
+
104
+ - **Cycle detection** — Automatically handles graphs with cycles
105
+ - **Edge markers** — Arrow, circle, diamond, and bar markers on edge endpoints
106
+ - **Dummy nodes** — Long edges are split with invisible waypoints for cleaner routing
107
+ - **Configurable spacing** — Control margins, edge spacing, and turn radius
108
+
109
+ ## Packages
110
+
111
+ | Package | Description |
112
+ |---------|-------------|
113
+ | [@3plate/graph-core](./packages/core/README.md) | Framework-agnostic core library |
114
+ | [@3plate/graph-react](./packages/react/README.md) | React components and hooks |
115
+ | [@3plate/graph-vue](./packages/vue/README.md) | Vue 3 components |
116
+ | [@3plate/graph-angular](./packages/angular/README.md) | Angular components |
117
+
118
+ ## Configuration
119
+
120
+ ### Graph Options
121
+
122
+ ```typescript
123
+ await graph({
124
+ root: 'my-graph',
125
+ nodes: [...],
126
+ edges: [...],
127
+ options: {
128
+ graph: {
129
+ orientation: 'LR', // 'TB' | 'BT' | 'LR' | 'RL'
130
+ nodeMargin: 20, // Space between nodes
131
+ layerMargin: 60, // Space between layers
132
+ edgeSpacing: 8, // Space between parallel edges
133
+ turnRadius: 8, // Rounded corner radius for edges
134
+ },
135
+ canvas: {
136
+ width: '100%',
137
+ height: 600,
138
+ padding: 40,
139
+ editable: true, // Enable edit mode
140
+ panZoom: true, // Enable pan and zoom
141
+ colorMode: 'system', // 'light' | 'dark' | 'system'
142
+ },
143
+ },
144
+ })
145
+ ```
98
146
 
99
- TODO
147
+ ### Custom Node Rendering
148
+
149
+ ```typescript
150
+ await graph({
151
+ root: 'my-graph',
152
+ nodes: myNodes,
153
+ edges: myEdges,
154
+ options: {
155
+ canvas: {
156
+ renderNode: (node) => {
157
+ const el = document.createElement('div')
158
+ el.className = 'my-custom-node'
159
+ el.innerHTML = `<h3>${node.title}</h3><p>${node.description}</p>`
160
+ return el
161
+ },
162
+ },
163
+ },
164
+ })
165
+ ```
100
166
 
101
- ### React
167
+ ### Theming by Type
168
+
169
+ ```typescript
170
+ await graph({
171
+ root: 'my-graph',
172
+ nodes: [
173
+ { id: 'start', type: 'input', title: 'Start' },
174
+ { id: 'process', type: 'process', title: 'Process' },
175
+ { id: 'error', type: 'error', title: 'Error' },
176
+ ],
177
+ edges: [...],
178
+ options: {
179
+ canvas: {
180
+ nodeTypes: {
181
+ input: { border: '#3b82f6' },
182
+ process: { border: '#8b5cf6' },
183
+ error: { bg: '#fef2f2', border: '#ef4444', text: '#991b1b' },
184
+ },
185
+ edgeTypes: {
186
+ error: { color: '#ef4444' },
187
+ success: { color: '#22c55e' },
188
+ },
189
+ },
190
+ },
191
+ })
192
+ ```
102
193
 
103
- TODO
194
+ ### Real-time Ingestion
195
+
196
+ ```typescript
197
+ // Connect to a WebSocket for live updates
198
+ await graph({
199
+ root: 'my-graph',
200
+ ingestion: {
201
+ type: 'websocket',
202
+ url: 'ws://localhost:8787',
203
+ },
204
+ })
205
+
206
+ // Or poll a file/endpoint
207
+ await graph({
208
+ root: 'my-graph',
209
+ ingestion: {
210
+ type: 'file',
211
+ url: '/api/graph-updates.ndjson',
212
+ intervalMs: 1000,
213
+ },
214
+ })
215
+ ```
104
216
 
105
- ### Vue
217
+ ### Event Handling
218
+
219
+ ```typescript
220
+ await graph({
221
+ root: 'my-graph',
222
+ nodes: [...],
223
+ edges: [...],
224
+ events: {
225
+ nodeClick: (node) => console.log('Clicked:', node),
226
+ edgeClick: (edge) => console.log('Edge clicked:', edge),
227
+ addNode: (props, done) => {
228
+ // Custom logic when user adds a node
229
+ const newNode = { id: generateId(), ...props }
230
+ done(newNode)
231
+ },
232
+ historyChange: (index, length) => {
233
+ console.log(`Step ${index + 1} of ${length}`)
234
+ },
235
+ },
236
+ })
237
+ ```
106
238
 
107
- TODO
239
+ ## API Methods
240
+
241
+ ```typescript
242
+ const api = await graph({ ... })
243
+
244
+ // Navigation
245
+ api.nav('first') // Jump to first state
246
+ api.nav('prev') // Go to previous state
247
+ api.nav('next') // Go to next state
248
+ api.nav('last') // Jump to latest state
249
+
250
+ // Updates
251
+ api.update(u => {
252
+ u.addNodes({ id: 'x', title: 'New' })
253
+ u.deleteNodes('old-node')
254
+ u.updateNodes({ id: 'x', title: 'Updated' })
255
+ u.addEdges({ source: 'a', target: 'x' })
256
+ u.deleteEdges('edge-id')
257
+ u.describe('Added new node') // Label for history
258
+ })
259
+
260
+ // Bulk operations
261
+ api.replaceSnapshot(nodes, edges)
262
+ api.replaceHistory(frames)
263
+
264
+ // Theming
265
+ api.setColorMode('dark')
266
+ api.updateStyles({ nodeTypes: { ... } })
267
+
268
+ // Cleanup
269
+ api.destroy()
270
+ ```
108
271
 
109
272
  ## Development
110
273
 
@@ -122,37 +285,35 @@ pnpm dev:site
122
285
  pnpm test
123
286
  ```
124
287
 
288
+ ## Inspiration
289
+
290
+ This library is inspired by [IonGraph Web](https://spidermonkey.dev/blog/2025/10/28/iongraph-web.html) from the SpiderMonkey team, which visualizes JavaScript JIT compilation graphs with stable, incremental layouts.
291
+
125
292
  ## Contributing
126
293
 
127
- We welcome contributions! Before submitting a pull request, please:
294
+ We welcome contributions! Before submitting a pull request:
128
295
 
129
296
  1. Read our [Contributing Guidelines](./CONTRIBUTING.md)
130
- 2. Sign the [Contributor License Agreement (CLA)](./CLA.md)
297
+ 2. Sign the [Contributor License Agreement](./CLA.md)
131
298
  3. Follow the code style and testing guidelines
132
299
 
133
- See [CONTRIBUTING.md](./CONTRIBUTING.md) for more details.
134
-
135
300
  ## License
136
301
 
137
- This project is licensed under the **GNU General Public License v3.0** - see the [LICENSE](./LICENSE) file for details.
302
+ **GNU General Public License v3.0** see [LICENSE](./LICENSE) for details.
138
303
 
139
304
  ### Why GPL?
140
305
 
141
- We've chosen GPL-3.0 to ensure that improvements to @3plate/graph remain open source and benefit the entire community. This means:
306
+ We've chosen GPL-3.0 to ensure improvements to @3plate/graph remain open source:
142
307
 
143
- - ✅ You can use @3plate/graph in open source projects
144
- - ✅ You can modify and distribute @3plate/graph
145
- - ✅ Commercial use is allowed
146
- - ⚠️ If you distribute modified versions, you must also make your changes available under GPL-3.0
308
+ - ✅ Use in open source projects
309
+ - ✅ Modify and distribute
310
+ - ✅ Commercial use allowed
311
+ - ⚠️ Distributed modifications must also be GPL-3.0
147
312
 
148
313
  ### Commercial Licensing
149
314
 
150
- If you need to use @3plate/graph in a proprietary/closed-source application without GPL restrictions, commercial licenses are available. Contact us at [nathan@3plate.com] for more information.
151
-
152
- ### Copyright
153
-
154
- Copyright (c) 2025 3Plate LLC
315
+ Need to use @3plate/graph in proprietary software without GPL restrictions? Commercial licenses are available contact [nathan@3plate.com](mailto:nathan@3plate.com).
155
316
 
156
317
  ---
157
318
 
158
- Made with by [3Plate LLC](https://www.3plate.com/)
319
+ **Copyright © 2025 [3Plate LLC](https://www.3plate.com/)**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@3plate/graph",
3
- "version": "0.1.6",
3
+ "version": "0.1.9",
4
4
  "description": "Graph library with stable layout and incremental updates",
5
5
  "type": "module",
6
6
  "license": "GPL-3.0",
@@ -23,10 +23,10 @@
23
23
  "access": "public"
24
24
  },
25
25
  "dependencies": {
26
- "@3plate/graph-angular": "0.1.6",
27
- "@3plate/graph-core": "0.1.6",
28
- "@3plate/graph-vue": "0.1.6",
29
- "@3plate/graph-react": "0.1.6"
26
+ "@3plate/graph-angular": "0.1.9",
27
+ "@3plate/graph-react": "0.1.9",
28
+ "@3plate/graph-core": "0.1.9",
29
+ "@3plate/graph-vue": "0.1.9"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@changesets/cli": "^2.29.8",