@flowuent-org/diagramming-core 1.3.4 → 1.3.6

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.
@@ -87,13 +87,19 @@ export const DiagramContent: React.FC<DiagramContentProps> = ({
87
87
  const canRedo = useCanRedo();
88
88
 
89
89
  // Zoom hooks - get zoom functions from ReactFlow
90
- const { zoomIn, zoomOut, fitView, setViewport, getViewport, getNodes } = useReactFlow();
90
+ const { zoomIn, zoomOut, fitView, setViewport, getViewport, getNodes, screenToFlowPosition } = useReactFlow();
91
91
 
92
92
  // Search bar state
93
93
  const [showSearchBar, setShowSearchBar] = useState(false);
94
94
 
95
- // Clipboard state for copy/paste
96
- const [copiedNode, setCopiedNode] = useState<Node | null>(null);
95
+ // Clipboard state for copy/paste - support multiple nodes
96
+ const [copiedNodes, setCopiedNodes] = useState<Node[]>([]);
97
+
98
+ // Store last click position on canvas for paste positioning
99
+ const [lastClickPosition, setLastClickPosition] = useState<{ x: number; y: number } | null>(null);
100
+
101
+ // Flag to prevent layout recalculation immediately after paste
102
+ const skipLayoutRef = useRef(false);
97
103
 
98
104
  // Rename state
99
105
  const [renamingNodeId, setRenamingNodeId] = useState<string | null>(null);
@@ -109,40 +115,111 @@ export const DiagramContent: React.FC<DiagramContentProps> = ({
109
115
  setShowSearchBar(true);
110
116
  }, []);
111
117
 
112
- // Copy selected node
118
+ // Copy selected nodes (single or multiple)
113
119
  const handleCopyNode = useCallback(() => {
114
- const nodeToCopy = visibleNodes.find(node => node.id === selectedNode || node.selected);
115
- if (nodeToCopy) {
116
- setCopiedNode(nodeToCopy);
120
+ // Get all selected nodes from ReactFlow
121
+ const selectedNodesList = getNodes().filter(node => node.selected);
122
+
123
+ // If multiple nodes are selected, copy all of them
124
+ if (selectedNodesList.length > 0) {
125
+ setCopiedNodes(selectedNodesList);
126
+ } else {
127
+ // Fallback to single node selection (custom selectedNode state)
128
+ const nodeToCopy = visibleNodes.find(node => node.id === selectedNode);
129
+ if (nodeToCopy) {
130
+ setCopiedNodes([nodeToCopy]);
131
+ }
117
132
  }
118
- }, [visibleNodes, selectedNode]);
133
+ }, [visibleNodes, selectedNode, getNodes]);
119
134
 
120
- // Paste node
135
+ // Paste nodes (single or multiple) at the clicked position
121
136
  const handlePasteNode = useCallback(() => {
122
- if (!copiedNode) return;
137
+ if (copiedNodes.length === 0) return;
123
138
 
124
- const newNode = {
125
- ...copiedNode,
126
- id: `${copiedNode.id}-copy-${Date.now()}`,
127
- position: {
128
- x: copiedNode.position.x + 50,
129
- y: copiedNode.position.y + 50,
130
- },
131
- selected: false,
132
- };
139
+ // Determine paste position:
140
+ // 1. Use last click position on canvas if available
141
+ // 2. Fallback to offset from original position
142
+ let pasteX: number;
143
+ let pasteY: number;
144
+
145
+ if (lastClickPosition) {
146
+ // Use stored click position
147
+ pasteX = lastClickPosition.x;
148
+ pasteY = lastClickPosition.y;
149
+ } else {
150
+ // Fallback: use offset from original position
151
+ const minX = Math.min(...copiedNodes.map(node => node.position.x));
152
+ const minY = Math.min(...copiedNodes.map(node => node.position.y));
153
+ pasteX = minX + 50;
154
+ pasteY = minY + 50;
155
+ }
156
+
157
+ // Find the minimum X and Y positions of copied nodes (reference point)
158
+ const minX = Math.min(...copiedNodes.map(node => node.position.x));
159
+ const minY = Math.min(...copiedNodes.map(node => node.position.y));
160
+
161
+ // Calculate offset from reference point to paste position
162
+ const offsetX = pasteX - minX;
163
+ const offsetY = pasteY - minY;
164
+
165
+ // Create new nodes with updated IDs and positions
166
+ const newNodes = copiedNodes.map((node, index) => {
167
+ // Calculate relative position from the minimum position
168
+ const relativeX = node.position.x - minX;
169
+ const relativeY = node.position.y - minY;
170
+
171
+ return {
172
+ ...node,
173
+ id: `${node.id}-copy-${Date.now()}-${index}`,
174
+ position: {
175
+ x: minX + relativeX + offsetX,
176
+ y: minY + relativeY + offsetY,
177
+ },
178
+ selected: false,
179
+ data: {
180
+ ...node.data,
181
+ isPinned: true, // Mark as pinned to prevent auto-layout from moving it
182
+ },
183
+ };
184
+ });
185
+
186
+ // Prevent layout recalculation from moving pasted nodes
187
+ skipLayoutRef.current = true;
188
+
189
+ // Add all new nodes to the diagram
190
+ setNodes([...nodes, ...newNodes as any]);
133
191
 
134
- setNodes([...nodes, newNode as any]);
135
- setSelectedNode(newNode.id);
136
- }, [copiedNode, nodes, setNodes, setSelectedNode]);
192
+ // Select the first pasted node (or all if multiple)
193
+ if (newNodes.length === 1) {
194
+ setSelectedNode(newNodes[0].id);
195
+ } else {
196
+ // For multiple nodes, select the first one (ReactFlow will handle multi-selection)
197
+ setSelectedNode(newNodes[0].id);
198
+ }
199
+ }, [copiedNodes, nodes, setNodes, setSelectedNode, lastClickPosition]);
137
200
 
138
- // Delete selected node
201
+ // Delete selected nodes (single or multiple)
139
202
  const handleDeleteNode = useCallback(() => {
140
- const nodeToDelete = visibleNodes.find(node => node.id === selectedNode || node.selected);
141
- if (nodeToDelete && onNodesChange) {
142
- onNodesChange([{ id: nodeToDelete.id, type: 'remove' }]);
203
+ // Get all selected nodes from ReactFlow
204
+ const selectedNodesList = getNodes().filter(node => node.selected);
205
+
206
+ if (selectedNodesList.length > 0) {
207
+ // Delete all selected nodes
208
+ const changes = selectedNodesList.map(node => ({
209
+ id: node.id,
210
+ type: 'remove' as const,
211
+ }));
212
+ onNodesChange(changes);
143
213
  setSelectedNode(null);
214
+ } else {
215
+ // Fallback to single node deletion (custom selectedNode state)
216
+ const nodeToDelete = visibleNodes.find(node => node.id === selectedNode);
217
+ if (nodeToDelete && onNodesChange) {
218
+ onNodesChange([{ id: nodeToDelete.id, type: 'remove' }]);
219
+ setSelectedNode(null);
220
+ }
144
221
  }
145
- }, [visibleNodes, selectedNode, onNodesChange, setSelectedNode]);
222
+ }, [visibleNodes, selectedNode, onNodesChange, setSelectedNode, getNodes]);
146
223
 
147
224
  // Rename node
148
225
  const handleRenameNode = useCallback(() => {
@@ -388,6 +465,12 @@ export const DiagramContent: React.FC<DiagramContentProps> = ({
388
465
 
389
466
  // Debounce layout recalculation to prevent continuous propagation
390
467
  useEffect(() => {
468
+ // Skip layout recalculation if we just pasted nodes
469
+ if (skipLayoutRef.current) {
470
+ skipLayoutRef.current = false;
471
+ return;
472
+ }
473
+
391
474
  // Clear any pending layout recalculation
392
475
  if (layoutTimeoutRef.current) {
393
476
  clearTimeout(layoutTimeoutRef.current);
@@ -536,18 +619,35 @@ export const DiagramContent: React.FC<DiagramContentProps> = ({
536
619
  onEdgesChange={onEdgesChange}
537
620
  onReconnect={onReconnect}
538
621
  onNodeClick={(event, node) => {
539
- event.stopPropagation();
540
- setSelectedNode(node.id);
622
+ // Don't interfere with multi-selection - let ReactFlow handle it
623
+ // Only set our custom selectedNode if it's a single click without modifiers
624
+ if (!event.ctrlKey && !event.metaKey && !event.shiftKey) {
625
+ // Check if multiple nodes are selected - if so, don't override
626
+ const selectedNodes = getNodes().filter(n => n.selected);
627
+ if (selectedNodes.length <= 1) {
628
+ event.stopPropagation();
629
+ setSelectedNode(node.id);
630
+ }
631
+ // If multiple nodes are selected, let ReactFlow handle the drag
632
+ }
541
633
  }}
542
634
  onPaneClick={(event) => {
543
635
  setSelectedNode(null);
544
636
  closeModalsOnClickOutside(event);
637
+ // Store click position for paste operation
638
+ const flowPosition = screenToFlowPosition({
639
+ x: event.clientX,
640
+ y: event.clientY,
641
+ });
642
+ setLastClickPosition(flowPosition);
545
643
  }}
546
644
  nodesConnectable={true}
547
645
  nodesFocusable={true}
548
646
  edgesFocusable={true}
549
647
  elementsSelectable={true}
550
648
  selectNodesOnDrag={false}
649
+ selectionOnDrag={true}
650
+ selectionKeyCode={["Control", "Meta"]}
551
651
  defaultEdgeOptions={{
552
652
  reconnectable: true,
553
653
  }}
@@ -672,7 +772,30 @@ export const DiagramContent: React.FC<DiagramContentProps> = ({
672
772
  connectionMode={ConnectionMode.Strict}
673
773
  suppressContentEditableWarning
674
774
  suppressHydrationWarning
675
- onPaneClick={closeModalsOnClickOutside}
775
+ onPaneClick={(event) => {
776
+ closeModalsOnClickOutside(event);
777
+ // Store click position for paste operation
778
+ const flowPosition = screenToFlowPosition({
779
+ x: event.clientX,
780
+ y: event.clientY,
781
+ });
782
+ setLastClickPosition(flowPosition);
783
+ }}
784
+ onNodeClick={(event, node) => {
785
+ // Don't interfere with multi-selection - let ReactFlow handle it
786
+ // Only set our custom selectedNode if it's a single click without modifiers
787
+ if (!event.ctrlKey && !event.metaKey && !event.shiftKey) {
788
+ // Check if multiple nodes are selected - if so, don't override
789
+ const selectedNodes = getNodes().filter(n => n.selected);
790
+ if (selectedNodes.length <= 1) {
791
+ event.stopPropagation();
792
+ setSelectedNode(node.id);
793
+ }
794
+ // If multiple nodes are selected, let ReactFlow handle the drag
795
+ }
796
+ }}
797
+ selectionOnDrag={true}
798
+ selectionKeyCode={["Control", "Meta"]}
676
799
  {...props}
677
800
  />
678
801
  {props.children}
@@ -6,7 +6,29 @@ import ParamsActionField from './lib/ParamsActionField/ParamsActionField';
6
6
  import EditorTab from './lib/EditorTab/EditorTab';
7
7
  import CloseableButton from './lib/ClosableButton/CloseableButton';
8
8
 
9
-
9
+ // Export SVG Icons
10
+ export {
11
+ ArticleAnalyzerIcon,
12
+ StartNodeIcon,
13
+ EndNodeIcon,
14
+ NavigationIcon,
15
+ ParallelIcon,
16
+ BranchIcon,
17
+ GroupIcon,
18
+ ReturnIcon,
19
+ LoopIcon,
20
+ SwitchIcon,
21
+ TryIcon,
22
+ CatchIcon,
23
+ TryCatchIcon,
24
+ FunctionIcon,
25
+ CallIcon,
26
+ LetIcon,
27
+ SetIcon,
28
+ EmptyNodeIcon,
29
+ EntityIcon,
30
+ } from './lib/SvgIcons';
31
+ export type { SvgIconProps } from './lib/SvgIcons';
10
32
 
11
33
  export {
12
34
  UserCard,
@@ -15,8 +37,5 @@ export {
15
37
  HTTPVerbSelection,
16
38
  ParamsActionField,
17
39
  EditorTab,
18
-
19
-
20
-
21
40
  CloseableButton
22
41
  };
@@ -0,0 +1,291 @@
1
+ import React from 'react';
2
+ import { SvgIconProps } from './types';
3
+
4
+ // Base SVG icon component
5
+ const BaseIcon: React.FC<SvgIconProps & { children: React.ReactNode }> = ({
6
+ size = 15,
7
+ color = '#86EFAC',
8
+ style,
9
+ children
10
+ }) => (
11
+ <svg
12
+ width={size}
13
+ height={size}
14
+ viewBox="0 0 15 15"
15
+ fill="none"
16
+ xmlns="http://www.w3.org/2000/svg"
17
+ style={style}
18
+ >
19
+ {children}
20
+ </svg>
21
+ );
22
+
23
+ // Article Analyzer Icon
24
+ export const ArticleAnalyzerIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#86EFAC', style }) => (
25
+ <svg
26
+ width={size || 12}
27
+ height={size ? (size * 15) / 12 : 15}
28
+ viewBox="0 0 12 15"
29
+ fill="none"
30
+ xmlns="http://www.w3.org/2000/svg"
31
+ style={style}
32
+ >
33
+ <path
34
+ d="M7.83333 0.5H1.83333C1.47971 0.5 1.14057 0.640476 0.890524 0.890524C0.640476 1.14057 0.5 1.47971 0.5 1.83333V12.5C0.5 12.8536 0.640476 13.1928 0.890524 13.4428C1.14057 13.6929 1.47971 13.8333 1.83333 13.8333H9.83333C10.187 13.8333 10.5261 13.6929 10.7761 13.4428C11.0262 13.1928 11.1667 12.8536 11.1667 12.5V3.83333L7.83333 0.5Z"
35
+ stroke={color || "#D8B4FE"}
36
+ strokeLinecap="round"
37
+ strokeLinejoin="round"
38
+ />
39
+ <path
40
+ d="M7.16797 0.5V3.16667C7.16797 3.52029 7.30844 3.85943 7.55849 4.10948C7.80854 4.35952 8.14768 4.5 8.5013 4.5H11.168"
41
+ stroke={color || "#D8B4FE"}
42
+ strokeLinecap="round"
43
+ strokeLinejoin="round"
44
+ />
45
+ <path
46
+ d="M4.5013 5.16699H3.16797"
47
+ stroke={color || "#D8B4FE"}
48
+ strokeLinecap="round"
49
+ strokeLinejoin="round"
50
+ />
51
+ <path
52
+ d="M8.5013 7.83398H3.16797"
53
+ stroke={color || "#D8B4FE"}
54
+ strokeLinecap="round"
55
+ strokeLinejoin="round"
56
+ />
57
+ <path
58
+ d="M8.5013 10.5H3.16797"
59
+ stroke={color || "#D8B4FE"}
60
+ strokeLinecap="round"
61
+ strokeLinejoin="round"
62
+ />
63
+ </svg>
64
+ );
65
+
66
+ // Start Node Icon
67
+ export const StartNodeIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#86EFAC', style }) => (
68
+ <BaseIcon size={size} color={color} style={style}>
69
+ <path
70
+ d="M7.16667 13.8333C10.8486 13.8333 13.8333 10.8486 13.8333 7.16667C13.8333 3.48477 10.8486 0.5 7.16667 0.5C3.48477 0.5 0.5 3.48477 0.5 7.16667C0.5 10.8486 3.48477 13.8333 7.16667 13.8333Z"
71
+ stroke={color}
72
+ strokeLinecap="round"
73
+ strokeLinejoin="round"
74
+ />
75
+ <path
76
+ d="M5.83203 4.5L9.83203 7.16667L5.83203 9.83333V4.5Z"
77
+ stroke={color}
78
+ strokeLinecap="round"
79
+ strokeLinejoin="round"
80
+ />
81
+ </BaseIcon>
82
+ );
83
+
84
+ // Navigation Icon
85
+ export const NavigationIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#93C5FD', style }) => (
86
+ <BaseIcon size={size} color={color} style={style}>
87
+ <path
88
+ d="M7.16667 13.8333C10.8486 13.8333 13.8333 10.8486 13.8333 7.16667C13.8333 3.48477 10.8486 0.5 7.16667 0.5C3.48477 0.5 0.5 3.48477 0.5 7.16667C0.5 10.8486 3.48477 13.8333 7.16667 13.8333Z"
89
+ stroke={color}
90
+ strokeLinecap="round"
91
+ strokeLinejoin="round"
92
+ />
93
+ <path
94
+ d="M7.16667 0.5C5.45482 2.29744 4.5 4.68449 4.5 7.16667C4.5 9.64884 5.45482 12.0359 7.16667 13.8333C8.87851 12.0359 9.83333 9.64884 9.83333 7.16667C9.83333 4.68449 8.87851 2.29744 7.16667 0.5Z"
95
+ stroke={color}
96
+ strokeLinecap="round"
97
+ strokeLinejoin="round"
98
+ />
99
+ <path
100
+ d="M0.5 7.16699H13.8333"
101
+ stroke={color}
102
+ strokeLinecap="round"
103
+ strokeLinejoin="round"
104
+ />
105
+ </BaseIcon>
106
+ );
107
+
108
+ // Workflow node type icons
109
+ export const ParallelIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#86EFAC', style }) => (
110
+ <BaseIcon size={size} color={color} style={style}>
111
+ <path
112
+ d="M7.16667 13.8333C10.8486 13.8333 13.8333 10.8486 13.8333 7.16667C13.8333 3.48477 10.8486 0.5 7.16667 0.5C3.48477 0.5 0.5 3.48477 0.5 7.16667C0.5 10.8486 3.48477 13.8333 7.16667 13.8333Z"
113
+ stroke={color}
114
+ strokeLinecap="round"
115
+ strokeLinejoin="round"
116
+ />
117
+ </BaseIcon>
118
+ );
119
+
120
+ export const BranchIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#86EFAC', style }) => (
121
+ <BaseIcon size={size} color={color} style={style}>
122
+ <path
123
+ d="M7.16667 13.8333C10.8486 13.8333 13.8333 10.8486 13.8333 7.16667C13.8333 3.48477 10.8486 0.5 7.16667 0.5C3.48477 0.5 0.5 3.48477 0.5 7.16667C0.5 10.8486 3.48477 13.8333 7.16667 13.8333Z"
124
+ stroke={color}
125
+ strokeLinecap="round"
126
+ strokeLinejoin="round"
127
+ />
128
+ </BaseIcon>
129
+ );
130
+
131
+ export const GroupIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#86EFAC', style }) => (
132
+ <BaseIcon size={size} color={color} style={style}>
133
+ <path
134
+ d="M7.16667 13.8333C10.8486 13.8333 13.8333 10.8486 13.8333 7.16667C13.8333 3.48477 10.8486 0.5 7.16667 0.5C3.48477 0.5 0.5 3.48477 0.5 7.16667C0.5 10.8486 3.48477 13.8333 7.16667 13.8333Z"
135
+ stroke={color}
136
+ strokeLinecap="round"
137
+ strokeLinejoin="round"
138
+ />
139
+ </BaseIcon>
140
+ );
141
+
142
+ export const ReturnIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#86EFAC', style }) => (
143
+ <BaseIcon size={size} color={color} style={style}>
144
+ <path
145
+ d="M7.16667 13.8333C10.8486 13.8333 13.8333 10.8486 13.8333 7.16667C13.8333 3.48477 10.8486 0.5 7.16667 0.5C3.48477 0.5 0.5 3.48477 0.5 7.16667C0.5 10.8486 3.48477 13.8333 7.16667 13.8333Z"
146
+ stroke={color}
147
+ strokeLinecap="round"
148
+ strokeLinejoin="round"
149
+ />
150
+ </BaseIcon>
151
+ );
152
+
153
+ export const LoopIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#86EFAC', style }) => (
154
+ <BaseIcon size={size} color={color} style={style}>
155
+ <path
156
+ d="M7.16667 13.8333C10.8486 13.8333 13.8333 10.8486 13.8333 7.16667C13.8333 3.48477 10.8486 0.5 7.16667 0.5C3.48477 0.5 0.5 3.48477 0.5 7.16667C0.5 10.8486 3.48477 13.8333 7.16667 13.8333Z"
157
+ stroke={color}
158
+ strokeLinecap="round"
159
+ strokeLinejoin="round"
160
+ />
161
+ </BaseIcon>
162
+ );
163
+
164
+ export const SwitchIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#86EFAC', style }) => (
165
+ <BaseIcon size={size} color={color} style={style}>
166
+ <path
167
+ d="M7.16667 13.8333C10.8486 13.8333 13.8333 10.8486 13.8333 7.16667C13.8333 3.48477 10.8486 0.5 7.16667 0.5C3.48477 0.5 0.5 3.48477 0.5 7.16667C0.5 10.8486 3.48477 13.8333 7.16667 13.8333Z"
168
+ stroke={color}
169
+ strokeLinecap="round"
170
+ strokeLinejoin="round"
171
+ />
172
+ </BaseIcon>
173
+ );
174
+
175
+ export const TryIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#86EFAC', style }) => (
176
+ <BaseIcon size={size} color={color} style={style}>
177
+ <path
178
+ d="M7.16667 13.8333C10.8486 13.8333 13.8333 10.8486 13.8333 7.16667C13.8333 3.48477 10.8486 0.5 7.16667 0.5C3.48477 0.5 0.5 3.48477 0.5 7.16667C0.5 10.8486 3.48477 13.8333 7.16667 13.8333Z"
179
+ stroke={color}
180
+ strokeLinecap="round"
181
+ strokeLinejoin="round"
182
+ />
183
+ </BaseIcon>
184
+ );
185
+
186
+ export const CatchIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#86EFAC', style }) => (
187
+ <BaseIcon size={size} color={color} style={style}>
188
+ <path
189
+ d="M7.16667 13.8333C10.8486 13.8333 13.8333 10.8486 13.8333 7.16667C13.8333 3.48477 10.8486 0.5 7.16667 0.5C3.48477 0.5 0.5 3.48477 0.5 7.16667C0.5 10.8486 3.48477 13.8333 7.16667 13.8333Z"
190
+ stroke={color}
191
+ strokeLinecap="round"
192
+ strokeLinejoin="round"
193
+ />
194
+ </BaseIcon>
195
+ );
196
+
197
+ export const TryCatchIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#86EFAC', style }) => (
198
+ <BaseIcon size={size} color={color} style={style}>
199
+ <path
200
+ d="M7.16667 13.8333C10.8486 13.8333 13.8333 10.8486 13.8333 7.16667C13.8333 3.48477 10.8486 0.5 7.16667 0.5C3.48477 0.5 0.5 3.48477 0.5 7.16667C0.5 10.8486 3.48477 13.8333 7.16667 13.8333Z"
201
+ stroke={color}
202
+ strokeLinecap="round"
203
+ strokeLinejoin="round"
204
+ />
205
+ </BaseIcon>
206
+ );
207
+
208
+ export const FunctionIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#86EFAC', style }) => (
209
+ <BaseIcon size={size} color={color} style={style}>
210
+ <path
211
+ d="M7.16667 13.8333C10.8486 13.8333 13.8333 10.8486 13.8333 7.16667C13.8333 3.48477 10.8486 0.5 7.16667 0.5C3.48477 0.5 0.5 3.48477 0.5 7.16667C0.5 10.8486 3.48477 13.8333 7.16667 13.8333Z"
212
+ stroke={color}
213
+ strokeLinecap="round"
214
+ strokeLinejoin="round"
215
+ />
216
+ </BaseIcon>
217
+ );
218
+
219
+ export const CallIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#86EFAC', style }) => (
220
+ <BaseIcon size={size} color={color} style={style}>
221
+ <path
222
+ d="M7.16667 13.8333C10.8486 13.8333 13.8333 10.8486 13.8333 7.16667C13.8333 3.48477 10.8486 0.5 7.16667 0.5C3.48477 0.5 0.5 3.48477 0.5 7.16667C0.5 10.8486 3.48477 13.8333 7.16667 13.8333Z"
223
+ stroke={color}
224
+ strokeLinecap="round"
225
+ strokeLinejoin="round"
226
+ />
227
+ </BaseIcon>
228
+ );
229
+
230
+ export const LetIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#86EFAC', style }) => (
231
+ <BaseIcon size={size} color={color} style={style}>
232
+ <path
233
+ d="M7.16667 13.8333C10.8486 13.8333 13.8333 10.8486 13.8333 7.16667C13.8333 3.48477 10.8486 0.5 7.16667 0.5C3.48477 0.5 0.5 3.48477 0.5 7.16667C0.5 10.8486 3.48477 13.8333 7.16667 13.8333Z"
234
+ stroke={color}
235
+ strokeLinecap="round"
236
+ strokeLinejoin="round"
237
+ />
238
+ </BaseIcon>
239
+ );
240
+
241
+ export const SetIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#86EFAC', style }) => (
242
+ <BaseIcon size={size} color={color} style={style}>
243
+ <path
244
+ d="M7.16667 13.8333C10.8486 13.8333 13.8333 10.8486 13.8333 7.16667C13.8333 3.48477 10.8486 0.5 7.16667 0.5C3.48477 0.5 0.5 3.48477 0.5 7.16667C0.5 10.8486 3.48477 13.8333 7.16667 13.8333Z"
245
+ stroke={color}
246
+ strokeLinecap="round"
247
+ strokeLinejoin="round"
248
+ />
249
+ </BaseIcon>
250
+ );
251
+
252
+ export const EmptyNodeIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#86EFAC', style }) => (
253
+ <BaseIcon size={size} color={color} style={style}>
254
+ <path
255
+ d="M7.16667 13.8333C10.8486 13.8333 13.8333 10.8486 13.8333 7.16667C13.8333 3.48477 10.8486 0.5 7.16667 0.5C3.48477 0.5 0.5 3.48477 0.5 7.16667C0.5 10.8486 3.48477 13.8333 7.16667 13.8333Z"
256
+ stroke={color}
257
+ strokeLinecap="round"
258
+ strokeLinejoin="round"
259
+ />
260
+ </BaseIcon>
261
+ );
262
+
263
+ export const EntityIcon: React.FC<SvgIconProps> = ({ size = 15, color = '#86EFAC', style }) => (
264
+ <BaseIcon size={size} color={color} style={style}>
265
+ <path
266
+ d="M7.16667 13.8333C10.8486 13.8333 13.8333 10.8486 13.8333 7.16667C13.8333 3.48477 10.8486 0.5 7.16667 0.5C3.48477 0.5 0.5 3.48477 0.5 7.16667C0.5 10.8486 3.48477 13.8333 7.16667 13.8333Z"
267
+ stroke={color}
268
+ strokeLinecap="round"
269
+ strokeLinejoin="round"
270
+ />
271
+ </BaseIcon>
272
+ );
273
+
274
+ // End Node Icon
275
+ export const EndNodeIcon: React.FC<SvgIconProps> = ({ size = 13, color = '#FCA5A5', style }) => (
276
+ <svg
277
+ width={size}
278
+ height={size}
279
+ viewBox="0 0 13 13"
280
+ fill="none"
281
+ xmlns="http://www.w3.org/2000/svg"
282
+ style={style}
283
+ >
284
+ <path
285
+ d="M11.1667 0.5H1.83333C1.09695 0.5 0.5 1.09695 0.5 1.83333V11.1667C0.5 11.903 1.09695 12.5 1.83333 12.5H11.1667C11.903 12.5 12.5 11.903 12.5 11.1667V1.83333C12.5 1.09695 11.903 0.5 11.1667 0.5Z"
286
+ stroke={color}
287
+ strokeLinecap="round"
288
+ strokeLinejoin="round"
289
+ />
290
+ </svg>
291
+ );
@@ -0,0 +1,25 @@
1
+ // Export types
2
+ export type { SvgIconProps } from './types';
3
+
4
+ // Export all icons from single icons file
5
+ export {
6
+ ArticleAnalyzerIcon,
7
+ StartNodeIcon,
8
+ EndNodeIcon,
9
+ NavigationIcon,
10
+ ParallelIcon,
11
+ BranchIcon,
12
+ GroupIcon,
13
+ ReturnIcon,
14
+ LoopIcon,
15
+ SwitchIcon,
16
+ TryIcon,
17
+ CatchIcon,
18
+ TryCatchIcon,
19
+ FunctionIcon,
20
+ CallIcon,
21
+ LetIcon,
22
+ SetIcon,
23
+ EmptyNodeIcon,
24
+ EntityIcon,
25
+ } from './icons';
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+
3
+ export interface SvgIconProps {
4
+ size?: number;
5
+ color?: string;
6
+ style?: React.CSSProperties;
7
+ }