@spaethtech/svelte-ui 0.1.10

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 (116) hide show
  1. package/README.md +81 -0
  2. package/dist/components/Badge/Badge.svelte +80 -0
  3. package/dist/components/Badge/Badge.svelte.d.ts +14 -0
  4. package/dist/components/Badge/index.d.ts +1 -0
  5. package/dist/components/Badge/index.js +1 -0
  6. package/dist/components/Button/Button.svelte +172 -0
  7. package/dist/components/Button/Button.svelte.d.ts +32 -0
  8. package/dist/components/Button/index.d.ts +1 -0
  9. package/dist/components/Button/index.js +1 -0
  10. package/dist/components/Dialog/Dialog.svelte +101 -0
  11. package/dist/components/Dialog/Dialog.svelte.d.ts +18 -0
  12. package/dist/components/Dialog/index.d.ts +1 -0
  13. package/dist/components/Dialog/index.js +1 -0
  14. package/dist/components/ElementManager/ElementManager.svelte +397 -0
  15. package/dist/components/ElementManager/ElementManager.svelte.d.ts +43 -0
  16. package/dist/components/ElementManager/index.d.ts +1 -0
  17. package/dist/components/ElementManager/index.js +1 -0
  18. package/dist/components/EmailInput/EmailInput.svelte +47 -0
  19. package/dist/components/EmailInput/EmailInput.svelte.d.ts +14 -0
  20. package/dist/components/EmailInput/index.d.ts +1 -0
  21. package/dist/components/EmailInput/index.js +1 -0
  22. package/dist/components/Icon/Icon.svelte +74 -0
  23. package/dist/components/Icon/Icon.svelte.d.ts +13 -0
  24. package/dist/components/Icon/index.d.ts +1 -0
  25. package/dist/components/Icon/index.js +1 -0
  26. package/dist/components/Input/Input.svelte +268 -0
  27. package/dist/components/Input/Input.svelte.d.ts +18 -0
  28. package/dist/components/Input/index.d.ts +1 -0
  29. package/dist/components/Input/index.js +1 -0
  30. package/dist/components/List/List.svelte +580 -0
  31. package/dist/components/List/List.svelte.d.ts +38 -0
  32. package/dist/components/List/index.d.ts +1 -0
  33. package/dist/components/List/index.js +1 -0
  34. package/dist/components/ListItem/ListItem.svelte +175 -0
  35. package/dist/components/ListItem/ListItem.svelte.d.ts +24 -0
  36. package/dist/components/ListItem/index.d.ts +2 -0
  37. package/dist/components/ListItem/index.js +2 -0
  38. package/dist/components/ListView/ListView.svelte +463 -0
  39. package/dist/components/ListView/ListView.svelte.d.ts +37 -0
  40. package/dist/components/ListView/index.d.ts +2 -0
  41. package/dist/components/ListView/index.js +2 -0
  42. package/dist/components/NodeGraph/BaseNode.d.ts +57 -0
  43. package/dist/components/NodeGraph/BaseNode.js +30 -0
  44. package/dist/components/NodeGraph/Edge.svelte +60 -0
  45. package/dist/components/NodeGraph/Edge.svelte.d.ts +16 -0
  46. package/dist/components/NodeGraph/ExpressionEvaluator.d.ts +82 -0
  47. package/dist/components/NodeGraph/ExpressionEvaluator.js +152 -0
  48. package/dist/components/NodeGraph/Node.svelte +100 -0
  49. package/dist/components/NodeGraph/Node.svelte.d.ts +10 -0
  50. package/dist/components/NodeGraph/NodeGraph.svelte +52 -0
  51. package/dist/components/NodeGraph/NodeGraph.svelte.d.ts +14 -0
  52. package/dist/components/NodeGraph/NodeInstance.svelte.d.ts +80 -0
  53. package/dist/components/NodeGraph/NodeInstance.svelte.js +241 -0
  54. package/dist/components/NodeGraph/NodePort.svelte +75 -0
  55. package/dist/components/NodeGraph/NodePort.svelte.d.ts +11 -0
  56. package/dist/components/NodeGraph/decorators.d.ts +81 -0
  57. package/dist/components/NodeGraph/decorators.js +148 -0
  58. package/dist/components/NodeGraph/index.d.ts +9 -0
  59. package/dist/components/NodeGraph/index.js +9 -0
  60. package/dist/components/NodeGraph/types.d.ts +94 -0
  61. package/dist/components/NodeGraph/types.js +33 -0
  62. package/dist/components/NotesEditor/NotesEditor.svelte +203 -0
  63. package/dist/components/NotesEditor/NotesEditor.svelte.d.ts +9 -0
  64. package/dist/components/NotesEditor/index.d.ts +1 -0
  65. package/dist/components/NotesEditor/index.js +1 -0
  66. package/dist/components/NumberInput/NumberInput.svelte +353 -0
  67. package/dist/components/NumberInput/NumberInput.svelte.d.ts +26 -0
  68. package/dist/components/NumberInput/index.d.ts +1 -0
  69. package/dist/components/NumberInput/index.js +1 -0
  70. package/dist/components/PasswordInput/PasswordInput.svelte +41 -0
  71. package/dist/components/PasswordInput/PasswordInput.svelte.d.ts +13 -0
  72. package/dist/components/PasswordInput/index.d.ts +1 -0
  73. package/dist/components/PasswordInput/index.js +1 -0
  74. package/dist/components/Popup/index.d.ts +1 -0
  75. package/dist/components/Popup/index.js +1 -0
  76. package/dist/components/Rating/Rating.svelte +77 -0
  77. package/dist/components/Rating/Rating.svelte.d.ts +7 -0
  78. package/dist/components/Rating/index.d.ts +1 -0
  79. package/dist/components/Rating/index.js +1 -0
  80. package/dist/components/ScrollView/ScrollView.svelte +285 -0
  81. package/dist/components/ScrollView/ScrollView.svelte.d.ts +19 -0
  82. package/dist/components/ScrollView/index.d.ts +1 -0
  83. package/dist/components/ScrollView/index.js +1 -0
  84. package/dist/components/SearchInput/SearchInput.svelte +50 -0
  85. package/dist/components/SearchInput/SearchInput.svelte.d.ts +15 -0
  86. package/dist/components/SearchInput/index.d.ts +1 -0
  87. package/dist/components/SearchInput/index.js +1 -0
  88. package/dist/components/Select/Select.svelte +278 -0
  89. package/dist/components/Select/Select.svelte.d.ts +35 -0
  90. package/dist/components/Select/index.d.ts +1 -0
  91. package/dist/components/Select/index.js +1 -0
  92. package/dist/components/TextArea/TextArea.svelte +734 -0
  93. package/dist/components/TextArea/TextArea.svelte.d.ts +19 -0
  94. package/dist/components/TextArea/index.d.ts +1 -0
  95. package/dist/components/TextArea/index.js +1 -0
  96. package/dist/components/ThemeSelector/ThemeSelector.svelte +64 -0
  97. package/dist/components/ThemeSelector/ThemeSelector.svelte.d.ts +3 -0
  98. package/dist/components/ThemeSelector/index.d.ts +1 -0
  99. package/dist/components/ThemeSelector/index.js +1 -0
  100. package/dist/components/TooltipHandler/TooltipHandler.svelte +593 -0
  101. package/dist/components/TooltipHandler/TooltipHandler.svelte.d.ts +10 -0
  102. package/dist/components/TooltipHandler/index.d.ts +1 -0
  103. package/dist/components/TooltipHandler/index.js +1 -0
  104. package/dist/index.d.ts +24 -0
  105. package/dist/index.js +26 -0
  106. package/dist/styles/sizes.d.ts +78 -0
  107. package/dist/styles/sizes.js +120 -0
  108. package/dist/styles/variants.d.ts +106 -0
  109. package/dist/styles/variants.js +194 -0
  110. package/dist/types/ManagerTypes.d.ts +42 -0
  111. package/dist/types/ManagerTypes.js +1 -0
  112. package/dist/types/sizes.d.ts +5 -0
  113. package/dist/types/sizes.js +1 -0
  114. package/dist/types/variants.d.ts +1 -0
  115. package/dist/types/variants.js +1 -0
  116. package/package.json +65 -0
@@ -0,0 +1,80 @@
1
+ import { getNodeMetadata } from "./decorators.js";
2
+ import type { BaseNode } from "./BaseNode.js";
3
+ import type { PortMetadata, Position } from "./types.js";
4
+ /**
5
+ * NodeInstance - Reactive wrapper for node definitions
6
+ *
7
+ * Wraps a BaseNode class with Svelte 5 runes for reactivity:
8
+ * - `$state` for position, selection, port values, dirty tracking
9
+ * - `$effect` for reactive connections and auto-execution
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * const mathNode = new NodeInstance(MathNode, 'node-1');
14
+ * mathNode.position = { x: 100, y: 100 };
15
+ * mathNode.execute();
16
+ * ```
17
+ */
18
+ export declare class NodeInstance {
19
+ id: string;
20
+ node: BaseNode;
21
+ metadata: ReturnType<typeof getNodeMetadata>;
22
+ position: Position;
23
+ selected: boolean;
24
+ dirty: boolean;
25
+ executing: boolean;
26
+ error: string | null;
27
+ dataInputs: PortMetadata[];
28
+ dataOutputs: PortMetadata[];
29
+ flowInputs: PortMetadata[];
30
+ flowOutputs: PortMetadata[];
31
+ constructor(NodeClass: new () => BaseNode, id: string, position?: Position);
32
+ /**
33
+ * Initialize port arrays from metadata
34
+ */
35
+ private initializePorts;
36
+ /**
37
+ * Set up auto-execution effect (if executeInEditor is true)
38
+ */
39
+ private setupAutoExecution;
40
+ /**
41
+ * Execute the node with pull-based evaluation
42
+ */
43
+ execute(): string | void;
44
+ /**
45
+ * Get the value of an output port
46
+ */
47
+ getOutputValue(portKey: string): any;
48
+ /**
49
+ * Connect an input port to a source node's output port
50
+ */
51
+ connect(inputPortKey: string, sourceNode: NodeInstance, sourcePortKey: string): void;
52
+ /**
53
+ * Disconnect an input port
54
+ */
55
+ disconnect(inputPortKey: string): void;
56
+ /**
57
+ * Mark this node as dirty (needs re-execution)
58
+ */
59
+ markDirty(): void;
60
+ /**
61
+ * Set an input port value (for unconnected ports)
62
+ */
63
+ setInputValue(portKey: string, value: any): void;
64
+ /**
65
+ * Get all input ports (data + flow)
66
+ */
67
+ getAllInputs(): PortMetadata[];
68
+ /**
69
+ * Get all output ports (data + flow)
70
+ */
71
+ getAllOutputs(): PortMetadata[];
72
+ /**
73
+ * Clone this instance (new instance of same node type)
74
+ */
75
+ clone(newId: string): NodeInstance;
76
+ /**
77
+ * Serialize to JSON (for saving)
78
+ */
79
+ toJSON(): any;
80
+ }
@@ -0,0 +1,241 @@
1
+ import { getNodeMetadata } from "./decorators.js";
2
+ import { PortMode } from "./types.js";
3
+ /**
4
+ * NodeInstance - Reactive wrapper for node definitions
5
+ *
6
+ * Wraps a BaseNode class with Svelte 5 runes for reactivity:
7
+ * - `$state` for position, selection, port values, dirty tracking
8
+ * - `$effect` for reactive connections and auto-execution
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const mathNode = new NodeInstance(MathNode, 'node-1');
13
+ * mathNode.position = { x: 100, y: 100 };
14
+ * mathNode.execute();
15
+ * ```
16
+ */
17
+ export class NodeInstance {
18
+ id;
19
+ node;
20
+ metadata;
21
+ // Reactive state
22
+ position = $state({ x: 0, y: 0 });
23
+ selected = $state(false);
24
+ dirty = $state(true);
25
+ executing = $state(false);
26
+ error = $state(null);
27
+ // Port arrays with runtime data
28
+ dataInputs = $state([]);
29
+ dataOutputs = $state([]);
30
+ flowInputs = $state([]);
31
+ flowOutputs = $state([]);
32
+ constructor(NodeClass, id, position) {
33
+ this.id = id;
34
+ this.node = new NodeClass();
35
+ this.metadata = getNodeMetadata(NodeClass);
36
+ if (position) {
37
+ this.position = position;
38
+ }
39
+ // Initialize port arrays with runtime state
40
+ this.initializePorts();
41
+ // Set up auto-execution if enabled
42
+ if (this.metadata.node.executeInEditor) {
43
+ this.setupAutoExecution();
44
+ }
45
+ }
46
+ /**
47
+ * Initialize port arrays from metadata
48
+ */
49
+ initializePorts() {
50
+ // Clone metadata and add runtime state
51
+ this.dataInputs = this.metadata.inputs
52
+ .filter((p) => p.mode === PortMode.Data)
53
+ .map((p) => ({
54
+ ...p,
55
+ value: p.defaultValue,
56
+ connected: false,
57
+ sourceNode: undefined,
58
+ sourcePort: undefined,
59
+ }));
60
+ this.dataOutputs = this.metadata.outputs
61
+ .filter((p) => p.mode === PortMode.Data)
62
+ .map((p) => ({ ...p, value: undefined }));
63
+ this.flowInputs = this.metadata.inputs
64
+ .filter((p) => p.mode === PortMode.Flow)
65
+ .map((p) => ({
66
+ ...p,
67
+ connected: false,
68
+ sourceNode: undefined,
69
+ sourcePort: undefined,
70
+ }));
71
+ this.flowOutputs = this.metadata.outputs
72
+ .filter((p) => p.mode === PortMode.Flow)
73
+ .map((p) => ({ ...p }));
74
+ // Initialize node properties with default values
75
+ for (const port of this.dataInputs) {
76
+ if (port.defaultValue !== undefined) {
77
+ this.node[port.key] = port.defaultValue;
78
+ }
79
+ }
80
+ }
81
+ /**
82
+ * Set up auto-execution effect (if executeInEditor is true)
83
+ */
84
+ setupAutoExecution() {
85
+ $effect(() => {
86
+ // Watch all data input values
87
+ this.dataInputs.forEach((input) => input.value);
88
+ // Auto-execute when any input changes
89
+ this.execute();
90
+ });
91
+ }
92
+ /**
93
+ * Execute the node with pull-based evaluation
94
+ */
95
+ execute() {
96
+ // Skip if already up-to-date
97
+ if (!this.dirty) {
98
+ return;
99
+ }
100
+ this.executing = true;
101
+ this.error = null;
102
+ try {
103
+ // Pull from connected sources (recursive)
104
+ for (const port of this.dataInputs) {
105
+ if (port.connected && port.sourceNode) {
106
+ port.sourceNode.execute(); // Recursive pull
107
+ const value = port.sourceNode.getOutputValue(port.sourcePort);
108
+ port.value = value;
109
+ this.node[port.key] = value;
110
+ }
111
+ else {
112
+ // Use local value
113
+ this.node[port.key] = port.value ?? port.defaultValue;
114
+ }
115
+ }
116
+ // Execute the node
117
+ const flowOutput = this.node.execute();
118
+ // Update output values
119
+ for (const port of this.dataOutputs) {
120
+ port.value = this.node[port.key];
121
+ }
122
+ // Mark as clean
123
+ this.dirty = false;
124
+ // Return flow output for flow-based execution
125
+ return flowOutput;
126
+ }
127
+ catch (err) {
128
+ this.error = err instanceof Error ? err.message : String(err);
129
+ console.error(`Error executing node ${this.id}:`, err);
130
+ }
131
+ finally {
132
+ this.executing = false;
133
+ }
134
+ }
135
+ /**
136
+ * Get the value of an output port
137
+ */
138
+ getOutputValue(portKey) {
139
+ const port = this.dataOutputs.find((p) => p.key === portKey);
140
+ return port?.value;
141
+ }
142
+ /**
143
+ * Connect an input port to a source node's output port
144
+ */
145
+ connect(inputPortKey, sourceNode, sourcePortKey) {
146
+ const inputPort = this.dataInputs.find((p) => p.key === inputPortKey);
147
+ if (!inputPort) {
148
+ throw new Error(`Input port ${inputPortKey} not found on node ${this.id}`);
149
+ }
150
+ const sourcePort = sourceNode.dataOutputs.find((p) => p.key === sourcePortKey);
151
+ if (!sourcePort) {
152
+ throw new Error(`Output port ${sourcePortKey} not found on source node ${sourceNode.id}`);
153
+ }
154
+ // Validate type compatibility (if types are specified)
155
+ if (inputPort.dataType &&
156
+ sourcePort.dataType &&
157
+ inputPort.dataType !== sourcePort.dataType) {
158
+ console.warn(`Type mismatch: ${sourcePort.dataType} → ${inputPort.dataType}`);
159
+ }
160
+ // Set connection
161
+ inputPort.connected = true;
162
+ inputPort.sourceNode = sourceNode;
163
+ inputPort.sourcePort = sourcePortKey;
164
+ // Mark as dirty
165
+ this.markDirty();
166
+ }
167
+ /**
168
+ * Disconnect an input port
169
+ */
170
+ disconnect(inputPortKey) {
171
+ const inputPort = this.dataInputs.find((p) => p.key === inputPortKey);
172
+ if (!inputPort) {
173
+ return;
174
+ }
175
+ inputPort.connected = false;
176
+ inputPort.sourceNode = undefined;
177
+ inputPort.sourcePort = undefined;
178
+ // Mark as dirty
179
+ this.markDirty();
180
+ }
181
+ /**
182
+ * Mark this node as dirty (needs re-execution)
183
+ */
184
+ markDirty() {
185
+ this.dirty = true;
186
+ }
187
+ /**
188
+ * Set an input port value (for unconnected ports)
189
+ */
190
+ setInputValue(portKey, value) {
191
+ const inputPort = this.dataInputs.find((p) => p.key === portKey);
192
+ if (!inputPort) {
193
+ return;
194
+ }
195
+ inputPort.value = value;
196
+ this.node[portKey] = value;
197
+ // Mark as dirty
198
+ this.markDirty();
199
+ }
200
+ /**
201
+ * Get all input ports (data + flow)
202
+ */
203
+ getAllInputs() {
204
+ return [...this.flowInputs, ...this.dataInputs];
205
+ }
206
+ /**
207
+ * Get all output ports (data + flow)
208
+ */
209
+ getAllOutputs() {
210
+ return [...this.flowOutputs, ...this.dataOutputs];
211
+ }
212
+ /**
213
+ * Clone this instance (new instance of same node type)
214
+ */
215
+ clone(newId) {
216
+ const NodeClass = this.node.constructor;
217
+ const clone = new NodeInstance(NodeClass, newId, { ...this.position });
218
+ // Copy input values (but not connections)
219
+ for (let i = 0; i < this.dataInputs.length; i++) {
220
+ clone.dataInputs[i].value = this.dataInputs[i].value;
221
+ }
222
+ return clone;
223
+ }
224
+ /**
225
+ * Serialize to JSON (for saving)
226
+ */
227
+ toJSON() {
228
+ return {
229
+ id: this.id,
230
+ type: this.node.constructor.name,
231
+ position: this.position,
232
+ inputs: this.dataInputs.map((p) => ({
233
+ key: p.key,
234
+ value: p.value,
235
+ connected: p.connected,
236
+ sourceNodeId: p.sourceNode?.id,
237
+ sourcePort: p.sourcePort,
238
+ })),
239
+ };
240
+ }
241
+ }
@@ -0,0 +1,75 @@
1
+ <script lang="ts">
2
+ import type { PortMetadata } from './types.js';
3
+
4
+ interface Props {
5
+ port: PortMetadata;
6
+ isInput: boolean;
7
+ connected?: boolean;
8
+ onConnect?: (port: PortMetadata) => void;
9
+ onDisconnect?: (port: PortMetadata) => void;
10
+ }
11
+
12
+ let {
13
+ port,
14
+ isInput,
15
+ connected = false,
16
+ onConnect,
17
+ onDisconnect
18
+ }: Props = $props();
19
+
20
+ function handleClick() {
21
+ if (connected && onDisconnect) {
22
+ onDisconnect(port);
23
+ } else if (onConnect) {
24
+ onConnect(port);
25
+ }
26
+ }
27
+ </script>
28
+
29
+ <button
30
+ class="port"
31
+ class:input={isInput}
32
+ class:output={!isInput}
33
+ class:connected
34
+ onclick={handleClick}
35
+ aria-label="{isInput ? 'Input' : 'Output'} port: {port.label}"
36
+ >
37
+ <div class="port-circle"></div>
38
+ </button>
39
+
40
+ <style>
41
+ .port {
42
+ position: relative;
43
+ width: 16px;
44
+ height: 16px;
45
+ padding: 0;
46
+ border: none;
47
+ background: transparent;
48
+ cursor: pointer;
49
+ }
50
+
51
+ .port-circle {
52
+ width: 12px;
53
+ height: 12px;
54
+ border: 2px solid var(--color-border);
55
+ border-radius: 50%;
56
+ background: var(--color-background);
57
+ transition: all 0.2s;
58
+ }
59
+
60
+ .port:hover .port-circle {
61
+ transform: scale(1.2);
62
+ border-color: var(--color-primary);
63
+ }
64
+
65
+ .port.connected .port-circle {
66
+ background: var(--color-primary);
67
+ border-color: var(--color-primary);
68
+ }
69
+
70
+ .port:focus-visible {
71
+ outline: 2px solid var(--color-primary);
72
+ outline-offset: 2px;
73
+ border-radius: 50%;
74
+ }
75
+ </style>
@@ -0,0 +1,11 @@
1
+ import type { PortMetadata } from './types.js';
2
+ interface Props {
3
+ port: PortMetadata;
4
+ isInput: boolean;
5
+ connected?: boolean;
6
+ onConnect?: (port: PortMetadata) => void;
7
+ onDisconnect?: (port: PortMetadata) => void;
8
+ }
9
+ declare const NodePort: import("svelte").Component<Props, {}, "">;
10
+ type NodePort = ReturnType<typeof NodePort>;
11
+ export default NodePort;
@@ -0,0 +1,81 @@
1
+ import type { NodeOptions, InputOptions, OutputOptions, PortMetadata, NodeMetadata } from './types.js';
2
+ /**
3
+ * @Node decorator - Defines a node type
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * @Node({
8
+ * title: 'Math Operation',
9
+ * description: 'Performs basic math',
10
+ * color: '#10b981',
11
+ * category: 'math',
12
+ * executeInEditor: true
13
+ * })
14
+ * class MathNode extends BaseNode {
15
+ * // ...
16
+ * }
17
+ * ```
18
+ */
19
+ export declare function Node(options: NodeOptions): <T extends {
20
+ new (...args: any[]): any;
21
+ }>(constructor: T) => T;
22
+ /**
23
+ * @Input decorator - Defines an input port on a node
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * // Data input with control
28
+ * @Input({ label: 'A', dataType: 'number', control: 'number' })
29
+ * a: number = 0;
30
+ *
31
+ * // Flow input
32
+ * @Input({ mode: PortMode.Flow })
33
+ * flow?: any;
34
+ *
35
+ * // Expression input (no port)
36
+ * @Input({ label: 'Expression', control: 'expression', showPort: false })
37
+ * expression: string = '0';
38
+ * ```
39
+ */
40
+ export declare function Input(options?: InputOptions): (target: any, propertyKey: string) => void;
41
+ /**
42
+ * @Output decorator - Defines an output port on a node
43
+ *
44
+ * @example
45
+ * ```typescript
46
+ * // Data output
47
+ * @Output({ label: 'Result', dataType: 'number' })
48
+ * result: number = 0;
49
+ *
50
+ * // Flow output
51
+ * @Output({ mode: PortMode.Flow, label: 'Done' })
52
+ * done?: any;
53
+ *
54
+ * // Multiple flow outputs (branching)
55
+ * @Output({ mode: PortMode.Flow, label: 'True' })
56
+ * onTrue?: any;
57
+ *
58
+ * @Output({ mode: PortMode.Flow, label: 'False' })
59
+ * onFalse?: any;
60
+ * ```
61
+ */
62
+ export declare function Output(options?: OutputOptions): (target: any, propertyKey: string) => void;
63
+ /**
64
+ * Get complete metadata for a node class
65
+ *
66
+ * @param nodeClass - The node class (must have decorators)
67
+ * @returns Complete node metadata including inputs and outputs
68
+ */
69
+ export declare function getNodeMetadata(nodeClass: any): NodeMetadata;
70
+ /**
71
+ * Get input ports for a node class
72
+ */
73
+ export declare function getInputPorts(nodeClass: any): PortMetadata[];
74
+ /**
75
+ * Get output ports for a node class
76
+ */
77
+ export declare function getOutputPorts(nodeClass: any): PortMetadata[];
78
+ /**
79
+ * Get node options for a node class
80
+ */
81
+ export declare function getNodeOptions(nodeClass: any): NodeOptions | undefined;
@@ -0,0 +1,148 @@
1
+ import { PortMode } from './types.js';
2
+ /**
3
+ * WeakMaps for storing metadata
4
+ * Using WeakMaps ensures automatic garbage collection and no memory leaks
5
+ */
6
+ const nodeMetadata = new WeakMap();
7
+ const inputMetadata = new WeakMap();
8
+ const outputMetadata = new WeakMap();
9
+ /**
10
+ * @Node decorator - Defines a node type
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * @Node({
15
+ * title: 'Math Operation',
16
+ * description: 'Performs basic math',
17
+ * color: '#10b981',
18
+ * category: 'math',
19
+ * executeInEditor: true
20
+ * })
21
+ * class MathNode extends BaseNode {
22
+ * // ...
23
+ * }
24
+ * ```
25
+ */
26
+ export function Node(options) {
27
+ return function (constructor) {
28
+ nodeMetadata.set(constructor.prototype, options);
29
+ return constructor;
30
+ };
31
+ }
32
+ /**
33
+ * @Input decorator - Defines an input port on a node
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * // Data input with control
38
+ * @Input({ label: 'A', dataType: 'number', control: 'number' })
39
+ * a: number = 0;
40
+ *
41
+ * // Flow input
42
+ * @Input({ mode: PortMode.Flow })
43
+ * flow?: any;
44
+ *
45
+ * // Expression input (no port)
46
+ * @Input({ label: 'Expression', control: 'expression', showPort: false })
47
+ * expression: string = '0';
48
+ * ```
49
+ */
50
+ export function Input(options = {}) {
51
+ return function (target, propertyKey) {
52
+ let inputs = inputMetadata.get(target);
53
+ if (!inputs) {
54
+ inputs = new Map();
55
+ inputMetadata.set(target, inputs);
56
+ }
57
+ // Smart defaults
58
+ const port = {
59
+ key: propertyKey,
60
+ label: options.label || propertyKey,
61
+ dataType: options.dataType,
62
+ mode: options.mode || PortMode.Data,
63
+ control: options.control,
64
+ showPort: options.showPort !== false, // Default true
65
+ alwaysShowControl: options.alwaysShowControl,
66
+ defaultValue: options.defaultValue,
67
+ options: options.options
68
+ };
69
+ inputs.set(propertyKey, port);
70
+ };
71
+ }
72
+ /**
73
+ * @Output decorator - Defines an output port on a node
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * // Data output
78
+ * @Output({ label: 'Result', dataType: 'number' })
79
+ * result: number = 0;
80
+ *
81
+ * // Flow output
82
+ * @Output({ mode: PortMode.Flow, label: 'Done' })
83
+ * done?: any;
84
+ *
85
+ * // Multiple flow outputs (branching)
86
+ * @Output({ mode: PortMode.Flow, label: 'True' })
87
+ * onTrue?: any;
88
+ *
89
+ * @Output({ mode: PortMode.Flow, label: 'False' })
90
+ * onFalse?: any;
91
+ * ```
92
+ */
93
+ export function Output(options = {}) {
94
+ return function (target, propertyKey) {
95
+ let outputs = outputMetadata.get(target);
96
+ if (!outputs) {
97
+ outputs = new Map();
98
+ outputMetadata.set(target, outputs);
99
+ }
100
+ const port = {
101
+ key: propertyKey,
102
+ label: options.label || propertyKey,
103
+ dataType: options.dataType,
104
+ mode: options.mode || PortMode.Data
105
+ };
106
+ outputs.set(propertyKey, port);
107
+ };
108
+ }
109
+ /**
110
+ * Get complete metadata for a node class
111
+ *
112
+ * @param nodeClass - The node class (must have decorators)
113
+ * @returns Complete node metadata including inputs and outputs
114
+ */
115
+ export function getNodeMetadata(nodeClass) {
116
+ const prototype = nodeClass.prototype;
117
+ const node = nodeMetadata.get(prototype);
118
+ if (!node) {
119
+ throw new Error(`Class ${nodeClass.name} is missing @Node decorator`);
120
+ }
121
+ const inputsMap = inputMetadata.get(prototype) || new Map();
122
+ const outputsMap = outputMetadata.get(prototype) || new Map();
123
+ return {
124
+ node,
125
+ inputs: Array.from(inputsMap.values()),
126
+ outputs: Array.from(outputsMap.values())
127
+ };
128
+ }
129
+ /**
130
+ * Get input ports for a node class
131
+ */
132
+ export function getInputPorts(nodeClass) {
133
+ const inputsMap = inputMetadata.get(nodeClass.prototype) || new Map();
134
+ return Array.from(inputsMap.values());
135
+ }
136
+ /**
137
+ * Get output ports for a node class
138
+ */
139
+ export function getOutputPorts(nodeClass) {
140
+ const outputsMap = outputMetadata.get(nodeClass.prototype) || new Map();
141
+ return Array.from(outputsMap.values());
142
+ }
143
+ /**
144
+ * Get node options for a node class
145
+ */
146
+ export function getNodeOptions(nodeClass) {
147
+ return nodeMetadata.get(nodeClass.prototype);
148
+ }
@@ -0,0 +1,9 @@
1
+ export { default as NodeGraph } from "./NodeGraph.svelte";
2
+ export { default as Node } from "./Node.svelte";
3
+ export { default as NodePort } from "./NodePort.svelte";
4
+ export { default as Edge } from "./Edge.svelte";
5
+ export { Node as NodeDecorator, Input, Output } from "./decorators.js";
6
+ export { BaseNode } from "./BaseNode.js";
7
+ export { NodeInstance } from "./NodeInstance.svelte.js";
8
+ export { ExpressionEvaluator } from "./ExpressionEvaluator.js";
9
+ export * from "./types.js";
@@ -0,0 +1,9 @@
1
+ export { default as NodeGraph } from "./NodeGraph.svelte";
2
+ export { default as Node } from "./Node.svelte";
3
+ export { default as NodePort } from "./NodePort.svelte";
4
+ export { default as Edge } from "./Edge.svelte";
5
+ export { Node as NodeDecorator, Input, Output } from "./decorators.js";
6
+ export { BaseNode } from "./BaseNode.js";
7
+ export { NodeInstance } from "./NodeInstance.svelte.js";
8
+ export { ExpressionEvaluator } from "./ExpressionEvaluator.js";
9
+ export * from "./types.js";