@genfeedai/workflow-ui 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/canvas.d.ts +22 -22
  2. package/dist/canvas.mjs +16 -16
  3. package/dist/{chunk-XPZAHIWY.mjs → chunk-2FUPL67V.mjs} +1592 -1044
  4. package/dist/{chunk-HWVTD2LC.mjs → chunk-53XDE62A.mjs} +818 -623
  5. package/dist/{chunk-PCIWWD37.mjs → chunk-7LV4UAUS.mjs} +19 -19
  6. package/dist/{chunk-7SKSRSS7.mjs → chunk-B4EAAKYF.mjs} +16 -16
  7. package/dist/{chunk-ZJD5WMR3.mjs → chunk-C6MQBJFC.mjs} +45 -13
  8. package/dist/{chunk-7H3WJJYS.mjs → chunk-ESVULCFY.mjs} +12 -6
  9. package/dist/{chunk-GWBGK3KL.mjs → chunk-FWJIAW2E.mjs} +82 -47
  10. package/dist/{chunk-R727OFBR.mjs → chunk-GPYIIWD5.mjs} +404 -350
  11. package/dist/{chunk-OQREHJXK.mjs → chunk-IYFWAJBB.mjs} +208 -203
  12. package/dist/{chunk-N5NJZTK4.mjs → chunk-MGLAKMDP.mjs} +23 -21
  13. package/dist/{chunk-LT3ZJJL6.mjs → chunk-OJWVEEMM.mjs} +497 -399
  14. package/dist/{chunk-ZD2BADZO.mjs → chunk-ORVDYXDP.mjs} +221 -175
  15. package/dist/{chunk-CV4M7CNU.mjs → chunk-QQVHGJ2G.mjs} +149 -142
  16. package/dist/{chunk-6PSJTBNV.mjs → chunk-U4QPE4CY.mjs} +387 -347
  17. package/dist/{chunk-EFXQT23N.mjs → chunk-VVQ4CH77.mjs} +5 -5
  18. package/dist/{chunk-VRN3UWE5.mjs → chunk-XRC3O5GK.mjs} +73 -73
  19. package/dist/{chunk-FT33LFII.mjs → chunk-YUIK4AHM.mjs} +1 -1
  20. package/dist/{chunk-FMJPFB6W.mjs → chunk-ZSITTZ4S.mjs} +630 -569
  21. package/dist/hooks.d.ts +37 -37
  22. package/dist/hooks.mjs +10 -10
  23. package/dist/index.d.ts +26 -11
  24. package/dist/index.mjs +99 -19
  25. package/dist/lib.d.ts +203 -203
  26. package/dist/lib.mjs +228 -198
  27. package/dist/nodes.d.ts +2 -2
  28. package/dist/nodes.mjs +12 -12
  29. package/dist/panels.d.ts +2 -3
  30. package/dist/panels.mjs +3 -3
  31. package/dist/provider.d.ts +2 -2
  32. package/dist/provider.mjs +2 -2
  33. package/dist/stores.d.ts +5 -5
  34. package/dist/stores.mjs +5 -5
  35. package/dist/toolbar.d.ts +42 -24
  36. package/dist/toolbar.mjs +4 -4
  37. package/dist/ui.d.ts +2 -2
  38. package/dist/ui.mjs +2 -2
  39. package/dist/{useCommentNavigation-BakbiiIc.d.ts → useRequiredInputs-ByoIS-fT.d.ts} +160 -160
  40. package/dist/{promptLibraryStore-Dl3Q3cP6.d.ts → workflowStore-Bsz0nd5c.d.ts} +368 -368
  41. package/dist/workflowStore-N2F7WIG3.mjs +2 -0
  42. package/package.json +77 -75
  43. package/src/styles/workflow-ui.css +56 -19
  44. package/dist/workflowStore-UAAKOOIK.mjs +0 -2
  45. package/dist/{types-IEKYuYhu.d.ts → types-CRXJnajq.d.ts} +1 -1
@@ -1,13 +1,13 @@
1
- import { selectNodes, selectEdges, selectRemoveNode, selectDuplicateNode, selectAddNode, useContextMenuStore, selectToggleNodeLock, selectCreateGroup, selectWorkflowId, selectSetSelectedNodeIds, selectUpdateNodeData } from './chunk-PCIWWD37.mjs';
2
- import { useSettingsStore } from './chunk-LT3ZJJL6.mjs';
3
- import { useWorkflowStore } from './chunk-R727OFBR.mjs';
4
- import { useWorkflowUIConfig } from './chunk-FT33LFII.mjs';
1
+ import { useWorkflowUIConfig } from './chunk-YUIK4AHM.mjs';
2
+ import { selectNodes, selectEdges, selectRemoveNode, selectDuplicateNode, selectAddNode, useContextMenuStore, selectToggleNodeLock, selectCreateGroup, selectWorkflowId, selectSetSelectedNodeIds, selectUpdateNodeData } from './chunk-7LV4UAUS.mjs';
3
+ import { useSettingsStore } from './chunk-OJWVEEMM.mjs';
4
+ import { useWorkflowStore } from './chunk-GPYIIWD5.mjs';
5
5
  import { useEffect, useState, useCallback, useRef, useMemo } from 'react';
6
6
  import { nanoid } from 'nanoid';
7
7
  import { useReactFlow } from '@xyflow/react';
8
8
  import Dagre from '@dagrejs/dagre';
9
9
  import { getNodesByCategory, NODE_DEFINITIONS } from '@genfeedai/types';
10
- import { ChevronRight, Group, Copy, Lock, LockOpen, AlignHorizontalJustifyCenter, AlignVerticalJustifyCenter, Trash2, GitBranch, ArrowLeftFromLine, ArrowRightToLine, CheckCircle, Subtitles, Pencil, Grid3X3, Maximize, Crop, Film, Scissors, Layers, Wand2, Maximize2, Navigation, AudioLines, Mic, Brain, Video, Sparkles, FileVideo, Volume2, FileText, MessageSquare, Image, Monitor, Clipboard, LayoutGrid, Palette } from 'lucide-react';
10
+ import { ChevronRight, Group, Copy, Lock, LockOpen, AlignHorizontalJustifyCenter, AlignVerticalJustifyCenter, Trash2, Wand2, Volume2, Video, Subtitles, Sparkles, Scissors, Pencil, Navigation, Mic, MessageSquare, Maximize2, Maximize, Layers, Image, Grid3X3, GitBranch, Film, FileVideo, FileText, Crop, CheckCircle, Brain, AudioLines, ArrowRightToLine, ArrowLeftFromLine, Monitor, Clipboard, LayoutGrid, Palette } from 'lucide-react';
11
11
  import { jsx, jsxs } from 'react/jsx-runtime';
12
12
 
13
13
  function useCanvasKeyboardShortcuts({
@@ -45,10 +45,12 @@ function useCanvasKeyboardShortcuts({
45
45
  if (e.key === "f" && !isMod && !e.shiftKey) {
46
46
  e.preventDefault();
47
47
  if (selectedNodeIds.length > 0) {
48
- const selectedNodes = nodes.filter((n) => selectedNodeIds.includes(n.id));
49
- fitView({ nodes: selectedNodes, padding: 0.3, duration: 200 });
48
+ const selectedNodes = nodes.filter(
49
+ (n) => selectedNodeIds.includes(n.id)
50
+ );
51
+ fitView({ duration: 200, nodes: selectedNodes, padding: 0.3 });
50
52
  } else {
51
- fitView({ padding: 0.2, duration: 200 });
53
+ fitView({ duration: 200, padding: 0.2 });
52
54
  }
53
55
  }
54
56
  if (e.key === "?" && e.shiftKey && !isMod) {
@@ -87,22 +89,34 @@ function useCanvasKeyboardShortcuts({
87
89
  }
88
90
  if (e.key === "I" && e.shiftKey && !isMod) {
89
91
  e.preventDefault();
90
- const position = { x: window.innerWidth / 2 - 150, y: window.innerHeight / 2 - 150 };
92
+ const position = {
93
+ x: window.innerWidth / 2 - 150,
94
+ y: window.innerHeight / 2 - 150
95
+ };
91
96
  addNode("imageGen", position);
92
97
  }
93
98
  if (e.key === "V" && e.shiftKey && !isMod) {
94
99
  e.preventDefault();
95
- const position = { x: window.innerWidth / 2 - 150, y: window.innerHeight / 2 - 150 };
100
+ const position = {
101
+ x: window.innerWidth / 2 - 150,
102
+ y: window.innerHeight / 2 - 150
103
+ };
96
104
  addNode("videoGen", position);
97
105
  }
98
106
  if (e.key === "P" && e.shiftKey && !isMod) {
99
107
  e.preventDefault();
100
- const position = { x: window.innerWidth / 2 - 150, y: window.innerHeight / 2 - 150 };
108
+ const position = {
109
+ x: window.innerWidth / 2 - 150,
110
+ y: window.innerHeight / 2 - 150
111
+ };
101
112
  addNode("prompt", position);
102
113
  }
103
114
  if ((e.key === "L" || e.key === "l") && e.shiftKey && !isMod) {
104
115
  e.preventDefault();
105
- const position = { x: window.innerWidth / 2 - 150, y: window.innerHeight / 2 - 150 };
116
+ const position = {
117
+ x: window.innerWidth / 2 - 150,
118
+ y: window.innerHeight / 2 - 150
119
+ };
106
120
  addNode("llm", position);
107
121
  }
108
122
  if (e.key === "z" && isMod && !e.shiftKey) {
@@ -142,18 +156,18 @@ function createPastePayload(clipboard, offsetX, offsetY) {
142
156
  const minY = Math.min(...clipboardNodes.map((n) => n.position.y));
143
157
  const newNodes = clipboardNodes.map((node) => ({
144
158
  ...node,
159
+ data: {
160
+ ...node.data,
161
+ error: void 0,
162
+ jobId: null,
163
+ status: "idle"
164
+ },
145
165
  id: idMap.get(node.id),
146
166
  position: {
147
167
  x: node.position.x - minX + offsetX,
148
168
  y: node.position.y - minY + offsetY
149
169
  },
150
- selected: true,
151
- data: {
152
- ...node.data,
153
- status: "idle",
154
- jobId: null,
155
- error: void 0
156
- }
170
+ selected: true
157
171
  }));
158
172
  const newEdges = clipboardEdges.map((edge) => ({
159
173
  ...edge,
@@ -161,7 +175,7 @@ function createPastePayload(clipboard, offsetX, offsetY) {
161
175
  source: idMap.get(edge.source),
162
176
  target: idMap.get(edge.target)
163
177
  }));
164
- return { nodes: newNodes, edges: newEdges };
178
+ return { edges: newEdges, nodes: newNodes };
165
179
  }
166
180
  function useNodeActions() {
167
181
  const nodes = useWorkflowStore(selectNodes);
@@ -185,7 +199,7 @@ function useNodeActions() {
185
199
  (nodeId) => {
186
200
  const node = nodes.find((n) => n.id === nodeId);
187
201
  if (node) {
188
- setClipboard({ nodes: [node], edges: [], isCut: false });
202
+ setClipboard({ edges: [], isCut: false, nodes: [node] });
189
203
  }
190
204
  },
191
205
  [nodes]
@@ -194,9 +208,11 @@ function useNodeActions() {
194
208
  (nodeIds) => {
195
209
  const nodeSet = new Set(nodeIds);
196
210
  const nodesToCopy = nodes.filter((n) => nodeSet.has(n.id));
197
- const edgesToCopy = edges.filter((e) => nodeSet.has(e.source) && nodeSet.has(e.target));
211
+ const edgesToCopy = edges.filter(
212
+ (e) => nodeSet.has(e.source) && nodeSet.has(e.target)
213
+ );
198
214
  if (nodesToCopy.length > 0) {
199
- setClipboard({ nodes: nodesToCopy, edges: edgesToCopy, isCut: false });
215
+ setClipboard({ edges: edgesToCopy, isCut: false, nodes: nodesToCopy });
200
216
  }
201
217
  },
202
218
  [nodes, edges]
@@ -205,7 +221,7 @@ function useNodeActions() {
205
221
  (nodeId) => {
206
222
  const node = nodes.find((n) => n.id === nodeId);
207
223
  if (node) {
208
- setClipboard({ nodes: [node], edges: [], isCut: true });
224
+ setClipboard({ edges: [], isCut: true, nodes: [node] });
209
225
  removeNode(nodeId);
210
226
  }
211
227
  },
@@ -215,9 +231,11 @@ function useNodeActions() {
215
231
  (nodeIds) => {
216
232
  const nodeSet = new Set(nodeIds);
217
233
  const nodesToCut = nodes.filter((n) => nodeSet.has(n.id));
218
- const edgesToCut = edges.filter((e) => nodeSet.has(e.source) && nodeSet.has(e.target));
234
+ const edgesToCut = edges.filter(
235
+ (e) => nodeSet.has(e.source) && nodeSet.has(e.target)
236
+ );
219
237
  if (nodesToCut.length > 0) {
220
- setClipboard({ nodes: nodesToCut, edges: edgesToCut, isCut: true });
238
+ setClipboard({ edges: edgesToCut, isCut: true, nodes: nodesToCut });
221
239
  for (const nodeId of nodeIds) {
222
240
  removeNode(nodeId);
223
241
  }
@@ -254,8 +272,8 @@ function useNodeActions() {
254
272
  setClipboard(null);
255
273
  }
256
274
  return {
257
- nodeIds: payload.nodes.map((n) => n.id),
258
- edgeIds: payload.edges.map((e) => e.id)
275
+ edgeIds: payload.edges.map((e) => e.id),
276
+ nodeIds: payload.nodes.map((n) => n.id)
259
277
  };
260
278
  },
261
279
  [clipboard]
@@ -273,16 +291,16 @@ function useNodeActions() {
273
291
  );
274
292
  return {
275
293
  clipboard,
276
- deleteNode,
277
- duplicate,
278
- copyNode,
279
294
  copyMultipleNodes,
280
- cutNode,
295
+ copyNode,
281
296
  cutMultipleNodes,
297
+ cutNode,
282
298
  deleteMultipleNodes,
299
+ deleteNode,
300
+ duplicate,
283
301
  duplicateMultipleNodes,
284
- pasteNodes,
285
- getPasteData
302
+ getPasteData,
303
+ pasteNodes
286
304
  };
287
305
  }
288
306
  var DEFAULT_NODE_WIDTH = 280;
@@ -290,10 +308,10 @@ var DEFAULT_NODE_HEIGHT = 200;
290
308
  var MIN_GAP = 40;
291
309
  function getNodeRect(node) {
292
310
  return {
293
- x: node.position.x,
294
- y: node.position.y,
311
+ height: node.measured?.height ?? DEFAULT_NODE_HEIGHT,
295
312
  width: node.measured?.width ?? DEFAULT_NODE_WIDTH,
296
- height: node.measured?.height ?? DEFAULT_NODE_HEIGHT
313
+ x: node.position.x,
314
+ y: node.position.y
297
315
  };
298
316
  }
299
317
  function getInputHandleIndex(nodeType, handleId) {
@@ -334,11 +352,14 @@ function reorderByHandlePosition(nodes, edges) {
334
352
  for (const edge of targetEdges) {
335
353
  const sourceNode = nodeMap.get(edge.source);
336
354
  if (!sourceNode) continue;
337
- const handleIndex = getInputHandleIndex(targetNode.type, edge.targetHandle ?? "");
355
+ const handleIndex = getInputHandleIndex(
356
+ targetNode.type,
357
+ edge.targetHandle ?? ""
358
+ );
338
359
  sourceInfos.push({
339
- nodeId: edge.source,
360
+ currentY: sourceNode.position.y,
340
361
  handleIndex,
341
- currentY: sourceNode.position.y
362
+ nodeId: edge.source
342
363
  });
343
364
  }
344
365
  if (sourceInfos.length < 2) continue;
@@ -403,18 +424,18 @@ function getLayoutedNodes(nodes, edges, options = {}) {
403
424
  const { direction = "LR", nodeSpacing = 50, rankSpacing = 120 } = options;
404
425
  const graph = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));
405
426
  graph.setGraph({
406
- rankdir: direction,
407
- nodesep: nodeSpacing,
408
- ranksep: rankSpacing,
427
+ acyclicer: "greedy",
409
428
  marginx: 50,
410
429
  marginy: 50,
430
+ nodesep: nodeSpacing,
431
+ rankdir: direction,
411
432
  ranker: "network-simplex",
412
- acyclicer: "greedy"
433
+ ranksep: rankSpacing
413
434
  });
414
435
  for (const node of nodes) {
415
436
  const width = node.measured?.width ?? DEFAULT_NODE_WIDTH;
416
437
  const height = node.measured?.height ?? DEFAULT_NODE_HEIGHT;
417
- graph.setNode(node.id, { width, height });
438
+ graph.setNode(node.id, { height, width });
418
439
  }
419
440
  for (const edge of edges) {
420
441
  graph.setEdge(edge.source, edge.target);
@@ -442,7 +463,10 @@ function usePaneActions() {
442
463
  const reactFlow = useReactFlow();
443
464
  const addNodeAtPosition = useCallback(
444
465
  (type, screenX, screenY) => {
445
- const position = reactFlow.screenToFlowPosition({ x: screenX, y: screenY });
466
+ const position = reactFlow.screenToFlowPosition({
467
+ x: screenX,
468
+ y: screenY
469
+ });
446
470
  addNode(type, position);
447
471
  },
448
472
  [addNode, reactFlow]
@@ -463,7 +487,9 @@ function usePaneActions() {
463
487
  const edgeStyle = useSettingsStore.getState().edgeStyle;
464
488
  const currentNodes = reactFlow.getNodes();
465
489
  const currentEdges = reactFlow.getEdges();
466
- const layoutedNodes = getLayoutedNodes(currentNodes, currentEdges, { direction });
490
+ const layoutedNodes = getLayoutedNodes(currentNodes, currentEdges, {
491
+ direction
492
+ });
467
493
  reactFlow.setNodes(layoutedNodes);
468
494
  reactFlow.setEdges(
469
495
  (eds) => eds.map((edge) => ({
@@ -479,18 +505,21 @@ function usePaneActions() {
479
505
  );
480
506
  return {
481
507
  addNodeAtPosition,
482
- selectAll,
508
+ autoLayout,
483
509
  fitView,
484
- autoLayout
510
+ selectAll
485
511
  };
486
512
  }
487
- function getEdgeMenuItems({ edgeId, onDelete }) {
513
+ function getEdgeMenuItems({
514
+ edgeId,
515
+ onDelete
516
+ }) {
488
517
  return [
489
518
  {
519
+ danger: true,
520
+ icon: /* @__PURE__ */ jsx(Trash2, { className: "w-4 h-4" }),
490
521
  id: "delete",
491
522
  label: "Delete Connection",
492
- icon: /* @__PURE__ */ jsx(Trash2, { className: "w-4 h-4" }),
493
- danger: true,
494
523
  onClick: () => onDelete(edgeId)
495
524
  }
496
525
  ];
@@ -730,28 +759,38 @@ function ContextMenu({ x, y, items, onClose }) {
730
759
  );
731
760
  }
732
761
  var NODE_COLOR_VALUES = {
733
- none: null,
734
- purple: "#a855f7",
735
762
  blue: "#3b82f6",
763
+ gray: "#6b7280",
736
764
  green: "#22c55e",
737
- yellow: "#eab308",
765
+ none: null,
738
766
  orange: "#f97316",
739
- red: "#ef4444",
740
767
  pink: "#ec4899",
741
- gray: "#6b7280"
768
+ purple: "#a855f7",
769
+ red: "#ef4444",
770
+ yellow: "#eab308"
742
771
  };
743
772
  var NODE_COLOR_LABELS = {
744
- none: "Default",
745
- purple: "Purple",
746
773
  blue: "Blue",
774
+ gray: "Gray",
747
775
  green: "Green",
748
- yellow: "Yellow",
776
+ none: "Default",
749
777
  orange: "Orange",
750
- red: "Red",
751
778
  pink: "Pink",
752
- gray: "Gray"
779
+ purple: "Purple",
780
+ red: "Red",
781
+ yellow: "Yellow"
753
782
  };
754
- var NODE_COLORS = ["none", "purple", "blue", "green", "yellow", "orange", "red", "pink", "gray"];
783
+ var NODE_COLORS = [
784
+ "none",
785
+ "purple",
786
+ "blue",
787
+ "green",
788
+ "yellow",
789
+ "orange",
790
+ "red",
791
+ "pink",
792
+ "gray"
793
+ ];
755
794
  function getNodeMenuItems({
756
795
  nodeId,
757
796
  isLocked,
@@ -768,18 +807,18 @@ function getNodeMenuItems({
768
807
  }) {
769
808
  const items = [
770
809
  {
810
+ icon: /* @__PURE__ */ jsx(Copy, { className: "w-4 h-4" }),
771
811
  id: "duplicate",
772
812
  label: "Duplicate",
773
- icon: /* @__PURE__ */ jsx(Copy, { className: "w-4 h-4" }),
774
- shortcut: "\u2318D",
775
- onClick: () => onDuplicate(nodeId)
813
+ onClick: () => onDuplicate(nodeId),
814
+ shortcut: "\u2318D"
776
815
  }
777
816
  ];
778
817
  if (hasMediaOutput && onSetAsThumbnail) {
779
818
  items.push({
819
+ icon: /* @__PURE__ */ jsx(Image, { className: "w-4 h-4" }),
780
820
  id: "setThumbnail",
781
821
  label: "Set as Thumbnail",
782
- icon: /* @__PURE__ */ jsx(Image, { className: "w-4 h-4" }),
783
822
  onClick: () => onSetAsThumbnail(nodeId)
784
823
  });
785
824
  }
@@ -788,8 +827,6 @@ function getNodeMenuItems({
788
827
  const colorValue = NODE_COLOR_VALUES[color];
789
828
  const isSelected = colorValue === currentColor || color === "none" && !currentColor;
790
829
  return {
791
- id: `color-${color}`,
792
- label: `${isSelected ? "\u2713 " : ""}${NODE_COLOR_LABELS[color]}`,
793
830
  icon: /* @__PURE__ */ jsx(
794
831
  "div",
795
832
  {
@@ -797,100 +834,102 @@ function getNodeMenuItems({
797
834
  style: { backgroundColor: colorValue || "transparent" }
798
835
  }
799
836
  ),
837
+ id: `color-${color}`,
838
+ label: `${isSelected ? "\u2713 " : ""}${NODE_COLOR_LABELS[color]}`,
800
839
  onClick: () => onSetColor(nodeId, colorValue)
801
840
  };
802
841
  });
803
842
  items.push({
843
+ icon: /* @__PURE__ */ jsx(Palette, { className: "w-4 h-4" }),
804
844
  id: "setColor",
805
845
  label: "Set Color",
806
- icon: /* @__PURE__ */ jsx(Palette, { className: "w-4 h-4" }),
807
846
  submenu: colorSubmenu
808
847
  });
809
848
  }
810
849
  items.push(createSeparator("separator-1"));
811
850
  items.push(
812
851
  isLocked ? {
852
+ icon: /* @__PURE__ */ jsx(LockOpen, { className: "w-4 h-4" }),
813
853
  id: "unlock",
814
854
  label: "Unlock Node",
815
- icon: /* @__PURE__ */ jsx(LockOpen, { className: "w-4 h-4" }),
816
- shortcut: "L",
817
- onClick: () => onUnlock(nodeId)
855
+ onClick: () => onUnlock(nodeId),
856
+ shortcut: "L"
818
857
  } : {
858
+ icon: /* @__PURE__ */ jsx(Lock, { className: "w-4 h-4" }),
819
859
  id: "lock",
820
860
  label: "Lock Node",
821
- icon: /* @__PURE__ */ jsx(Lock, { className: "w-4 h-4" }),
822
- shortcut: "L",
823
- onClick: () => onLock(nodeId)
861
+ onClick: () => onLock(nodeId),
862
+ shortcut: "L"
824
863
  }
825
864
  );
826
865
  items.push(createSeparator("separator-2"));
827
866
  items.push(
828
867
  {
868
+ icon: /* @__PURE__ */ jsx(Scissors, { className: "w-4 h-4" }),
829
869
  id: "cut",
830
870
  label: "Cut",
831
- icon: /* @__PURE__ */ jsx(Scissors, { className: "w-4 h-4" }),
832
- shortcut: "\u2318X",
833
- onClick: () => onCut(nodeId)
871
+ onClick: () => onCut(nodeId),
872
+ shortcut: "\u2318X"
834
873
  },
835
874
  {
875
+ icon: /* @__PURE__ */ jsx(Copy, { className: "w-4 h-4" }),
836
876
  id: "copy",
837
877
  label: "Copy",
838
- icon: /* @__PURE__ */ jsx(Copy, { className: "w-4 h-4" }),
839
- shortcut: "\u2318C",
840
- onClick: () => onCopy(nodeId)
878
+ onClick: () => onCopy(nodeId),
879
+ shortcut: "\u2318C"
841
880
  }
842
881
  );
843
882
  items.push(createSeparator("separator-3"));
844
883
  items.push({
884
+ danger: true,
885
+ icon: /* @__PURE__ */ jsx(Trash2, { className: "w-4 h-4" }),
845
886
  id: "delete",
846
887
  label: "Delete",
847
- icon: /* @__PURE__ */ jsx(Trash2, { className: "w-4 h-4" }),
848
- shortcut: "\u232B",
849
- danger: true,
850
- onClick: () => onDelete(nodeId)
888
+ onClick: () => onDelete(nodeId),
889
+ shortcut: "\u232B"
851
890
  });
852
891
  return items;
853
892
  }
854
893
  var NODE_ICONS = {
855
- Image: Image,
856
- MessageSquare,
894
+ ArrowLeftFromLine,
895
+ ArrowRightToLine,
896
+ AudioLines,
897
+ Brain,
898
+ CheckCircle,
899
+ Crop,
857
900
  FileText,
858
- Volume2,
859
901
  FileVideo,
860
- Sparkles,
861
- Video,
862
- Brain,
863
- Mic,
864
- AudioLines,
865
- Navigation,
866
- Maximize2,
867
- Wand2,
868
- Layers,
869
- Scissors: Scissors,
870
902
  Film,
871
- Crop,
872
- Maximize,
903
+ GitBranch,
873
904
  Grid3X3,
905
+ Image: Image,
906
+ Layers,
907
+ Maximize,
908
+ Maximize2,
909
+ MessageSquare,
910
+ Mic,
911
+ Navigation,
874
912
  Pencil,
913
+ Scissors: Scissors,
914
+ Sparkles,
875
915
  Subtitles,
876
- CheckCircle,
877
- ArrowRightToLine,
878
- ArrowLeftFromLine,
879
- GitBranch
916
+ Video,
917
+ Volume2,
918
+ Wand2
880
919
  };
881
920
  var CATEGORY_LABELS = {
882
- input: "Input",
883
921
  ai: "AI Generation",
884
- processing: "Processing",
922
+ composition: "Composition",
923
+ input: "Input",
885
924
  output: "Output",
886
- composition: "Composition"
925
+ processing: "Processing"
887
926
  };
888
927
  var CATEGORY_ICONS = {
889
- input: Image,
890
928
  ai: Sparkles,
891
- processing: Wand2,
929
+ composition: GitBranch,
930
+ input: Image,
892
931
  output: Monitor,
893
- composition: GitBranch
932
+ processing: Wand2
894
933
  };
895
934
  function getPaneMenuItems({
896
935
  screenX,
@@ -908,15 +947,15 @@ function getPaneMenuItems({
908
947
  const CategoryIcon = CATEGORY_ICONS[category];
909
948
  const nodes = nodesByCategory[category];
910
949
  return {
950
+ icon: /* @__PURE__ */ jsx(CategoryIcon, { className: "w-4 h-4" }),
911
951
  id: `add-${category}`,
912
952
  label: CATEGORY_LABELS[category],
913
- icon: /* @__PURE__ */ jsx(CategoryIcon, { className: "w-4 h-4" }),
914
953
  submenu: nodes.map((node) => {
915
954
  const NodeIcon = NODE_ICONS[node.icon] ?? Sparkles;
916
955
  return {
956
+ icon: /* @__PURE__ */ jsx(NodeIcon, { className: "w-4 h-4" }),
917
957
  id: `add-${node.type}`,
918
958
  label: node.label,
919
- icon: /* @__PURE__ */ jsx(NodeIcon, { className: "w-4 h-4" }),
920
959
  onClick: () => onAddNode(node.type, screenX, screenY)
921
960
  };
922
961
  })
@@ -926,33 +965,33 @@ function getPaneMenuItems({
926
965
  ...addNodeItems,
927
966
  createSeparator("separator-1"),
928
967
  {
968
+ disabled: !hasClipboard,
969
+ icon: /* @__PURE__ */ jsx(Clipboard, { className: "w-4 h-4" }),
929
970
  id: "paste",
930
971
  label: "Paste",
931
- icon: /* @__PURE__ */ jsx(Clipboard, { className: "w-4 h-4" }),
932
- shortcut: "\u2318V",
933
- disabled: !hasClipboard,
934
- onClick: onPaste
972
+ onClick: onPaste,
973
+ shortcut: "\u2318V"
935
974
  },
936
975
  createSeparator("separator-2"),
937
976
  {
938
977
  id: "select-all",
939
978
  label: "Select All",
940
- shortcut: "\u2318A",
941
- onClick: onSelectAll
979
+ onClick: onSelectAll,
980
+ shortcut: "\u2318A"
942
981
  },
943
982
  {
983
+ icon: /* @__PURE__ */ jsx(Maximize, { className: "w-4 h-4" }),
944
984
  id: "fit-view",
945
985
  label: "Fit View",
946
- icon: /* @__PURE__ */ jsx(Maximize, { className: "w-4 h-4" }),
947
- shortcut: "F",
948
- onClick: onFitView
986
+ onClick: onFitView,
987
+ shortcut: "F"
949
988
  },
950
989
  {
990
+ icon: /* @__PURE__ */ jsx(LayoutGrid, { className: "w-4 h-4" }),
951
991
  id: "auto-layout",
952
992
  label: "Auto-layout Nodes",
953
- icon: /* @__PURE__ */ jsx(LayoutGrid, { className: "w-4 h-4" }),
954
- shortcut: "L",
955
- onClick: onAutoLayout
993
+ onClick: onAutoLayout,
994
+ shortcut: "L"
956
995
  }
957
996
  ];
958
997
  }
@@ -969,54 +1008,54 @@ function getSelectionMenuItems({
969
1008
  const count = nodeIds.length;
970
1009
  return [
971
1010
  {
1011
+ icon: /* @__PURE__ */ jsx(Group, { className: "w-4 h-4" }),
972
1012
  id: "group",
973
1013
  label: "Create Group",
974
- icon: /* @__PURE__ */ jsx(Group, { className: "w-4 h-4" }),
975
- shortcut: "\u2318G",
976
- onClick: () => onGroup(nodeIds)
1014
+ onClick: () => onGroup(nodeIds),
1015
+ shortcut: "\u2318G"
977
1016
  },
978
1017
  {
1018
+ icon: /* @__PURE__ */ jsx(Copy, { className: "w-4 h-4" }),
979
1019
  id: "duplicate-all",
980
1020
  label: `Duplicate ${count} Nodes`,
981
- icon: /* @__PURE__ */ jsx(Copy, { className: "w-4 h-4" }),
982
- shortcut: "\u2318D",
983
- onClick: () => onDuplicateAll(nodeIds)
1021
+ onClick: () => onDuplicateAll(nodeIds),
1022
+ shortcut: "\u2318D"
984
1023
  },
985
1024
  createSeparator("separator-1"),
986
1025
  {
1026
+ icon: /* @__PURE__ */ jsx(Lock, { className: "w-4 h-4" }),
987
1027
  id: "lock-all",
988
1028
  label: "Lock All",
989
- icon: /* @__PURE__ */ jsx(Lock, { className: "w-4 h-4" }),
990
- shortcut: "L",
991
- onClick: () => onLockAll(nodeIds)
1029
+ onClick: () => onLockAll(nodeIds),
1030
+ shortcut: "L"
992
1031
  },
993
1032
  {
1033
+ icon: /* @__PURE__ */ jsx(LockOpen, { className: "w-4 h-4" }),
994
1034
  id: "unlock-all",
995
1035
  label: "Unlock All",
996
- icon: /* @__PURE__ */ jsx(LockOpen, { className: "w-4 h-4" }),
997
1036
  onClick: () => onUnlockAll(nodeIds)
998
1037
  },
999
1038
  createSeparator("separator-2"),
1000
1039
  {
1040
+ icon: /* @__PURE__ */ jsx(AlignHorizontalJustifyCenter, { className: "w-4 h-4" }),
1001
1041
  id: "align-horizontal",
1002
1042
  label: "Align Horizontally",
1003
- icon: /* @__PURE__ */ jsx(AlignHorizontalJustifyCenter, { className: "w-4 h-4" }),
1004
1043
  onClick: () => onAlignHorizontal(nodeIds)
1005
1044
  },
1006
1045
  {
1046
+ icon: /* @__PURE__ */ jsx(AlignVerticalJustifyCenter, { className: "w-4 h-4" }),
1007
1047
  id: "align-vertical",
1008
1048
  label: "Align Vertically",
1009
- icon: /* @__PURE__ */ jsx(AlignVerticalJustifyCenter, { className: "w-4 h-4" }),
1010
1049
  onClick: () => onAlignVertical(nodeIds)
1011
1050
  },
1012
1051
  createSeparator("separator-3"),
1013
1052
  {
1053
+ danger: true,
1054
+ icon: /* @__PURE__ */ jsx(Trash2, { className: "w-4 h-4" }),
1014
1055
  id: "delete-all",
1015
1056
  label: `Delete ${count} Nodes`,
1016
- icon: /* @__PURE__ */ jsx(Trash2, { className: "w-4 h-4" }),
1017
- shortcut: "\u232B",
1018
- danger: true,
1019
- onClick: () => onDeleteAll(nodeIds)
1057
+ onClick: () => onDeleteAll(nodeIds),
1058
+ shortcut: "\u232B"
1020
1059
  }
1021
1060
  ];
1022
1061
  }
@@ -1057,30 +1096,30 @@ function useContextMenu() {
1057
1096
  const { addNodeAtPosition, selectAll, fitView, autoLayout } = usePaneActions();
1058
1097
  const reactFlow = useReactFlow();
1059
1098
  const stableHandlersRef = useRef({
1060
- duplicate,
1099
+ addNodeAtPosition,
1100
+ autoLayout,
1061
1101
  copyNode,
1062
1102
  cutNode,
1063
- deleteNode,
1064
1103
  deleteMultipleNodes,
1104
+ deleteNode,
1105
+ duplicate,
1065
1106
  duplicateMultipleNodes,
1066
- removeEdge,
1067
- addNodeAtPosition,
1068
- selectAll,
1069
1107
  fitView,
1070
- autoLayout
1108
+ removeEdge,
1109
+ selectAll
1071
1110
  });
1072
1111
  stableHandlersRef.current = {
1073
- duplicate,
1112
+ addNodeAtPosition,
1113
+ autoLayout,
1074
1114
  copyNode,
1075
1115
  cutNode,
1076
- deleteNode,
1077
1116
  deleteMultipleNodes,
1117
+ deleteNode,
1118
+ duplicate,
1078
1119
  duplicateMultipleNodes,
1079
- removeEdge,
1080
- addNodeAtPosition,
1081
- selectAll,
1082
1120
  fitView,
1083
- autoLayout
1121
+ removeEdge,
1122
+ selectAll
1084
1123
  };
1085
1124
  const lockNode = useCallback(
1086
1125
  (nodeId) => {
@@ -1168,7 +1207,14 @@ function useContextMenu() {
1168
1207
  if (!pasteData) return;
1169
1208
  addNodesAndEdges(pasteData.nodes, pasteData.edges);
1170
1209
  setSelectedNodeIds(pasteData.nodes.map((n) => n.id));
1171
- }, [clipboard, position, reactFlow, getPasteData, addNodesAndEdges, setSelectedNodeIds]);
1210
+ }, [
1211
+ clipboard,
1212
+ position,
1213
+ reactFlow,
1214
+ getPasteData,
1215
+ addNodesAndEdges,
1216
+ setSelectedNodeIds
1217
+ ]);
1172
1218
  const setNodeColor = useCallback(
1173
1219
  (nodeId, color) => {
1174
1220
  updateNodeData(nodeId, { color: color || void 0 });
@@ -1210,18 +1256,18 @@ function useContextMenu() {
1210
1256
  const nodeHasMediaOutput = hasMediaOutput(targetId);
1211
1257
  const currentColor = node?.data?.color;
1212
1258
  return getNodeMenuItems({
1213
- nodeId: targetId,
1214
- isLocked,
1215
- hasMediaOutput: nodeHasMediaOutput,
1216
1259
  currentColor,
1217
- onDuplicate: handlers.duplicate,
1218
- onLock: lockNode,
1219
- onUnlock: unlockNode,
1220
- onCut: handlers.cutNode,
1260
+ hasMediaOutput: nodeHasMediaOutput,
1261
+ isLocked,
1262
+ nodeId: targetId,
1221
1263
  onCopy: handlers.copyNode,
1264
+ onCut: handlers.cutNode,
1222
1265
  onDelete: handlers.deleteNode,
1266
+ onDuplicate: handlers.duplicate,
1267
+ onLock: lockNode,
1223
1268
  onSetAsThumbnail: workflowId && workflowsApi ? setAsThumbnail : void 0,
1224
- onSetColor: setNodeColor
1269
+ onSetColor: setNodeColor,
1270
+ onUnlock: unlockNode
1225
1271
  });
1226
1272
  }
1227
1273
  case "edge":
@@ -1232,26 +1278,26 @@ function useContextMenu() {
1232
1278
  });
1233
1279
  case "pane":
1234
1280
  return getPaneMenuItems({
1235
- screenX: position.x,
1236
- screenY: position.y,
1237
1281
  hasClipboard: !!clipboard,
1238
1282
  onAddNode: handlers.addNodeAtPosition,
1283
+ onAutoLayout: () => handlers.autoLayout("LR"),
1284
+ onFitView: handlers.fitView,
1239
1285
  onPaste: pasteNodes,
1240
1286
  onSelectAll: handlers.selectAll,
1241
- onFitView: handlers.fitView,
1242
- onAutoLayout: () => handlers.autoLayout("LR")
1287
+ screenX: position.x,
1288
+ screenY: position.y
1243
1289
  });
1244
1290
  case "selection":
1245
1291
  if (!targetIds || targetIds.length === 0) return [];
1246
1292
  return getSelectionMenuItems({
1247
1293
  nodeIds: targetIds,
1248
- onGroup: groupNodes,
1249
- onDuplicateAll: handlers.duplicateMultipleNodes,
1250
- onLockAll: lockAllNodes,
1251
- onUnlockAll: unlockAllNodes,
1252
1294
  onAlignHorizontal: alignNodesHorizontally,
1253
1295
  onAlignVertical: alignNodesVertically,
1254
- onDeleteAll: handlers.deleteMultipleNodes
1296
+ onDeleteAll: handlers.deleteMultipleNodes,
1297
+ onDuplicateAll: handlers.duplicateMultipleNodes,
1298
+ onGroup: groupNodes,
1299
+ onLockAll: lockAllNodes,
1300
+ onUnlockAll: unlockAllNodes
1255
1301
  });
1256
1302
  default:
1257
1303
  return [];
@@ -1279,15 +1325,15 @@ function useContextMenu() {
1279
1325
  ]);
1280
1326
  const menuItems = useMemo(() => getMenuItems(), [getMenuItems]);
1281
1327
  return {
1328
+ close,
1282
1329
  isOpen,
1283
- position,
1284
- menuType,
1285
1330
  menuItems,
1286
- openNodeMenu,
1331
+ menuType,
1287
1332
  openEdgeMenu,
1333
+ openNodeMenu,
1288
1334
  openPaneMenu,
1289
1335
  openSelectionMenu,
1290
- close
1336
+ position
1291
1337
  };
1292
1338
  }
1293
1339