@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.
- package/README.md +81 -0
- package/dist/components/Badge/Badge.svelte +80 -0
- package/dist/components/Badge/Badge.svelte.d.ts +14 -0
- package/dist/components/Badge/index.d.ts +1 -0
- package/dist/components/Badge/index.js +1 -0
- package/dist/components/Button/Button.svelte +172 -0
- package/dist/components/Button/Button.svelte.d.ts +32 -0
- package/dist/components/Button/index.d.ts +1 -0
- package/dist/components/Button/index.js +1 -0
- package/dist/components/Dialog/Dialog.svelte +101 -0
- package/dist/components/Dialog/Dialog.svelte.d.ts +18 -0
- package/dist/components/Dialog/index.d.ts +1 -0
- package/dist/components/Dialog/index.js +1 -0
- package/dist/components/ElementManager/ElementManager.svelte +397 -0
- package/dist/components/ElementManager/ElementManager.svelte.d.ts +43 -0
- package/dist/components/ElementManager/index.d.ts +1 -0
- package/dist/components/ElementManager/index.js +1 -0
- package/dist/components/EmailInput/EmailInput.svelte +47 -0
- package/dist/components/EmailInput/EmailInput.svelte.d.ts +14 -0
- package/dist/components/EmailInput/index.d.ts +1 -0
- package/dist/components/EmailInput/index.js +1 -0
- package/dist/components/Icon/Icon.svelte +74 -0
- package/dist/components/Icon/Icon.svelte.d.ts +13 -0
- package/dist/components/Icon/index.d.ts +1 -0
- package/dist/components/Icon/index.js +1 -0
- package/dist/components/Input/Input.svelte +268 -0
- package/dist/components/Input/Input.svelte.d.ts +18 -0
- package/dist/components/Input/index.d.ts +1 -0
- package/dist/components/Input/index.js +1 -0
- package/dist/components/List/List.svelte +580 -0
- package/dist/components/List/List.svelte.d.ts +38 -0
- package/dist/components/List/index.d.ts +1 -0
- package/dist/components/List/index.js +1 -0
- package/dist/components/ListItem/ListItem.svelte +175 -0
- package/dist/components/ListItem/ListItem.svelte.d.ts +24 -0
- package/dist/components/ListItem/index.d.ts +2 -0
- package/dist/components/ListItem/index.js +2 -0
- package/dist/components/ListView/ListView.svelte +463 -0
- package/dist/components/ListView/ListView.svelte.d.ts +37 -0
- package/dist/components/ListView/index.d.ts +2 -0
- package/dist/components/ListView/index.js +2 -0
- package/dist/components/NodeGraph/BaseNode.d.ts +57 -0
- package/dist/components/NodeGraph/BaseNode.js +30 -0
- package/dist/components/NodeGraph/Edge.svelte +60 -0
- package/dist/components/NodeGraph/Edge.svelte.d.ts +16 -0
- package/dist/components/NodeGraph/ExpressionEvaluator.d.ts +82 -0
- package/dist/components/NodeGraph/ExpressionEvaluator.js +152 -0
- package/dist/components/NodeGraph/Node.svelte +100 -0
- package/dist/components/NodeGraph/Node.svelte.d.ts +10 -0
- package/dist/components/NodeGraph/NodeGraph.svelte +52 -0
- package/dist/components/NodeGraph/NodeGraph.svelte.d.ts +14 -0
- package/dist/components/NodeGraph/NodeInstance.svelte.d.ts +80 -0
- package/dist/components/NodeGraph/NodeInstance.svelte.js +241 -0
- package/dist/components/NodeGraph/NodePort.svelte +75 -0
- package/dist/components/NodeGraph/NodePort.svelte.d.ts +11 -0
- package/dist/components/NodeGraph/decorators.d.ts +81 -0
- package/dist/components/NodeGraph/decorators.js +148 -0
- package/dist/components/NodeGraph/index.d.ts +9 -0
- package/dist/components/NodeGraph/index.js +9 -0
- package/dist/components/NodeGraph/types.d.ts +94 -0
- package/dist/components/NodeGraph/types.js +33 -0
- package/dist/components/NotesEditor/NotesEditor.svelte +203 -0
- package/dist/components/NotesEditor/NotesEditor.svelte.d.ts +9 -0
- package/dist/components/NotesEditor/index.d.ts +1 -0
- package/dist/components/NotesEditor/index.js +1 -0
- package/dist/components/NumberInput/NumberInput.svelte +353 -0
- package/dist/components/NumberInput/NumberInput.svelte.d.ts +26 -0
- package/dist/components/NumberInput/index.d.ts +1 -0
- package/dist/components/NumberInput/index.js +1 -0
- package/dist/components/PasswordInput/PasswordInput.svelte +41 -0
- package/dist/components/PasswordInput/PasswordInput.svelte.d.ts +13 -0
- package/dist/components/PasswordInput/index.d.ts +1 -0
- package/dist/components/PasswordInput/index.js +1 -0
- package/dist/components/Popup/index.d.ts +1 -0
- package/dist/components/Popup/index.js +1 -0
- package/dist/components/Rating/Rating.svelte +77 -0
- package/dist/components/Rating/Rating.svelte.d.ts +7 -0
- package/dist/components/Rating/index.d.ts +1 -0
- package/dist/components/Rating/index.js +1 -0
- package/dist/components/ScrollView/ScrollView.svelte +285 -0
- package/dist/components/ScrollView/ScrollView.svelte.d.ts +19 -0
- package/dist/components/ScrollView/index.d.ts +1 -0
- package/dist/components/ScrollView/index.js +1 -0
- package/dist/components/SearchInput/SearchInput.svelte +50 -0
- package/dist/components/SearchInput/SearchInput.svelte.d.ts +15 -0
- package/dist/components/SearchInput/index.d.ts +1 -0
- package/dist/components/SearchInput/index.js +1 -0
- package/dist/components/Select/Select.svelte +278 -0
- package/dist/components/Select/Select.svelte.d.ts +35 -0
- package/dist/components/Select/index.d.ts +1 -0
- package/dist/components/Select/index.js +1 -0
- package/dist/components/TextArea/TextArea.svelte +734 -0
- package/dist/components/TextArea/TextArea.svelte.d.ts +19 -0
- package/dist/components/TextArea/index.d.ts +1 -0
- package/dist/components/TextArea/index.js +1 -0
- package/dist/components/ThemeSelector/ThemeSelector.svelte +64 -0
- package/dist/components/ThemeSelector/ThemeSelector.svelte.d.ts +3 -0
- package/dist/components/ThemeSelector/index.d.ts +1 -0
- package/dist/components/ThemeSelector/index.js +1 -0
- package/dist/components/TooltipHandler/TooltipHandler.svelte +593 -0
- package/dist/components/TooltipHandler/TooltipHandler.svelte.d.ts +10 -0
- package/dist/components/TooltipHandler/index.d.ts +1 -0
- package/dist/components/TooltipHandler/index.js +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +26 -0
- package/dist/styles/sizes.d.ts +78 -0
- package/dist/styles/sizes.js +120 -0
- package/dist/styles/variants.d.ts +106 -0
- package/dist/styles/variants.js +194 -0
- package/dist/types/ManagerTypes.d.ts +42 -0
- package/dist/types/ManagerTypes.js +1 -0
- package/dist/types/sizes.d.ts +5 -0
- package/dist/types/sizes.js +1 -0
- package/dist/types/variants.d.ts +1 -0
- package/dist/types/variants.js +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
type Option = Record<string, any> & {
|
|
3
|
+
value: string;
|
|
4
|
+
label: string;
|
|
5
|
+
};
|
|
6
|
+
interface Props {
|
|
7
|
+
options?: Option[];
|
|
8
|
+
value?: string | string[];
|
|
9
|
+
multiSelect?: boolean;
|
|
10
|
+
showCheckboxes?: boolean;
|
|
11
|
+
maxVisibleItems?: number;
|
|
12
|
+
itemHeight?: number;
|
|
13
|
+
minHeight?: number;
|
|
14
|
+
class?: string;
|
|
15
|
+
containerClass?: string;
|
|
16
|
+
disabled?: boolean;
|
|
17
|
+
children?: Snippet;
|
|
18
|
+
url?: string;
|
|
19
|
+
searchParam?: string;
|
|
20
|
+
transform?: (apiResponse: any) => Option[];
|
|
21
|
+
debounceMs?: number;
|
|
22
|
+
maxResults?: number;
|
|
23
|
+
headers?: Record<string, string>;
|
|
24
|
+
searchTerm?: string;
|
|
25
|
+
showLoading?: boolean;
|
|
26
|
+
loadingText?: string;
|
|
27
|
+
showError?: boolean;
|
|
28
|
+
errorText?: string;
|
|
29
|
+
emptyText?: string;
|
|
30
|
+
onError?: (error: Error) => void;
|
|
31
|
+
onLoadStart?: () => void;
|
|
32
|
+
onLoadEnd?: () => void;
|
|
33
|
+
onSelection?: (option: Option | Option[]) => void;
|
|
34
|
+
}
|
|
35
|
+
declare const ListView: import("svelte").Component<Props, {}, "value" | "searchTerm">;
|
|
36
|
+
type ListView = ReturnType<typeof ListView>;
|
|
37
|
+
export default ListView;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BaseNode - Abstract base class for all node definitions
|
|
3
|
+
*
|
|
4
|
+
* All custom nodes must extend this class and implement the execute() method.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* @Node({
|
|
9
|
+
* title: 'Math Operation',
|
|
10
|
+
* color: '#10b981',
|
|
11
|
+
* executeInEditor: true
|
|
12
|
+
* })
|
|
13
|
+
* export class MathNode extends BaseNode {
|
|
14
|
+
* @Input({ label: 'A', dataType: 'number' })
|
|
15
|
+
* a: number = 0;
|
|
16
|
+
*
|
|
17
|
+
* @Input({ label: 'B', dataType: 'number' })
|
|
18
|
+
* b: number = 0;
|
|
19
|
+
*
|
|
20
|
+
* @Output({ label: 'Result', dataType: 'number' })
|
|
21
|
+
* result: number = 0;
|
|
22
|
+
*
|
|
23
|
+
* execute() {
|
|
24
|
+
* this.result = this.a + this.b;
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare abstract class BaseNode {
|
|
30
|
+
/**
|
|
31
|
+
* Execute the node's logic
|
|
32
|
+
*
|
|
33
|
+
* - For data nodes: Update output properties based on input properties
|
|
34
|
+
* - For flow nodes: Perform side effects and optionally return the flow output to follow
|
|
35
|
+
*
|
|
36
|
+
* @returns void for normal execution, or string (flow output key) for branching nodes
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* // Data node
|
|
41
|
+
* execute() {
|
|
42
|
+
* this.result = this.a + this.b;
|
|
43
|
+
* }
|
|
44
|
+
*
|
|
45
|
+
* // Flow node
|
|
46
|
+
* execute() {
|
|
47
|
+
* console.log(this.message);
|
|
48
|
+
* }
|
|
49
|
+
*
|
|
50
|
+
* // Branch node (multiple flow outputs)
|
|
51
|
+
* execute() {
|
|
52
|
+
* return this.condition ? 'onTrue' : 'onFalse';
|
|
53
|
+
* }
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
abstract execute(): void | string;
|
|
57
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BaseNode - Abstract base class for all node definitions
|
|
3
|
+
*
|
|
4
|
+
* All custom nodes must extend this class and implement the execute() method.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* @Node({
|
|
9
|
+
* title: 'Math Operation',
|
|
10
|
+
* color: '#10b981',
|
|
11
|
+
* executeInEditor: true
|
|
12
|
+
* })
|
|
13
|
+
* export class MathNode extends BaseNode {
|
|
14
|
+
* @Input({ label: 'A', dataType: 'number' })
|
|
15
|
+
* a: number = 0;
|
|
16
|
+
*
|
|
17
|
+
* @Input({ label: 'B', dataType: 'number' })
|
|
18
|
+
* b: number = 0;
|
|
19
|
+
*
|
|
20
|
+
* @Output({ label: 'Result', dataType: 'number' })
|
|
21
|
+
* result: number = 0;
|
|
22
|
+
*
|
|
23
|
+
* execute() {
|
|
24
|
+
* this.result = this.a + this.b;
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export class BaseNode {
|
|
30
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
interface Props {
|
|
3
|
+
from: { x: number; y: number };
|
|
4
|
+
to: { x: number; y: number };
|
|
5
|
+
selected?: boolean;
|
|
6
|
+
color?: string;
|
|
7
|
+
animated?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
let {
|
|
11
|
+
from,
|
|
12
|
+
to,
|
|
13
|
+
selected = false,
|
|
14
|
+
color = "var(--color-border)",
|
|
15
|
+
animated = false,
|
|
16
|
+
}: Props = $props();
|
|
17
|
+
|
|
18
|
+
// Calculate SVG path for bezier curve
|
|
19
|
+
const path = $derived.by(() => {
|
|
20
|
+
const dx = to.x - from.x;
|
|
21
|
+
const dy = to.y - from.y;
|
|
22
|
+
|
|
23
|
+
// Control point offset for smooth curves
|
|
24
|
+
const offset = Math.min(Math.abs(dx) * 0.5, 100);
|
|
25
|
+
|
|
26
|
+
return `M ${from.x} ${from.y} C ${from.x + offset} ${from.y}, ${to.x - offset} ${to.y}, ${to.x} ${to.y}`;
|
|
27
|
+
});
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<svg
|
|
31
|
+
class="edge absolute inset-0 pointer-events-none"
|
|
32
|
+
style="overflow: visible;"
|
|
33
|
+
>
|
|
34
|
+
<path
|
|
35
|
+
d={path}
|
|
36
|
+
fill="none"
|
|
37
|
+
stroke={selected ? "var(--color-primary)" : color}
|
|
38
|
+
stroke-width={selected ? "3" : "2"}
|
|
39
|
+
class:animated
|
|
40
|
+
/>
|
|
41
|
+
</svg>
|
|
42
|
+
|
|
43
|
+
<style>
|
|
44
|
+
.edge path {
|
|
45
|
+
transition:
|
|
46
|
+
stroke 0.2s,
|
|
47
|
+
stroke-width 0.2s;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.edge path.animated {
|
|
51
|
+
stroke-dasharray: 5, 5;
|
|
52
|
+
animation: dash 1s linear infinite;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@keyframes dash {
|
|
56
|
+
to {
|
|
57
|
+
stroke-dashoffset: -10;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
from: {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
};
|
|
6
|
+
to: {
|
|
7
|
+
x: number;
|
|
8
|
+
y: number;
|
|
9
|
+
};
|
|
10
|
+
selected?: boolean;
|
|
11
|
+
color?: string;
|
|
12
|
+
animated?: boolean;
|
|
13
|
+
}
|
|
14
|
+
declare const Edge: import("svelte").Component<Props, {}, "">;
|
|
15
|
+
type Edge = ReturnType<typeof Edge>;
|
|
16
|
+
export default Edge;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { VariableScope } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Variable store with three-level scope hierarchy
|
|
4
|
+
*/
|
|
5
|
+
export interface VariableStore {
|
|
6
|
+
global: Record<string, any>;
|
|
7
|
+
project: Record<string, any>;
|
|
8
|
+
workflow: Record<string, any>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* ExpressionEvaluator - Evaluates JavaScript expressions with variable substitution
|
|
12
|
+
*
|
|
13
|
+
* Supports:
|
|
14
|
+
* - Single expressions: `{{ age * 2 }}` → returns number
|
|
15
|
+
* - Template strings: `Hello {{ firstName }}!` → returns string
|
|
16
|
+
* - Object properties: `{{ user.name }}`
|
|
17
|
+
* - Complex expressions: `{{ items.length > 0 }}`
|
|
18
|
+
*
|
|
19
|
+
* Variable resolution order: Workflow → Project → Global
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const evaluator = new ExpressionEvaluator({
|
|
24
|
+
* global: { pi: 3.14159 },
|
|
25
|
+
* project: { projectName: 'MyProject' },
|
|
26
|
+
* workflow: { age: 25 }
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* evaluator.evaluate('{{ age * 2 }}'); // 50
|
|
30
|
+
* evaluator.evaluate('Hello {{ projectName }}!'); // "Hello MyProject!"
|
|
31
|
+
* evaluator.evaluate('{{ pi * 2 }}'); // 6.28318
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare class ExpressionEvaluator {
|
|
35
|
+
private variables;
|
|
36
|
+
constructor(variables?: Partial<VariableStore>);
|
|
37
|
+
/**
|
|
38
|
+
* Set a variable in the specified scope
|
|
39
|
+
*/
|
|
40
|
+
setVariable(name: string, value: any, scope?: VariableScope): void;
|
|
41
|
+
/**
|
|
42
|
+
* Get a variable with automatic scope resolution
|
|
43
|
+
* Resolution order: Workflow → Project → Global
|
|
44
|
+
*/
|
|
45
|
+
getVariable(name: string): any;
|
|
46
|
+
/**
|
|
47
|
+
* Get all variables merged with proper precedence
|
|
48
|
+
*/
|
|
49
|
+
private getAllVariables;
|
|
50
|
+
/**
|
|
51
|
+
* Evaluate an expression string
|
|
52
|
+
*
|
|
53
|
+
* @param input - The expression string (may contain {{ }} delimiters)
|
|
54
|
+
* @returns The evaluated result
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```typescript
|
|
58
|
+
* evaluate('{{ age }}') // Variable lookup
|
|
59
|
+
* evaluate('{{ age * 2 }}') // Expression evaluation
|
|
60
|
+
* evaluate('Hello {{ name }}!') // Template string
|
|
61
|
+
* evaluate('{{ user.name }}') // Object property
|
|
62
|
+
* evaluate('{{ items.length > 0 }}') // Boolean expression
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
evaluate(input: string): any;
|
|
66
|
+
/**
|
|
67
|
+
* Evaluate a single expression (without {{ }} delimiters)
|
|
68
|
+
*/
|
|
69
|
+
private evaluateExpression;
|
|
70
|
+
/**
|
|
71
|
+
* Update the variable store
|
|
72
|
+
*/
|
|
73
|
+
updateVariables(variables: Partial<VariableStore>): void;
|
|
74
|
+
/**
|
|
75
|
+
* Clear variables in a specific scope
|
|
76
|
+
*/
|
|
77
|
+
clearScope(scope: VariableScope): void;
|
|
78
|
+
/**
|
|
79
|
+
* Get all variables in a specific scope
|
|
80
|
+
*/
|
|
81
|
+
getScope(scope: VariableScope): Record<string, any>;
|
|
82
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { VariableScope } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* ExpressionEvaluator - Evaluates JavaScript expressions with variable substitution
|
|
4
|
+
*
|
|
5
|
+
* Supports:
|
|
6
|
+
* - Single expressions: `{{ age * 2 }}` → returns number
|
|
7
|
+
* - Template strings: `Hello {{ firstName }}!` → returns string
|
|
8
|
+
* - Object properties: `{{ user.name }}`
|
|
9
|
+
* - Complex expressions: `{{ items.length > 0 }}`
|
|
10
|
+
*
|
|
11
|
+
* Variable resolution order: Workflow → Project → Global
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const evaluator = new ExpressionEvaluator({
|
|
16
|
+
* global: { pi: 3.14159 },
|
|
17
|
+
* project: { projectName: 'MyProject' },
|
|
18
|
+
* workflow: { age: 25 }
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* evaluator.evaluate('{{ age * 2 }}'); // 50
|
|
22
|
+
* evaluator.evaluate('Hello {{ projectName }}!'); // "Hello MyProject!"
|
|
23
|
+
* evaluator.evaluate('{{ pi * 2 }}'); // 6.28318
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export class ExpressionEvaluator {
|
|
27
|
+
variables;
|
|
28
|
+
constructor(variables) {
|
|
29
|
+
this.variables = {
|
|
30
|
+
global: variables?.global || {},
|
|
31
|
+
project: variables?.project || {},
|
|
32
|
+
workflow: variables?.workflow || {}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Set a variable in the specified scope
|
|
37
|
+
*/
|
|
38
|
+
setVariable(name, value, scope = VariableScope.Workflow) {
|
|
39
|
+
this.variables[scope][name] = value;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Get a variable with automatic scope resolution
|
|
43
|
+
* Resolution order: Workflow → Project → Global
|
|
44
|
+
*/
|
|
45
|
+
getVariable(name) {
|
|
46
|
+
if (name in this.variables.workflow) {
|
|
47
|
+
return this.variables.workflow[name];
|
|
48
|
+
}
|
|
49
|
+
if (name in this.variables.project) {
|
|
50
|
+
return this.variables.project[name];
|
|
51
|
+
}
|
|
52
|
+
if (name in this.variables.global) {
|
|
53
|
+
return this.variables.global[name];
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get all variables merged with proper precedence
|
|
59
|
+
*/
|
|
60
|
+
getAllVariables() {
|
|
61
|
+
return {
|
|
62
|
+
...this.variables.global,
|
|
63
|
+
...this.variables.project,
|
|
64
|
+
...this.variables.workflow
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Evaluate an expression string
|
|
69
|
+
*
|
|
70
|
+
* @param input - The expression string (may contain {{ }} delimiters)
|
|
71
|
+
* @returns The evaluated result
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```typescript
|
|
75
|
+
* evaluate('{{ age }}') // Variable lookup
|
|
76
|
+
* evaluate('{{ age * 2 }}') // Expression evaluation
|
|
77
|
+
* evaluate('Hello {{ name }}!') // Template string
|
|
78
|
+
* evaluate('{{ user.name }}') // Object property
|
|
79
|
+
* evaluate('{{ items.length > 0 }}') // Boolean expression
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
evaluate(input) {
|
|
83
|
+
if (typeof input !== 'string') {
|
|
84
|
+
return input;
|
|
85
|
+
}
|
|
86
|
+
const expressionRegex = /\{\{([^}]+)\}\}/g;
|
|
87
|
+
const matches = input.match(expressionRegex);
|
|
88
|
+
// No expressions found - return as is
|
|
89
|
+
if (!matches) {
|
|
90
|
+
return input;
|
|
91
|
+
}
|
|
92
|
+
// Single expression that spans entire string - return evaluated value
|
|
93
|
+
if (matches.length === 1 && input.trim() === matches[0].trim()) {
|
|
94
|
+
const expression = matches[0].replace(/\{\{|\}\}/g, '').trim();
|
|
95
|
+
return this.evaluateExpression(expression);
|
|
96
|
+
}
|
|
97
|
+
// Template string with multiple expressions - replace each and return string
|
|
98
|
+
let result = input;
|
|
99
|
+
for (const match of matches) {
|
|
100
|
+
const expression = match.replace(/\{\{|\}\}/g, '').trim();
|
|
101
|
+
const value = this.evaluateExpression(expression);
|
|
102
|
+
result = result.replace(match, String(value ?? ''));
|
|
103
|
+
}
|
|
104
|
+
return result;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Evaluate a single expression (without {{ }} delimiters)
|
|
108
|
+
*/
|
|
109
|
+
evaluateExpression(expression) {
|
|
110
|
+
try {
|
|
111
|
+
// Create a function that evaluates the expression with variables in scope
|
|
112
|
+
const variables = this.getAllVariables();
|
|
113
|
+
const varNames = Object.keys(variables);
|
|
114
|
+
const varValues = Object.values(variables);
|
|
115
|
+
// Create function with variables as parameters
|
|
116
|
+
// eslint-disable-next-line no-new-func
|
|
117
|
+
const fn = new Function(...varNames, `return (${expression});`);
|
|
118
|
+
// Execute with variable values
|
|
119
|
+
return fn(...varValues);
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
console.error(`Error evaluating expression: ${expression}`, error);
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Update the variable store
|
|
128
|
+
*/
|
|
129
|
+
updateVariables(variables) {
|
|
130
|
+
if (variables.global) {
|
|
131
|
+
this.variables.global = { ...this.variables.global, ...variables.global };
|
|
132
|
+
}
|
|
133
|
+
if (variables.project) {
|
|
134
|
+
this.variables.project = { ...this.variables.project, ...variables.project };
|
|
135
|
+
}
|
|
136
|
+
if (variables.workflow) {
|
|
137
|
+
this.variables.workflow = { ...this.variables.workflow, ...variables.workflow };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Clear variables in a specific scope
|
|
142
|
+
*/
|
|
143
|
+
clearScope(scope) {
|
|
144
|
+
this.variables[scope] = {};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get all variables in a specific scope
|
|
148
|
+
*/
|
|
149
|
+
getScope(scope) {
|
|
150
|
+
return { ...this.variables[scope] };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { NodeInstance } from "./NodeInstance.svelte.js";
|
|
3
|
+
import type { Snippet } from "svelte";
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
instance: NodeInstance;
|
|
7
|
+
selected?: boolean;
|
|
8
|
+
children?: Snippet;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let { instance, selected = false, children }: Props = $props();
|
|
12
|
+
|
|
13
|
+
const metadata = instance.metadata;
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<div
|
|
17
|
+
class="node"
|
|
18
|
+
class:selected
|
|
19
|
+
class:executing={instance.executing}
|
|
20
|
+
class:error={instance.error}
|
|
21
|
+
style:left="{instance.position.x}px"
|
|
22
|
+
style:top="{instance.position.y}px"
|
|
23
|
+
style:border-color={selected
|
|
24
|
+
? "var(--color-primary)"
|
|
25
|
+
: "var(--color-border)"}
|
|
26
|
+
>
|
|
27
|
+
<!-- Header -->
|
|
28
|
+
<div
|
|
29
|
+
class="node-header px-3 py-2 text-white font-medium text-sm"
|
|
30
|
+
style:background-color={metadata.node.color || "var(--color-primary)"}
|
|
31
|
+
>
|
|
32
|
+
{metadata.node.title}
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<!-- Body -->
|
|
36
|
+
<div class="node-body p-3 bg-[var(--color-background)]">
|
|
37
|
+
<!-- Input ports -->
|
|
38
|
+
<div class="inputs space-y-2">
|
|
39
|
+
{#each instance.getAllInputs() as port}
|
|
40
|
+
<div class="port-row flex items-center justify-between gap-2">
|
|
41
|
+
<span class="text-sm text-[var(--color-text)]"
|
|
42
|
+
>{port.label}</span
|
|
43
|
+
>
|
|
44
|
+
<!-- Port rendering TODO -->
|
|
45
|
+
</div>
|
|
46
|
+
{/each}
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<!-- Custom content -->
|
|
50
|
+
{#if children}
|
|
51
|
+
{@render children()}
|
|
52
|
+
{/if}
|
|
53
|
+
|
|
54
|
+
<!-- Output ports -->
|
|
55
|
+
<div class="outputs space-y-2 mt-2">
|
|
56
|
+
{#each instance.getAllOutputs() as port}
|
|
57
|
+
<div class="port-row flex items-center justify-between gap-2">
|
|
58
|
+
<span class="text-sm text-[var(--color-text)]"
|
|
59
|
+
>{port.label}</span
|
|
60
|
+
>
|
|
61
|
+
<!-- Port rendering TODO -->
|
|
62
|
+
</div>
|
|
63
|
+
{/each}
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
{#if instance.error}
|
|
68
|
+
<div class="node-error px-3 py-1 bg-red-100 text-red-700 text-xs">
|
|
69
|
+
{instance.error}
|
|
70
|
+
</div>
|
|
71
|
+
{/if}
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<style>
|
|
75
|
+
.node {
|
|
76
|
+
position: absolute;
|
|
77
|
+
min-width: 200px;
|
|
78
|
+
border: 2px solid;
|
|
79
|
+
border-radius: 8px;
|
|
80
|
+
overflow: hidden;
|
|
81
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
82
|
+
cursor: move;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.node.selected {
|
|
86
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.node.executing {
|
|
90
|
+
opacity: 0.8;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.node.error {
|
|
94
|
+
border-color: #dc2626 !important;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.node-header {
|
|
98
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
|
99
|
+
}
|
|
100
|
+
</style>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { NodeInstance } from "./NodeInstance.svelte.js";
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
interface Props {
|
|
4
|
+
instance: NodeInstance;
|
|
5
|
+
selected?: boolean;
|
|
6
|
+
children?: Snippet;
|
|
7
|
+
}
|
|
8
|
+
declare const Node: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type Node = ReturnType<typeof Node>;
|
|
10
|
+
export default Node;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { NodeInstance } from './NodeInstance.svelte.js';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
nodes?: NodeInstance[];
|
|
7
|
+
width?: number;
|
|
8
|
+
height?: number;
|
|
9
|
+
gridSize?: number;
|
|
10
|
+
showGrid?: boolean;
|
|
11
|
+
editable?: boolean;
|
|
12
|
+
children?: Snippet;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let {
|
|
16
|
+
nodes = [],
|
|
17
|
+
width,
|
|
18
|
+
height,
|
|
19
|
+
gridSize = 20,
|
|
20
|
+
showGrid = true,
|
|
21
|
+
editable = true,
|
|
22
|
+
children
|
|
23
|
+
}: Props = $props();
|
|
24
|
+
</script>
|
|
25
|
+
|
|
26
|
+
<div
|
|
27
|
+
class="nodegraph-canvas relative overflow-hidden bg-[var(--color-background)]"
|
|
28
|
+
style:width={width ? `${width}px` : '100%'}
|
|
29
|
+
style:height={height ? `${height}px` : '100%'}
|
|
30
|
+
>
|
|
31
|
+
{#if showGrid}
|
|
32
|
+
<div class="grid-pattern absolute inset-0 pointer-events-none"></div>
|
|
33
|
+
{/if}
|
|
34
|
+
|
|
35
|
+
<!-- Nodes and edges will be rendered here -->
|
|
36
|
+
<div class="nodes-container absolute inset-0">
|
|
37
|
+
<!-- TODO: Render nodes and edges -->
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
{#if children}
|
|
41
|
+
{@render children()}
|
|
42
|
+
{/if}
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<style>
|
|
46
|
+
.grid-pattern {
|
|
47
|
+
background-image:
|
|
48
|
+
linear-gradient(to right, rgba(128, 128, 128, 0.1) 1px, transparent 1px),
|
|
49
|
+
linear-gradient(to bottom, rgba(128, 128, 128, 0.1) 1px, transparent 1px);
|
|
50
|
+
background-size: 20px 20px;
|
|
51
|
+
}
|
|
52
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { NodeInstance } from './NodeInstance.svelte.js';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
interface Props {
|
|
4
|
+
nodes?: NodeInstance[];
|
|
5
|
+
width?: number;
|
|
6
|
+
height?: number;
|
|
7
|
+
gridSize?: number;
|
|
8
|
+
showGrid?: boolean;
|
|
9
|
+
editable?: boolean;
|
|
10
|
+
children?: Snippet;
|
|
11
|
+
}
|
|
12
|
+
declare const NodeGraph: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type NodeGraph = ReturnType<typeof NodeGraph>;
|
|
14
|
+
export default NodeGraph;
|