@utisha/graph-editor 1.0.5 → 1.0.7

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.
@@ -1,7 +1,9 @@
1
- import { EventEmitter, OnChanges, OnInit, SimpleChanges } from '@angular/core';
1
+ import { EventEmitter, OnChanges, OnInit, SimpleChanges, Type } from '@angular/core';
2
2
  import { Graph, GraphEdge, GraphNode, Position } from './graph.model';
3
- import { ContextMenuEvent, GraphEditorConfig, NodeTypeDefinition, SelectionState, ValidationResult } from './graph-editor.config';
3
+ import { ContextMenuEvent, GraphEditorConfig, NodeTypeDefinition, SelectionState, ToolbarItem, ValidationResult } from './graph-editor.config';
4
4
  import { SvgIconDefinition } from './icons/workflow-icons';
5
+ import { NodeHtmlTemplateDirective, NodeSvgTemplateDirective, EdgeTemplateDirective, NodeTemplateContext, EdgeTemplateContext } from './template.directives';
6
+ import { ResolvedTheme } from './theme.resolver';
5
7
  import * as i0 from "@angular/core";
6
8
  /**
7
9
  * Main graph editor component.
@@ -55,7 +57,7 @@ export declare class GraphEditorComponent implements OnInit, OnChanges {
55
57
  port: 'top' | 'bottom' | 'left' | 'right';
56
58
  } | null;
57
59
  showAttachmentPoints: import("@angular/core").WritableSignal<string | null>;
58
- activeTool: import("@angular/core").WritableSignal<"hand" | "line">;
60
+ activeTool: import("@angular/core").WritableSignal<"line" | "hand">;
59
61
  private pendingEdge;
60
62
  previewLine: import("@angular/core").WritableSignal<{
61
63
  source: Position;
@@ -80,12 +82,17 @@ export declare class GraphEditorComponent implements OnInit, OnChanges {
80
82
  width: number;
81
83
  height: number;
82
84
  }>;
85
+ resolvedTheme: ResolvedTheme;
83
86
  shadowsEnabled: import("@angular/core").Signal<boolean>;
87
+ protected nodeHtmlTemplate: import("@angular/core").Signal<NodeHtmlTemplateDirective | undefined>;
88
+ protected nodeSvgTemplate: import("@angular/core").Signal<NodeSvgTemplateDirective | undefined>;
89
+ protected edgeTemplate: import("@angular/core").Signal<EdgeTemplateDirective | undefined>;
84
90
  selectedEdgeMidpoint: import("@angular/core").Signal<{
85
91
  edge: GraphEdge;
86
92
  x: number;
87
93
  y: number;
88
94
  } | null>;
95
+ private readonly hostEl;
89
96
  constructor();
90
97
  ngOnChanges(changes: SimpleChanges): void;
91
98
  ngOnInit(): void;
@@ -141,6 +148,8 @@ export declare class GraphEditorComponent implements OnInit, OnChanges {
141
148
  height: number;
142
149
  };
143
150
  getEdgePath(edge: GraphEdge): string;
151
+ /** Get the control point offset direction for a port (used by bezier path). */
152
+ private getPortControlOffset;
144
153
  getEdgeColor(edge: GraphEdge): string;
145
154
  getEdgeMarkerEnd(edge: GraphEdge): string | null;
146
155
  getEdgeMarkerStart(edge: GraphEdge): string | null;
@@ -175,6 +184,17 @@ export declare class GraphEditorComponent implements OnInit, OnChanges {
175
184
  * When there are too many node types to fit vertically, creates additional columns.
176
185
  */
177
186
  getPaletteColumns(): NodeTypeDefinition[][];
187
+ /**
188
+ * Check whether a toolbar item should be shown.
189
+ * If `config.toolbar.items` is not set, all items are visible.
190
+ */
191
+ showToolbarItem(item: ToolbarItem): boolean;
192
+ /**
193
+ * Check whether a divider should be shown between two toolbar groups.
194
+ * A divider is shown when at least one item from the group before and
195
+ * at least one item from the group after are visible.
196
+ */
197
+ showToolbarDivider(before: ToolbarItem[], after: ToolbarItem[]): boolean;
178
198
  /**
179
199
  * Get the position for the node image (top-left corner of image).
180
200
  * Uses same positioning logic as icon but accounts for image dimensions.
@@ -230,6 +250,14 @@ export declare class GraphEditorComponent implements OnInit, OnChanges {
230
250
  private findClosestPort;
231
251
  private getPortWorldPosition;
232
252
  private findClosestPortForEdge;
253
+ /** Get the component type for a node (from NodeTypeDefinition.component, if set). */
254
+ getNodeComponent(node: GraphNode): Type<any> | null;
255
+ /** Build inputs map for ngComponentOutlet when rendering a node's custom component. */
256
+ getNodeComponentInputs(node: GraphNode): Record<string, any>;
257
+ /** Build the template context for custom node templates. */
258
+ getNodeTemplateContext(node: GraphNode): NodeTemplateContext;
259
+ /** Build the template context for custom edge templates. */
260
+ getEdgeTemplateContext(edge: GraphEdge): EdgeTemplateContext;
233
261
  static ɵfac: i0.ɵɵFactoryDeclaration<GraphEditorComponent, never>;
234
- static ɵcmp: i0.ɵɵComponentDeclaration<GraphEditorComponent, "graph-editor", never, { "config": { "alias": "config"; "required": true; }; "graph": { "alias": "graph"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "visualizationMode": { "alias": "visualizationMode"; "required": false; }; "overlayData": { "alias": "overlayData"; "required": false; }; }, { "graphChange": "graphChange"; "nodeAdded": "nodeAdded"; "nodeUpdated": "nodeUpdated"; "nodeRemoved": "nodeRemoved"; "edgeAdded": "edgeAdded"; "edgeUpdated": "edgeUpdated"; "edgeRemoved": "edgeRemoved"; "selectionChange": "selectionChange"; "validationChange": "validationChange"; "nodeClick": "nodeClick"; "nodeDoubleClick": "nodeDoubleClick"; "edgeClick": "edgeClick"; "edgeDoubleClick": "edgeDoubleClick"; "canvasClick": "canvasClick"; "contextMenu": "contextMenu"; }, never, never, true, never>;
262
+ static ɵcmp: i0.ɵɵComponentDeclaration<GraphEditorComponent, "graph-editor", never, { "config": { "alias": "config"; "required": true; }; "graph": { "alias": "graph"; "required": false; }; "readonly": { "alias": "readonly"; "required": false; }; "visualizationMode": { "alias": "visualizationMode"; "required": false; }; "overlayData": { "alias": "overlayData"; "required": false; }; }, { "graphChange": "graphChange"; "nodeAdded": "nodeAdded"; "nodeUpdated": "nodeUpdated"; "nodeRemoved": "nodeRemoved"; "edgeAdded": "edgeAdded"; "edgeUpdated": "edgeUpdated"; "edgeRemoved": "edgeRemoved"; "selectionChange": "selectionChange"; "validationChange": "validationChange"; "nodeClick": "nodeClick"; "nodeDoubleClick": "nodeDoubleClick"; "edgeClick": "edgeClick"; "edgeDoubleClick": "edgeDoubleClick"; "canvasClick": "canvasClick"; "contextMenu": "contextMenu"; }, ["nodeHtmlTemplate", "nodeSvgTemplate", "edgeTemplate"], never, true, never>;
235
263
  }
@@ -18,6 +18,8 @@ export interface GraphEditorConfig {
18
18
  theme?: ThemeConfig;
19
19
  /** Palette configuration */
20
20
  palette?: PaletteConfig;
21
+ /** Top toolbar configuration */
22
+ toolbar?: ToolbarConfig;
21
23
  }
22
24
  /**
23
25
  * Node type configuration.
@@ -207,10 +209,160 @@ export interface ContextMenuContext {
207
209
  * Theme configuration.
208
210
  */
209
211
  export interface ThemeConfig {
210
- /** CSS custom property values */
212
+ /** CSS custom property values (applied to host element) */
211
213
  variables?: Record<string, string>;
212
214
  /** Enable drop shadows on nodes and edges (default: true) */
213
215
  shadows?: boolean;
216
+ /** Canvas theming */
217
+ canvas?: CanvasTheme;
218
+ /** Node theming */
219
+ node?: NodeTheme;
220
+ /** Edge theming */
221
+ edge?: EdgeTheme;
222
+ /** Port/attachment point theming */
223
+ port?: PortTheme;
224
+ /** Selection theming */
225
+ selection?: SelectionTheme;
226
+ /** Font configuration */
227
+ font?: FontTheme;
228
+ /** Toolbar & palette chrome theming */
229
+ toolbar?: ToolbarTheme;
230
+ }
231
+ /**
232
+ * Canvas visual theme.
233
+ */
234
+ export interface CanvasTheme {
235
+ /** Canvas background color (default: '#f8f9fa') */
236
+ background?: string;
237
+ /** Grid pattern type (default: 'line') */
238
+ gridType?: 'line' | 'dot';
239
+ /** Grid line/dot color (default: '#e0e0e0') */
240
+ gridColor?: string;
241
+ }
242
+ /**
243
+ * Node visual theme.
244
+ */
245
+ export interface NodeTheme {
246
+ /** Node background fill (default: 'white') */
247
+ background?: string;
248
+ /** Node border color (default: '#e2e8f0') */
249
+ borderColor?: string;
250
+ /** Node border width in px (default: 1.5) */
251
+ borderWidth?: number;
252
+ /** Node corner radius in px (default: 12) */
253
+ borderRadius?: number;
254
+ /** Border color when selected (default: selection.color) */
255
+ selectedBorderColor?: string;
256
+ /** Border width when selected in px (default: 2.5) */
257
+ selectedBorderWidth?: number;
258
+ /** Shadow color (default: 'rgba(0,0,0,0.08)') */
259
+ shadowColor?: string;
260
+ /** Label text color (default: '#1e293b') */
261
+ labelColor?: string;
262
+ /** Label font family (default: 'system-ui, -apple-system, sans-serif') */
263
+ labelFont?: string;
264
+ /**
265
+ * Per-type visual overrides. Keys are node type identifiers.
266
+ * @example { 'llm-call': { accentColor: '#1D6A96' } }
267
+ */
268
+ typeStyles?: Record<string, NodeTypeStyle>;
269
+ }
270
+ /**
271
+ * Per-node-type visual overrides.
272
+ */
273
+ export interface NodeTypeStyle {
274
+ /** Node background for this type */
275
+ background?: string;
276
+ /** Node border color for this type */
277
+ borderColor?: string;
278
+ /** Accent/header background color */
279
+ accentColor?: string;
280
+ /** Accent/header text color */
281
+ accentTextColor?: string;
282
+ }
283
+ /**
284
+ * Edge visual theme.
285
+ */
286
+ export interface EdgeTheme {
287
+ /** Edge stroke color (default: '#94a3b8') */
288
+ stroke?: string;
289
+ /** Edge stroke width in px (default: 2) */
290
+ strokeWidth?: number;
291
+ /** Edge stroke color when selected (default: selection.color) */
292
+ selectedStroke?: string;
293
+ /** Edge stroke width when selected in px (default: 2.5) */
294
+ selectedStrokeWidth?: number;
295
+ /** Arrow marker fill color (default: '#94a3b8') */
296
+ markerColor?: string;
297
+ /** Arrow marker fill color when selected (default: selection.color) */
298
+ selectedMarkerColor?: string;
299
+ /** Edge path routing algorithm (default: 'straight') */
300
+ pathType?: 'straight' | 'bezier' | 'step';
301
+ }
302
+ /**
303
+ * Port/attachment point visual theme.
304
+ */
305
+ export interface PortTheme {
306
+ /** Port fill color (default: '#94a3b8') */
307
+ fill?: string;
308
+ /** Port border color (default: 'white') */
309
+ stroke?: string;
310
+ /** Port border width in px (default: 2) */
311
+ strokeWidth?: number;
312
+ /** Port radius in px (default: 6) */
313
+ radius?: number;
314
+ /** Port fill color on hover (default: '#2563eb') */
315
+ hoverFill?: string;
316
+ /** Port radius on hover in px (default: 8) */
317
+ hoverRadius?: number;
318
+ }
319
+ /**
320
+ * Selection visual theme.
321
+ */
322
+ export interface SelectionTheme {
323
+ /** Primary selection color — also used as default for node/edge selected states (default: '#3b82f6') */
324
+ color?: string;
325
+ /** Box selection fill (default: 'rgba(59, 130, 246, 0.1)') */
326
+ boxFill?: string;
327
+ /** Box selection stroke (default: selection.color) */
328
+ boxStroke?: string;
329
+ }
330
+ /**
331
+ * Font theme.
332
+ */
333
+ export interface FontTheme {
334
+ /** Primary font family (default: 'system-ui, -apple-system, sans-serif') */
335
+ family?: string;
336
+ /** Monospace font family (default: 'monospace') */
337
+ monoFamily?: string;
338
+ }
339
+ /**
340
+ * Toolbar & palette chrome theme.
341
+ * Controls the top toolbar, left palette, and edge direction selector.
342
+ */
343
+ export interface ToolbarTheme {
344
+ /** Panel background (default: 'rgba(255, 255, 255, 0.95)') */
345
+ background?: string;
346
+ /** Panel border radius in px (default: 8) */
347
+ borderRadius?: number;
348
+ /** Panel box shadow (default: '0 2px 8px rgba(0, 0, 0, 0.1)') */
349
+ shadow?: string;
350
+ /** Button background (default: '#ffffff') */
351
+ buttonBackground?: string;
352
+ /** Button border color (default: '#e5e7eb') */
353
+ buttonBorderColor?: string;
354
+ /** Button text/icon color (default: '#4b5563') */
355
+ buttonTextColor?: string;
356
+ /** Button hover background (default: '#f9fafb') */
357
+ buttonHoverBackground?: string;
358
+ /** Button hover border & text color — matches selection.color by default */
359
+ buttonHoverAccent?: string;
360
+ /** Active (pressed) tool button background (default: selection.color) */
361
+ buttonActiveBackground?: string;
362
+ /** Active tool button text color (default: '#ffffff') */
363
+ buttonActiveTextColor?: string;
364
+ /** Divider line color between button groups (default: '#e5e7eb') */
365
+ dividerColor?: string;
214
366
  }
215
367
  /**
216
368
  * Palette configuration.
@@ -221,6 +373,26 @@ export interface PaletteConfig {
221
373
  collapsible?: boolean;
222
374
  groupByCategory?: boolean;
223
375
  }
376
+ /**
377
+ * Toolbar item identifiers for the top toolbar.
378
+ * - `'hand'` — Hand tool (move nodes)
379
+ * - `'line'` — Line tool (draw connections)
380
+ * - `'zoom-in'` — Zoom in
381
+ * - `'zoom-out'` — Zoom out
382
+ * - `'layout'` — Auto layout
383
+ * - `'fit'` — Fit to screen
384
+ */
385
+ export type ToolbarItem = 'hand' | 'line' | 'zoom-in' | 'zoom-out' | 'layout' | 'fit';
386
+ /**
387
+ * Top toolbar configuration.
388
+ * Controls visibility of the top toolbar and which buttons are shown.
389
+ */
390
+ export interface ToolbarConfig {
391
+ /** Show the top toolbar (default: true) */
392
+ enabled?: boolean;
393
+ /** Which toolbar buttons to show. If omitted, all buttons are shown. */
394
+ items?: ToolbarItem[];
395
+ }
224
396
  /**
225
397
  * Selection state.
226
398
  */
@@ -0,0 +1,116 @@
1
+ import { TemplateRef } from '@angular/core';
2
+ import { GraphNode, GraphEdge } from './graph.model';
3
+ import { NodeTypeDefinition } from './graph-editor.config';
4
+ import * as i0 from "@angular/core";
5
+ /**
6
+ * Context provided to node templates (both HTML and SVG).
7
+ *
8
+ * Usage:
9
+ * ```html
10
+ * <ng-template geNodeHtml let-ctx>
11
+ * <div>{{ ctx.node.data.name }}</div>
12
+ * </ng-template>
13
+ * ```
14
+ */
15
+ export interface NodeTemplateContext {
16
+ $implicit: {
17
+ /** The raw node data */
18
+ node: GraphNode;
19
+ /** The node type definition from config */
20
+ type: NodeTypeDefinition;
21
+ /** Whether this node is currently selected */
22
+ selected: boolean;
23
+ /** Current node width (respects resize) */
24
+ width: number;
25
+ /** Current node height (respects resize) */
26
+ height: number;
27
+ };
28
+ }
29
+ /**
30
+ * Context provided to edge templates.
31
+ *
32
+ * Usage:
33
+ * ```html
34
+ * <ng-template geEdge let-ctx>
35
+ * <svg:path [attr.d]="ctx.path" stroke="red" />
36
+ * </ng-template>
37
+ * ```
38
+ */
39
+ export interface EdgeTemplateContext {
40
+ $implicit: {
41
+ /** The raw edge data */
42
+ edge: GraphEdge;
43
+ /** Computed SVG path string */
44
+ path: string;
45
+ /** Whether this edge is currently selected */
46
+ selected: boolean;
47
+ };
48
+ }
49
+ /**
50
+ * Marks an `<ng-template>` as a custom HTML node renderer.
51
+ * Content is rendered inside an `<svg:foreignObject>` — write standard HTML/CSS.
52
+ *
53
+ * @example
54
+ * ```html
55
+ * <graph-editor [config]="config" [graph]="graph">
56
+ * <ng-template geNodeHtml let-ctx>
57
+ * <div class="my-node" [class.selected]="ctx.selected">
58
+ * <div class="header">{{ ctx.type.label }}</div>
59
+ * <div class="body">{{ ctx.node.data.name }}</div>
60
+ * </div>
61
+ * </ng-template>
62
+ * </graph-editor>
63
+ * ```
64
+ */
65
+ export declare class NodeHtmlTemplateDirective {
66
+ templateRef: TemplateRef<NodeTemplateContext>;
67
+ static ngTemplateContextGuard(_dir: NodeHtmlTemplateDirective, _ctx: unknown): _ctx is NodeTemplateContext;
68
+ static ɵfac: i0.ɵɵFactoryDeclaration<NodeHtmlTemplateDirective, never>;
69
+ static ɵdir: i0.ɵɵDirectiveDeclaration<NodeHtmlTemplateDirective, "ng-template[geNodeHtml]", never, {}, {}, never, never, true, never>;
70
+ }
71
+ /**
72
+ * Marks an `<ng-template>` as a custom SVG node renderer.
73
+ * Content is rendered inside an `<svg:g>` — use `svg:` prefixed elements.
74
+ *
75
+ * @example
76
+ * ```html
77
+ * <graph-editor [config]="config" [graph]="graph">
78
+ * <ng-template geNodeSvg let-ctx>
79
+ * <svg:rect [attr.width]="ctx.width" [attr.height]="ctx.height"
80
+ * rx="8" fill="white" stroke="#ccc" />
81
+ * <svg:text x="10" y="24">{{ ctx.node.data.name }}</svg:text>
82
+ * </ng-template>
83
+ * </graph-editor>
84
+ * ```
85
+ *
86
+ * **Important:** All SVG elements inside the template MUST use the `svg:` prefix
87
+ * (e.g. `<svg:rect>`, `<svg:text>`, `<svg:g>`).
88
+ */
89
+ export declare class NodeSvgTemplateDirective {
90
+ templateRef: TemplateRef<NodeTemplateContext>;
91
+ static ngTemplateContextGuard(_dir: NodeSvgTemplateDirective, _ctx: unknown): _ctx is NodeTemplateContext;
92
+ static ɵfac: i0.ɵɵFactoryDeclaration<NodeSvgTemplateDirective, never>;
93
+ static ɵdir: i0.ɵɵDirectiveDeclaration<NodeSvgTemplateDirective, "ng-template[geNodeSvg]", never, {}, {}, never, never, true, never>;
94
+ }
95
+ /**
96
+ * Marks an `<ng-template>` as a custom edge renderer.
97
+ * Content is rendered inside an `<svg:g>` — use `svg:` prefixed elements.
98
+ * The library still handles the invisible hit-area and endpoint circles.
99
+ *
100
+ * @example
101
+ * ```html
102
+ * <graph-editor [config]="config" [graph]="graph">
103
+ * <ng-template geEdge let-ctx>
104
+ * <svg:path [attr.d]="ctx.path"
105
+ * [attr.stroke]="ctx.selected ? 'blue' : 'gray'"
106
+ * stroke-width="2" fill="none" />
107
+ * </ng-template>
108
+ * </graph-editor>
109
+ * ```
110
+ */
111
+ export declare class EdgeTemplateDirective {
112
+ templateRef: TemplateRef<EdgeTemplateContext>;
113
+ static ngTemplateContextGuard(_dir: EdgeTemplateDirective, _ctx: unknown): _ctx is EdgeTemplateContext;
114
+ static ɵfac: i0.ɵɵFactoryDeclaration<EdgeTemplateDirective, never>;
115
+ static ɵdir: i0.ɵɵDirectiveDeclaration<EdgeTemplateDirective, "ng-template[geEdge]", never, {}, {}, never, never, true, never>;
116
+ }
@@ -0,0 +1,78 @@
1
+ import { ThemeConfig } from './graph-editor.config';
2
+ /**
3
+ * Fully-resolved theme with no optional fields.
4
+ * Every value has a sensible default so templates can reference without null-checking.
5
+ */
6
+ export interface ResolvedTheme {
7
+ shadows: boolean;
8
+ canvas: {
9
+ background: string;
10
+ gridType: 'line' | 'dot';
11
+ gridColor: string;
12
+ };
13
+ node: {
14
+ background: string;
15
+ borderColor: string;
16
+ borderWidth: number;
17
+ borderRadius: number;
18
+ selectedBorderColor: string;
19
+ selectedBorderWidth: number;
20
+ shadowColor: string;
21
+ labelColor: string;
22
+ labelFont: string;
23
+ typeStyles: Record<string, {
24
+ background?: string;
25
+ borderColor?: string;
26
+ accentColor?: string;
27
+ accentTextColor?: string;
28
+ }>;
29
+ };
30
+ edge: {
31
+ stroke: string;
32
+ strokeWidth: number;
33
+ selectedStroke: string;
34
+ selectedStrokeWidth: number;
35
+ markerColor: string;
36
+ selectedMarkerColor: string;
37
+ pathType: 'straight' | 'bezier' | 'step';
38
+ };
39
+ port: {
40
+ fill: string;
41
+ stroke: string;
42
+ strokeWidth: number;
43
+ radius: number;
44
+ hoverFill: string;
45
+ hoverRadius: number;
46
+ };
47
+ selection: {
48
+ color: string;
49
+ boxFill: string;
50
+ boxStroke: string;
51
+ };
52
+ font: {
53
+ family: string;
54
+ monoFamily: string;
55
+ };
56
+ toolbar: {
57
+ background: string;
58
+ borderRadius: number;
59
+ shadow: string;
60
+ buttonBackground: string;
61
+ buttonBorderColor: string;
62
+ buttonTextColor: string;
63
+ buttonHoverBackground: string;
64
+ buttonHoverAccent: string;
65
+ buttonActiveBackground: string;
66
+ buttonActiveTextColor: string;
67
+ dividerColor: string;
68
+ };
69
+ }
70
+ /**
71
+ * Resolves a partial ThemeConfig into a complete ResolvedTheme with all defaults filled.
72
+ */
73
+ export declare function resolveTheme(theme?: ThemeConfig): ResolvedTheme;
74
+ /**
75
+ * Applies resolved theme values as CSS custom properties on a host element.
76
+ * This enables consumer templates to use `var(--ge-*)` in their CSS.
77
+ */
78
+ export declare function applyThemeCssProperties(host: HTMLElement, t: ResolvedTheme, userVars?: Record<string, string>): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@utisha/graph-editor",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Configuration-driven visual graph editor for Angular 19+",
5
5
  "author": "Utisha",
6
6
  "license": "MIT",
package/public-api.d.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  export { GraphEditorComponent } from './lib/graph-editor.component';
2
2
  export type { Graph, GraphNode, GraphEdge, Position, NodeMetadata, EdgeMetadata, EdgeStyle, GraphMetadata } from './lib/graph.model';
3
- export type { GraphEditorConfig, NodesConfig, EdgesConfig, CanvasConfig, ValidationConfig, LayoutConfig, InteractionConfig, ThemeConfig, PaletteConfig, NodeTypeDefinition, PortConfig, PortDefinition, NodeConstraints, GridConfig, ZoomConfig, PanConfig, ValidationRule, ValidationError, LayoutOptions, ContextMenuConfig, ContextMenuItem, ContextMenuContext, SelectionState, ValidationResult, ContextMenuEvent } from './lib/graph-editor.config';
3
+ export type { GraphEditorConfig, NodesConfig, EdgesConfig, CanvasConfig, ValidationConfig, LayoutConfig, InteractionConfig, ThemeConfig, PaletteConfig, ToolbarConfig, ToolbarItem, NodeTypeDefinition, PortConfig, PortDefinition, NodeConstraints, GridConfig, ZoomConfig, PanConfig, ValidationRule, ValidationError, LayoutOptions, ContextMenuConfig, ContextMenuItem, ContextMenuContext, SelectionState, ValidationResult, ContextMenuEvent, CanvasTheme, NodeTheme, NodeTypeStyle, EdgeTheme, PortTheme, SelectionTheme, FontTheme, ToolbarTheme } from './lib/graph-editor.config';
4
4
  export type { SvgIconDefinition } from './lib/icons/workflow-icons';
5
5
  export { renderIconSvg, iconToDataUrl } from './lib/icons/workflow-icons';
6
+ export { NodeHtmlTemplateDirective, NodeSvgTemplateDirective, EdgeTemplateDirective } from './lib/template.directives';
7
+ export type { NodeTemplateContext, EdgeTemplateContext } from './lib/template.directives';
8
+ export type { ResolvedTheme } from './lib/theme.resolver';