@3plate/graph-core 0.1.4 → 0.1.6

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/dist/index.d.cts CHANGED
@@ -4,37 +4,105 @@ type NodeAlign = 'natural' | 'top' | 'bottom' | 'left' | 'right';
4
4
  type Orientation = 'TB' | 'BT' | 'LR' | 'RL';
5
5
  type Nav = 'first' | 'last' | 'prev' | 'next';
6
6
  type LayoutStep = 'alignChildren' | 'alignParents' | 'compact';
7
+ type Dims = {
8
+ w: number;
9
+ h: number;
10
+ };
7
11
 
8
12
  type MarkerType = 'arrow' | 'circle' | 'diamond' | 'bar' | 'none';
9
13
 
14
+ /**
15
+ * Arguments to the API constructor.
16
+ *
17
+ * The caller can specify nodes and edges, or history,
18
+ * but not both.
19
+ *
20
+ * The root element ID is required.
21
+ */
10
22
  type APIArguments<N, E> = {
23
+ /** Options for the API */
11
24
  options?: APIOptions<N, E>;
25
+ /** Initial nodes */
12
26
  nodes?: N[];
27
+ /** Initial edges */
13
28
  edges?: E[];
29
+ /** Initial history */
14
30
  history?: Update<N, E>[];
31
+ /** Events */
32
+ events?: EventsOptions<N, E>;
33
+ /** Root element ID */
15
34
  root: string;
16
35
  };
36
+ /** Options for the API */
17
37
  type APIOptions<N, E> = {
38
+ /** Options for the graph */
18
39
  graph?: GraphOptions;
40
+ /** Options for the canvas */
19
41
  canvas?: CanvasOptions<N>;
42
+ /** Options for node and edge properties */
20
43
  props?: PropsOptions<N, E>;
21
44
  };
45
+ /** Options for the graph */
22
46
  type GraphOptions = {
47
+ /** Order in which edges are merged; see `MergeOrder` */
23
48
  mergeOrder?: MergeOrder;
49
+ /** Margin between nodes */
24
50
  nodeMargin?: number;
51
+ /** Size of dummy nodes */
25
52
  dummyNodeSize?: number;
53
+ /** Alignment of nodes */
26
54
  nodeAlign?: NodeAlign;
55
+ /** Spacing between edges */
27
56
  edgeSpacing?: number;
57
+ /** Turn radius */
28
58
  turnRadius?: number;
59
+ /** Orientation of the graph */
29
60
  orientation?: Orientation;
61
+ /** Margin between layers */
30
62
  layerMargin?: number;
63
+ /** Number of iterations for alignment */
31
64
  alignIterations?: number;
65
+ /** Alignment threshold */
32
66
  alignThreshold?: number;
67
+ /** Whether to separate track sets */
33
68
  separateTrackSets?: boolean;
69
+ /** Marker size */
34
70
  markerSize?: number;
71
+ /** Layout steps */
35
72
  layoutSteps?: LayoutStep[] | null;
36
73
  };
37
- type RenderNode<N> = (node: N) => HTMLElement;
74
+ /**
75
+ * Events that can be handled by the user.
76
+ */
77
+ type EventsOptions<N, E> = {
78
+ /** Called when a node is clicked */
79
+ nodeClick?: (node: N) => void;
80
+ /** Called when an edge is clicked */
81
+ edgeClick?: (edge: E) => void;
82
+ /** Called when a node is double-clicked */
83
+ editNode?: (node: N, callback: (node: N) => void) => void;
84
+ /** Called when a node should be added */
85
+ newNode?: (callback: (node: N) => void) => void;
86
+ /** Called when an edge is double-clicked */
87
+ editEdge?: (edge: E, callback: (edge: E) => void) => void;
88
+ /** Called when a node should be added */
89
+ addNode?: (node: NewNode, callback: (node: N) => void) => void;
90
+ /** Called when an edge should be added */
91
+ addEdge?: (edge: NewEdge<N>, callback: (edge: E) => void) => void;
92
+ /** Called when an edge should be removed */
93
+ removeEdge?: (edge: E, callback: (remove: boolean) => void) => void;
94
+ /** Called when a node should be removed */
95
+ removeNode?: (node: N, callback: (remove: boolean) => void) => void;
96
+ /** Called when a node should be updated */
97
+ updateNode?: (node: N, update: Record<string, any>, callback: (node: N) => void) => void;
98
+ /** Called when an edge should be updated */
99
+ updateEdge?: (edge: E, update: Record<string, any>, callback: (edge: E) => void) => void;
100
+ /** Called when history index/length changes */
101
+ historyChange?: (index: number, length: number) => void;
102
+ };
103
+ /** Function to render a node */
104
+ type RenderNode<N> = (node: N, props?: NodeProps<N>) => HTMLElement;
105
+ /** Color mode */
38
106
  type ColorMode = 'light' | 'dark' | 'system';
39
107
  /** Canvas background and general colors */
40
108
  type CanvasTheme = {
@@ -72,81 +140,218 @@ type EdgeTheme = {
72
140
  };
73
141
  /** Combined theme with all customizable properties */
74
142
  type ThemeVars = CanvasTheme & NodeTheme & PortTheme & EdgeTheme;
143
+ /** Options for the canvas */
75
144
  type CanvasOptions<N> = {
145
+ /** Canvas width in pixels or percentage */
76
146
  width?: number | string;
147
+ /** Canvas height in pixels or percentage */
77
148
  height?: number | string;
78
- /** Padding inside the canvas viewport (default: 20) */
149
+ /** Padding inside the canvas viewport */
79
150
  padding?: number;
80
- classPrefix?: string;
81
- markerSize?: number;
151
+ /** Whether the canvas is editable */
82
152
  editable?: boolean;
153
+ /** Whether to enable pan and zoom */
83
154
  panZoom?: boolean;
155
+ /** Function to render a node */
84
156
  renderNode?: RenderNode<N>;
157
+ /** Color mode */
85
158
  colorMode?: ColorMode;
159
+ /** Theme */
86
160
  theme?: ThemeVars;
161
+ /** Node type themes */
87
162
  nodeTypes?: Record<string, ThemeVars>;
163
+ /** Edge type themes */
88
164
  edgeTypes?: Record<string, ThemeVars>;
165
+ /** Marker size in pixels */
166
+ markerSize?: number;
89
167
  };
168
+ /** Options for node and edge properties */
90
169
  type PropsOptions<N, E> = {
170
+ /** Function to get node properties */
91
171
  node?: GetNodeProps<N>;
172
+ /** Function to get edge properties */
92
173
  edge?: GetEdgeProps<N, E>;
93
174
  };
175
+ /** Update to apply to the graph */
94
176
  type Update<N, E> = {
177
+ /** Nodes to add */
95
178
  addNodes?: N[];
179
+ /** Nodes to remove */
96
180
  removeNodes?: N[];
181
+ /** Nodes to update */
97
182
  updateNodes?: N[];
183
+ /** Edges to add */
98
184
  addEdges?: E[];
185
+ /** Edges to remove */
99
186
  removeEdges?: E[];
187
+ /** Edges to update */
100
188
  updateEdges?: E[];
189
+ /** Description of the update */
101
190
  description?: string;
102
191
  };
103
- type NodeProps<N> = {
192
+ /** Node properties */
193
+ type NodeProps<N> = NewNode & {
194
+ /** Node ID */
104
195
  id?: string;
196
+ /** Function to render a node */
197
+ render?: RenderNode<N>;
198
+ };
199
+ /** New node properties */
200
+ type NewNode = {
201
+ /** Node title */
105
202
  title?: string;
203
+ /** Node text */
106
204
  text?: string;
205
+ /** Node type */
107
206
  type?: string;
207
+ /** Node ports */
108
208
  ports?: {
209
+ /** Input ports */
109
210
  in?: (string | PortProps)[];
211
+ /** Output ports */
110
212
  out?: (string | PortProps)[];
111
213
  };
112
- render?: RenderNode<N>;
113
214
  };
114
- type EdgeEnd<N> = string | N | {
215
+ /** New edge properties */
216
+ type NewEdge<N> = {
217
+ /** Source node */
218
+ source: {
219
+ node: N;
220
+ port?: string;
221
+ marker?: MarkerType;
222
+ };
223
+ target: {
224
+ node: N;
225
+ port?: string;
226
+ marker?: MarkerType;
227
+ };
228
+ type?: string;
229
+ };
230
+ /** Edge end properties */
231
+ type EdgeEnd<N> =
232
+ /** Edge end node ID */
233
+ string |
234
+ /** Edge end node */
235
+ N |
236
+ /** Structured edge end with id */
237
+ {
238
+ /** Edge end node ID */
115
239
  id: string;
240
+ /** Edge end port ID */
116
241
  port?: string;
242
+ /** Edge end marker type */
117
243
  marker?: MarkerType;
118
- } | {
244
+ } |
245
+ /** Structured edge end with node object */
246
+ {
247
+ /** Edge end node object */
119
248
  node: N;
249
+ /** Edge end port ID */
120
250
  port?: string;
251
+ /** Edge end marker type */
121
252
  marker?: MarkerType;
122
253
  };
254
+ /** Edge properties */
123
255
  type EdgeProps<N> = {
256
+ /** Edge ID */
124
257
  id?: string;
258
+ /** Edge label */
125
259
  label?: string;
260
+ /** Edge source */
126
261
  source: EdgeEnd<N>;
262
+ /** Edge target */
127
263
  target: EdgeEnd<N>;
264
+ /** Edge type */
128
265
  type?: string;
129
266
  };
267
+ /** Port properties */
130
268
  type PortProps = {
269
+ /** Port ID */
131
270
  id: string;
271
+ /** Port label */
132
272
  label?: string;
133
273
  };
274
+ /** Function to get node properties */
134
275
  type GetNodeProps<N> = (node: N) => NodeProps<N>;
276
+ /** Function to get edge properties */
135
277
  type GetEdgeProps<N, E> = (edge: E) => EdgeProps<N>;
136
278
 
279
+ type SegId = string;
280
+
281
+ type NodeId = string;
282
+ type PortData = {
283
+ id: string;
284
+ label?: string;
285
+ offset?: number;
286
+ size?: number;
287
+ };
288
+ type PublicNodeData = {
289
+ id: NodeId;
290
+ data: any;
291
+ version: number;
292
+ title?: string;
293
+ text?: string;
294
+ type?: string;
295
+ ports: {
296
+ in?: PortData[];
297
+ out?: PortData[];
298
+ };
299
+ render?: RenderNode<any>;
300
+ dims?: Dims;
301
+ };
302
+
303
+ type EdgeId = string;
304
+ type PublicEdgeData = {
305
+ id: string;
306
+ data: any;
307
+ label?: string;
308
+ source: {
309
+ id: string;
310
+ port?: string;
311
+ marker?: MarkerType;
312
+ };
313
+ target: {
314
+ id: string;
315
+ port?: string;
316
+ marker?: MarkerType;
317
+ };
318
+ type?: string;
319
+ };
320
+
137
321
  declare class Updater<N, E> {
138
322
  update: Update<N, E>;
139
323
  constructor();
140
324
  describe(desc: string): Updater<N, E>;
141
325
  addNode(node: any): Updater<N, E>;
326
+ addNodes(...nodes: any[]): Updater<N, E>;
142
327
  deleteNode(node: any): Updater<N, E>;
328
+ deleteNodes(...nodes: any[]): Updater<N, E>;
143
329
  updateNode(node: any): Updater<N, E>;
330
+ updateNodes(...nodes: any[]): Updater<N, E>;
144
331
  addEdge(edge: any): Updater<N, E>;
332
+ addEdges(...edges: any[]): Updater<N, E>;
145
333
  deleteEdge(edge: any): Updater<N, E>;
334
+ deleteEdges(...edges: any[]): Updater<N, E>;
146
335
  updateEdge(edge: any): Updater<N, E>;
336
+ updateEdges(...edges: any[]): Updater<N, E>;
147
337
  static add<N, E>(nodes: N[], edges: E[]): Updater<N, E>;
148
338
  }
149
339
 
340
+ type EditEdgeProps = {
341
+ id: string;
342
+ type?: string;
343
+ source: {
344
+ id: string;
345
+ port?: string;
346
+ marker?: MarkerType;
347
+ };
348
+ target: {
349
+ id: string;
350
+ port?: string;
351
+ marker?: MarkerType;
352
+ };
353
+ };
354
+ /** Core graph API */
150
355
  declare class API<N, E> {
151
356
  private state;
152
357
  private seq;
@@ -157,27 +362,60 @@ declare class API<N, E> {
157
362
  private nodeIds;
158
363
  private edgeIds;
159
364
  private nodeVersions;
365
+ private nodeOverrides;
366
+ private edgeOverrides;
367
+ private nodeFields;
160
368
  private nextNodeId;
161
369
  private nextEdgeId;
370
+ private events;
162
371
  private root;
163
372
  constructor(args: APIArguments<N, E>);
373
+ reset(): void;
374
+ /** Initialize the API */
164
375
  init(): Promise<void>;
376
+ private applyHistory;
377
+ /** Current history index (0-based) */
378
+ getHistoryIndex(): number;
379
+ /** Current history length */
380
+ getHistoryLength(): number;
381
+ /** Toggle canvas editable mode without re-creating the graph */
382
+ setEditable(editable: boolean): void;
383
+ /** Replace entire history (clears prior) */
384
+ replaceHistory(frames: Update<N, E>[]): Promise<void>;
385
+ /** Rebuild from snapshot (nodes/edges) */
386
+ replaceSnapshot(nodes: N[], edges: E[], description?: string): Promise<void>;
387
+ private get graph();
388
+ /** Navigate to a different state */
165
389
  nav(nav: Nav): void;
166
390
  private applyDiff;
167
- addNode(node: any): Promise<void>;
168
- deleteNode(node: any): Promise<void>;
169
- updateNode(node: any): Promise<void>;
170
- addEdge(edge: any): Promise<void>;
171
- deleteEdge(edge: any): Promise<void>;
172
- applyUpdate(update: Update<N, E>): Promise<void>;
173
- private setNodePositions;
391
+ /** Add a node */
392
+ addNode(node: N): Promise<void>;
393
+ /** Delete a node */
394
+ deleteNode(node: N): Promise<void>;
395
+ /** Update a node */
396
+ updateNode(node: N): Promise<void>;
397
+ /** Add an edge */
398
+ addEdge(edge: E): Promise<void>;
399
+ /** Delete an edge */
400
+ deleteEdge(edge: E): Promise<void>;
401
+ /** Update an edge */
402
+ updateEdge(edge: E): Promise<void>;
403
+ /** Perform a batch of updates */
174
404
  update(callback: (updater: Updater<N, E>) => void): Promise<void>;
405
+ /** Rebuild the graph from scratch (removes all then re-adds all nodes/edges) */
406
+ rebuild(): Promise<void>;
407
+ private applyUpdate;
408
+ private setNodePositions;
175
409
  private measureNodes;
176
410
  private parseNode;
411
+ private detectNodeFields;
412
+ getNodeFields(): Map<string, 'string' | 'number' | 'boolean'>;
177
413
  private parseEdge;
178
414
  private parseEdgeEnd;
179
415
  private parseStringEdge;
180
416
  private parsePorts;
417
+ getNode(id: NodeId): PublicNodeData;
418
+ getEdge(id: EdgeId): PublicEdgeData;
181
419
  private getNodeId;
182
420
  private getEdgeId;
183
421
  private _addNode;
@@ -186,8 +424,203 @@ declare class API<N, E> {
186
424
  private _addEdge;
187
425
  private _removeEdge;
188
426
  private _updateEdge;
427
+ handleClickNode(id: NodeId): void;
428
+ handleClickEdge(id: SegId): void;
429
+ handleNewNode(): Promise<void>;
430
+ handleNewNodeFrom(source: {
431
+ id: string;
432
+ port?: string;
433
+ }): Promise<void>;
434
+ handleEditNode(id: NodeId): Promise<void>;
435
+ handleEditEdge(id: SegId): Promise<void>;
436
+ handleAddEdge(data: EditEdgeProps): Promise<void>;
437
+ handleDeleteNode(id: NodeId): Promise<void>;
438
+ handleDeleteEdge(id: EdgeId): Promise<void>;
439
+ }
440
+
441
+ type SnapshotMessage<N, E> = {
442
+ type: 'snapshot';
443
+ nodes: N[];
444
+ edges: E[];
445
+ description?: string;
446
+ };
447
+ type UpdateMessage<N, E> = {
448
+ type: 'update';
449
+ description?: string;
450
+ } & Update<N, E>;
451
+ type HistoryMessage<N, E> = {
452
+ type: 'history';
453
+ frames: Update<N, E>[];
454
+ };
455
+ type IngestMessage<N, E> = SnapshotMessage<N, E> | UpdateMessage<N, E> | HistoryMessage<N, E>;
456
+ /**
457
+ * Ingest class handles applying ingest messages to an API instance.
458
+ * This is the core ingestion functionality, separate from UI concerns.
459
+ */
460
+ declare class Ingest<N, E> {
461
+ api: API<N, E>;
462
+ constructor(api: API<N, E>);
463
+ /**
464
+ * Apply an incoming ingest message to the API.
465
+ * - snapshot: rebuild state from nodes/edges (clears prior history)
466
+ * - update: apply incremental update
467
+ * - history: initialize from a set of frames (clears prior history)
468
+ */
469
+ apply(msg: IngestMessage<N, E>): Promise<void>;
470
+ }
471
+
472
+ type StatusListener$2 = (status: 'connecting' | 'connected' | 'reconnecting' | 'closed' | 'error', detail?: any) => void;
473
+ declare class WebSocketSource<N, E> {
474
+ private url;
475
+ private ws;
476
+ private onMessage;
477
+ private onStatus?;
478
+ private reconnectMs;
479
+ private closedByUser;
480
+ private connectStartTime;
481
+ private totalTimeoutMs;
482
+ private totalTimeoutTimer;
483
+ constructor(url: string, onMessage: (msg: IngestMessage<N, E>) => void, onStatus?: StatusListener$2, reconnectMs?: number);
484
+ connect(): void;
485
+ disconnect(): void;
486
+ private startTotalTimeout;
487
+ private clearTotalTimeout;
488
+ private open;
489
+ }
490
+
491
+ type StatusListener$1 = (status: 'idle' | 'opened' | 'reading' | 'error' | 'closed', detail?: any) => void;
492
+ declare class FileSystemSource<N, E> {
493
+ private handle;
494
+ private onMessage;
495
+ private onStatus?;
496
+ private timer;
497
+ private lastSize;
498
+ private filename;
499
+ private intervalMs;
500
+ constructor(onMessage: (msg: IngestMessage<N, E>) => void, onStatus?: StatusListener$1, filename?: string, intervalMs?: number);
501
+ openDirectory(): Promise<void>;
502
+ close(): void;
503
+ private startPolling;
504
+ private readNewLines;
505
+ }
506
+
507
+ type StatusListener = (status: 'idle' | 'opened' | 'reading' | 'error' | 'closed', detail?: any) => void;
508
+ declare class FileSource<N, E> {
509
+ private url;
510
+ private onMessage;
511
+ private onStatus?;
512
+ private timer;
513
+ private lastETag;
514
+ private lastContent;
515
+ private intervalMs;
516
+ private closed;
517
+ constructor(url: string, onMessage: (msg: IngestMessage<N, E>) => void, onStatus?: StatusListener, intervalMs?: number);
518
+ connect(): Promise<void>;
519
+ close(): void;
520
+ private startPolling;
521
+ private poll;
522
+ }
523
+
524
+ /**
525
+ * Types for the Playground component
526
+ */
527
+ type ExampleNode = string | {
528
+ id: string;
529
+ title?: string;
530
+ type?: string;
531
+ ports?: {
532
+ in?: string[];
533
+ out?: string[];
534
+ };
535
+ };
536
+ type ExampleEdgeEnd = string | {
537
+ id: string;
538
+ port?: string;
539
+ marker?: 'arrow' | 'circle' | 'diamond' | 'bar';
540
+ };
541
+ type ExampleEdge = string | {
542
+ source: ExampleEdgeEnd;
543
+ target: ExampleEdgeEnd;
544
+ type?: string;
545
+ };
546
+ type ExampleOptions = {
547
+ canvas?: {
548
+ colorMode?: 'light' | 'dark' | 'system';
549
+ nodeTypes?: Record<string, Record<string, string>>;
550
+ edgeTypes?: Record<string, Record<string, string>>;
551
+ };
552
+ };
553
+ type ExampleSource = {
554
+ type: 'file';
555
+ path: string;
556
+ } | {
557
+ type: 'websocket';
558
+ url: string;
559
+ };
560
+ type Example = {
561
+ name: string;
562
+ description?: string;
563
+ nodes: ExampleNode[];
564
+ edges: ExampleEdge[];
565
+ options?: ExampleOptions;
566
+ source?: ExampleSource;
567
+ };
568
+ type PlaygroundOptions = {
569
+ root: string | HTMLElement;
570
+ examples: Record<string, Example>;
571
+ defaultExample?: string;
572
+ };
573
+
574
+ declare class Playground {
575
+ private options;
576
+ private rootElement;
577
+ private currentExample;
578
+ private currentGraph;
579
+ private ingest;
580
+ private isEditable;
581
+ private wsSource;
582
+ private fsSource;
583
+ private fileSource;
584
+ private wsStatus;
585
+ private fsStatus;
586
+ private fileStatus;
587
+ private activeSourceType;
588
+ private wsUrl;
589
+ private sourceModal;
590
+ private helpOverlay;
591
+ private exampleList;
592
+ private graphContainerId;
593
+ constructor(options: PlaygroundOptions);
594
+ init(): Promise<void>;
595
+ private injectStyles;
596
+ private createDOM;
597
+ private setupEventListeners;
598
+ private getResolvedColorMode;
599
+ private getOptions;
600
+ private renderGraph;
601
+ private updateHistoryLabel;
602
+ private connectExampleSource;
603
+ private disconnectAllSources;
604
+ private openHelp;
605
+ private closeHelp;
606
+ private handleIngestMessage;
607
+ private updateSourceIcon;
608
+ private updateWsStatus;
609
+ private updateFsStatus;
610
+ private updateFileStatus;
611
+ private createSourceModal;
612
+ private selectSourceType;
613
+ private updateSourceModalContent;
614
+ private updateSourceModal;
615
+ private openSourceModal;
616
+ private closeSourceModal;
617
+ private handleConnect;
618
+ private handleDisconnect;
619
+ private handleChangeConnection;
620
+ private handleOpenFolder;
621
+ private handleCloseFolder;
189
622
  }
190
623
 
191
624
  declare function graph<N, E>(args?: APIArguments<N, E>): Promise<API<N, E>>;
192
625
 
193
- export { graph as default, graph };
626
+ export { type Example, type ExampleEdge, type ExampleNode, type ExampleOptions, FileSource, FileSystemSource, type HistoryMessage, Ingest, type IngestMessage, Playground, type PlaygroundOptions, type SnapshotMessage, type UpdateMessage, WebSocketSource, graph as default, graph };