@samba425/diagramforge-react 0.1.0 → 0.1.1
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 +389 -0
- package/package.json +2 -1
package/README.md
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
# @samba425/diagramforge-react
|
|
2
|
+
|
|
3
|
+
**Embeddable, offline-first diagram editor for React** — a draw.io / Lucidchart alternative you can drop into any React 18+ or 19 app with a single component.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@samba425/diagramforge-react)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://react.dev)
|
|
8
|
+
|
|
9
|
+
**Live demo:** [samba425.github.io/Udraw](https://samba425.github.io/Udraw/)
|
|
10
|
+
**Source:** [github.com/samba425/Udraw](https://github.com/samba425/Udraw)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Why use this?
|
|
15
|
+
|
|
16
|
+
| Need | How DiagramForge helps |
|
|
17
|
+
|------|------------------------|
|
|
18
|
+
| Add diagrams to your SaaS app | Embed the full editor with `<DiagramEditor />` — no iframe hacks |
|
|
19
|
+
| No vendor lock-in | Open source (MIT), JSON document format, export SVG/PNG/PDF |
|
|
20
|
+
| Works offline | 100% client-side rendering; optional AI backend is separate |
|
|
21
|
+
| Rich shape libraries | Flowchart, UML, AWS, Azure, K8s, BPMN, org charts, and more |
|
|
22
|
+
| Developer-friendly | TypeScript types, `onChange` callback, programmatic API for shapes/edges |
|
|
23
|
+
|
|
24
|
+
Built with a **custom SVG engine** (not a wrapper around draw.io). Your users get pan/zoom, connectors, layers, grouping, undo/redo, templates, presentation mode, and import/export — inside your product.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install @samba425/diagramforge-react
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Peer dependencies:** `react` and `react-dom` (^18 or ^19).
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Quick start
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { DiagramEditor } from '@samba425/diagramforge-react';
|
|
42
|
+
import '@samba425/diagramforge-react/styles.css';
|
|
43
|
+
|
|
44
|
+
export function DiagramPage() {
|
|
45
|
+
return (
|
|
46
|
+
<DiagramEditor
|
|
47
|
+
height="80vh"
|
|
48
|
+
onChange={(project) => {
|
|
49
|
+
console.log('Diagram updated:', project.name);
|
|
50
|
+
}}
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
> **Required:** Always import `@samba425/diagramforge-react/styles.css`. The editor uses Tailwind + CSS theme variables and will look broken without it.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## `<DiagramEditor />` props
|
|
61
|
+
|
|
62
|
+
| Prop | Type | Default | Description |
|
|
63
|
+
|------|------|---------|-------------|
|
|
64
|
+
| `initialProject` | `Project` | empty diagram | Starting document. Remount or change `key` to load a new doc. |
|
|
65
|
+
| `onChange` | `(project: Project) => void` | — | Called whenever the document changes. Use to save to your API or state. |
|
|
66
|
+
| `readOnly` | `boolean` | `false` | View-only mode (pan and zoom). |
|
|
67
|
+
| `apiBaseUrl` | `string` | — | Backend URL for AI diagram generation. |
|
|
68
|
+
| `themeMode` | `'light' \| 'dark' \| 'system'` | `'system'` | Color theme. |
|
|
69
|
+
| `height` | CSS size | `'100%'` | Editor container height. |
|
|
70
|
+
| `width` | CSS size | `'100%'` | Editor container width. |
|
|
71
|
+
| `className` | `string` | — | CSS class on the root wrapper. |
|
|
72
|
+
| `style` | `CSSProperties` | — | Inline styles on the root wrapper. |
|
|
73
|
+
| `standalone` | `boolean` | `false` | Enables welcome dialog + IndexedDB autosave (first-party app mode). |
|
|
74
|
+
| `features` | `DiagramEditorFeatures` | see below | Toggle panels and behaviour. |
|
|
75
|
+
|
|
76
|
+
### Feature flags (`features`)
|
|
77
|
+
|
|
78
|
+
| Flag | Embed default | Description |
|
|
79
|
+
|------|---------------|-------------|
|
|
80
|
+
| `ai` | `true` | AI generation panel |
|
|
81
|
+
| `presentation` | `true` | F5 fullscreen slideshow |
|
|
82
|
+
| `sourceEditor` | `true` | JSON / YAML / Mermaid source view |
|
|
83
|
+
| `minimap` | `true` | Canvas minimap |
|
|
84
|
+
| `welcome` | `false` | Startup welcome / recovery dialog |
|
|
85
|
+
| `persistence` | `false` | Autosave to IndexedDB |
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
<DiagramEditor
|
|
89
|
+
features={{ ai: false, welcome: false, persistence: false }}
|
|
90
|
+
/>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Common integration patterns
|
|
96
|
+
|
|
97
|
+
### Save to your backend
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
import { DiagramEditor, serializeProject, type Project } from '@samba425/diagramforge-react';
|
|
101
|
+
import '@samba425/diagramforge-react/styles.css';
|
|
102
|
+
|
|
103
|
+
async function saveDiagram(project: Project) {
|
|
104
|
+
await fetch('/api/diagrams/123', {
|
|
105
|
+
method: 'PUT',
|
|
106
|
+
headers: { 'Content-Type': 'application/json' },
|
|
107
|
+
body: serializeProject(project),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function Editor() {
|
|
112
|
+
return <DiagramEditor onChange={saveDiagram} height="100vh" />;
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Load existing diagram (controlled)
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
import { useState } from 'react';
|
|
120
|
+
import { DiagramEditor, parseProject, type Project } from '@samba425/diagramforge-react';
|
|
121
|
+
import '@samba425/diagramforge-react/styles.css';
|
|
122
|
+
|
|
123
|
+
function ControlledEditor({ json }: { json: string }) {
|
|
124
|
+
const [project, setProject] = useState(() => parseProject(json));
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<DiagramEditor
|
|
128
|
+
key={project.id}
|
|
129
|
+
initialProject={project}
|
|
130
|
+
onChange={setProject}
|
|
131
|
+
height="80vh"
|
|
132
|
+
/>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Read-only viewer
|
|
138
|
+
|
|
139
|
+
```tsx
|
|
140
|
+
<DiagramEditor
|
|
141
|
+
initialProject={loadedProject}
|
|
142
|
+
readOnly
|
|
143
|
+
features={{ ai: false, sourceEditor: false }}
|
|
144
|
+
height="600px"
|
|
145
|
+
/>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Dark theme
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
<DiagramEditor themeMode="dark" height="80vh" />
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Minimal embed (no AI, no autosave)
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
<DiagramEditor
|
|
158
|
+
height="calc(100vh - 64px)"
|
|
159
|
+
features={{ ai: false, welcome: false, persistence: false }}
|
|
160
|
+
onChange={(p) => localStorage.setItem('diagram', JSON.stringify(p))}
|
|
161
|
+
/>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## Build diagrams in code
|
|
167
|
+
|
|
168
|
+
Create shapes and edges programmatically, then pass as `initialProject`:
|
|
169
|
+
|
|
170
|
+
```tsx
|
|
171
|
+
import {
|
|
172
|
+
DiagramEditor,
|
|
173
|
+
createProject,
|
|
174
|
+
createPage,
|
|
175
|
+
createShape,
|
|
176
|
+
createEdge,
|
|
177
|
+
createLayer,
|
|
178
|
+
} from '@samba425/diagramforge-react';
|
|
179
|
+
import '@samba425/diagramforge-react/styles.css';
|
|
180
|
+
|
|
181
|
+
const layer = createLayer('Main');
|
|
182
|
+
const page = createPage('Page 1', [layer.id]);
|
|
183
|
+
page.layers = [layer];
|
|
184
|
+
|
|
185
|
+
const boxA = createShape(
|
|
186
|
+
{ kind: 'rectangle', x: 80, y: 80, width: 160, height: 72, text: 'Start' },
|
|
187
|
+
layer.id,
|
|
188
|
+
);
|
|
189
|
+
const boxB = createShape(
|
|
190
|
+
{ kind: 'rectangle', x: 320, y: 80, width: 160, height: 72, text: 'End' },
|
|
191
|
+
layer.id,
|
|
192
|
+
);
|
|
193
|
+
page.shapes[boxA.id] = boxA;
|
|
194
|
+
page.shapes[boxB.id] = boxB;
|
|
195
|
+
page.order.push(boxA.id, boxB.id);
|
|
196
|
+
|
|
197
|
+
const edge = createEdge(
|
|
198
|
+
{ source: { shapeId: boxA.id }, target: { shapeId: boxB.id } },
|
|
199
|
+
page.id,
|
|
200
|
+
);
|
|
201
|
+
page.edges[edge.id] = edge;
|
|
202
|
+
page.order.push(edge.id);
|
|
203
|
+
|
|
204
|
+
const project = createProject({ name: 'My flow', pages: [page] });
|
|
205
|
+
|
|
206
|
+
export function App() {
|
|
207
|
+
return <DiagramEditor initialProject={project} height="80vh" />;
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Export & share
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
import {
|
|
217
|
+
exportSvg,
|
|
218
|
+
exportPng,
|
|
219
|
+
exportJson,
|
|
220
|
+
buildShareUrl,
|
|
221
|
+
loadTemplate,
|
|
222
|
+
} from '@samba425/diagramforge-react';
|
|
223
|
+
|
|
224
|
+
// From a Project object and active page:
|
|
225
|
+
await exportPng(project, pageId, { scale: 2 });
|
|
226
|
+
await exportSvg(project, pageId);
|
|
227
|
+
exportJson(project);
|
|
228
|
+
|
|
229
|
+
// Shareable URL (no server required):
|
|
230
|
+
const url = buildShareUrl(project, { viewOnly: false });
|
|
231
|
+
|
|
232
|
+
// Built-in templates: 'flowchart' | 'aws' | 'org-chart' | 'retro' | ...
|
|
233
|
+
const project = loadTemplate('flowchart');
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## Optional AI generation
|
|
239
|
+
|
|
240
|
+
The editor includes an AI panel. By default it uses a **built-in offline heuristic** generator. For LLM-powered diagrams, run the optional [backend server](https://github.com/samba425/Udraw/tree/main/backend) and point the editor at it:
|
|
241
|
+
|
|
242
|
+
```tsx
|
|
243
|
+
<DiagramEditor apiBaseUrl="https://your-api.example.com" />
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Or set `VITE_API_BASE_URL` in your Vite app.
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Exported API
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
// Component
|
|
254
|
+
export { DiagramEditor };
|
|
255
|
+
export type { DiagramEditorProps, DiagramEditorFeatures };
|
|
256
|
+
|
|
257
|
+
// Document types
|
|
258
|
+
export type { Project, Page, Layer, Shape, Edge, ToolId, ThemeMode, Camera, Point, Rect };
|
|
259
|
+
|
|
260
|
+
// File format
|
|
261
|
+
export { parseProject, serializeProject, FILE_SIGNATURE };
|
|
262
|
+
|
|
263
|
+
// Export
|
|
264
|
+
export { exportSvg, exportPng, exportPdf, exportJson, exportZip };
|
|
265
|
+
|
|
266
|
+
// Templates & share
|
|
267
|
+
export { DIAGRAM_TEMPLATES, loadTemplate };
|
|
268
|
+
export { encodeShareHash, decodeShareHash, buildShareUrl };
|
|
269
|
+
|
|
270
|
+
// Source editor (JSON / YAML / Mermaid)
|
|
271
|
+
export { projectToSourceText, applySourceToCanvas };
|
|
272
|
+
|
|
273
|
+
// Factories
|
|
274
|
+
export { createProject, createPage, createShape, createEdge, createLayer };
|
|
275
|
+
|
|
276
|
+
// Plugins (advanced)
|
|
277
|
+
export { pluginManager };
|
|
278
|
+
export type { Plugin };
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Full TypeScript declarations ship in `dist/index.d.ts`.
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## What’s included in the editor
|
|
286
|
+
|
|
287
|
+
- **Infinite SVG canvas** — pan, wheel zoom, grid, snap, smart guides
|
|
288
|
+
- **Shape libraries** — Basic, Flowchart, UML, AWS, Azure, Network, Kubernetes, BPMN, Mind Map, Org Chart, Sticky Notes, Icons
|
|
289
|
+
- **Connectors** — straight, orthogonal, curved, bezier; arrows, labels, animated lines
|
|
290
|
+
- **Grouping** — group/ungroup, named groups, enter group (double-click), drag shapes into groups
|
|
291
|
+
- **Layers & pages** — multi-page documents with layer visibility and lock
|
|
292
|
+
- **Undo / redo**, clipboard, duplicate, align & distribute
|
|
293
|
+
- **Import / export** — PNG, SVG, PDF, JSON, ZIP; import draw.io XML, Mermaid, PlantUML
|
|
294
|
+
- **Presentation mode** (F5), minimap, in-diagram search
|
|
295
|
+
- **Themes** — light / dark / system
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## Keyboard shortcuts (built-in)
|
|
300
|
+
|
|
301
|
+
| Shortcut | Action |
|
|
302
|
+
|----------|--------|
|
|
303
|
+
| `V` | Select tool |
|
|
304
|
+
| `H` | Pan tool |
|
|
305
|
+
| `R` / `O` / `D` | Rectangle / Ellipse / Diamond |
|
|
306
|
+
| `C` | Connector |
|
|
307
|
+
| `Ctrl+G` | Group selection |
|
|
308
|
+
| `Ctrl+Shift+G` | Ungroup |
|
|
309
|
+
| `Ctrl+Z` / `Ctrl+Shift+Z` | Undo / Redo |
|
|
310
|
+
| `Ctrl+C` / `Ctrl+V` | Copy / Paste |
|
|
311
|
+
| `Delete` | Delete selection |
|
|
312
|
+
| `F5` | Presentation mode |
|
|
313
|
+
|
|
314
|
+
See the full list in the app via **?** or the [keyboard shortcuts doc](https://github.com/samba425/Udraw/blob/main/docs/keyboard-shortcuts.md).
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## Framework notes
|
|
319
|
+
|
|
320
|
+
### Vite
|
|
321
|
+
|
|
322
|
+
Works out of the box. Import the CSS as shown above.
|
|
323
|
+
|
|
324
|
+
### Next.js (App Router)
|
|
325
|
+
|
|
326
|
+
Use a client component:
|
|
327
|
+
|
|
328
|
+
```tsx
|
|
329
|
+
'use client';
|
|
330
|
+
|
|
331
|
+
import dynamic from 'next/dynamic';
|
|
332
|
+
|
|
333
|
+
const DiagramEditor = dynamic(
|
|
334
|
+
() => import('@samba425/diagramforge-react').then((m) => m.DiagramEditor),
|
|
335
|
+
{ ssr: false },
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
import '@samba425/diagramforge-react/styles.css';
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Create React App
|
|
342
|
+
|
|
343
|
+
Same as Quick start — import CSS in your root component or `index.tsx`.
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## Limitations (v0.1)
|
|
348
|
+
|
|
349
|
+
- **One editor instance per page** — uses global Zustand stores; multiple `<DiagramEditor />` on the same page is not yet supported.
|
|
350
|
+
- **Bundle size** — full editor bundle (~1.6 MB ESM); code-split if needed.
|
|
351
|
+
- **SSR** — client-only; disable SSR where you embed (see Next.js example).
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## Example app
|
|
356
|
+
|
|
357
|
+
Clone the repo and run the embed example:
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
git clone https://github.com/samba425/Udraw.git
|
|
361
|
+
cd Udraw/frontend && npm run build:lib
|
|
362
|
+
cd ../examples/embed-react && npm install && npm run dev
|
|
363
|
+
# → http://localhost:5199
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## Documentation
|
|
369
|
+
|
|
370
|
+
| Topic | Link |
|
|
371
|
+
|-------|------|
|
|
372
|
+
| Embed guide | [docs/embed-package.md](https://github.com/samba425/Udraw/blob/main/docs/embed-package.md) |
|
|
373
|
+
| Developer guide | [docs/developer-guide.md](https://github.com/samba425/Udraw/blob/main/docs/developer-guide.md) |
|
|
374
|
+
| Architecture | [docs/architecture.md](https://github.com/samba425/Udraw/blob/main/docs/architecture.md) |
|
|
375
|
+
| Plugin API | [docs/plugin-api.md](https://github.com/samba425/Udraw/blob/main/docs/plugin-api.md) |
|
|
376
|
+
| Backend API (AI) | [docs/backend-api.md](https://github.com/samba425/Udraw/blob/main/docs/backend-api.md) |
|
|
377
|
+
|
|
378
|
+
---
|
|
379
|
+
|
|
380
|
+
## Contributing & support
|
|
381
|
+
|
|
382
|
+
- **Issues:** [github.com/samba425/Udraw/issues](https://github.com/samba425/Udraw/issues)
|
|
383
|
+
- **License:** [MIT](https://github.com/samba425/Udraw/blob/main/LICENSE)
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## Author
|
|
388
|
+
|
|
389
|
+
[samba425](https://github.com/samba425) — built as an open-source alternative to proprietary diagram tools.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@samba425/diagramforge-react",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"module": "./dist/diagramforge.js",
|
|
36
36
|
"types": "./dist/index.d.ts",
|
|
37
37
|
"files": [
|
|
38
|
+
"README.md",
|
|
38
39
|
"dist/diagramforge.js",
|
|
39
40
|
"dist/diagramforge.umd.cjs",
|
|
40
41
|
"dist/diagramforge.css",
|