@genfeedai/workflow-ui 0.1.3 → 0.1.5

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 (84) hide show
  1. package/dist/canvas.d.mts +16 -2
  2. package/dist/canvas.mjs +10 -8
  3. package/dist/chunk-6PSJTBNV.mjs +638 -0
  4. package/dist/chunk-7H3WJJYS.mjs +52 -0
  5. package/dist/{chunk-HCXI63ME.mjs → chunk-AUQGOJOQ.mjs} +27 -4
  6. package/dist/{chunk-AOTUCJMA.mjs → chunk-GWBGK3KL.mjs} +2 -2
  7. package/dist/chunk-JTPADIUO.mjs +130 -0
  8. package/dist/{chunk-SQK4JDYY.mjs → chunk-LT3ZJJL6.mjs} +9 -2
  9. package/dist/{chunk-7P2JWDC7.mjs → chunk-O5II6BOJ.mjs} +1198 -254
  10. package/dist/{chunk-AUZR6REQ.mjs → chunk-OQREHJXK.mjs} +1 -1
  11. package/dist/chunk-OY7BRSGG.mjs +60 -0
  12. package/dist/{chunk-E3YBVMYZ.mjs → chunk-PANZDSP6.mjs} +274 -305
  13. package/dist/chunk-PCIWWD37.mjs +90 -0
  14. package/dist/{chunk-RIGVIEYB.mjs → chunk-R727OFBR.mjs} +11 -1
  15. package/dist/chunk-ZD2BADZO.mjs +1294 -0
  16. package/dist/contextMenuStore-DMg0hJQ1.d.mts +22 -0
  17. package/dist/hooks.d.mts +53 -244
  18. package/dist/hooks.mjs +6 -6
  19. package/dist/index.d.mts +11 -7
  20. package/dist/index.mjs +13 -11
  21. package/dist/lib.d.mts +250 -4
  22. package/dist/lib.mjs +562 -2
  23. package/dist/nodes.d.mts +3 -1
  24. package/dist/nodes.mjs +6 -6
  25. package/dist/panels.mjs +3 -4
  26. package/dist/{promptLibraryStore-zqb59nsu.d.mts → promptLibraryStore-Bgw5LzvD.d.mts} +33 -5
  27. package/dist/provider.d.mts +2 -2
  28. package/dist/provider.mjs +0 -1
  29. package/dist/stores.d.mts +4 -3
  30. package/dist/stores.mjs +3 -40
  31. package/dist/toolbar.d.mts +3 -1
  32. package/dist/toolbar.mjs +5 -4
  33. package/dist/{types-ipAnBzAJ.d.mts → types-CF6DPx0P.d.mts} +8 -3
  34. package/dist/ui.d.mts +1 -1
  35. package/dist/ui.mjs +0 -1
  36. package/dist/{hooks.d.ts → useCommentNavigation-NzJjkaj2.d.mts} +15 -2
  37. package/dist/workflowStore-UAAKOOIK.mjs +2 -0
  38. package/package.json +31 -25
  39. package/dist/canvas.d.ts +0 -27
  40. package/dist/canvas.js +0 -45
  41. package/dist/chunk-3SPPKCWR.js +0 -458
  42. package/dist/chunk-3TMV3K34.js +0 -534
  43. package/dist/chunk-3YFFDHC5.js +0 -300
  44. package/dist/chunk-4MZ62VMF.js +0 -37
  45. package/dist/chunk-5HJFQVUR.js +0 -61
  46. package/dist/chunk-5LQ4QBR5.js +0 -2
  47. package/dist/chunk-6DOEUDD5.js +0 -254
  48. package/dist/chunk-AXFOCPPP.js +0 -998
  49. package/dist/chunk-BMFRA6GK.js +0 -1546
  50. package/dist/chunk-E323WAZG.mjs +0 -272
  51. package/dist/chunk-ECD5J2BA.js +0 -6022
  52. package/dist/chunk-EMGXUNBL.js +0 -120
  53. package/dist/chunk-EMUMKW5C.js +0 -107
  54. package/dist/chunk-FOMOOERN.js +0 -2
  55. package/dist/chunk-IASLG6IA.mjs +0 -118
  56. package/dist/chunk-IHF35QZD.js +0 -1095
  57. package/dist/chunk-JLWKW3G5.js +0 -2
  58. package/dist/chunk-KDIWRSYV.js +0 -375
  59. package/dist/chunk-L5TF4EHW.mjs +0 -1
  60. package/dist/chunk-RJ262NXS.js +0 -24
  61. package/dist/chunk-RXNEDWK2.js +0 -141
  62. package/dist/chunk-SEV2DWKF.js +0 -744
  63. package/dist/chunk-ZJWP5KGZ.mjs +0 -33
  64. package/dist/hooks.js +0 -56
  65. package/dist/index.d.ts +0 -29
  66. package/dist/index.js +0 -180
  67. package/dist/lib.d.ts +0 -164
  68. package/dist/lib.js +0 -144
  69. package/dist/nodes.d.ts +0 -128
  70. package/dist/nodes.js +0 -151
  71. package/dist/panels.d.ts +0 -22
  72. package/dist/panels.js +0 -21
  73. package/dist/promptLibraryStore-BZnfmEkc.d.ts +0 -464
  74. package/dist/provider.d.ts +0 -29
  75. package/dist/provider.js +0 -17
  76. package/dist/stores.d.ts +0 -96
  77. package/dist/stores.js +0 -113
  78. package/dist/toolbar.d.ts +0 -73
  79. package/dist/toolbar.js +0 -34
  80. package/dist/types-ipAnBzAJ.d.ts +0 -46
  81. package/dist/ui.d.ts +0 -67
  82. package/dist/ui.js +0 -84
  83. package/dist/workflowStore-7SDJC4UR.mjs +0 -3
  84. package/dist/workflowStore-LNJQ5RZG.js +0 -12
@@ -1,1546 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkECD5J2BA_js = require('./chunk-ECD5J2BA.js');
4
- var chunk3YFFDHC5_js = require('./chunk-3YFFDHC5.js');
5
- var chunkEMGXUNBL_js = require('./chunk-EMGXUNBL.js');
6
- var chunk5HJFQVUR_js = require('./chunk-5HJFQVUR.js');
7
- var chunk6DOEUDD5_js = require('./chunk-6DOEUDD5.js');
8
- var chunkAXFOCPPP_js = require('./chunk-AXFOCPPP.js');
9
- var chunkIHF35QZD_js = require('./chunk-IHF35QZD.js');
10
- var react$1 = require('@xyflow/react');
11
- var lucideReact = require('lucide-react');
12
- var react = require('react');
13
- require('@xyflow/react/dist/style.css');
14
- var types = require('@genfeedai/types');
15
- var clsx = require('clsx');
16
- var jsxRuntime = require('react/jsx-runtime');
17
- var Image = require('next/image');
18
-
19
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
20
-
21
- var Image__default = /*#__PURE__*/_interopDefault(Image);
22
-
23
- // src/types/groups.ts
24
- var GROUP_COLORS = {
25
- purple: {
26
- bg: "bg-purple-500/10",
27
- border: "border-purple-500/30",
28
- text: "text-purple-400"
29
- },
30
- blue: {
31
- bg: "bg-blue-500/10",
32
- border: "border-blue-500/30",
33
- text: "text-blue-400"
34
- },
35
- green: {
36
- bg: "bg-green-500/10",
37
- border: "border-green-500/30",
38
- text: "text-green-400"
39
- },
40
- yellow: {
41
- bg: "bg-yellow-500/10",
42
- border: "border-yellow-500/30",
43
- text: "text-yellow-400"
44
- },
45
- orange: {
46
- bg: "bg-orange-500/10",
47
- border: "border-orange-500/30",
48
- text: "text-orange-400"
49
- },
50
- red: {
51
- bg: "bg-red-500/10",
52
- border: "border-red-500/30",
53
- text: "text-red-400"
54
- },
55
- pink: {
56
- bg: "bg-pink-500/10",
57
- border: "border-pink-500/30",
58
- text: "text-pink-400"
59
- },
60
- gray: {
61
- bg: "bg-gray-500/10",
62
- border: "border-gray-500/30",
63
- text: "text-gray-400"
64
- }
65
- };
66
- var DEFAULT_GROUP_COLORS = [
67
- "purple",
68
- "blue",
69
- "green",
70
- "yellow",
71
- "orange",
72
- "red",
73
- "pink",
74
- "gray"
75
- ];
76
- var HEADER_HEIGHT = 32;
77
- function calculateGroupBounds(nodeIds, nodeMap) {
78
- if (nodeIds.length === 0) return null;
79
- let minX = Infinity;
80
- let minY = Infinity;
81
- let maxX = -Infinity;
82
- let maxY = -Infinity;
83
- let foundAny = false;
84
- for (const nodeId of nodeIds) {
85
- const node = nodeMap.get(nodeId);
86
- if (!node) continue;
87
- foundAny = true;
88
- const width = node.measured?.width ?? 200;
89
- const height = node.measured?.height ?? 100;
90
- minX = Math.min(minX, node.position.x);
91
- minY = Math.min(minY, node.position.y);
92
- maxX = Math.max(maxX, node.position.x + width);
93
- maxY = Math.max(maxY, node.position.y + height);
94
- }
95
- if (!foundAny) return null;
96
- const padding = 24;
97
- return {
98
- x: minX - padding,
99
- y: minY - padding - HEADER_HEIGHT,
100
- width: maxX - minX + padding * 2,
101
- height: maxY - minY + padding * 2 + HEADER_HEIGHT
102
- };
103
- }
104
- function GroupBackground({ group, bounds }) {
105
- const colors = GROUP_COLORS[group.color ?? "purple"];
106
- return /* @__PURE__ */ jsxRuntime.jsx(
107
- "div",
108
- {
109
- className: clsx.clsx(
110
- "absolute rounded-lg border-2 border-dashed",
111
- colors.bg,
112
- colors.border,
113
- group.isLocked && "opacity-60"
114
- ),
115
- style: {
116
- left: bounds.x,
117
- top: bounds.y,
118
- width: bounds.width,
119
- height: bounds.height
120
- }
121
- }
122
- );
123
- }
124
- function GroupControls({ group, bounds, nodeMap, zoom }) {
125
- const { setNodes } = react$1.useReactFlow();
126
- const { toggleGroupLock, deleteGroup, setGroupColor, setDirty, renameGroup } = chunkIHF35QZD_js.useWorkflowStore();
127
- const [showColorPicker, setShowColorPicker] = react.useState(false);
128
- const [isEditing, setIsEditing] = react.useState(false);
129
- const [editName, setEditName] = react.useState(group.name);
130
- const inputRef = react.useRef(null);
131
- const colorPickerRef = react.useRef(null);
132
- const [isDragging, setIsDragging] = react.useState(false);
133
- const dragStartRef = react.useRef(null);
134
- const nodeStartPositionsRef = react.useRef(/* @__PURE__ */ new Map());
135
- react.useEffect(() => {
136
- if (!isEditing) {
137
- setEditName(group.name);
138
- }
139
- }, [group.name, isEditing]);
140
- react.useEffect(() => {
141
- if (isEditing && inputRef.current) {
142
- inputRef.current.focus();
143
- inputRef.current.select();
144
- }
145
- }, [isEditing]);
146
- react.useEffect(() => {
147
- const handleClickOutside = (e) => {
148
- if (colorPickerRef.current && !colorPickerRef.current.contains(e.target)) {
149
- setShowColorPicker(false);
150
- }
151
- };
152
- if (showColorPicker) {
153
- document.addEventListener("mousedown", handleClickOutside);
154
- }
155
- return () => document.removeEventListener("mousedown", handleClickOutside);
156
- }, [showColorPicker]);
157
- const handleNameSubmit = react.useCallback(() => {
158
- if (editName.trim() && editName !== group.name) {
159
- renameGroup(group.id, editName.trim());
160
- } else {
161
- setEditName(group.name);
162
- }
163
- setIsEditing(false);
164
- }, [editName, group.name, group.id, renameGroup]);
165
- const handleKeyDown = react.useCallback(
166
- (e) => {
167
- if (e.key === "Enter") {
168
- handleNameSubmit();
169
- } else if (e.key === "Escape") {
170
- setEditName(group.name);
171
- setIsEditing(false);
172
- }
173
- },
174
- [handleNameSubmit, group.name]
175
- );
176
- const handleMouseDown = react.useCallback(
177
- (e) => {
178
- if (group.isLocked) return;
179
- if (e.target.closest("button") || e.target.closest("input")) {
180
- return;
181
- }
182
- e.preventDefault();
183
- e.stopPropagation();
184
- setIsDragging(true);
185
- dragStartRef.current = { x: e.clientX, y: e.clientY };
186
- const positions = /* @__PURE__ */ new Map();
187
- for (const nodeId of group.nodeIds) {
188
- const node = nodeMap.get(nodeId);
189
- if (node) {
190
- positions.set(nodeId, { x: node.position.x, y: node.position.y });
191
- }
192
- }
193
- nodeStartPositionsRef.current = positions;
194
- },
195
- [group.isLocked, group.nodeIds, nodeMap]
196
- );
197
- react.useEffect(() => {
198
- if (!isDragging) return;
199
- const handleMouseMove = (e) => {
200
- if (!dragStartRef.current) return;
201
- const deltaX = (e.clientX - dragStartRef.current.x) / zoom;
202
- const deltaY = (e.clientY - dragStartRef.current.y) / zoom;
203
- setNodes(
204
- (currentNodes) => currentNodes.map((node) => {
205
- const startPos = nodeStartPositionsRef.current.get(node.id);
206
- if (!startPos) return node;
207
- return {
208
- ...node,
209
- position: {
210
- x: startPos.x + deltaX,
211
- y: startPos.y + deltaY
212
- }
213
- };
214
- })
215
- );
216
- };
217
- const handleMouseUp = () => {
218
- setDirty(true);
219
- setIsDragging(false);
220
- dragStartRef.current = null;
221
- };
222
- window.addEventListener("mousemove", handleMouseMove);
223
- window.addEventListener("mouseup", handleMouseUp);
224
- return () => {
225
- window.removeEventListener("mousemove", handleMouseMove);
226
- window.removeEventListener("mouseup", handleMouseUp);
227
- };
228
- }, [isDragging, zoom, setNodes, setDirty]);
229
- const colors = GROUP_COLORS[group.color ?? "purple"];
230
- const handleColorSelect = (color) => {
231
- setGroupColor(group.id, color);
232
- setShowColorPicker(false);
233
- };
234
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
235
- /* @__PURE__ */ jsxRuntime.jsxs(
236
- "div",
237
- {
238
- onMouseDown: handleMouseDown,
239
- className: clsx.clsx(
240
- "absolute flex items-center justify-between px-3 rounded-t-lg select-none pointer-events-auto",
241
- colors.bg,
242
- colors.border,
243
- "border-2 border-b-0 border-dashed",
244
- !group.isLocked && "cursor-grab",
245
- isDragging && "cursor-grabbing",
246
- group.isLocked && "opacity-60"
247
- ),
248
- style: {
249
- left: bounds.x,
250
- top: bounds.y,
251
- width: bounds.width,
252
- height: HEADER_HEIGHT
253
- },
254
- children: [
255
- isEditing ? /* @__PURE__ */ jsxRuntime.jsx(
256
- "input",
257
- {
258
- ref: inputRef,
259
- type: "text",
260
- value: editName,
261
- onChange: (e) => setEditName(e.target.value),
262
- onBlur: handleNameSubmit,
263
- onKeyDown: handleKeyDown,
264
- className: clsx.clsx(
265
- "flex-1 bg-transparent border-none outline-none text-sm font-medium px-0 py-0",
266
- colors.text
267
- ),
268
- style: { minWidth: 0 }
269
- }
270
- ) : /* @__PURE__ */ jsxRuntime.jsx(
271
- "span",
272
- {
273
- className: clsx.clsx("font-medium truncate cursor-text", colors.text),
274
- style: { fontSize: 14 },
275
- onClick: () => setIsEditing(true),
276
- children: group.name
277
- }
278
- ),
279
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
280
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", ref: colorPickerRef, children: [
281
- /* @__PURE__ */ jsxRuntime.jsx(
282
- "button",
283
- {
284
- onClick: (e) => {
285
- e.stopPropagation();
286
- setShowColorPicker(!showColorPicker);
287
- },
288
- className: clsx.clsx("p-1 rounded hover:bg-white/10 transition-colors", colors.text),
289
- title: "Change group color",
290
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Palette, { className: "w-4 h-4" })
291
- }
292
- ),
293
- showColorPicker && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute top-8 right-0 z-50 bg-card border border-border rounded-lg shadow-lg p-2 flex gap-1 flex-wrap w-[120px]", children: DEFAULT_GROUP_COLORS.map((color) => /* @__PURE__ */ jsxRuntime.jsx(
294
- "button",
295
- {
296
- onClick: (e) => {
297
- e.stopPropagation();
298
- handleColorSelect(color);
299
- },
300
- className: clsx.clsx(
301
- "w-6 h-6 rounded-md border-2 transition-transform hover:scale-110",
302
- GROUP_COLORS[color].bg,
303
- color === group.color ? "border-white" : "border-transparent"
304
- ),
305
- title: color
306
- },
307
- color
308
- )) })
309
- ] }),
310
- /* @__PURE__ */ jsxRuntime.jsx(
311
- "button",
312
- {
313
- onClick: (e) => {
314
- e.stopPropagation();
315
- toggleGroupLock(group.id);
316
- },
317
- className: clsx.clsx("p-1 rounded hover:bg-white/10 transition-colors", colors.text),
318
- title: group.isLocked ? "Unlock group" : "Lock group",
319
- children: group.isLocked ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Lock, { className: "w-4 h-4" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Unlock, { className: "w-4 h-4" })
320
- }
321
- ),
322
- /* @__PURE__ */ jsxRuntime.jsx(
323
- "button",
324
- {
325
- onClick: (e) => {
326
- e.stopPropagation();
327
- deleteGroup(group.id);
328
- },
329
- className: clsx.clsx("p-1 rounded hover:bg-white/10 transition-colors", colors.text),
330
- title: "Delete group",
331
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "w-4 h-4" })
332
- }
333
- )
334
- ] })
335
- ]
336
- }
337
- ),
338
- group.isLocked && /* @__PURE__ */ jsxRuntime.jsx(
339
- "div",
340
- {
341
- className: clsx.clsx(
342
- "absolute px-2 py-0.5 rounded text-xs font-medium pointer-events-none",
343
- colors.bg,
344
- colors.text
345
- ),
346
- style: {
347
- left: bounds.x + 12,
348
- top: bounds.y + HEADER_HEIGHT + 8
349
- },
350
- children: "LOCKED"
351
- }
352
- )
353
- ] });
354
- }
355
- function GroupBackgroundsPortalComponent() {
356
- const { groups } = chunkIHF35QZD_js.useWorkflowStore();
357
- const nodes = react$1.useNodes();
358
- const nodeMap = react.useMemo(() => new Map(nodes.map((n) => [n.id, n])), [nodes]);
359
- const groupBounds = react.useMemo(() => {
360
- const result = /* @__PURE__ */ new Map();
361
- for (const group of groups) {
362
- const bounds = calculateGroupBounds(group.nodeIds, nodeMap);
363
- if (bounds) {
364
- result.set(group.id, bounds);
365
- }
366
- }
367
- return result;
368
- }, [groups, nodeMap]);
369
- if (groups.length === 0) return null;
370
- return /* @__PURE__ */ jsxRuntime.jsx(react$1.ViewportPortal, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", top: 0, left: 0, zIndex: -1, pointerEvents: "none" }, children: groups.map((group) => {
371
- const bounds = groupBounds.get(group.id);
372
- if (!bounds) return null;
373
- return /* @__PURE__ */ jsxRuntime.jsx(GroupBackground, { group, bounds }, group.id);
374
- }) }) });
375
- }
376
- function GroupControlsOverlayComponent() {
377
- const { groups } = chunkIHF35QZD_js.useWorkflowStore();
378
- const nodes = react$1.useNodes();
379
- const { zoom } = react$1.useViewport();
380
- const nodeMap = react.useMemo(() => new Map(nodes.map((n) => [n.id, n])), [nodes]);
381
- const groupBounds = react.useMemo(() => {
382
- const result = /* @__PURE__ */ new Map();
383
- for (const group of groups) {
384
- const bounds = calculateGroupBounds(group.nodeIds, nodeMap);
385
- if (bounds) {
386
- result.set(group.id, bounds);
387
- }
388
- }
389
- return result;
390
- }, [groups, nodeMap]);
391
- if (groups.length === 0) return null;
392
- return /* @__PURE__ */ jsxRuntime.jsx(react$1.ViewportPortal, { children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { position: "absolute", top: 0, left: 0, zIndex: 1e3, pointerEvents: "none" }, children: groups.map((group) => {
393
- const bounds = groupBounds.get(group.id);
394
- if (!bounds) return null;
395
- return /* @__PURE__ */ jsxRuntime.jsx(
396
- GroupControls,
397
- {
398
- group,
399
- bounds,
400
- nodeMap,
401
- zoom
402
- },
403
- group.id
404
- );
405
- }) }) });
406
- }
407
- var GroupBackgroundsPortal = react.memo(GroupBackgroundsPortalComponent);
408
- var GroupControlsOverlay = react.memo(GroupControlsOverlayComponent);
409
- function GroupOverlayComponent() {
410
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
411
- /* @__PURE__ */ jsxRuntime.jsx(GroupBackgroundsPortal, {}),
412
- /* @__PURE__ */ jsxRuntime.jsx(GroupControlsOverlay, {})
413
- ] });
414
- }
415
- var GroupOverlay = react.memo(GroupOverlayComponent);
416
- var SNAP_THRESHOLD = 5;
417
- function HelperLinesComponent({ draggingNodeId }) {
418
- const [lines, setLines] = react.useState([]);
419
- const nodes = chunkIHF35QZD_js.useWorkflowStore((state) => state.nodes);
420
- const transform = react$1.useStore((state) => state.transform);
421
- const calculateHelperLines = react.useCallback(
422
- (draggingId) => {
423
- const draggingNode = nodes.find((n) => n.id === draggingId);
424
- if (!draggingNode) {
425
- setLines([]);
426
- return;
427
- }
428
- const otherNodes = nodes.filter((n) => n.id !== draggingId && !n.selected);
429
- if (otherNodes.length === 0) {
430
- setLines([]);
431
- return;
432
- }
433
- const dragWidth = draggingNode.measured?.width ?? draggingNode.width ?? 220;
434
- const dragHeight = draggingNode.measured?.height ?? draggingNode.height ?? 100;
435
- const dragLeft = draggingNode.position.x;
436
- const dragRight = dragLeft + dragWidth;
437
- const dragTop = draggingNode.position.y;
438
- const dragBottom = dragTop + dragHeight;
439
- const dragCenterX = dragLeft + dragWidth / 2;
440
- const dragCenterY = dragTop + dragHeight / 2;
441
- const newLines = [];
442
- for (const node of otherNodes) {
443
- const nodeWidth = node.measured?.width ?? node.width ?? 220;
444
- const nodeHeight = node.measured?.height ?? node.height ?? 100;
445
- const nodeLeft = node.position.x;
446
- const nodeRight = nodeLeft + nodeWidth;
447
- const nodeTop = node.position.y;
448
- const nodeBottom = nodeTop + nodeHeight;
449
- const nodeCenterX = nodeLeft + nodeWidth / 2;
450
- const nodeCenterY = nodeTop + nodeHeight / 2;
451
- const verticalChecks = [
452
- { dragPos: dragLeft, nodePos: nodeLeft, label: "left-left" },
453
- { dragPos: dragLeft, nodePos: nodeRight, label: "left-right" },
454
- { dragPos: dragRight, nodePos: nodeLeft, label: "right-left" },
455
- { dragPos: dragRight, nodePos: nodeRight, label: "right-right" },
456
- { dragPos: dragCenterX, nodePos: nodeCenterX, label: "center-center-x" }
457
- ];
458
- for (const check of verticalChecks) {
459
- if (Math.abs(check.dragPos - check.nodePos) <= SNAP_THRESHOLD) {
460
- newLines.push({
461
- type: "vertical",
462
- position: check.nodePos,
463
- start: Math.min(dragTop, nodeTop) - 20,
464
- end: Math.max(dragBottom, nodeBottom) + 20
465
- });
466
- }
467
- }
468
- const horizontalChecks = [
469
- { dragPos: dragTop, nodePos: nodeTop, label: "top-top" },
470
- { dragPos: dragTop, nodePos: nodeBottom, label: "top-bottom" },
471
- { dragPos: dragBottom, nodePos: nodeTop, label: "bottom-top" },
472
- { dragPos: dragBottom, nodePos: nodeBottom, label: "bottom-bottom" },
473
- { dragPos: dragCenterY, nodePos: nodeCenterY, label: "center-center-y" }
474
- ];
475
- for (const check of horizontalChecks) {
476
- if (Math.abs(check.dragPos - check.nodePos) <= SNAP_THRESHOLD) {
477
- newLines.push({
478
- type: "horizontal",
479
- position: check.nodePos,
480
- start: Math.min(dragLeft, nodeLeft) - 20,
481
- end: Math.max(dragRight, nodeRight) + 20
482
- });
483
- }
484
- }
485
- }
486
- const uniqueLines = [];
487
- const seenPositions = /* @__PURE__ */ new Set();
488
- for (const line of newLines) {
489
- const key = `${line.type}-${Math.round(line.position)}`;
490
- if (!seenPositions.has(key)) {
491
- seenPositions.add(key);
492
- const existingLine = uniqueLines.find(
493
- (l) => l.type === line.type && Math.abs(l.position - line.position) < 1
494
- );
495
- if (existingLine) {
496
- existingLine.start = Math.min(existingLine.start, line.start);
497
- existingLine.end = Math.max(existingLine.end, line.end);
498
- } else {
499
- uniqueLines.push(line);
500
- }
501
- }
502
- }
503
- setLines(uniqueLines);
504
- },
505
- [nodes]
506
- );
507
- react.useEffect(() => {
508
- if (draggingNodeId) {
509
- calculateHelperLines(draggingNodeId);
510
- } else {
511
- setLines([]);
512
- }
513
- }, [draggingNodeId, calculateHelperLines]);
514
- if (lines.length === 0) return null;
515
- const [tx, ty, zoom] = transform;
516
- return /* @__PURE__ */ jsxRuntime.jsx(
517
- "svg",
518
- {
519
- className: "absolute inset-0 pointer-events-none z-[1000]",
520
- style: { width: "100%", height: "100%", overflow: "visible" },
521
- children: lines.map((line, index) => {
522
- if (line.type === "vertical") {
523
- const x = line.position * zoom + tx;
524
- const y1 = line.start * zoom + ty;
525
- const y2 = line.end * zoom + ty;
526
- return /* @__PURE__ */ jsxRuntime.jsx(
527
- "line",
528
- {
529
- x1: x,
530
- y1,
531
- x2: x,
532
- y2,
533
- stroke: "#3b82f6",
534
- strokeWidth: 1,
535
- strokeDasharray: "4 2"
536
- },
537
- `v-${index}`
538
- );
539
- } else {
540
- const y = line.position * zoom + ty;
541
- const x1 = line.start * zoom + tx;
542
- const x2 = line.end * zoom + tx;
543
- return /* @__PURE__ */ jsxRuntime.jsx(
544
- "line",
545
- {
546
- x1,
547
- y1: y,
548
- x2,
549
- y2: y,
550
- stroke: "#3b82f6",
551
- strokeWidth: 1,
552
- strokeDasharray: "4 2"
553
- },
554
- `h-${index}`
555
- );
556
- }
557
- })
558
- }
559
- );
560
- }
561
- var HelperLines = react.memo(HelperLinesComponent);
562
- function NodeSearch() {
563
- const { activeModal, closeModal } = chunkAXFOCPPP_js.useUIStore();
564
- const { nodes, setSelectedNodeIds } = chunkIHF35QZD_js.useWorkflowStore();
565
- const reactFlow = react$1.useReactFlow();
566
- const [search, setSearch] = react.useState("");
567
- const [selectedIndex, setSelectedIndex] = react.useState(0);
568
- const listRef = react.useRef(null);
569
- const backdropRef = react.useRef(null);
570
- const inputRef = react.useRef(null);
571
- const isOpen = activeModal === "nodeSearch";
572
- react.useEffect(() => {
573
- if (isOpen && inputRef.current) {
574
- inputRef.current.focus();
575
- }
576
- }, [isOpen]);
577
- const filteredNodes = react.useMemo(() => {
578
- if (!search.trim()) return nodes;
579
- const query = search.toLowerCase();
580
- return nodes.filter((node) => {
581
- const label = (node.data.label || "").toLowerCase();
582
- const type = (node.type || "").toLowerCase();
583
- const comment = (node.data.comment || "").toLowerCase();
584
- const nodeDefLabel = types.NODE_DEFINITIONS[node.type]?.label?.toLowerCase() || "";
585
- return label.includes(query) || type.includes(query) || comment.includes(query) || nodeDefLabel.includes(query);
586
- });
587
- }, [nodes, search]);
588
- react.useEffect(() => {
589
- setSelectedIndex(0);
590
- }, []);
591
- react.useEffect(() => {
592
- if (listRef.current) {
593
- const selectedItem = listRef.current.children[selectedIndex];
594
- selectedItem?.scrollIntoView({ block: "nearest" });
595
- }
596
- }, [selectedIndex]);
597
- const handleSelectNode = react.useCallback(
598
- (node) => {
599
- setSelectedNodeIds([node.id]);
600
- reactFlow.fitView({
601
- nodes: [node],
602
- padding: 0.5,
603
- duration: 300
604
- });
605
- closeModal();
606
- setSearch("");
607
- },
608
- [setSelectedNodeIds, reactFlow, closeModal]
609
- );
610
- const handleKeyDown = react.useCallback(
611
- (e) => {
612
- if (e.key === "ArrowDown") {
613
- e.preventDefault();
614
- setSelectedIndex((prev) => Math.min(prev + 1, filteredNodes.length - 1));
615
- } else if (e.key === "ArrowUp") {
616
- e.preventDefault();
617
- setSelectedIndex((prev) => Math.max(prev - 1, 0));
618
- } else if (e.key === "Enter" && filteredNodes[selectedIndex]) {
619
- e.preventDefault();
620
- handleSelectNode(filteredNodes[selectedIndex]);
621
- } else if (e.key === "Escape") {
622
- e.preventDefault();
623
- handleClose();
624
- }
625
- },
626
- [filteredNodes, selectedIndex, handleSelectNode]
627
- );
628
- const handleClose = () => {
629
- closeModal();
630
- setSearch("");
631
- setSelectedIndex(0);
632
- };
633
- const handleBackdropClick = (e) => {
634
- if (e.target === backdropRef.current) {
635
- handleClose();
636
- }
637
- };
638
- if (!isOpen) return null;
639
- return /* @__PURE__ */ jsxRuntime.jsx(
640
- "div",
641
- {
642
- ref: backdropRef,
643
- onClick: handleBackdropClick,
644
- className: "fixed inset-0 z-50 flex items-start justify-center pt-[20vh]",
645
- style: { backgroundColor: "rgba(0, 0, 0, 0.5)" },
646
- children: /* @__PURE__ */ jsxRuntime.jsxs(
647
- "div",
648
- {
649
- className: "bg-[var(--background)] border border-[var(--border)] rounded-lg shadow-xl w-full max-w-lg",
650
- role: "dialog",
651
- "aria-label": "Find Node",
652
- children: [
653
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-[var(--border)]", children: [
654
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
655
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "w-4 h-4 text-[var(--muted-foreground)]" }),
656
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: "Find Node" })
657
- ] }),
658
- /* @__PURE__ */ jsxRuntime.jsx(
659
- "button",
660
- {
661
- onClick: handleClose,
662
- className: "p-1 rounded hover:bg-[var(--secondary)] transition-colors",
663
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" })
664
- }
665
- )
666
- ] }),
667
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", onKeyDown: handleKeyDown, children: [
668
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative mb-3", children: [
669
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
670
- /* @__PURE__ */ jsxRuntime.jsx(
671
- "input",
672
- {
673
- ref: inputRef,
674
- type: "text",
675
- placeholder: "Search nodes by name, type, or comment...",
676
- value: search,
677
- onChange: (e) => setSearch(e.target.value),
678
- className: "w-full pl-9 pr-3 py-2 text-sm bg-[var(--secondary)] border border-[var(--border)] rounded-md outline-none focus:ring-1 focus:ring-[var(--ring)]",
679
- autoFocus: true
680
- }
681
- )
682
- ] }),
683
- /* @__PURE__ */ jsxRuntime.jsx("div", { ref: listRef, className: "max-h-[300px] overflow-y-auto space-y-1", children: filteredNodes.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-center text-muted-foreground py-8", children: search ? `No nodes found for "${search}"` : "No nodes in workflow" }) : filteredNodes.map((node, index) => {
684
- const nodeDef = types.NODE_DEFINITIONS[node.type];
685
- const comment = node.data.comment;
686
- return /* @__PURE__ */ jsxRuntime.jsxs(
687
- "button",
688
- {
689
- onClick: () => handleSelectNode(node),
690
- className: `w-full flex items-center gap-3 p-2 rounded text-left transition-colors ${index === selectedIndex ? "bg-primary/10 border border-primary/30" : "hover:bg-secondary/50 border border-transparent"}`,
691
- children: [
692
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0 w-8 h-8 rounded bg-secondary flex items-center justify-center text-xs font-medium", children: nodeDef?.label?.charAt(0) || "?" }),
693
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
694
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium truncate text-sm", children: node.data.label }),
695
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground truncate", children: [
696
- nodeDef?.label || node.type,
697
- comment && ` \xB7 ${comment}`
698
- ] })
699
- ] })
700
- ]
701
- },
702
- node.id
703
- );
704
- }) }),
705
- filteredNodes.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 pt-3 border-t border-border text-xs text-muted-foreground flex gap-4", children: [
706
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
707
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-1.5 py-0.5 bg-secondary rounded", children: "up/down" }),
708
- " Navigate"
709
- ] }),
710
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
711
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-1.5 py-0.5 bg-secondary rounded", children: "Enter" }),
712
- " Select"
713
- ] }),
714
- /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
715
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-1.5 py-0.5 bg-secondary rounded", children: "Esc" }),
716
- " Close"
717
- ] })
718
- ] })
719
- ] })
720
- ]
721
- }
722
- )
723
- }
724
- );
725
- }
726
- var SHORTCUTS = [
727
- // Navigation
728
- { keys: "Scroll", description: "Pan canvas", category: "Navigation" },
729
- { keys: "Ctrl + Scroll", description: "Zoom in/out", category: "Navigation" },
730
- { keys: "F", description: "Fit view to selection (or all)", category: "Navigation" },
731
- { keys: "M", description: "Toggle sidebar", category: "Navigation" },
732
- // Selection
733
- { keys: "Click", description: "Select node", category: "Selection" },
734
- { keys: "Shift + Click", description: "Add to selection", category: "Selection" },
735
- { keys: "Drag", description: "Marquee select", category: "Selection" },
736
- { keys: "Ctrl + A", description: "Select all nodes", category: "Selection" },
737
- { keys: "Ctrl + F", description: "Search nodes", category: "Selection" },
738
- // Editing
739
- { keys: "Ctrl + Z", description: "Undo", category: "Editing" },
740
- { keys: "Ctrl + Shift + Z", description: "Redo", category: "Editing" },
741
- { keys: "Ctrl + C", description: "Copy", category: "Editing" },
742
- { keys: "Ctrl + X", description: "Cut", category: "Editing" },
743
- { keys: "Ctrl + V", description: "Paste", category: "Editing" },
744
- { keys: "Ctrl + D", description: "Duplicate", category: "Editing" },
745
- { keys: "Delete / Backspace", description: "Delete selected", category: "Editing" },
746
- // Nodes
747
- { keys: "Shift + I", description: "Add Image Gen node", category: "Nodes" },
748
- { keys: "Shift + V", description: "Add Video Gen node", category: "Nodes" },
749
- { keys: "Shift + P", description: "Add Prompt node", category: "Nodes" },
750
- { keys: "Shift + L", description: "Add LLM node", category: "Nodes" },
751
- // Organization
752
- { keys: "L", description: "Toggle lock on selected", category: "Organization" },
753
- { keys: "Ctrl + G", description: "Group selected nodes", category: "Organization" },
754
- { keys: "Ctrl + Shift + G", description: "Ungroup", category: "Organization" },
755
- { keys: "Ctrl + Shift + L", description: "Unlock all nodes", category: "Organization" },
756
- // Help
757
- { keys: "?", description: "Show this help", category: "Help" }
758
- ];
759
- var CATEGORIES = ["Navigation", "Selection", "Editing", "Nodes", "Organization", "Help"];
760
- function ShortcutHelpModal() {
761
- const { activeModal, closeModal } = chunkAXFOCPPP_js.useUIStore();
762
- const [searchQuery, setSearchQuery] = react.useState("");
763
- const backdropRef = react.useRef(null);
764
- const inputRef = react.useRef(null);
765
- const isOpen = activeModal === "shortcutHelp";
766
- const filteredShortcuts = react.useMemo(() => {
767
- if (!searchQuery.trim()) return SHORTCUTS;
768
- const query = searchQuery.toLowerCase();
769
- return SHORTCUTS.filter(
770
- (shortcut) => shortcut.keys.toLowerCase().includes(query) || shortcut.description.toLowerCase().includes(query) || shortcut.category.toLowerCase().includes(query)
771
- );
772
- }, [searchQuery]);
773
- const groupedShortcuts = react.useMemo(() => {
774
- const grouped = {};
775
- for (const category of CATEGORIES) {
776
- const items = filteredShortcuts.filter((s) => s.category === category);
777
- if (items.length > 0) {
778
- grouped[category] = items;
779
- }
780
- }
781
- return grouped;
782
- }, [filteredShortcuts]);
783
- const handleClose = () => {
784
- closeModal();
785
- setSearchQuery("");
786
- };
787
- const handleBackdropClick = (e) => {
788
- if (e.target === backdropRef.current) {
789
- handleClose();
790
- }
791
- };
792
- if (!isOpen) return null;
793
- return /* @__PURE__ */ jsxRuntime.jsx(
794
- "div",
795
- {
796
- ref: backdropRef,
797
- onClick: handleBackdropClick,
798
- className: "fixed inset-0 z-50 flex items-start justify-center pt-[15vh]",
799
- style: { backgroundColor: "rgba(0, 0, 0, 0.5)" },
800
- children: /* @__PURE__ */ jsxRuntime.jsxs(
801
- "div",
802
- {
803
- className: "bg-[var(--background)] border border-[var(--border)] rounded-lg shadow-xl w-full max-w-2xl",
804
- role: "dialog",
805
- "aria-label": "Keyboard Shortcuts",
806
- children: [
807
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-[var(--border)]", children: [
808
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
809
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Keyboard, { className: "w-4 h-4 text-[var(--muted-foreground)]" }),
810
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: "Keyboard Shortcuts" })
811
- ] }),
812
- /* @__PURE__ */ jsxRuntime.jsx(
813
- "button",
814
- {
815
- onClick: handleClose,
816
- className: "p-1 rounded hover:bg-[var(--secondary)] transition-colors",
817
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-4 h-4" })
818
- }
819
- )
820
- ] }),
821
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4", children: [
822
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative mb-4", children: [
823
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }),
824
- /* @__PURE__ */ jsxRuntime.jsx(
825
- "input",
826
- {
827
- ref: inputRef,
828
- type: "text",
829
- placeholder: "Search shortcuts...",
830
- value: searchQuery,
831
- onChange: (e) => setSearchQuery(e.target.value),
832
- className: "w-full pl-9 pr-3 py-2 text-sm bg-[var(--secondary)] border border-[var(--border)] rounded-md outline-none focus:ring-1 focus:ring-[var(--ring)]",
833
- autoFocus: true
834
- }
835
- )
836
- ] }),
837
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-h-[60vh] overflow-y-auto space-y-6 pr-2", children: [
838
- Object.entries(groupedShortcuts).map(([category, shortcuts]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
839
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-semibold text-muted-foreground mb-2", children: category }),
840
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1", children: shortcuts.map((shortcut) => /* @__PURE__ */ jsxRuntime.jsxs(
841
- "div",
842
- {
843
- className: "flex items-center justify-between py-1.5 px-2 rounded hover:bg-secondary/50",
844
- children: [
845
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm", children: shortcut.description }),
846
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-xs font-mono bg-secondary rounded border border-border", children: shortcut.keys })
847
- ]
848
- },
849
- shortcut.keys
850
- )) })
851
- ] }, category)),
852
- filteredShortcuts.length === 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center text-muted-foreground py-8", children: [
853
- 'No shortcuts found for "',
854
- searchQuery,
855
- '"'
856
- ] })
857
- ] })
858
- ] })
859
- ]
860
- }
861
- )
862
- }
863
- );
864
- }
865
- var PROMPT_NODE_TYPES = ["prompt"];
866
- function NodeDetailModal() {
867
- const { activeModal, nodeDetailNodeId, nodeDetailStartIndex, closeNodeDetailModal } = chunkAXFOCPPP_js.useUIStore();
868
- const { getNodeById } = chunkIHF35QZD_js.useWorkflowStore();
869
- const { openEditor } = chunk6DOEUDD5_js.usePromptEditorStore();
870
- const [zoomLevel, setZoomLevel] = react.useState(1);
871
- const [panOffset, setPanOffset] = react.useState({ x: 0, y: 0 });
872
- const [isPanning, setIsPanning] = react.useState(false);
873
- const [panStart, setPanStart] = react.useState({ x: 0, y: 0 });
874
- const [currentIndex, setCurrentIndex] = react.useState(0);
875
- const node = react.useMemo(() => {
876
- if (!nodeDetailNodeId) return null;
877
- return getNodeById(nodeDetailNodeId);
878
- }, [nodeDetailNodeId, getNodeById]);
879
- react.useEffect(() => {
880
- if (activeModal !== "nodeDetail" || !node) return;
881
- if (PROMPT_NODE_TYPES.includes(node.type)) {
882
- const promptData = node.data;
883
- closeNodeDetailModal();
884
- openEditor(node.id, promptData.prompt ?? "");
885
- }
886
- }, [activeModal, node, closeNodeDetailModal, openEditor]);
887
- const mediaInfo = react.useMemo(() => {
888
- if (!node) return { url: null, type: null };
889
- return chunk3YFFDHC5_js.getMediaFromNode(node.type, node.data);
890
- }, [node]);
891
- const nodeDef = react.useMemo(() => {
892
- if (!node) return null;
893
- return types.NODE_DEFINITIONS[node.type];
894
- }, [node]);
895
- const imageUrls = mediaInfo.urls ?? [];
896
- const hasMultipleImages = imageUrls.length > 1;
897
- const displayUrl = hasMultipleImages ? imageUrls[currentIndex] ?? mediaInfo.url : mediaInfo.url;
898
- const goToPrevious = react.useCallback(() => {
899
- setCurrentIndex((prev) => Math.max(prev - 1, 0));
900
- setZoomLevel(1);
901
- setPanOffset({ x: 0, y: 0 });
902
- }, []);
903
- const goToNext = react.useCallback(() => {
904
- setCurrentIndex((prev) => Math.min(prev + 1, imageUrls.length - 1));
905
- setZoomLevel(1);
906
- setPanOffset({ x: 0, y: 0 });
907
- }, [imageUrls.length]);
908
- react.useEffect(() => {
909
- setZoomLevel(1);
910
- setPanOffset({ x: 0, y: 0 });
911
- setCurrentIndex(nodeDetailStartIndex);
912
- }, [nodeDetailNodeId, nodeDetailStartIndex]);
913
- react.useEffect(() => {
914
- const handleKeyDown = (e) => {
915
- if (activeModal !== "nodeDetail") return;
916
- if (e.key === "Escape") {
917
- closeNodeDetailModal();
918
- }
919
- if (e.key === "+" || e.key === "=") {
920
- setZoomLevel((prev) => Math.min(prev + 0.25, 4));
921
- }
922
- if (e.key === "-") {
923
- setZoomLevel((prev) => Math.max(prev - 0.25, 0.25));
924
- }
925
- if (e.key === "0") {
926
- setZoomLevel(1);
927
- setPanOffset({ x: 0, y: 0 });
928
- }
929
- if (e.key === "ArrowLeft") {
930
- goToPrevious();
931
- }
932
- if (e.key === "ArrowRight") {
933
- goToNext();
934
- }
935
- };
936
- window.addEventListener("keydown", handleKeyDown);
937
- return () => window.removeEventListener("keydown", handleKeyDown);
938
- }, [activeModal, closeNodeDetailModal, goToPrevious, goToNext]);
939
- const handleMouseDown = react.useCallback(
940
- (e) => {
941
- if (zoomLevel > 1) {
942
- setIsPanning(true);
943
- setPanStart({ x: e.clientX - panOffset.x, y: e.clientY - panOffset.y });
944
- }
945
- },
946
- [zoomLevel, panOffset]
947
- );
948
- const handleMouseMove = react.useCallback(
949
- (e) => {
950
- if (isPanning) {
951
- setPanOffset({
952
- x: e.clientX - panStart.x,
953
- y: e.clientY - panStart.y
954
- });
955
- }
956
- },
957
- [isPanning, panStart]
958
- );
959
- const handleMouseUp = react.useCallback(() => {
960
- setIsPanning(false);
961
- }, []);
962
- const handleDownload = react.useCallback(() => {
963
- const url = displayUrl ?? mediaInfo.url;
964
- if (!url) return;
965
- const link = document.createElement("a");
966
- link.href = url;
967
- const suffix = hasMultipleImages ? `_${currentIndex + 1}` : "";
968
- link.download = `${node?.data.label || "output"}${suffix}.${mediaInfo.type === "video" ? "mp4" : "png"}`;
969
- document.body.appendChild(link);
970
- link.click();
971
- document.body.removeChild(link);
972
- }, [displayUrl, mediaInfo, node, hasMultipleImages, currentIndex]);
973
- if (activeModal !== "nodeDetail" || !node || !nodeDef) {
974
- return null;
975
- }
976
- if (PROMPT_NODE_TYPES.includes(node.type)) {
977
- return null;
978
- }
979
- const nodeData = node.data;
980
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
981
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-50 bg-black/80", onClick: closeNodeDetailModal }),
982
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-4 z-50 flex flex-col bg-card rounded-lg border border-border shadow-xl overflow-hidden", children: [
983
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-border", children: [
984
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
985
- /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-medium text-foreground", children: nodeData.label }),
986
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground bg-secondary px-2 py-0.5 rounded", children: nodeDef.label })
987
- ] }),
988
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
989
- displayUrl && /* @__PURE__ */ jsxRuntime.jsxs(chunk5HJFQVUR_js.Button, { variant: "outline", size: "sm", onClick: handleDownload, children: [
990
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { className: "h-4 w-4 mr-1" }),
991
- "Download"
992
- ] }),
993
- /* @__PURE__ */ jsxRuntime.jsx(chunk5HJFQVUR_js.Button, { variant: "ghost", size: "icon-sm", onClick: closeNodeDetailModal, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-5 h-5" }) })
994
- ] })
995
- ] }),
996
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsxs(
997
- "div",
998
- {
999
- className: "relative w-full h-full flex items-center justify-center bg-background overflow-hidden",
1000
- onMouseDown: handleMouseDown,
1001
- onMouseMove: handleMouseMove,
1002
- onMouseUp: handleMouseUp,
1003
- onMouseLeave: handleMouseUp,
1004
- style: { cursor: zoomLevel > 1 ? isPanning ? "grabbing" : "grab" : "default" },
1005
- children: [
1006
- displayUrl ? /* @__PURE__ */ jsxRuntime.jsxs(
1007
- "div",
1008
- {
1009
- className: "transition-transform duration-100",
1010
- style: {
1011
- transform: `scale(${zoomLevel}) translate(${panOffset.x / zoomLevel}px, ${panOffset.y / zoomLevel}px)`
1012
- },
1013
- children: [
1014
- mediaInfo.type === "image" && /* @__PURE__ */ jsxRuntime.jsx(
1015
- Image__default.default,
1016
- {
1017
- src: displayUrl,
1018
- alt: nodeData.label,
1019
- width: 800,
1020
- height: 600,
1021
- className: "max-h-[calc(100vh-200px)] max-w-[calc(100vw-100px)] object-contain rounded-lg",
1022
- unoptimized: true
1023
- }
1024
- ),
1025
- mediaInfo.type === "video" && /* @__PURE__ */ jsxRuntime.jsx(
1026
- "video",
1027
- {
1028
- src: displayUrl,
1029
- controls: true,
1030
- autoPlay: true,
1031
- loop: true,
1032
- className: "max-h-[calc(100vh-200px)] max-w-[calc(100vw-100px)] rounded-lg"
1033
- }
1034
- )
1035
- ]
1036
- }
1037
- ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-muted-foreground text-center", children: [
1038
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg", children: "No preview available" }),
1039
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm mt-2", children: "Generate content to see the preview" })
1040
- ] }),
1041
- hasMultipleImages && currentIndex > 0 && /* @__PURE__ */ jsxRuntime.jsx(
1042
- chunk5HJFQVUR_js.Button,
1043
- {
1044
- variant: "ghost",
1045
- size: "icon-sm",
1046
- onClick: goToPrevious,
1047
- className: "absolute left-4 top-1/2 -translate-y-1/2 bg-card/80 hover:bg-card border border-border shadow-md",
1048
- title: "Previous image (\u2190)",
1049
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "w-5 h-5" })
1050
- }
1051
- ),
1052
- hasMultipleImages && currentIndex < imageUrls.length - 1 && /* @__PURE__ */ jsxRuntime.jsx(
1053
- chunk5HJFQVUR_js.Button,
1054
- {
1055
- variant: "ghost",
1056
- size: "icon-sm",
1057
- onClick: goToNext,
1058
- className: "absolute right-4 top-1/2 -translate-y-1/2 bg-card/80 hover:bg-card border border-border shadow-md",
1059
- title: "Next image (\u2192)",
1060
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "w-5 h-5" })
1061
- }
1062
- ),
1063
- hasMultipleImages && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute bottom-4 left-1/2 -translate-x-1/2 bg-card/80 border border-border rounded-full px-3 py-1 text-xs text-muted-foreground shadow-md", children: [
1064
- currentIndex + 1,
1065
- " / ",
1066
- imageUrls.length
1067
- ] }),
1068
- displayUrl && mediaInfo.type === "image" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute bottom-4 right-4 flex items-center gap-2 bg-card border border-border rounded-lg p-1", children: [
1069
- /* @__PURE__ */ jsxRuntime.jsx(
1070
- chunk5HJFQVUR_js.Button,
1071
- {
1072
- variant: "ghost",
1073
- size: "icon-sm",
1074
- onClick: () => setZoomLevel((prev) => Math.max(prev - 0.25, 0.25)),
1075
- title: "Zoom out (-)",
1076
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZoomOut, { className: "w-4 h-4" })
1077
- }
1078
- ),
1079
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground w-12 text-center", children: [
1080
- Math.round(zoomLevel * 100),
1081
- "%"
1082
- ] }),
1083
- /* @__PURE__ */ jsxRuntime.jsx(
1084
- chunk5HJFQVUR_js.Button,
1085
- {
1086
- variant: "ghost",
1087
- size: "icon-sm",
1088
- onClick: () => setZoomLevel((prev) => Math.min(prev + 0.25, 4)),
1089
- title: "Zoom in (+)",
1090
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZoomIn, { className: "w-4 h-4" })
1091
- }
1092
- ),
1093
- /* @__PURE__ */ jsxRuntime.jsx(
1094
- chunk5HJFQVUR_js.Button,
1095
- {
1096
- variant: "ghost",
1097
- size: "sm",
1098
- onClick: () => {
1099
- setZoomLevel(1);
1100
- setPanOffset({ x: 0, y: 0 });
1101
- },
1102
- title: "Reset zoom (0)",
1103
- children: "Reset"
1104
- }
1105
- )
1106
- ] })
1107
- ]
1108
- }
1109
- ) })
1110
- ] })
1111
- ] });
1112
- }
1113
- var DEFAULT_NODE_COLOR = "#6b7280";
1114
- function supportsImageInput(schema) {
1115
- if (!schema) return true;
1116
- const properties = schema.properties;
1117
- if (!properties) return true;
1118
- return !!(properties.image || properties.image_input || properties.start_image || properties.first_frame_image || properties.reference_images);
1119
- }
1120
- function getEdgeDataType(edge, nodeMap) {
1121
- const sourceNode = nodeMap.get(edge.source);
1122
- if (!sourceNode) return null;
1123
- const nodeDef = types.NODE_DEFINITIONS[sourceNode.type];
1124
- if (!nodeDef) return null;
1125
- const sourceHandle = nodeDef.outputs.find((h) => h.id === edge.sourceHandle);
1126
- return sourceHandle?.type ?? null;
1127
- }
1128
- function WorkflowCanvas({ nodeTypes: nodeTypesProp } = {}) {
1129
- const {
1130
- nodes,
1131
- edges,
1132
- onNodesChange,
1133
- onEdgesChange,
1134
- onConnect,
1135
- isValidConnection,
1136
- findCompatibleHandle,
1137
- addNode,
1138
- selectedNodeIds,
1139
- setSelectedNodeIds,
1140
- toggleNodeLock,
1141
- createGroup,
1142
- deleteGroup,
1143
- unlockAllNodes,
1144
- groups,
1145
- getConnectedNodeIds
1146
- } = chunkIHF35QZD_js.useWorkflowStore();
1147
- const {
1148
- selectNode,
1149
- setHighlightedNodeIds,
1150
- highlightedNodeIds,
1151
- showPalette,
1152
- togglePalette,
1153
- openModal
1154
- } = chunkAXFOCPPP_js.useUIStore();
1155
- const reactFlow = react$1.useReactFlow();
1156
- const { edgeStyle, showMinimap } = chunkAXFOCPPP_js.useSettingsStore();
1157
- const isRunning = chunkAXFOCPPP_js.useExecutionStore((state) => state.isRunning);
1158
- const currentNodeId = chunkAXFOCPPP_js.useExecutionStore((state) => state.currentNodeId);
1159
- const executingNodeIds = chunkAXFOCPPP_js.useExecutionStore((state) => state.executingNodeIds);
1160
- const activeNodeExecutions = chunkAXFOCPPP_js.useExecutionStore((state) => state.activeNodeExecutions);
1161
- const hasActiveNodeExecutions = chunkAXFOCPPP_js.useExecutionStore((state) => state.activeNodeExecutions.size > 0);
1162
- const [isMinimapVisible, setIsMinimapVisible] = react.useState(false);
1163
- const [draggingNodeId, setDraggingNodeId] = react.useState(null);
1164
- const hideTimeoutRef = react.useRef(null);
1165
- const MINIMAP_HIDE_DELAY = 1500;
1166
- const openShortcutHelp = react.useCallback(() => openModal("shortcutHelp"), [openModal]);
1167
- const openNodeSearch = react.useCallback(() => openModal("nodeSearch"), [openModal]);
1168
- chunkEMGXUNBL_js.useCanvasKeyboardShortcuts({
1169
- selectedNodeIds,
1170
- groups,
1171
- nodes,
1172
- toggleNodeLock,
1173
- createGroup,
1174
- deleteGroup,
1175
- unlockAllNodes,
1176
- addNode,
1177
- togglePalette,
1178
- fitView: reactFlow.fitView,
1179
- openShortcutHelp,
1180
- openNodeSearch
1181
- });
1182
- react.useEffect(() => {
1183
- if (selectedNodeIds.length === 0) {
1184
- setHighlightedNodeIds([]);
1185
- } else {
1186
- const connectedIds = getConnectedNodeIds(selectedNodeIds);
1187
- setHighlightedNodeIds(connectedIds);
1188
- }
1189
- }, [selectedNodeIds, getConnectedNodeIds, setHighlightedNodeIds]);
1190
- const nodeMap = react.useMemo(() => new Map(nodes.map((n) => [n.id, n])), [nodes]);
1191
- const isEdgeTargetingDisabledInput = react.useCallback(
1192
- (edge) => {
1193
- const targetNode = nodeMap.get(edge.target);
1194
- if (!targetNode) return false;
1195
- if (targetNode.type === "imageGen" && edge.targetHandle === "images") {
1196
- const nodeData = targetNode.data;
1197
- const hasImageSupport = supportsImageInput(nodeData?.selectedModel?.inputSchema);
1198
- return !hasImageSupport;
1199
- }
1200
- if (targetNode.type === "videoGen") {
1201
- if (edge.targetHandle === "image" || edge.targetHandle === "lastFrame") {
1202
- const nodeData = targetNode.data;
1203
- const hasImageSupport = supportsImageInput(nodeData?.selectedModel?.inputSchema);
1204
- return !hasImageSupport;
1205
- }
1206
- }
1207
- return false;
1208
- },
1209
- [nodeMap]
1210
- );
1211
- const styledEdges = react.useMemo(() => {
1212
- const executionScope = executingNodeIds.length > 0 ? new Set(executingNodeIds) : null;
1213
- const highlightedSet = highlightedNodeIds.length > 0 ? new Set(highlightedNodeIds) : null;
1214
- return edges.map((edge) => {
1215
- const dataType = getEdgeDataType(edge, nodeMap);
1216
- const typeClass = dataType ? `edge-${dataType}` : "";
1217
- const isDisabledTarget = isEdgeTargetingDisabledInput(edge);
1218
- if (!isRunning && hasActiveNodeExecutions) {
1219
- const isActiveEdge = activeNodeExecutions.has(edge.source) || activeNodeExecutions.has(edge.target);
1220
- if (isActiveEdge && !isDisabledTarget) {
1221
- return {
1222
- ...edge,
1223
- animated: false,
1224
- className: `${typeClass} executing`.trim()
1225
- };
1226
- }
1227
- }
1228
- if (isRunning) {
1229
- const isInExecutionScope = !executionScope || executionScope.has(edge.source) || executionScope.has(edge.target);
1230
- const isExecutingEdge = currentNodeId && (edge.source === currentNodeId || edge.target === currentNodeId);
1231
- if (isDisabledTarget) {
1232
- return {
1233
- ...edge,
1234
- animated: false,
1235
- className: `${typeClass} edge-disabled`.trim()
1236
- };
1237
- }
1238
- if (!isInExecutionScope) {
1239
- return {
1240
- ...edge,
1241
- animated: false,
1242
- className: typeClass
1243
- };
1244
- }
1245
- return {
1246
- ...edge,
1247
- animated: false,
1248
- className: `${typeClass} ${isExecutingEdge ? "executing" : "active-pipe"}`.trim()
1249
- };
1250
- }
1251
- if (isDisabledTarget) {
1252
- return {
1253
- ...edge,
1254
- className: `${typeClass} edge-disabled`.trim()
1255
- };
1256
- }
1257
- if (highlightedSet) {
1258
- const isConnected = highlightedSet.has(edge.source) && highlightedSet.has(edge.target);
1259
- return {
1260
- ...edge,
1261
- className: `${typeClass} ${isConnected ? "highlighted" : "dimmed"}`.trim()
1262
- };
1263
- }
1264
- return {
1265
- ...edge,
1266
- className: typeClass
1267
- };
1268
- });
1269
- }, [
1270
- edges,
1271
- nodeMap,
1272
- highlightedNodeIds,
1273
- isRunning,
1274
- currentNodeId,
1275
- executingNodeIds,
1276
- activeNodeExecutions,
1277
- hasActiveNodeExecutions,
1278
- isEdgeTargetingDisabledInput
1279
- ]);
1280
- const handleNodeClick = react.useCallback(
1281
- (_event, node) => {
1282
- selectNode(node.id);
1283
- },
1284
- [selectNode]
1285
- );
1286
- const handlePaneClick = react.useCallback(() => {
1287
- selectNode(null);
1288
- setSelectedNodeIds([]);
1289
- }, [selectNode, setSelectedNodeIds]);
1290
- const handleSelectionChange = react.useCallback(
1291
- ({ nodes: selectedNodes }) => {
1292
- setSelectedNodeIds(selectedNodes.map((n) => n.id));
1293
- },
1294
- [setSelectedNodeIds]
1295
- );
1296
- const handleNodeContextMenu = react.useCallback(
1297
- (event, node) => {
1298
- event.preventDefault();
1299
- },
1300
- [selectedNodeIds]
1301
- );
1302
- const handleEdgeContextMenu = react.useCallback(
1303
- (event, edge) => {
1304
- event.preventDefault();
1305
- },
1306
- []
1307
- );
1308
- const handlePaneContextMenu = react.useCallback(
1309
- (event) => {
1310
- event.preventDefault();
1311
- },
1312
- []
1313
- );
1314
- const handleSelectionContextMenu = react.useCallback(
1315
- (event, selectedNodes) => {
1316
- event.preventDefault();
1317
- },
1318
- []
1319
- );
1320
- const handleDrop = react.useCallback(
1321
- (event) => {
1322
- event.preventDefault();
1323
- const nodeType = event.dataTransfer.getData("nodeType");
1324
- if (!nodeType) return;
1325
- const position = reactFlow.screenToFlowPosition({
1326
- x: event.clientX,
1327
- y: event.clientY
1328
- });
1329
- addNode(nodeType, position);
1330
- },
1331
- [addNode, reactFlow]
1332
- );
1333
- const handleDragOver = react.useCallback((event) => {
1334
- event.preventDefault();
1335
- event.dataTransfer.dropEffect = "move";
1336
- }, []);
1337
- const handleNodeDragStart = react.useCallback((_event, node) => {
1338
- setDraggingNodeId(node.id);
1339
- }, []);
1340
- const handleNodeDrag = react.useCallback((_event, node) => {
1341
- setDraggingNodeId(node.id);
1342
- }, []);
1343
- const handleNodeDragStop = react.useCallback(() => {
1344
- setDraggingNodeId(null);
1345
- }, []);
1346
- const handleConnectEnd = react.useCallback(
1347
- (event, connectionState) => {
1348
- const state = connectionState;
1349
- const sourceNodeId = state.fromNode?.id;
1350
- const sourceHandleId = state.fromHandle?.id;
1351
- if (!sourceNodeId || !sourceHandleId) return;
1352
- const target = event.target;
1353
- const nodeElement = target.closest(".react-flow__node");
1354
- if (!nodeElement) return;
1355
- const targetNodeId = nodeElement.getAttribute("data-id");
1356
- if (!targetNodeId || targetNodeId === sourceNodeId) return;
1357
- const droppedOnHandle = target.closest(".react-flow__handle");
1358
- if (droppedOnHandle) return;
1359
- const compatibleHandle = findCompatibleHandle(sourceNodeId, sourceHandleId, targetNodeId);
1360
- if (!compatibleHandle) return;
1361
- onConnect({
1362
- source: sourceNodeId,
1363
- sourceHandle: sourceHandleId,
1364
- target: targetNodeId,
1365
- targetHandle: compatibleHandle
1366
- });
1367
- },
1368
- [findCompatibleHandle, onConnect]
1369
- );
1370
- const checkValidConnection = react.useCallback(
1371
- (connection) => {
1372
- const conn = {
1373
- source: connection.source,
1374
- target: connection.target,
1375
- sourceHandle: connection.sourceHandle ?? null,
1376
- targetHandle: connection.targetHandle ?? null
1377
- };
1378
- return isValidConnection(conn);
1379
- },
1380
- [isValidConnection]
1381
- );
1382
- const handleMoveStart = react.useCallback(() => {
1383
- if (!showMinimap) return;
1384
- if (hideTimeoutRef.current) {
1385
- clearTimeout(hideTimeoutRef.current);
1386
- hideTimeoutRef.current = null;
1387
- }
1388
- setIsMinimapVisible(true);
1389
- }, [showMinimap]);
1390
- const handleMoveEnd = react.useCallback(() => {
1391
- if (!showMinimap) return;
1392
- if (hideTimeoutRef.current) {
1393
- clearTimeout(hideTimeoutRef.current);
1394
- }
1395
- hideTimeoutRef.current = setTimeout(() => {
1396
- setIsMinimapVisible(false);
1397
- hideTimeoutRef.current = null;
1398
- }, MINIMAP_HIDE_DELAY);
1399
- }, [showMinimap]);
1400
- react.useEffect(() => {
1401
- return () => {
1402
- if (hideTimeoutRef.current) {
1403
- clearTimeout(hideTimeoutRef.current);
1404
- }
1405
- };
1406
- }, []);
1407
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full h-full relative", onDrop: handleDrop, onDragOver: handleDragOver, children: [
1408
- !showPalette && /* @__PURE__ */ jsxRuntime.jsx(
1409
- "button",
1410
- {
1411
- onClick: togglePalette,
1412
- className: "absolute top-3 left-3 z-10 p-1.5 bg-[var(--background)] border border-[var(--border)] rounded-md hover:bg-[var(--secondary)] transition-colors group",
1413
- title: "Open sidebar (M)",
1414
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelLeft, { className: "w-4 h-4 text-[var(--muted-foreground)] group-hover:text-[var(--foreground)]" })
1415
- }
1416
- ),
1417
- /* @__PURE__ */ jsxRuntime.jsxs(
1418
- react$1.ReactFlow,
1419
- {
1420
- nodes,
1421
- edges: styledEdges,
1422
- onNodesChange,
1423
- onEdgesChange,
1424
- onConnect,
1425
- onConnectEnd: handleConnectEnd,
1426
- onNodeClick: handleNodeClick,
1427
- onPaneClick: handlePaneClick,
1428
- onSelectionChange: handleSelectionChange,
1429
- onNodeContextMenu: handleNodeContextMenu,
1430
- onEdgeContextMenu: handleEdgeContextMenu,
1431
- onPaneContextMenu: handlePaneContextMenu,
1432
- onSelectionContextMenu: handleSelectionContextMenu,
1433
- onNodeDragStart: handleNodeDragStart,
1434
- onNodeDrag: handleNodeDrag,
1435
- onNodeDragStop: handleNodeDragStop,
1436
- isValidConnection: checkValidConnection,
1437
- nodeTypes: nodeTypesProp ?? chunkECD5J2BA_js.nodeTypes,
1438
- fitView: true,
1439
- snapToGrid: true,
1440
- snapGrid: [16, 16],
1441
- connectionMode: react$1.ConnectionMode.Loose,
1442
- selectionMode: react$1.SelectionMode.Partial,
1443
- selectionOnDrag: true,
1444
- panOnDrag: [1, 2],
1445
- onMoveStart: handleMoveStart,
1446
- onMoveEnd: handleMoveEnd,
1447
- deleteKeyCode: ["Backspace", "Delete"],
1448
- defaultEdgeOptions: {
1449
- type: edgeStyle,
1450
- animated: false
1451
- },
1452
- edgesFocusable: true,
1453
- edgesReconnectable: true,
1454
- proOptions: { hideAttribution: true },
1455
- onlyRenderVisibleElements: nodes.length > 50,
1456
- children: [
1457
- /* @__PURE__ */ jsxRuntime.jsx(GroupOverlay, {}),
1458
- /* @__PURE__ */ jsxRuntime.jsx(
1459
- react$1.Background,
1460
- {
1461
- variant: react$1.BackgroundVariant.Dots,
1462
- gap: 16,
1463
- size: 1,
1464
- color: "rgba(255, 255, 255, 0.08)"
1465
- }
1466
- ),
1467
- /* @__PURE__ */ jsxRuntime.jsx(react$1.Controls, {}),
1468
- showMinimap && /* @__PURE__ */ jsxRuntime.jsx(
1469
- react$1.MiniMap,
1470
- {
1471
- nodeStrokeWidth: 0,
1472
- nodeColor: () => DEFAULT_NODE_COLOR,
1473
- zoomable: true,
1474
- pannable: true,
1475
- maskColor: "rgba(0, 0, 0, 0.8)",
1476
- className: `!bg-transparent !border-[var(--border)] !rounded-lg transition-opacity duration-300 ${isMinimapVisible ? "opacity-100" : "opacity-0 pointer-events-none"}`
1477
- }
1478
- ),
1479
- /* @__PURE__ */ jsxRuntime.jsx(HelperLines, { draggingNodeId })
1480
- ]
1481
- }
1482
- ),
1483
- /* @__PURE__ */ jsxRuntime.jsx(NodeDetailModal, {}),
1484
- /* @__PURE__ */ jsxRuntime.jsx(ShortcutHelpModal, {}),
1485
- /* @__PURE__ */ jsxRuntime.jsx(NodeSearch, {})
1486
- ] });
1487
- }
1488
- function PauseEdgeComponent({
1489
- id,
1490
- sourceX,
1491
- sourceY,
1492
- targetX,
1493
- targetY,
1494
- sourcePosition,
1495
- targetPosition,
1496
- style = {},
1497
- markerEnd,
1498
- data
1499
- }) {
1500
- const [edgePath, labelX, labelY] = react$1.getBezierPath({
1501
- sourceX,
1502
- sourceY,
1503
- sourcePosition,
1504
- targetX,
1505
- targetY,
1506
- targetPosition
1507
- });
1508
- const hasPause = data?.hasPause === true;
1509
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1510
- /* @__PURE__ */ jsxRuntime.jsx(
1511
- react$1.BaseEdge,
1512
- {
1513
- path: edgePath,
1514
- markerEnd,
1515
- style: {
1516
- ...style,
1517
- ...hasPause && {
1518
- strokeDasharray: "5 5",
1519
- stroke: "#f59e0b"
1520
- }
1521
- }
1522
- }
1523
- ),
1524
- hasPause && /* @__PURE__ */ jsxRuntime.jsx(
1525
- "foreignObject",
1526
- {
1527
- width: 20,
1528
- height: 20,
1529
- x: labelX - 10,
1530
- y: labelY - 10,
1531
- className: "pointer-events-none",
1532
- children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center w-5 h-5 rounded-full bg-amber-500 text-white", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Pause, { className: "w-3 h-3" }) })
1533
- }
1534
- )
1535
- ] });
1536
- }
1537
- var PauseEdge = react.memo(PauseEdgeComponent);
1538
-
1539
- exports.DEFAULT_GROUP_COLORS = DEFAULT_GROUP_COLORS;
1540
- exports.GROUP_COLORS = GROUP_COLORS;
1541
- exports.GroupOverlay = GroupOverlay;
1542
- exports.HelperLines = HelperLines;
1543
- exports.NodeSearch = NodeSearch;
1544
- exports.PauseEdge = PauseEdge;
1545
- exports.ShortcutHelpModal = ShortcutHelpModal;
1546
- exports.WorkflowCanvas = WorkflowCanvas;