@babsey/code-graph 0.0.0

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.
@@ -0,0 +1,1799 @@
1
+ import { AbstractNode, NodeInterfaceType, NodeInterface, ButtonInterfaceComponent, CheckboxInterfaceComponent, IntegerInterfaceComponent, NumberInterfaceComponent, SelectInterfaceComponent, SliderInterfaceComponent, TextInputInterfaceComponent, TextareaInputInterfaceComponent, setType, allowMultipleConnections, IntegerInterface as IntegerInterface$1, TextInputInterface as TextInputInterface$1, displayInSidebar, sortTopologically, useViewModel, useTemporaryConnection, Components, useGraph, GRAPH_NODE_TYPE_PREFIX, useTransform, useNodeCategories, BaklavaEditor, DEFAULT_TOOLBAR_COMMANDS, useBaklava, DependencyEngine, applyResult } from "baklavajs";
2
+ import { ButtonInterfaceComponent as ButtonInterfaceComponent2, CheckboxInterfaceComponent as CheckboxInterfaceComponent2, IntegerInterfaceComponent as IntegerInterfaceComponent2, NumberInterfaceComponent as NumberInterfaceComponent2, SelectInterfaceComponent as SelectInterfaceComponent2, SliderInterfaceComponent as SliderInterfaceComponent2, TextInputInterfaceComponent as TextInputInterfaceComponent2, TextareaInputInterfaceComponent as TextareaInputInterfaceComponent2 } from "baklavajs";
3
+ import mustache from "mustache";
4
+ import { reactive, defineComponent, createElementBlock, openBlock, toDisplayString, markRaw, ref, computed, onMounted, onUpdated, normalizeClass, createCommentVNode, createElementVNode, unref, renderSlot, createStaticVNode, onBeforeUnmount, normalizeStyle, withModifiers, createBlock, withDirectives, Fragment, createTextVNode, createVNode, withKeys, vModelText, renderList, nextTick, toRef, resolveDynamicComponent, inject, Transition, withCtx, onUnmounted, normalizeProps, guardReactiveProps, mergeProps } from "vue";
5
+ import toposort from "toposort";
6
+ import { v4 } from "uuid";
7
+ import { usePointer } from "@vueuse/core";
8
+ class AbstractCodeNode extends AbstractNode {
9
+ state;
10
+ code;
11
+ isCodeNode = true;
12
+ inputs = {};
13
+ outputs = {};
14
+ constructor() {
15
+ super();
16
+ this.initializeIo();
17
+ this.width = 400;
18
+ this.twoColumn = true;
19
+ this.state = reactive({
20
+ codeTemplate: "{{ &outputs.code }}",
21
+ hidden: false,
22
+ integrated: false,
23
+ modules: [],
24
+ script: "",
25
+ variableName: ""
26
+ });
27
+ }
28
+ get codeTemplate() {
29
+ return this.state.codeTemplate;
30
+ }
31
+ get idx() {
32
+ return this.code?.codeNodes.filter((node) => !node.state.integrated).indexOf(this) ?? -1;
33
+ }
34
+ get idxByVariableNames() {
35
+ return this.code?.getNodesBySameVariableNames(this.state.variableName).indexOf(this) ?? -1;
36
+ }
37
+ get script() {
38
+ return this.state.script;
39
+ }
40
+ get shortId() {
41
+ return this.id.slice(0, 6);
42
+ }
43
+ get variableName() {
44
+ return this.state.variableName ? this.state.variableName + (this.idxByVariableNames + 1) : "";
45
+ }
46
+ /**
47
+ * Get connected nodes to the node.
48
+ * @param type inputs or outputs
49
+ * @returns code node instances
50
+ */
51
+ getConnectedNodes(type) {
52
+ let nodeIds = [];
53
+ if (type !== "inputs") {
54
+ const targets = this.graph?.connections.filter((c) => c.from.name !== "_node").filter((c) => c.from.nodeId === this.id).map((c) => c.to.nodeId);
55
+ if (targets) nodeIds = nodeIds.concat(targets);
56
+ }
57
+ if (type !== "outputs") {
58
+ const sources = this.graph?.connections.filter((c) => c.from.name !== "_node").filter((c) => c.to.nodeId === this.id).map((c) => c.from.nodeId);
59
+ if (sources) nodeIds = nodeIds.concat(sources);
60
+ }
61
+ if (!nodeIds || nodeIds.length == 0) return [];
62
+ return nodeIds.map((nodeId) => this.graph?.findNodeById(nodeId));
63
+ }
64
+ registerCode(code) {
65
+ this.code = code;
66
+ }
67
+ /**
68
+ * Render code of this node.
69
+ */
70
+ renderCode() {
71
+ const inputs = {};
72
+ Object.keys(this.inputs).forEach((intfKey) => {
73
+ if (intfKey === "_node") return;
74
+ const intf = this.inputs[intfKey];
75
+ const value = intf.isString ? `'${intf.value}'` : intf.value;
76
+ if (intf && intf.state) inputs[intfKey] = intf.state.script.length > 0 ? intf.state.script : value;
77
+ });
78
+ const outputs = {};
79
+ Object.keys(this.outputs).forEach((intfKey) => {
80
+ if (intfKey === "_node") return;
81
+ const intf = this.outputs[intfKey];
82
+ const value = intf.isString ? `'${intf.value}'` : intf.value;
83
+ if (intf && intf.state) outputs[intfKey] = value;
84
+ });
85
+ this.state.script = mustache.render(this.state.codeTemplate, { inputs, outputs });
86
+ if (this.outputs.code) this.outputs.code.state.script = this.state.script;
87
+ }
88
+ updateOutputVariableName() {
89
+ if (this.outputs.code) this.outputs.code.name = this.variableName;
90
+ }
91
+ }
92
+ class CodeNode extends AbstractCodeNode {
93
+ /**
94
+ * The default implementation does nothing.
95
+ * Overwrite this method to do calculation.
96
+ * @param inputs Values of all input interfaces
97
+ * @param globalValues Set of values passed to every node by the engine plugin
98
+ * @return Values for output interfaces
99
+ */
100
+ calculate;
101
+ load(state) {
102
+ super.load(state);
103
+ loadNodeState(this.graph, state);
104
+ }
105
+ save() {
106
+ const state = super.save();
107
+ saveNodeState(this.graph, state);
108
+ return state;
109
+ }
110
+ updateModules(modules) {
111
+ if (modules) {
112
+ this.state.modules = modules;
113
+ } else if (this.type.includes(".")) {
114
+ const modules2 = this.type.split(".");
115
+ this.state.modules.push(modules2.slice(0, modules2.length - 1).join("."));
116
+ }
117
+ }
118
+ }
119
+ const loadNodeState = (graph, nodeState) => {
120
+ if (!graph) return;
121
+ const node = graph.findNodeById(nodeState.id);
122
+ if (!node || node.subgraph) return;
123
+ const codeNode = node;
124
+ if (codeNode.state) {
125
+ codeNode.state.integrated = nodeState.integrated;
126
+ codeNode.state.modules = nodeState.modules;
127
+ codeNode.state.props = nodeState.props;
128
+ }
129
+ Object.entries(nodeState.inputs).forEach(([inputKey, inputItem]) => {
130
+ if (inputKey === "_node") return;
131
+ if (codeNode.inputs[inputKey]) codeNode.inputs[inputKey].hidden = inputItem.hidden;
132
+ });
133
+ Object.entries(nodeState.outputs).forEach(([outputKey, outputItem]) => {
134
+ if (outputKey === "_node") return;
135
+ if (codeNode.outputs[outputKey]) codeNode.outputs[outputKey].hidden = outputItem.hidden;
136
+ });
137
+ };
138
+ const saveNodeState = (graph, nodeState) => {
139
+ if (!graph) return;
140
+ const node = graph.findNodeById(nodeState.id);
141
+ if (!node || node.subgraph) return;
142
+ const codeNode = node;
143
+ if (codeNode.state) {
144
+ nodeState.integrated = codeNode.state.integrated;
145
+ nodeState.modules = codeNode.state.modules;
146
+ }
147
+ Object.entries(nodeState.inputs).forEach(([inputKey, inputItem]) => {
148
+ if (inputKey === "_node") return;
149
+ if (codeNode.inputs[inputKey]) inputItem.hidden = codeNode.inputs[inputKey].hidden;
150
+ });
151
+ Object.entries(nodeState.outputs).forEach(([outputKey, outputItem]) => {
152
+ if (outputKey === "_node") return;
153
+ if (codeNode.outputs[outputKey]) outputItem.hidden = codeNode.outputs[outputKey].hidden;
154
+ });
155
+ };
156
+ new NodeInterfaceType("boolean");
157
+ new NodeInterfaceType("dict");
158
+ new NodeInterfaceType("list");
159
+ const nodeType = new NodeInterfaceType("node");
160
+ const numberType = new NodeInterfaceType("number");
161
+ const stringType = new NodeInterfaceType("string");
162
+ const _hoisted_1$f = ["title"];
163
+ const _sfc_main$g = /* @__PURE__ */ defineComponent({
164
+ __name: "CodeNodeInterface",
165
+ props: {
166
+ intf: {}
167
+ },
168
+ setup(__props) {
169
+ return (_ctx, _cache) => {
170
+ return openBlock(), createElementBlock("div", {
171
+ title: _ctx.intf.state?.script
172
+ }, toDisplayString(_ctx.intf.name), 9, _hoisted_1$f);
173
+ };
174
+ }
175
+ });
176
+ class CodeNodeInterface extends NodeInterface {
177
+ optional = false;
178
+ code;
179
+ state;
180
+ constructor(name, value) {
181
+ super(name, value);
182
+ this.setComponent(markRaw(_sfc_main$g));
183
+ this.state = reactive({
184
+ script: ""
185
+ });
186
+ }
187
+ get shortId() {
188
+ return this.id.slice(0, 6);
189
+ }
190
+ // override get value(): T {
191
+ // return super.value
192
+ // }
193
+ // override set value(value: T) {
194
+ // super.value = value;
195
+ // if (this.name !== '_node') this.setHidden(false);
196
+ // }
197
+ }
198
+ class ButtonInterface extends CodeNodeInterface {
199
+ component = markRaw(ButtonInterfaceComponent);
200
+ callback;
201
+ constructor(name, callback) {
202
+ super(name, void 0);
203
+ this.callback = callback;
204
+ this.setPort(false);
205
+ }
206
+ }
207
+ class CheckboxInterface extends CodeNodeInterface {
208
+ component = markRaw(CheckboxInterfaceComponent);
209
+ }
210
+ class BaseNumericInterface extends CodeNodeInterface {
211
+ min;
212
+ max;
213
+ constructor(name, value, min, max) {
214
+ super(name, value);
215
+ this.min = min;
216
+ this.max = max;
217
+ }
218
+ validate(v) {
219
+ return (this.min === void 0 || v >= this.min) && (this.max === void 0 || v <= this.max);
220
+ }
221
+ }
222
+ class IntegerInterface extends BaseNumericInterface {
223
+ component = markRaw(IntegerInterfaceComponent);
224
+ validate(v) {
225
+ return Number.isInteger(v) && super.validate(v);
226
+ }
227
+ }
228
+ class CodeInputInterface extends CodeNodeInterface {
229
+ isCodeInput = true;
230
+ constructor(name = "", value) {
231
+ super(name, value);
232
+ this.setComponent(markRaw(_sfc_main$g));
233
+ }
234
+ }
235
+ class CodeOutputInterface extends CodeNodeInterface {
236
+ isCodeOutput = true;
237
+ constructor(name = "", value = "") {
238
+ super(name, value);
239
+ this.setComponent(markRaw(_sfc_main$g));
240
+ }
241
+ get script() {
242
+ return this.state.script;
243
+ }
244
+ get value() {
245
+ return super.value;
246
+ }
247
+ set value(value) {
248
+ super.value = value;
249
+ this.state.script = this.name.length > 0 ? this.name : this.value;
250
+ }
251
+ }
252
+ class NumberInterface extends BaseNumericInterface {
253
+ component = markRaw(NumberInterfaceComponent);
254
+ }
255
+ class SelectInterface extends CodeNodeInterface {
256
+ component = markRaw(SelectInterfaceComponent);
257
+ items;
258
+ constructor(name, value, items) {
259
+ super(name, value);
260
+ this.items = items;
261
+ }
262
+ }
263
+ class SliderInterface extends BaseNumericInterface {
264
+ component = markRaw(SliderInterfaceComponent);
265
+ min;
266
+ max;
267
+ constructor(name, value, min, max) {
268
+ super(name, value, min, max);
269
+ this.min = min;
270
+ this.max = max;
271
+ }
272
+ }
273
+ class TextInterface extends CodeNodeInterface {
274
+ component = markRaw(TextInputInterfaceComponent);
275
+ constructor(name, value) {
276
+ super(name, value);
277
+ this.setPort(false);
278
+ }
279
+ }
280
+ class TextInputInterface extends CodeNodeInterface {
281
+ isString = true;
282
+ component = markRaw(TextInputInterfaceComponent);
283
+ }
284
+ class TextareaInputInterface extends CodeNodeInterface {
285
+ component = markRaw(TextareaInputInterfaceComponent);
286
+ }
287
+ function defineCodeNode(definition) {
288
+ return class extends CodeNode {
289
+ type = definition.type;
290
+ inputs = {};
291
+ outputs = {};
292
+ constructor() {
293
+ super();
294
+ this._title = definition.title ?? definition.type;
295
+ this.updateModules(definition.modules);
296
+ if (definition.codeTemplate) this.state.codeTemplate = definition.codeTemplate(this);
297
+ if (definition.variableName) this.state.variableName = definition.variableName;
298
+ this.addInput(
299
+ "_node",
300
+ new CodeNodeInterface("", []).use(setType, nodeType).use(allowMultipleConnections).setHidden(true)
301
+ );
302
+ this.addOutput(
303
+ "_node",
304
+ new CodeNodeInterface("", []).use(setType, nodeType).use(allowMultipleConnections).setHidden(true)
305
+ );
306
+ this.executeFactory("input", definition.inputs);
307
+ this.executeFactory("output", definition.outputs);
308
+ definition.onCreate?.call(this);
309
+ }
310
+ calculate = definition.calculate ? (inputs, globalValues) => ({
311
+ ...definition.calculate.call(this, inputs, globalValues),
312
+ _node: null
313
+ }) : void 0;
314
+ onPlaced() {
315
+ definition.onPlaced?.call(this);
316
+ }
317
+ onDestroy() {
318
+ definition.onDestroy?.call(this);
319
+ }
320
+ onCodeUpdate() {
321
+ definition.onCodeUpdate?.call(this);
322
+ }
323
+ executeFactory(type, factory) {
324
+ Object.keys(factory || {}).forEach((k) => {
325
+ const intf = factory[k]();
326
+ if (type === "input") {
327
+ this.addInput(k, intf);
328
+ } else {
329
+ this.addOutput(k, intf);
330
+ }
331
+ });
332
+ }
333
+ };
334
+ }
335
+ class DynamicCodeNode extends CodeNode {
336
+ /**
337
+ * The default implementation does nothing.
338
+ * Overwrite this method to do calculation.
339
+ * @param inputs Values of all input interfaces
340
+ * @param globalValues Set of values passed to every node by the engine plugin
341
+ * @return Values for output interfaces
342
+ */
343
+ calculate;
344
+ }
345
+ function defineDynamicCodeNode(definition) {
346
+ return class extends DynamicCodeNode {
347
+ type = definition.type;
348
+ inputs = {};
349
+ outputs = {};
350
+ calculate;
351
+ preventUpdate = false;
352
+ staticInputKeys = Object.keys(definition.inputs ?? {});
353
+ staticOutputKeys = Object.keys(definition.outputs ?? {});
354
+ constructor() {
355
+ super();
356
+ this._title = definition.title ?? definition.type;
357
+ this.updateModules(definition.modules);
358
+ if (definition.codeTemplate) this.state.codeTemplate = definition.codeTemplate(this);
359
+ if (definition.variableName) this.state.variableName = definition.variableName;
360
+ this.addInput(
361
+ "_node",
362
+ new CodeNodeInterface("", []).use(setType, nodeType).use(allowMultipleConnections).setHidden(true)
363
+ );
364
+ this.addOutput(
365
+ "_node",
366
+ new CodeNodeInterface("", []).use(setType, nodeType).use(allowMultipleConnections).setHidden(true)
367
+ );
368
+ this.staticInputKeys.push("_node");
369
+ this.staticOutputKeys.push("_node");
370
+ this.executeFactory("input", definition.inputs);
371
+ this.executeFactory("output", definition.outputs);
372
+ if (definition.calculate) {
373
+ this.calculate = (inputs, globalValues) => ({
374
+ ...definition.calculate?.call(this, inputs, globalValues),
375
+ _node: null
376
+ });
377
+ }
378
+ definition.onCreate?.call(this);
379
+ }
380
+ onPlaced() {
381
+ this.events.update.subscribe(this, (data) => {
382
+ if (!data) return;
383
+ if (data.type === "input" && this.staticInputKeys.includes(data.name) || data.type === "output" && this.staticOutputKeys.includes(data.name)) {
384
+ this.onUpdate();
385
+ }
386
+ });
387
+ this.onUpdate();
388
+ definition.onPlaced?.call(this);
389
+ }
390
+ onDestroy() {
391
+ definition.onDestroy?.call(this);
392
+ }
393
+ onCodeUpdate() {
394
+ definition.onCodeUpdate?.call(this);
395
+ }
396
+ load(state) {
397
+ this.preventUpdate = true;
398
+ this.hooks.beforeLoad.execute(state);
399
+ this.id = state.id;
400
+ this.title = state.title;
401
+ for (const k of this.staticInputKeys) {
402
+ this.inputs[k].load(state.inputs[k]);
403
+ this.inputs[k].nodeId = this.id;
404
+ if (k === "_node") continue;
405
+ this.inputs[k].hidden = state.inputs[k].hidden;
406
+ }
407
+ for (const k of this.staticOutputKeys) {
408
+ this.outputs[k].load(state.outputs[k]);
409
+ this.outputs[k].nodeId = this.id;
410
+ if (k === "_node") continue;
411
+ this.outputs[k].hidden = state.outputs[k].hidden;
412
+ }
413
+ this.preventUpdate = false;
414
+ this.onUpdate();
415
+ this.preventUpdate = true;
416
+ for (const k of Object.keys(state.inputs)) {
417
+ if (this.staticInputKeys.includes(k)) continue;
418
+ if (!this.inputs[k]) {
419
+ const value = state.inputs[k].value;
420
+ let inputInterface;
421
+ if (typeof value == "number") {
422
+ inputInterface = new IntegerInterface$1(k, value).use(setType, numberType);
423
+ } else {
424
+ inputInterface = new TextInputInterface$1(k, JSON.stringify(value)).use(setType, stringType);
425
+ }
426
+ inputInterface.use(displayInSidebar, true);
427
+ this.addInput(k, inputInterface);
428
+ }
429
+ if (this.inputs[k]) {
430
+ this.inputs[k].load(state.inputs[k]);
431
+ this.inputs[k].nodeId = this.id;
432
+ }
433
+ }
434
+ for (const k of Object.keys(state.outputs)) {
435
+ if (this.staticOutputKeys.includes(k)) continue;
436
+ if (!this.outputs[k]) {
437
+ const outputInterface = new CodeOutputInterface(k);
438
+ this.addOutput(k, outputInterface);
439
+ }
440
+ if (this.outputs[k]) {
441
+ this.outputs[k].load(state.outputs[k]);
442
+ this.outputs[k].nodeId = this.id;
443
+ }
444
+ }
445
+ loadNodeState(this.graph, state);
446
+ this.preventUpdate = false;
447
+ this.events.loaded.emit(this);
448
+ }
449
+ onUpdate() {
450
+ if (this.preventUpdate) return;
451
+ if (this.graph) this.graph.activeTransactions++;
452
+ const inputValues = this.getStaticValues(this.staticInputKeys, this.inputs);
453
+ const outputValues = this.getStaticValues(this.staticOutputKeys, this.outputs);
454
+ const result = definition.onUpdate.call(this, inputValues, outputValues);
455
+ this.updateInterfaces("input", result.inputs ?? {}, result.forceUpdateInputs ?? []);
456
+ this.updateInterfaces("output", result.outputs ?? {}, result.forceUpdateOutputs ?? []);
457
+ if (this.graph) this.graph.activeTransactions--;
458
+ }
459
+ getStaticValues(keys, interfaces) {
460
+ const values = {};
461
+ for (const k of keys) {
462
+ values[k] = interfaces[k].value;
463
+ }
464
+ return values;
465
+ }
466
+ updateInterfaces(type, newInterfaces, forceUpdates) {
467
+ const staticKeys = type === "input" ? this.staticInputKeys : this.staticOutputKeys;
468
+ const currentInterfaces = type === "input" ? this.inputs : this.outputs;
469
+ for (const k of Object.keys(currentInterfaces)) {
470
+ if (staticKeys.includes(k) || newInterfaces[k] && !forceUpdates.includes(k)) continue;
471
+ if (type === "input") {
472
+ this.removeInput(k);
473
+ } else {
474
+ this.removeOutput(k);
475
+ }
476
+ }
477
+ for (const k of Object.keys(newInterfaces)) {
478
+ if (currentInterfaces[k]) continue;
479
+ const intf = newInterfaces[k]();
480
+ if (type === "input") {
481
+ this.addInput(k, intf);
482
+ } else {
483
+ this.addOutput(k, intf);
484
+ }
485
+ }
486
+ }
487
+ executeFactory(type, factory) {
488
+ Object.keys(factory || {}).forEach((k) => {
489
+ const intf = factory[k]();
490
+ if (type === "input") {
491
+ this.addInput(k, intf);
492
+ } else {
493
+ this.addOutput(k, intf);
494
+ }
495
+ });
496
+ }
497
+ };
498
+ }
499
+ class Code {
500
+ _id;
501
+ _viewModel;
502
+ _state;
503
+ constructor(viewModel) {
504
+ this._id = v4();
505
+ this._viewModel = viewModel;
506
+ this._state = reactive({
507
+ autosort: false,
508
+ modules: {},
509
+ script: "",
510
+ token: null,
511
+ template: ""
512
+ });
513
+ }
514
+ get codeNodes() {
515
+ return getCodeNodes(this.graph);
516
+ }
517
+ get connections() {
518
+ return this.graph.connections;
519
+ }
520
+ get graph() {
521
+ return this.viewModel.displayedGraph;
522
+ }
523
+ get id() {
524
+ return this._id;
525
+ }
526
+ get modules() {
527
+ let categories = [];
528
+ this.codeNodes.filter((node) => node.state.modules?.length > 0).forEach((node) => {
529
+ categories = categories.concat(node.state.modules);
530
+ });
531
+ if (!categories) return [];
532
+ categories.sort();
533
+ return Array.from(new Set(categories.map((category) => this.viewModel.state.modules[category])));
534
+ }
535
+ get nodeIds() {
536
+ return this.codeNodes.map((node) => node.id);
537
+ }
538
+ get nodes() {
539
+ return this.graph.nodes;
540
+ }
541
+ get scriptedCodeNodes() {
542
+ return getCodeNodes(this.graph).filter(
543
+ (codeNode) => codeNode.state?.script.length > 0
544
+ );
545
+ }
546
+ get shortId() {
547
+ return this.id.slice(0);
548
+ }
549
+ get state() {
550
+ return this._state;
551
+ }
552
+ get viewModel() {
553
+ return this._viewModel;
554
+ }
555
+ get visibleNodes() {
556
+ return this.codeNodes.filter((node) => !node.state?.hidden);
557
+ }
558
+ /**
559
+ * Add code node to graph.
560
+ * @param node code node
561
+ * @param props optional
562
+ */
563
+ addNode(node, props) {
564
+ if (props) node.state.props = props;
565
+ return this.graph.addNode(node);
566
+ }
567
+ /**
568
+ * Add code node at coordinates.
569
+ * @param node code node
570
+ * @param position position
571
+ * @param props optional
572
+ * @returns code node
573
+ */
574
+ addNodeAtCoordinates = (node, position = { x: 0, y: 0 }, props) => {
575
+ this.addNode(node, props);
576
+ if (node.position) node.position = position;
577
+ return node;
578
+ };
579
+ /**
580
+ * Add connection of code nodes
581
+ * @param from code node interface
582
+ * @param to code node interface
583
+ */
584
+ addConnection(from, to) {
585
+ if (from.name !== "_node") from.hidden = false;
586
+ if (to.name !== "_node") to.hidden = false;
587
+ this.graph.addConnection(from, to);
588
+ }
589
+ /**
590
+ * Clear code graph.
591
+ */
592
+ clear() {
593
+ this.graph._nodes = [];
594
+ this.graph._connections = [];
595
+ }
596
+ findNodeById(id) {
597
+ return this.graph.findNodeById(id);
598
+ }
599
+ findNodeByType(nodeType2) {
600
+ return this.codeNodes.find((codeNode) => codeNode.type === nodeType2);
601
+ }
602
+ getNodesBySameType(type) {
603
+ return this.codeNodes.filter((codeNode) => codeNode.type === type);
604
+ }
605
+ getNodesBySameVariableNames(variableName) {
606
+ return this.codeNodes.filter(
607
+ (codeNode) => codeNode.state.variableName === variableName
608
+ );
609
+ }
610
+ /**
611
+ * Check whether the graph has this connection.
612
+ * @param from node interface
613
+ * @param to node interface
614
+ * @returns boolean
615
+ */
616
+ hasConnection(from, to) {
617
+ return this.connections.some(
618
+ (connection) => connection.from.id === from.id && connection.to.id === to.id
619
+ );
620
+ }
621
+ /**
622
+ * Load template from the file.
623
+ */
624
+ loadTemplate(resolve) {
625
+ resolve.then((template) => {
626
+ this._state.template = template.default ?? "";
627
+ });
628
+ }
629
+ onCodeUpdate() {
630
+ this.codeNodes.forEach((codeNode) => codeNode.onCodeUpdate());
631
+ }
632
+ /**
633
+ * Remove connection from the graph
634
+ * @param connection connection between code nodes
635
+ */
636
+ removeConnection(connection) {
637
+ this.graph.removeConnection(connection);
638
+ }
639
+ /**
640
+ * Remove node from the graph.
641
+ * @param codeNode code node
642
+ */
643
+ removeNode(codeNode) {
644
+ this.graph.removeNode(codeNode);
645
+ }
646
+ /**
647
+ * Render node codes.
648
+ */
649
+ renderNodeCodes() {
650
+ if (this.codeNodes.length === 0) return;
651
+ this.codeNodes.forEach((node) => node.renderCode());
652
+ }
653
+ /**
654
+ * Render code.
655
+ */
656
+ renderCode() {
657
+ this.state.script = mustache.render(this.state.template || "", this);
658
+ }
659
+ /**
660
+ * Save code graph.
661
+ * @returns graph state
662
+ */
663
+ save() {
664
+ if (this.state.autosort) this.sortNodes();
665
+ const editorState = this.viewModel.editor.save();
666
+ editorState.graph.id = this.id;
667
+ this.saveNodeStates(editorState.graph.nodes);
668
+ return JSON.parse(JSON.stringify(editorState));
669
+ }
670
+ /**
671
+ * Save node states.
672
+ * @param nodeStates a list of node state.
673
+ */
674
+ saveNodeStates(nodeStates) {
675
+ nodeStates.forEach((nodeState, nodeIdx) => {
676
+ const node = this.nodes[nodeIdx];
677
+ Object.entries(nodeState.inputs).forEach(([inputKey]) => {
678
+ if (node.inputs[inputKey]) nodeState.inputs[inputKey].hidden = node.inputs[inputKey].hidden;
679
+ });
680
+ Object.entries(nodeState.outputs).forEach(([outputKey]) => {
681
+ if (node.inputs[outputKey]) nodeState.outputs[outputKey].hidden = node.outputs[outputKey].hidden;
682
+ });
683
+ });
684
+ }
685
+ /**
686
+ * Sort code nodes.
687
+ */
688
+ sortNodes() {
689
+ if (this.nodes.length === 0 || this.connections.length === 0) return;
690
+ try {
691
+ const edges = this.connections.map((connection) => [
692
+ connection.to.nodeId,
693
+ connection.from.nodeId
694
+ ]);
695
+ let nodeIds = [...this.nodeIds];
696
+ nodeIds.reverse();
697
+ nodeIds = toposort.array(nodeIds, edges);
698
+ nodeIds.reverse();
699
+ const unconnected = this.graph.nodes.map((node) => node.id).filter((nodeId) => !nodeIds.includes(nodeId));
700
+ nodeIds = nodeIds.concat(unconnected);
701
+ this.graph._nodes = nodeIds.map((nodeId) => this.findNodeById(nodeId));
702
+ } catch {
703
+ console.warn("Failed to sort nodes.");
704
+ }
705
+ }
706
+ updateOutputVariableNames() {
707
+ this.codeNodes.forEach((codeNode) => codeNode.updateOutputVariableName());
708
+ }
709
+ }
710
+ const getCodeNodes = (graph) => {
711
+ let nodes = [];
712
+ graph.nodes.forEach((node) => {
713
+ if (node.subgraph) {
714
+ nodes = nodes.concat(getCodeNodes(node.subgraph));
715
+ } else if (node.isCodeNode) {
716
+ nodes.push(node);
717
+ }
718
+ });
719
+ return nodes;
720
+ };
721
+ const getPositionAtColumn = (col = 0, offset = 100) => {
722
+ const width = 350;
723
+ const padding = 70;
724
+ return {
725
+ x: col * (width + padding),
726
+ y: offset
727
+ };
728
+ };
729
+ const getPositionBeforeNode = (node) => {
730
+ const position = { ...node.position };
731
+ position.x -= 400;
732
+ position.y += 50;
733
+ return position;
734
+ };
735
+ const transferCodeScript = (graph) => {
736
+ const { calculationOrder, connectionsFromNode } = sortTopologically(graph);
737
+ calculationOrder.forEach((node) => {
738
+ if (!node.isCodeNode) return;
739
+ const codeNode = node;
740
+ if (connectionsFromNode.has(codeNode)) {
741
+ connectionsFromNode.get(codeNode).forEach((c) => {
742
+ if (c.to.state && c.from.script) c.to.state.script = c.from.script;
743
+ });
744
+ }
745
+ });
746
+ };
747
+ const _hoisted_1$e = ["id"];
748
+ const _hoisted_2$5 = { class: "align-middle" };
749
+ const _sfc_main$f = /* @__PURE__ */ defineComponent({
750
+ __name: "CodeGraphNodeInterface",
751
+ props: {
752
+ node: {},
753
+ intf: {}
754
+ },
755
+ setup(__props) {
756
+ const props = __props;
757
+ const { viewModel } = useViewModel();
758
+ const { hoveredOver, temporaryConnection } = useTemporaryConnection();
759
+ const el = ref(null);
760
+ const isConnected = computed(() => props.intf.connectionCount > 0);
761
+ const classes = computed(() => ({
762
+ "--connected": isConnected.value
763
+ }));
764
+ const startHover = () => {
765
+ hoveredOver(props.intf);
766
+ };
767
+ const endHover = () => {
768
+ hoveredOver(void 0);
769
+ };
770
+ const onRender = () => {
771
+ if (el.value) {
772
+ viewModel.value.hooks.renderInterface.execute({ intf: props.intf, el: el.value });
773
+ }
774
+ };
775
+ onMounted(onRender);
776
+ onUpdated(onRender);
777
+ return (_ctx, _cache) => {
778
+ return openBlock(), createElementBlock("div", {
779
+ id: _ctx.intf.id,
780
+ ref_key: "el",
781
+ ref: el,
782
+ class: normalizeClass(["baklava-node-interface", classes.value])
783
+ }, [
784
+ _ctx.intf.port ? (openBlock(), createElementBlock("div", {
785
+ key: 0,
786
+ class: normalizeClass(["__port", { "--selected": unref(temporaryConnection)?.from === _ctx.intf }]),
787
+ onPointerover: startHover,
788
+ onPointerout: endHover
789
+ }, null, 34)) : createCommentVNode("", true),
790
+ createElementVNode("span", _hoisted_2$5, [
791
+ renderSlot(_ctx.$slots, "default")
792
+ ])
793
+ ], 10, _hoisted_1$e);
794
+ };
795
+ }
796
+ });
797
+ const _export_sfc = (sfc, props) => {
798
+ const target = sfc.__vccOpts || sfc;
799
+ for (const [key, val] of props) {
800
+ target[key] = val;
801
+ }
802
+ return target;
803
+ };
804
+ const _sfc_main$e = {};
805
+ const _hoisted_1$d = {
806
+ xmlns: "http://www.w3.org/2000/svg",
807
+ width: "24",
808
+ height: "24",
809
+ viewBox: "0 0 24 24",
810
+ fill: "currentColor",
811
+ class: "baklava-icon icon icon-tabler icons-tabler-filled icon-tabler-layout-sidebar-left-collapse"
812
+ };
813
+ function _sfc_render$9(_ctx, _cache) {
814
+ return openBlock(), createElementBlock("svg", _hoisted_1$d, [..._cache[0] || (_cache[0] = [
815
+ createElementVNode("path", {
816
+ stroke: "none",
817
+ d: "M0 0h24v24H0z",
818
+ fill: "none"
819
+ }, null, -1),
820
+ createElementVNode("path", { d: "M18 3a3 3 0 0 1 2.995 2.824l.005 .176v12a3 3 0 0 1 -2.824 2.995l-.176 .005h-12a3 3 0 0 1 -2.995 -2.824l-.005 -.176v-12a3 3 0 0 1 2.824 -2.995l.176 -.005h12zm0 2h-9v14h9a1 1 0 0 0 .993 -.883l.007 -.117v-12a1 1 0 0 0 -.883 -.993l-.117 -.007zm-2.293 4.293a1 1 0 0 1 .083 1.32l-.083 .094l-1.292 1.293l1.292 1.293a1 1 0 0 1 .083 1.32l-.083 .094a1 1 0 0 1 -1.32 .083l-.094 -.083l-2 -2a1 1 0 0 1 -.083 -1.32l.083 -.094l2 -2a1 1 0 0 1 1.414 0z" }, null, -1)
821
+ ])]);
822
+ }
823
+ const LayoutSidebarLeftCollapse = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["render", _sfc_render$9]]);
824
+ const _sfc_main$d = {};
825
+ const _hoisted_1$c = {
826
+ xmlns: "http://www.w3.org/2000/svg",
827
+ width: "24",
828
+ height: "24",
829
+ viewBox: "0 0 24 24",
830
+ fill: "currentColor",
831
+ class: "baklava-icon icon icon-tabler icons-tabler-filled icon-tabler-layout-sidebar-left-expand"
832
+ };
833
+ function _sfc_render$8(_ctx, _cache) {
834
+ return openBlock(), createElementBlock("svg", _hoisted_1$c, [..._cache[0] || (_cache[0] = [
835
+ createElementVNode("path", {
836
+ stroke: "none",
837
+ d: "M0 0h24v24H0z",
838
+ fill: "none"
839
+ }, null, -1),
840
+ createElementVNode("path", { d: "M18 3a3 3 0 0 1 2.995 2.824l.005 .176v12a3 3 0 0 1 -2.824 2.995l-.176 .005h-12a3 3 0 0 1 -2.995 -2.824l-.005 -.176v-12a3 3 0 0 1 2.824 -2.995l.176 -.005h12zm0 2h-9v14h9a1 1 0 0 0 .993 -.883l.007 -.117v-12a1 1 0 0 0 -.883 -.993l-.117 -.007zm-4.387 4.21l.094 .083l2 2a1 1 0 0 1 .083 1.32l-.083 .094l-2 2a1 1 0 0 1 -1.497 -1.32l.083 -.094l1.292 -1.293l-1.292 -1.293a1 1 0 0 1 -.083 -1.32l.083 -.094a1 1 0 0 1 1.32 -.083z" }, null, -1)
841
+ ])]);
842
+ }
843
+ const LayoutSidebarLeftExpand = /* @__PURE__ */ _export_sfc(_sfc_main$d, [["render", _sfc_render$8]]);
844
+ const _sfc_main$c = {};
845
+ const _hoisted_1$b = {
846
+ xmlns: "http://www.w3.org/2000/svg",
847
+ width: "24",
848
+ height: "24",
849
+ viewBox: "0 0 24 24",
850
+ fill: "currentColor",
851
+ class: "balkava-icon icon icon-tabler icons-tabler-filled icon-tabler-layout-sidebar-right"
852
+ };
853
+ function _sfc_render$7(_ctx, _cache) {
854
+ return openBlock(), createElementBlock("svg", _hoisted_1$b, [..._cache[0] || (_cache[0] = [
855
+ createElementVNode("path", {
856
+ stroke: "none",
857
+ d: "M0 0h24v24H0z",
858
+ fill: "none"
859
+ }, null, -1),
860
+ createElementVNode("path", { d: "M6 21a3 3 0 0 1 -3 -3v-12a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v12a3 3 0 0 1 -3 3zm8 -16h-8a1 1 0 0 0 -1 1v12a1 1 0 0 0 1 1h8z" }, null, -1)
861
+ ])]);
862
+ }
863
+ const LayoutSidebarRight = /* @__PURE__ */ _export_sfc(_sfc_main$c, [["render", _sfc_render$7]]);
864
+ const _sfc_main$b = {};
865
+ const _hoisted_1$a = {
866
+ xmlns: "http://www.w3.org/2000/svg",
867
+ width: "24",
868
+ height: "24",
869
+ viewBox: "0 0 24 24",
870
+ fill: "currentColor",
871
+ class: "baklava-icon icon icon-tabler icons-tabler-filled icon-tabler-layout-sidebar-right-collapse"
872
+ };
873
+ function _sfc_render$6(_ctx, _cache) {
874
+ return openBlock(), createElementBlock("svg", _hoisted_1$a, [..._cache[0] || (_cache[0] = [
875
+ createElementVNode("path", {
876
+ stroke: "none",
877
+ d: "M0 0h24v24H0z",
878
+ fill: "none"
879
+ }, null, -1),
880
+ createElementVNode("path", { d: "M18 3a3 3 0 0 1 2.995 2.824l.005 .176v12a3 3 0 0 1 -2.824 2.995l-.176 .005h-12a3 3 0 0 1 -2.995 -2.824l-.005 -.176v-12a3 3 0 0 1 2.824 -2.995l.176 -.005h12zm-3 2h-9a1 1 0 0 0 -.993 .883l-.007 .117v12a1 1 0 0 0 .883 .993l.117 .007h9v-14zm-5.387 4.21l.094 .083l2 2a1 1 0 0 1 .083 1.32l-.083 .094l-2 2a1 1 0 0 1 -1.497 -1.32l.083 -.094l1.292 -1.293l-1.292 -1.293a1 1 0 0 1 -.083 -1.32l.083 -.094a1 1 0 0 1 1.32 -.083z" }, null, -1)
881
+ ])]);
882
+ }
883
+ const LayoutSidebarRightCollapse = /* @__PURE__ */ _export_sfc(_sfc_main$b, [["render", _sfc_render$6]]);
884
+ const _sfc_main$a = {};
885
+ const _hoisted_1$9 = {
886
+ xmlns: "http://www.w3.org/2000/svg",
887
+ width: "24",
888
+ height: "24",
889
+ viewBox: "0 0 24 24",
890
+ fill: "currentColor",
891
+ class: "baklava-icon icon icon-tabler icons-tabler-filled icon-tabler-layout-sidebar-right-expand"
892
+ };
893
+ function _sfc_render$5(_ctx, _cache) {
894
+ return openBlock(), createElementBlock("svg", _hoisted_1$9, [..._cache[0] || (_cache[0] = [
895
+ createElementVNode("path", {
896
+ stroke: "none",
897
+ d: "M0 0h24v24H0z",
898
+ fill: "none"
899
+ }, null, -1),
900
+ createElementVNode("path", { d: "M18 3a3 3 0 0 1 2.995 2.824l.005 .176v12a3 3 0 0 1 -2.824 2.995l-.176 .005h-12a3 3 0 0 1 -2.995 -2.824l-.005 -.176v-12a3 3 0 0 1 2.824 -2.995l.176 -.005h12zm-3 2h-9a1 1 0 0 0 -.993 .883l-.007 .117v12a1 1 0 0 0 .883 .993l.117 .007h9v-14zm-3.293 4.293a1 1 0 0 1 .083 1.32l-.083 .094l-1.292 1.293l1.292 1.293a1 1 0 0 1 .083 1.32l-.083 .094a1 1 0 0 1 -1.32 .083l-.094 -.083l-2 -2a1 1 0 0 1 -.083 -1.32l.083 -.094l2 -2a1 1 0 0 1 1.414 0z" }, null, -1)
901
+ ])]);
902
+ }
903
+ const LayoutSidebarRightExpand = /* @__PURE__ */ _export_sfc(_sfc_main$a, [["render", _sfc_render$5]]);
904
+ const _sfc_main$9 = {};
905
+ const _hoisted_1$8 = {
906
+ xmlns: "http://www.w3.org/2000/svg",
907
+ class: "baklava-icon",
908
+ width: "24",
909
+ height: "24",
910
+ viewBox: "0 0 24 24",
911
+ fill: "none",
912
+ stroke: "currentColor",
913
+ "stroke-width": "2",
914
+ "stroke-linecap": "round",
915
+ "stroke-linejoin": "round"
916
+ };
917
+ function _sfc_render$4(_ctx, _cache) {
918
+ return openBlock(), createElementBlock("svg", _hoisted_1$8, [..._cache[0] || (_cache[0] = [
919
+ createStaticVNode('<path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M5 2h5v4h-5z"></path><path d="M15 10h5v4h-5z"></path><path d="M5 18h5v4h-5z"></path><path d="M5 10h5v4h-5z"></path><path d="M10 12h5"></path><path d="M7.5 6v4"></path><path d="M7.5 14v4"></path>', 8)
920
+ ])]);
921
+ }
922
+ const Schema = /* @__PURE__ */ _export_sfc(_sfc_main$9, [["render", _sfc_render$4]]);
923
+ const _sfc_main$8 = {};
924
+ const _hoisted_1$7 = {
925
+ xmlns: "http://www.w3.org/2000/svg",
926
+ class: "baklava-icon",
927
+ width: "24",
928
+ height: "24",
929
+ viewBox: "0 0 24 24",
930
+ fill: "none",
931
+ stroke: "currentColor",
932
+ "stroke-width": "2",
933
+ "stroke-linecap": "round",
934
+ "stroke-linejoin": "round"
935
+ };
936
+ function _sfc_render$3(_ctx, _cache) {
937
+ return openBlock(), createElementBlock("svg", _hoisted_1$7, [..._cache[0] || (_cache[0] = [
938
+ createStaticVNode('<path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M6 2h4v4m-4 0h-1v-1"></path><path d="M15 11v-1h5v4h-2"></path><path d="M5 18h5v4h-5z"></path><path d="M5 10h5v4h-5z"></path><path d="M10 12h2"></path><path d="M7.5 7.5v2.5"></path><path d="M7.5 14v4"></path><path d="M3 3l18 18"></path>', 9)
939
+ ])]);
940
+ }
941
+ const SchemaOff = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["render", _sfc_render$3]]);
942
+ const _sfc_main$7 = {};
943
+ const _hoisted_1$6 = {
944
+ xmlns: "http://www.w3.org/2000/svg",
945
+ class: "baklava-icon",
946
+ width: "24",
947
+ height: "24",
948
+ viewBox: "0 0 24 24",
949
+ fill: "none",
950
+ stroke: "currentColor",
951
+ "stroke-width": "2",
952
+ "stroke-linecap": "round",
953
+ "stroke-linejoin": "round"
954
+ };
955
+ function _sfc_render$2(_ctx, _cache) {
956
+ return openBlock(), createElementBlock("svg", _hoisted_1$6, [..._cache[0] || (_cache[0] = [
957
+ createStaticVNode('<path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M3 3l18 18"></path><path d="M4 7h3m4 0h9"></path><path d="M10 11l0 6"></path><path d="M14 14l0 3"></path><path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l.077 -.923"></path><path d="M18.384 14.373l.616 -7.373"></path><path d="M9 5v-1a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3"></path>', 8)
958
+ ])]);
959
+ }
960
+ const TrashOff = /* @__PURE__ */ _export_sfc(_sfc_main$7, [["render", _sfc_render$2]]);
961
+ const _sfc_main$6 = {};
962
+ const _hoisted_1$5 = {
963
+ xmlns: "http://www.w3.org/2000/svg",
964
+ class: "baklava-icon",
965
+ width: "16",
966
+ height: "16",
967
+ viewBox: "0 0 24 24",
968
+ "stroke-width": "2",
969
+ stroke: "currentColor",
970
+ fill: "none",
971
+ "stroke-linecap": "round",
972
+ "stroke-linejoin": "round"
973
+ };
974
+ function _sfc_render$1(_ctx, _cache) {
975
+ return openBlock(), createElementBlock("svg", _hoisted_1$5, [..._cache[0] || (_cache[0] = [
976
+ createElementVNode("path", {
977
+ stroke: "none",
978
+ d: "M0 0h24v24H0z",
979
+ fill: "none"
980
+ }, null, -1),
981
+ createElementVNode("circle", {
982
+ cx: "12",
983
+ cy: "12",
984
+ r: "1"
985
+ }, null, -1),
986
+ createElementVNode("circle", {
987
+ cx: "12",
988
+ cy: "19",
989
+ r: "1"
990
+ }, null, -1),
991
+ createElementVNode("circle", {
992
+ cx: "12",
993
+ cy: "5",
994
+ r: "1"
995
+ }, null, -1)
996
+ ])]);
997
+ }
998
+ const VerticalDots = /* @__PURE__ */ _export_sfc(_sfc_main$6, [["render", _sfc_render$1]]);
999
+ const _hoisted_1$4 = ["id", "data-node-type"];
1000
+ const _hoisted_2$4 = {
1001
+ class: "__title-label",
1002
+ style: { "flex-grow": "1" }
1003
+ };
1004
+ const _hoisted_3$2 = { key: 0 };
1005
+ const _hoisted_4$1 = {
1006
+ class: "__menu",
1007
+ style: { "display": "flex" }
1008
+ };
1009
+ const _hoisted_5 = { class: "__outputs" };
1010
+ const _hoisted_6 = { key: 0 };
1011
+ const _hoisted_7 = ["id", "title"];
1012
+ const _hoisted_8 = { class: "__inputs" };
1013
+ const _hoisted_9 = { key: 0 };
1014
+ const _hoisted_10 = ["id", "title"];
1015
+ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
1016
+ __name: "CodeGraphNode",
1017
+ props: {
1018
+ node: {},
1019
+ selected: { type: Boolean, default: false },
1020
+ dragging: { type: Boolean }
1021
+ },
1022
+ emits: ["select", "start-drag", "update"],
1023
+ setup(__props, { emit: __emit }) {
1024
+ const ContextMenu = Components.ContextMenu;
1025
+ const NodeInterface2 = Components.NodeInterface;
1026
+ const props = __props;
1027
+ const node = computed(() => props.node);
1028
+ const emit = __emit;
1029
+ const { viewModel } = useViewModel();
1030
+ const { graph, switchGraph } = useGraph();
1031
+ const el = ref(null);
1032
+ const renaming = ref(false);
1033
+ const tempName = ref("");
1034
+ const renameInputEl = ref(null);
1035
+ const isResizing = ref(false);
1036
+ let resizeStartWidth = 0;
1037
+ let resizeStartMouseX = 0;
1038
+ const showContextMenu = ref(false);
1039
+ const contextMenuItems = computed(() => {
1040
+ const items = [
1041
+ { value: "edit", label: "Edit" },
1042
+ { value: "rename", label: "Rename" },
1043
+ { value: "delete", label: "Delete" }
1044
+ ];
1045
+ if (props.node.type.startsWith(GRAPH_NODE_TYPE_PREFIX)) {
1046
+ items.push({ value: "editSubgraph", label: "Edit Subgraph" });
1047
+ }
1048
+ return items;
1049
+ });
1050
+ const classes = computed(() => ({
1051
+ "--selected": props.selected,
1052
+ "--dragging": props.dragging,
1053
+ "--two-column": !!props.node.twoColumn,
1054
+ "--hidden": node.value.state?.hidden
1055
+ }));
1056
+ const classesContent = computed(() => ({
1057
+ "--reverse-y": props.node.reverseY ?? viewModel.value.settings.nodes.reverseY
1058
+ }));
1059
+ const styles = computed(() => ({
1060
+ "top": `${props.node.position?.y ?? 0}px`,
1061
+ "left": `${props.node.position?.x ?? 0}px`,
1062
+ "--width": `${props.node.width ?? viewModel.value.settings.nodes.defaultWidth}px`
1063
+ }));
1064
+ const displayedInputs = computed(() => Object.values(props.node.inputs).filter((ni) => !ni.hidden));
1065
+ const displayedOutputs = computed(() => Object.values(props.node.outputs).filter((ni) => !ni.hidden));
1066
+ const select = () => {
1067
+ emit("select");
1068
+ };
1069
+ const startDrag = (ev) => {
1070
+ if (!props.selected) {
1071
+ select();
1072
+ }
1073
+ emit("start-drag", ev);
1074
+ };
1075
+ const openContextMenu = () => {
1076
+ showContextMenu.value = true;
1077
+ };
1078
+ const closeSidebar = () => {
1079
+ const sidebar = viewModel.value.displayedGraph.sidebar;
1080
+ sidebar.nodeId = "";
1081
+ sidebar.visible = false;
1082
+ };
1083
+ const openSidebar = () => {
1084
+ const sidebar = viewModel.value.displayedGraph.sidebar;
1085
+ sidebar.nodeId = props.node.id;
1086
+ sidebar.visible = true;
1087
+ };
1088
+ const updateSidebar = () => {
1089
+ const sidebar = viewModel.value.displayedGraph.sidebar;
1090
+ sidebar.nodeId = props.node.id;
1091
+ };
1092
+ const onContextMenuClick = async (action) => {
1093
+ switch (action) {
1094
+ case "edit":
1095
+ openSidebar();
1096
+ break;
1097
+ case "delete":
1098
+ graph.value.removeNode(props.node);
1099
+ break;
1100
+ case "rename":
1101
+ tempName.value = props.node.title;
1102
+ renaming.value = true;
1103
+ await nextTick();
1104
+ renameInputEl.value?.focus();
1105
+ break;
1106
+ case "editSubgraph":
1107
+ switchGraph(props.node.template);
1108
+ break;
1109
+ }
1110
+ };
1111
+ const doneRenaming = () => {
1112
+ props.node.title = tempName.value;
1113
+ renaming.value = false;
1114
+ };
1115
+ const onRender = () => {
1116
+ if (el.value) {
1117
+ viewModel.value.hooks.renderNode.execute({ node: props.node, el: el.value });
1118
+ }
1119
+ };
1120
+ const startResize = (ev) => {
1121
+ isResizing.value = true;
1122
+ resizeStartWidth = props.node.width;
1123
+ resizeStartMouseX = ev.clientX;
1124
+ ev.preventDefault();
1125
+ };
1126
+ const doResize = (ev) => {
1127
+ if (!isResizing.value) return;
1128
+ const deltaX = ev.clientX - resizeStartMouseX;
1129
+ const newWidth = resizeStartWidth + deltaX / graph.value.scaling;
1130
+ const minWidth = viewModel.value.settings.nodes.minWidth;
1131
+ const maxWidth = viewModel.value.settings.nodes.maxWidth;
1132
+ props.node.width = Math.max(minWidth, Math.min(maxWidth, newWidth));
1133
+ };
1134
+ const stopResize = () => {
1135
+ isResizing.value = false;
1136
+ };
1137
+ onMounted(() => {
1138
+ onRender();
1139
+ window.addEventListener("mousemove", doResize);
1140
+ window.addEventListener("mouseup", stopResize);
1141
+ });
1142
+ onUpdated(onRender);
1143
+ onBeforeUnmount(() => {
1144
+ window.removeEventListener("mousemove", doResize);
1145
+ window.removeEventListener("mouseup", stopResize);
1146
+ });
1147
+ return (_ctx, _cache) => {
1148
+ return openBlock(), createElementBlock("div", {
1149
+ id: node.value.id,
1150
+ ref_key: "el",
1151
+ ref: el,
1152
+ class: normalizeClass([classes.value, "baklava-node"]),
1153
+ "data-node-type": node.value.type,
1154
+ style: normalizeStyle(styles.value),
1155
+ onPointerdown: select
1156
+ }, [
1157
+ unref(viewModel).settings.nodes.resizable ? (openBlock(), createElementBlock("div", {
1158
+ key: 0,
1159
+ class: "__resize-handle",
1160
+ onMousedown: startResize
1161
+ }, null, 32)) : createCommentVNode("", true),
1162
+ createElementVNode("div", {
1163
+ class: "__title",
1164
+ onPointerdown: withModifiers(startDrag, ["self", "stop"]),
1165
+ onContextmenu: withModifiers(openContextMenu, ["prevent"])
1166
+ }, [
1167
+ node.value.inputs._node ? (openBlock(), createBlock(_sfc_main$f, {
1168
+ key: 0,
1169
+ node: node.value,
1170
+ intf: node.value.inputs._node,
1171
+ class: "--input",
1172
+ "data-interface-type": "node",
1173
+ style: { "flex-grow": "0" }
1174
+ }, null, 8, ["node", "intf"])) : createCommentVNode("", true),
1175
+ !renaming.value ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [
1176
+ createElementVNode("div", _hoisted_2$4, [
1177
+ node.value.idx > -1 ? (openBlock(), createElementBlock("span", _hoisted_3$2, toDisplayString(node.value.idx + 1) + " - ", 1)) : createCommentVNode("", true),
1178
+ createTextVNode(toDisplayString(node.value.title) + " (" + toDisplayString(node.value.shortId) + ") ", 1)
1179
+ ]),
1180
+ createElementVNode("div", _hoisted_4$1, [
1181
+ !node.value.subgraph ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
1182
+ !unref(viewModel).displayedGraph.sidebar.visible && unref(viewModel).displayedGraph.sidebar.nodeId !== node.value.id ? (openBlock(), createBlock(unref(LayoutSidebarRightExpand), {
1183
+ key: 0,
1184
+ class: "--clickable mx-1",
1185
+ onClick: openSidebar
1186
+ })) : unref(viewModel).displayedGraph.sidebar.visible && unref(viewModel).displayedGraph.sidebar.nodeId !== node.value.id ? (openBlock(), createBlock(unref(LayoutSidebarRight), {
1187
+ key: 1,
1188
+ class: "--clickable mx-1",
1189
+ onClick: updateSidebar
1190
+ })) : (openBlock(), createBlock(unref(LayoutSidebarRightCollapse), {
1191
+ key: 2,
1192
+ class: "--clickable mx-1",
1193
+ onClick: closeSidebar
1194
+ }))
1195
+ ], 64)) : createCommentVNode("", true),
1196
+ createVNode(unref(VerticalDots), {
1197
+ class: "--clickable mx-1",
1198
+ onClick: openContextMenu
1199
+ }),
1200
+ createVNode(unref(ContextMenu), {
1201
+ modelValue: showContextMenu.value,
1202
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => showContextMenu.value = $event),
1203
+ x: 0,
1204
+ y: 0,
1205
+ items: contextMenuItems.value,
1206
+ onClick: onContextMenuClick
1207
+ }, null, 8, ["modelValue", "items"])
1208
+ ])
1209
+ ], 64)) : withDirectives((openBlock(), createElementBlock("input", {
1210
+ key: 2,
1211
+ ref_key: "renameInputEl",
1212
+ ref: renameInputEl,
1213
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => tempName.value = $event),
1214
+ class: "baklava-input",
1215
+ placeholder: "Node Name",
1216
+ style: { "flex-grow": "1" },
1217
+ type: "text",
1218
+ onBlur: doneRenaming,
1219
+ onKeydown: withKeys(doneRenaming, ["enter"])
1220
+ }, null, 544)), [
1221
+ [vModelText, tempName.value]
1222
+ ]),
1223
+ node.value.outputs._node ? (openBlock(), createBlock(_sfc_main$f, {
1224
+ key: 3,
1225
+ node: node.value,
1226
+ intf: node.value.outputs._node,
1227
+ class: "--output",
1228
+ "data-interface-type": "node"
1229
+ }, null, 8, ["node", "intf"])) : createCommentVNode("", true)
1230
+ ], 32),
1231
+ createElementVNode("div", {
1232
+ class: normalizeClass(["__content", classesContent.value]),
1233
+ onKeydown: _cache[2] || (_cache[2] = withKeys(withModifiers(() => {
1234
+ }, ["stop"]), ["delete"])),
1235
+ onContextmenu: _cache[3] || (_cache[3] = withModifiers(() => {
1236
+ }, ["prevent"]))
1237
+ }, [
1238
+ createElementVNode("div", _hoisted_5, [
1239
+ (openBlock(true), createElementBlock(Fragment, null, renderList(displayedOutputs.value, (output) => {
1240
+ return openBlock(), createElementBlock(Fragment, {
1241
+ key: output.id
1242
+ }, [
1243
+ node.value.state?.hidden ? (openBlock(), createElementBlock("div", _hoisted_6, [
1244
+ output.port ? (openBlock(), createElementBlock("div", {
1245
+ key: 0,
1246
+ id: output.id,
1247
+ title: output.name,
1248
+ class: "baklava-node-interface --output --connected"
1249
+ }, [..._cache[4] || (_cache[4] = [
1250
+ createElementVNode("div", { class: "__port" }, null, -1)
1251
+ ])], 8, _hoisted_7)) : createCommentVNode("", true)
1252
+ ])) : renderSlot(_ctx.$slots, "nodeInterface", {
1253
+ key: 1,
1254
+ type: "output",
1255
+ node: node.value,
1256
+ intf: output
1257
+ }, () => [
1258
+ createVNode(unref(NodeInterface2), {
1259
+ node: node.value,
1260
+ intf: output
1261
+ }, null, 8, ["node", "intf"])
1262
+ ])
1263
+ ], 64);
1264
+ }), 128))
1265
+ ]),
1266
+ createElementVNode("div", _hoisted_8, [
1267
+ (openBlock(true), createElementBlock(Fragment, null, renderList(displayedInputs.value, (input) => {
1268
+ return openBlock(), createElementBlock(Fragment, {
1269
+ key: input.id
1270
+ }, [
1271
+ node.value.state?.hidden ? (openBlock(), createElementBlock("div", _hoisted_9, [
1272
+ input.port ? (openBlock(), createElementBlock("div", {
1273
+ key: 0,
1274
+ id: input.id,
1275
+ title: input.name,
1276
+ class: "baklava-node-interface --input --connected"
1277
+ }, [..._cache[5] || (_cache[5] = [
1278
+ createElementVNode("div", { class: "__port" }, null, -1)
1279
+ ])], 8, _hoisted_10)) : createCommentVNode("", true)
1280
+ ])) : renderSlot(_ctx.$slots, "nodeInterface", {
1281
+ key: 1,
1282
+ node: node.value,
1283
+ intf: input,
1284
+ type: "input"
1285
+ }, () => [
1286
+ createVNode(unref(NodeInterface2), {
1287
+ node: node.value,
1288
+ intf: input,
1289
+ title: input.name
1290
+ }, null, 8, ["node", "intf", "title"])
1291
+ ])
1292
+ ], 64);
1293
+ }), 128))
1294
+ ])
1295
+ ], 34)
1296
+ ], 46, _hoisted_1$4);
1297
+ };
1298
+ }
1299
+ });
1300
+ const _hoisted_1$3 = ["title"];
1301
+ const _hoisted_2$3 = {
1302
+ key: 0,
1303
+ class: "__label"
1304
+ };
1305
+ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
1306
+ __name: "Checkbox",
1307
+ props: {
1308
+ modelValue: { type: Boolean },
1309
+ inversed: { type: Boolean },
1310
+ name: {}
1311
+ },
1312
+ emits: ["update:modelValue"],
1313
+ setup(__props, { emit: __emit }) {
1314
+ const emit = __emit;
1315
+ return (_ctx, _cache) => {
1316
+ return openBlock(), createElementBlock("div", {
1317
+ class: normalizeClass(["baklava-checkbox", { "--checked": _ctx.inversed ? !_ctx.modelValue : _ctx.modelValue }]),
1318
+ title: _ctx.name,
1319
+ onClick: _cache[0] || (_cache[0] = ($event) => emit("update:modelValue", !_ctx.modelValue))
1320
+ }, [
1321
+ _cache[1] || (_cache[1] = createElementVNode("div", { class: "__checkmark-container" }, [
1322
+ createElementVNode("svg", {
1323
+ xmlns: "http://www.w3.org/2000/svg",
1324
+ width: "18",
1325
+ height: "18",
1326
+ viewBox: "0 0 18 18"
1327
+ }, [
1328
+ createElementVNode("path", {
1329
+ class: "__checkmark",
1330
+ d: "M 6 5 L 6 10 L 16 10",
1331
+ transform: "rotate(-45 10 10)"
1332
+ })
1333
+ ])
1334
+ ], -1)),
1335
+ _ctx.name ? (openBlock(), createElementBlock("div", _hoisted_2$3, toDisplayString(_ctx.name), 1)) : createCommentVNode("", true)
1336
+ ], 10, _hoisted_1$3);
1337
+ };
1338
+ }
1339
+ });
1340
+ const _hoisted_1$2 = { class: "__header" };
1341
+ const _hoisted_2$2 = { class: "__node-name" };
1342
+ const _hoisted_3$1 = { style: { "display": "flex" } };
1343
+ const _hoisted_4 = {
1344
+ key: 1,
1345
+ class: "__interface"
1346
+ };
1347
+ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
1348
+ __name: "CodeGraphSidebar",
1349
+ setup(__props) {
1350
+ const { viewModel } = useViewModel();
1351
+ const { graph } = useGraph();
1352
+ const el = ref(null);
1353
+ const width = toRef(viewModel.value.settings.sidebar, "width");
1354
+ const resizable = computed(() => viewModel.value.settings.sidebar.resizable);
1355
+ let resizeStartWidth = 0;
1356
+ let resizeStartMouseX = 0;
1357
+ const node = computed(() => {
1358
+ const id = graph.value.sidebar.nodeId;
1359
+ return graph.value.nodes.find((x) => x.id === id);
1360
+ });
1361
+ const codeNode = computed(() => node.value);
1362
+ const styles = computed(() => ({
1363
+ width: `${width.value}px`
1364
+ }));
1365
+ const displayedInterfaces = computed(() => {
1366
+ if (!node.value) return [];
1367
+ const allIntfs = [...Object.values(node.value.inputs), ...Object.values(node.value.outputs)];
1368
+ return allIntfs.filter((intf) => intf.displayInSidebar && intf.component);
1369
+ });
1370
+ const close = () => {
1371
+ graph.value.sidebar.visible = false;
1372
+ };
1373
+ const doneRenaming = () => {
1374
+ node.value?.events.update.emit(null);
1375
+ };
1376
+ const startResize = (event) => {
1377
+ resizeStartWidth = width.value;
1378
+ resizeStartMouseX = event.clientX;
1379
+ window.addEventListener("mousemove", onMouseMove);
1380
+ window.addEventListener(
1381
+ "mouseup",
1382
+ () => {
1383
+ window.removeEventListener("mousemove", onMouseMove);
1384
+ },
1385
+ { once: true }
1386
+ );
1387
+ };
1388
+ const onMouseMove = (event) => {
1389
+ const maxwidth = el.value?.parentElement?.getBoundingClientRect().width ?? 500;
1390
+ const deltaX = event.clientX - resizeStartMouseX;
1391
+ let newWidth = resizeStartWidth - deltaX;
1392
+ if (newWidth < 300) {
1393
+ newWidth = 300;
1394
+ } else if (newWidth > 0.9 * maxwidth) {
1395
+ newWidth = 0.9 * maxwidth;
1396
+ }
1397
+ width.value = newWidth;
1398
+ };
1399
+ return (_ctx, _cache) => {
1400
+ return openBlock(), createElementBlock("div", {
1401
+ ref_key: "el",
1402
+ ref: el,
1403
+ class: normalizeClass(["baklava-sidebar", { "--open": unref(graph).sidebar.visible }]),
1404
+ style: normalizeStyle(styles.value)
1405
+ }, [
1406
+ resizable.value ? (openBlock(), createElementBlock("div", {
1407
+ key: 0,
1408
+ class: "__resizer",
1409
+ onMousedown: startResize
1410
+ }, null, 32)) : createCommentVNode("", true),
1411
+ createElementVNode("div", _hoisted_1$2, [
1412
+ createElementVNode("button", {
1413
+ tabindex: "-1",
1414
+ class: "__close",
1415
+ onClick: close
1416
+ }, "×"),
1417
+ createElementVNode("div", _hoisted_2$2, [
1418
+ createElementVNode("b", null, toDisplayString(node.value ? node.value.title : ""), 1)
1419
+ ])
1420
+ ]),
1421
+ (openBlock(true), createElementBlock(Fragment, null, renderList(displayedInterfaces.value, (intf) => {
1422
+ return openBlock(), createElementBlock("div", {
1423
+ key: intf.id,
1424
+ class: "__interface"
1425
+ }, [
1426
+ createElementVNode("div", _hoisted_3$1, [
1427
+ createVNode(_sfc_main$4, {
1428
+ modelValue: intf.hidden,
1429
+ "onUpdate:modelValue": [
1430
+ ($event) => intf.hidden = $event,
1431
+ _cache[0] || (_cache[0] = () => node.value?.events.update.emit(null))
1432
+ ],
1433
+ inversed: "",
1434
+ style: { "margin-right": "8px" }
1435
+ }, null, 8, ["modelValue", "onUpdate:modelValue"]),
1436
+ (openBlock(), createBlock(resolveDynamicComponent(intf.component), {
1437
+ modelValue: intf.value,
1438
+ "onUpdate:modelValue": ($event) => intf.value = $event,
1439
+ node: node.value,
1440
+ intf,
1441
+ style: { "width": "100%" }
1442
+ }, null, 8, ["modelValue", "onUpdate:modelValue", "node", "intf"]))
1443
+ ])
1444
+ ]);
1445
+ }), 128)),
1446
+ codeNode.value && codeNode.value.state ? (openBlock(), createElementBlock("div", _hoisted_4, [
1447
+ _cache[2] || (_cache[2] = createElementVNode("label", null, "Variable name", -1)),
1448
+ withDirectives(createElementVNode("input", {
1449
+ "onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => codeNode.value.state.variableName = $event),
1450
+ type: "text",
1451
+ class: "baklava-input",
1452
+ title: "Variable name",
1453
+ onBlur: doneRenaming,
1454
+ onKeydown: withKeys(doneRenaming, ["enter"])
1455
+ }, null, 544), [
1456
+ [vModelText, codeNode.value.state.variableName]
1457
+ ])
1458
+ ])) : createCommentVNode("", true)
1459
+ ], 6);
1460
+ };
1461
+ }
1462
+ });
1463
+ const _sfc_main$2 = defineComponent({
1464
+ props: {
1465
+ type: {
1466
+ type: String,
1467
+ required: true
1468
+ },
1469
+ title: {
1470
+ type: String,
1471
+ required: true
1472
+ }
1473
+ },
1474
+ setup(props) {
1475
+ const { viewModel } = useViewModel();
1476
+ const { switchGraph } = useGraph();
1477
+ const showContextMenu = ref(false);
1478
+ const hasContextMenu = computed(() => props.type.startsWith(GRAPH_NODE_TYPE_PREFIX));
1479
+ const contextMenuItems = [
1480
+ { label: "Edit Subgraph", value: "editSubgraph" },
1481
+ { label: "Delete Subgraph", value: "deleteSubgraph" }
1482
+ ];
1483
+ const openContextMenu = () => {
1484
+ showContextMenu.value = true;
1485
+ };
1486
+ const onContextMenuClick = (action) => {
1487
+ const graphTemplateId = props.type.substring(GRAPH_NODE_TYPE_PREFIX.length);
1488
+ const graphTemplate = viewModel.value.editor.graphTemplates.find((gt) => gt.id === graphTemplateId);
1489
+ if (!graphTemplate) {
1490
+ return;
1491
+ }
1492
+ switch (action) {
1493
+ case "editSubgraph":
1494
+ switchGraph(graphTemplate);
1495
+ break;
1496
+ case "deleteSubgraph":
1497
+ viewModel.value.editor.removeGraphTemplate(graphTemplate);
1498
+ break;
1499
+ }
1500
+ };
1501
+ return { showContextMenu, hasContextMenu, contextMenuItems, openContextMenu, onContextMenuClick };
1502
+ }
1503
+ });
1504
+ const _hoisted_1$1 = ["data-node-type"];
1505
+ const _hoisted_2$1 = { class: "__title" };
1506
+ const _hoisted_3 = { class: "__title-label" };
1507
+ function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
1508
+ return openBlock(), createElementBlock("div", {
1509
+ class: "baklava-node --palette",
1510
+ "data-node-type": _ctx.type
1511
+ }, [
1512
+ createElementVNode("div", _hoisted_2$1, [
1513
+ createElementVNode("div", _hoisted_3, toDisplayString(_ctx.title), 1)
1514
+ ])
1515
+ ], 8, _hoisted_1$1);
1516
+ }
1517
+ const PaletteEntry = /* @__PURE__ */ _export_sfc(_sfc_main$2, [["render", _sfc_render]]);
1518
+ const _hoisted_1 = {
1519
+ class: "baklava-node --palette",
1520
+ style: { "margin-top": "-20px", "margin-bottom": "30px" }
1521
+ };
1522
+ const _hoisted_2 = { key: 0 };
1523
+ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
1524
+ __name: "CodeNodePalette",
1525
+ setup(__props) {
1526
+ const { viewModel } = useViewModel();
1527
+ const { x: mouseX, y: mouseY } = usePointer();
1528
+ const { transform } = useTransform();
1529
+ const categories = useNodeCategories(viewModel);
1530
+ const editorEl = inject("editorEl");
1531
+ const searchQuery = ref("");
1532
+ const draggedNode = ref(null);
1533
+ const filterCategoryBySearch = (categories2) => {
1534
+ if (searchQuery.value) {
1535
+ return categories2.filter(
1536
+ (c) => Object.values(c.nodeTypes).some(
1537
+ (nodeType2) => nodeType2.title.toLowerCase().includes(searchQuery.value?.toLowerCase())
1538
+ )
1539
+ );
1540
+ }
1541
+ return categories2;
1542
+ };
1543
+ const filterNodesBySearch = (nodeTypes) => {
1544
+ if (searchQuery.value) {
1545
+ return Object.values(nodeTypes).filter(
1546
+ (nt) => nt.title.toLowerCase().includes(searchQuery.value?.toLowerCase())
1547
+ );
1548
+ }
1549
+ return Object.values(nodeTypes);
1550
+ };
1551
+ const draggedNodeStyles = computed(() => {
1552
+ if (!draggedNode.value || !editorEl?.value) return {};
1553
+ const { left, top } = editorEl.value.getBoundingClientRect();
1554
+ return {
1555
+ top: `${mouseY.value - top}px`,
1556
+ left: `${mouseX.value - left}px`
1557
+ };
1558
+ });
1559
+ const onDragStart = (type, nodeInformation) => {
1560
+ draggedNode.value = {
1561
+ type,
1562
+ nodeInformation
1563
+ };
1564
+ const onDragEnd = () => {
1565
+ const instance = reactive(new nodeInformation.type());
1566
+ viewModel.value.displayedGraph.addNode(instance);
1567
+ const rect = editorEl.value.getBoundingClientRect();
1568
+ const [x, y] = transform(mouseX.value - rect.left, mouseY.value - rect.top);
1569
+ instance.position.x = x;
1570
+ instance.position.y = y;
1571
+ draggedNode.value = null;
1572
+ document.removeEventListener("pointerup", onDragEnd);
1573
+ };
1574
+ document.addEventListener("pointerup", onDragEnd);
1575
+ };
1576
+ return (_ctx, _cache) => {
1577
+ return openBlock(), createElementBlock(Fragment, null, [
1578
+ createElementVNode("div", {
1579
+ class: normalizeClass(["baklava-node-palette", { "--open": unref(viewModel).settings.palette.enabled }]),
1580
+ onContextmenu: _cache[1] || (_cache[1] = withModifiers(() => {
1581
+ }, ["stop", "prevent"]))
1582
+ }, [
1583
+ createElementVNode("div", _hoisted_1, [
1584
+ withDirectives(createElementVNode("input", {
1585
+ "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => searchQuery.value = $event),
1586
+ type: "text",
1587
+ class: "baklava-input",
1588
+ title: "Filter node types"
1589
+ }, null, 512), [
1590
+ [vModelText, searchQuery.value]
1591
+ ])
1592
+ ]),
1593
+ (openBlock(true), createElementBlock(Fragment, null, renderList(filterCategoryBySearch(unref(categories)), (c) => {
1594
+ return openBlock(), createElementBlock("section", {
1595
+ key: c.name
1596
+ }, [
1597
+ c.name !== "default" ? (openBlock(), createElementBlock("h3", _hoisted_2, toDisplayString(c.name), 1)) : createCommentVNode("", true),
1598
+ (openBlock(true), createElementBlock(Fragment, null, renderList(filterNodesBySearch(c.nodeTypes), (ni, nt) => {
1599
+ return openBlock(), createBlock(PaletteEntry, {
1600
+ key: nt,
1601
+ type: nt,
1602
+ title: ni.title,
1603
+ onPointerdown: ($event) => onDragStart(nt, ni)
1604
+ }, null, 8, ["type", "title", "onPointerdown"]);
1605
+ }), 128))
1606
+ ]);
1607
+ }), 128))
1608
+ ], 34),
1609
+ createVNode(Transition, { name: "fade" }, {
1610
+ default: withCtx(() => [
1611
+ draggedNode.value ? (openBlock(), createElementBlock("div", {
1612
+ key: 0,
1613
+ class: "baklava-dragged-node",
1614
+ style: normalizeStyle(draggedNodeStyles.value)
1615
+ }, [
1616
+ createVNode(PaletteEntry, {
1617
+ type: draggedNode.value.type,
1618
+ title: draggedNode.value.nodeInformation.title
1619
+ }, null, 8, ["type", "title"])
1620
+ ], 4)) : createCommentVNode("", true)
1621
+ ]),
1622
+ _: 1
1623
+ })
1624
+ ], 64);
1625
+ };
1626
+ }
1627
+ });
1628
+ const _sfc_main = /* @__PURE__ */ defineComponent({
1629
+ __name: "CodeGraphEditor",
1630
+ props: {
1631
+ viewModel: {}
1632
+ },
1633
+ setup(__props) {
1634
+ const props = __props;
1635
+ const viewModel = toRef(props, "viewModel");
1636
+ const onUpdate = (node) => node.events.update.emit(null);
1637
+ onMounted(() => {
1638
+ viewModel.value.subscribe();
1639
+ viewModel.value.engine.start();
1640
+ });
1641
+ onUnmounted(() => {
1642
+ viewModel.value.unsubscribe();
1643
+ viewModel.value.engine.stop();
1644
+ });
1645
+ return (_ctx, _cache) => {
1646
+ return openBlock(), createBlock(unref(BaklavaEditor), { "view-model": viewModel.value }, {
1647
+ palette: withCtx(() => [
1648
+ createVNode(_sfc_main$1)
1649
+ ]),
1650
+ node: withCtx((nodeProps) => [
1651
+ createVNode(_sfc_main$5, mergeProps(nodeProps, {
1652
+ onUpdate: ($event) => onUpdate(nodeProps.node)
1653
+ }), null, 16, ["onUpdate"])
1654
+ ]),
1655
+ sidebar: withCtx((nodeProps) => [
1656
+ createVNode(_sfc_main$3, normalizeProps(guardReactiveProps(nodeProps)), null, 16)
1657
+ ]),
1658
+ _: 1
1659
+ }, 8, ["view-model"]);
1660
+ };
1661
+ }
1662
+ });
1663
+ const addToolbarCommands = (viewModel) => {
1664
+ const TOGGLE_PALETTE_COMMAND = "TOGGLE_PALETTE";
1665
+ viewModel.commandHandler.registerCommand(TOGGLE_PALETTE_COMMAND, {
1666
+ execute: () => viewModel.settings.palette.enabled = !viewModel.settings.palette.enabled,
1667
+ canExecute: () => true
1668
+ });
1669
+ const CLEAR_ALL_COMMAND = "CLEAR_ALL";
1670
+ viewModel.commandHandler.registerCommand(CLEAR_ALL_COMMAND, {
1671
+ execute: () => viewModel.displayedGraph.nodes.forEach((node) => viewModel.displayedGraph.removeNode(node)),
1672
+ canExecute: () => viewModel.displayedGraph.nodes.length > 0
1673
+ });
1674
+ const TOGGLE_MINIMAP_COMMAND = "TOGGLE_MINIMAP";
1675
+ viewModel.commandHandler.registerCommand(TOGGLE_MINIMAP_COMMAND, {
1676
+ execute: () => viewModel.settings.enableMinimap = !viewModel.settings.enableMinimap,
1677
+ canExecute: () => viewModel.displayedGraph.nodes.length > 1
1678
+ });
1679
+ viewModel.settings.toolbar.commands = [
1680
+ {
1681
+ command: TOGGLE_PALETTE_COMMAND,
1682
+ title: "Toggle palette",
1683
+ // Tooltip text
1684
+ icon: computed(() => viewModel.settings.palette.enabled ? LayoutSidebarLeftCollapse : LayoutSidebarLeftExpand)
1685
+ },
1686
+ ...DEFAULT_TOOLBAR_COMMANDS,
1687
+ {
1688
+ command: CLEAR_ALL_COMMAND,
1689
+ title: "Clear all",
1690
+ // Tooltip text
1691
+ icon: TrashOff
1692
+ },
1693
+ {
1694
+ command: TOGGLE_MINIMAP_COMMAND,
1695
+ title: "Toggle minimap",
1696
+ // Tooltip text
1697
+ icon: computed(() => viewModel.settings.enableMinimap ? SchemaOff : Schema)
1698
+ }
1699
+ ];
1700
+ };
1701
+ const DEFAULT_SETTINGS = {
1702
+ enableMinimap: false,
1703
+ toolbar: {
1704
+ enabled: true
1705
+ },
1706
+ palette: {
1707
+ enabled: true
1708
+ },
1709
+ sidebar: {
1710
+ enabled: true,
1711
+ resizable: true,
1712
+ width: 350
1713
+ },
1714
+ displayValueOnHover: false
1715
+ };
1716
+ function useCodeGraph(existingEditor) {
1717
+ const viewModel = useBaklava(existingEditor);
1718
+ addToolbarCommands(viewModel);
1719
+ viewModel.code = new Code(viewModel);
1720
+ const settings = {};
1721
+ Object.keys(DEFAULT_SETTINGS).forEach((K) => {
1722
+ settings[K] = typeof DEFAULT_SETTINGS[K] === "object" ? { ...viewModel.settings[K], ...DEFAULT_SETTINGS[K] } : DEFAULT_SETTINGS[K];
1723
+ });
1724
+ viewModel.settings = reactive({ ...viewModel.settings, ...settings });
1725
+ viewModel.settings.nodes.defaultWidth = 350;
1726
+ viewModel.state = reactive({
1727
+ modules: {},
1728
+ token: null
1729
+ });
1730
+ viewModel.engine = new DependencyEngine(viewModel.editor);
1731
+ viewModel.subscribe = () => {
1732
+ if (viewModel.state.token) viewModel.unsubscribe();
1733
+ const token = Symbol();
1734
+ viewModel.displayedGraph.events.addNode.subscribe(token, (node) => node.code = viewModel.code);
1735
+ viewModel.engine.events.beforeRun.subscribe(token, () => {
1736
+ viewModel.engine.pause();
1737
+ viewModel.code.onCodeUpdate();
1738
+ viewModel.code.sortNodes();
1739
+ viewModel.code.updateOutputVariableNames();
1740
+ viewModel.engine.resume();
1741
+ });
1742
+ viewModel.engine.events.afterRun.subscribe(token, (result) => {
1743
+ viewModel.engine.pause();
1744
+ applyResult(result, viewModel.editor);
1745
+ transferCodeScript(viewModel.displayedGraph);
1746
+ viewModel.code.renderNodeCodes();
1747
+ viewModel.code.renderCode();
1748
+ viewModel.engine.resume();
1749
+ });
1750
+ viewModel.state.token = token;
1751
+ };
1752
+ viewModel.unsubscribe = () => {
1753
+ if (!viewModel.state.token) return;
1754
+ const token = viewModel.state.token;
1755
+ viewModel.displayedGraph.events.addNode.unsubscribe(token);
1756
+ viewModel.engine.events.beforeRun.unsubscribe(token);
1757
+ viewModel.engine.events.afterRun.unsubscribe(token);
1758
+ viewModel.state.token = null;
1759
+ };
1760
+ return viewModel;
1761
+ }
1762
+ export {
1763
+ AbstractCodeNode,
1764
+ ButtonInterface,
1765
+ ButtonInterfaceComponent2 as ButtonInterfaceComponent,
1766
+ CheckboxInterface,
1767
+ CheckboxInterfaceComponent2 as CheckboxInterfaceComponent,
1768
+ Code,
1769
+ _sfc_main as CodeGraphEditor,
1770
+ CodeInputInterface,
1771
+ CodeNode,
1772
+ CodeNodeInterface,
1773
+ CodeOutputInterface,
1774
+ DEFAULT_SETTINGS,
1775
+ DynamicCodeNode,
1776
+ IntegerInterface,
1777
+ IntegerInterfaceComponent2 as IntegerInterfaceComponent,
1778
+ NumberInterface,
1779
+ NumberInterfaceComponent2 as NumberInterfaceComponent,
1780
+ SelectInterface,
1781
+ SelectInterfaceComponent2 as SelectInterfaceComponent,
1782
+ SliderInterface,
1783
+ SliderInterfaceComponent2 as SliderInterfaceComponent,
1784
+ TextInputInterface,
1785
+ TextInputInterfaceComponent2 as TextInputInterfaceComponent,
1786
+ TextInterface,
1787
+ TextareaInputInterface,
1788
+ TextareaInputInterfaceComponent2 as TextareaInputInterfaceComponent,
1789
+ addToolbarCommands,
1790
+ defineCodeNode,
1791
+ defineDynamicCodeNode,
1792
+ getCodeNodes,
1793
+ getPositionAtColumn,
1794
+ getPositionBeforeNode,
1795
+ loadNodeState,
1796
+ saveNodeState,
1797
+ transferCodeScript,
1798
+ useCodeGraph
1799
+ };