@d34dman/flowdrop 0.0.57 → 0.0.59

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 (54) hide show
  1. package/README.md +9 -8
  2. package/dist/adapters/WorkflowAdapter.d.ts +2 -1
  3. package/dist/adapters/agentspec/AgentSpecAdapter.d.ts +4 -0
  4. package/dist/adapters/agentspec/AgentSpecAdapter.js +27 -22
  5. package/dist/adapters/agentspec/componentTypeDefaults.d.ts +73 -0
  6. package/dist/adapters/agentspec/componentTypeDefaults.js +238 -0
  7. package/dist/adapters/agentspec/{nodeTypeRegistry.d.ts → defaultNodeTypes.d.ts} +21 -30
  8. package/dist/adapters/agentspec/{nodeTypeRegistry.js → defaultNodeTypes.js} +31 -59
  9. package/dist/adapters/agentspec/index.d.ts +3 -1
  10. package/dist/adapters/agentspec/index.js +4 -2
  11. package/dist/components/App.svelte +57 -13
  12. package/dist/components/NodeSidebar.svelte +20 -8
  13. package/dist/components/NodeSidebar.svelte.d.ts +2 -1
  14. package/dist/components/WorkflowEditor.svelte +14 -13
  15. package/dist/components/form/FormMarkdownEditor.svelte +546 -422
  16. package/dist/components/form/FormMarkdownEditor.svelte.d.ts +2 -0
  17. package/dist/components/form/FormUISchemaRenderer.svelte +4 -8
  18. package/dist/components/form/types.d.ts +1 -1
  19. package/dist/components/nodes/WorkflowNode.svelte +1 -2
  20. package/dist/core/index.d.ts +13 -3
  21. package/dist/core/index.js +16 -3
  22. package/dist/form/code.js +6 -1
  23. package/dist/form/fieldRegistry.d.ts +79 -15
  24. package/dist/form/fieldRegistry.js +104 -49
  25. package/dist/form/full.d.ts +2 -2
  26. package/dist/form/full.js +2 -2
  27. package/dist/form/index.d.ts +3 -3
  28. package/dist/form/index.js +6 -2
  29. package/dist/form/markdown.d.ts +3 -3
  30. package/dist/form/markdown.js +8 -4
  31. package/dist/index.d.ts +2 -2
  32. package/dist/index.js +2 -2
  33. package/dist/registry/BaseRegistry.d.ts +92 -0
  34. package/dist/registry/BaseRegistry.js +124 -0
  35. package/dist/registry/builtinFormats.d.ts +23 -0
  36. package/dist/registry/builtinFormats.js +70 -0
  37. package/dist/registry/builtinNodes.js +4 -0
  38. package/dist/registry/index.d.ts +2 -1
  39. package/dist/registry/index.js +2 -0
  40. package/dist/registry/nodeComponentRegistry.d.ts +26 -57
  41. package/dist/registry/nodeComponentRegistry.js +29 -82
  42. package/dist/registry/workflowFormatRegistry.d.ts +122 -0
  43. package/dist/registry/workflowFormatRegistry.js +96 -0
  44. package/dist/schema/index.d.ts +23 -0
  45. package/dist/schema/index.js +23 -0
  46. package/dist/schemas/v1/workflow.schema.json +1078 -0
  47. package/dist/stores/portCoordinateStore.js +1 -4
  48. package/dist/stores/workflowStore.d.ts +3 -0
  49. package/dist/stores/workflowStore.js +3 -0
  50. package/dist/svelte-app.d.ts +4 -0
  51. package/dist/svelte-app.js +9 -1
  52. package/dist/types/index.d.ts +18 -0
  53. package/dist/types/index.js +4 -0
  54. package/package.json +20 -13
@@ -1,30 +1,24 @@
1
1
  /**
2
- * Agent Spec Node Type Registry
2
+ * Agent Spec Default Node Types
3
3
  *
4
- * Maps Agent Spec component types to FlowDrop NodeMetadata definitions.
5
- * Each Agent Spec node type gets a full NodeMetadata with visual type,
6
- * category, default ports, config schema, and icon.
4
+ * Provides optional starter node type definitions for the Agent Spec format.
5
+ * These are full NodeMetadata objects with visual type, category, default ports,
6
+ * config schema, and icon — suitable for populating the sidebar.
7
+ *
8
+ * These definitions are NOT required by the adapter — the adapter uses
9
+ * componentTypeDefaults.ts for import/export infrastructure.
10
+ * Users can provide their own node definitions instead.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { getDefaultAgentSpecNodeTypes } from '@d34dman/flowdrop/core';
15
+ *
16
+ * mountFlowDropApp(container, {
17
+ * nodes: getDefaultAgentSpecNodeTypes(), // or your own definitions
18
+ * });
19
+ * ```
7
20
  */
8
- /** Namespace prefix for Agent Spec node type IDs */
9
- const AGENTSPEC_NS = 'agentspec';
10
- /** Standard trigger input port shared by most nodes */
11
- const TRIGGER_INPUT = {
12
- id: 'trigger',
13
- name: 'Trigger',
14
- type: 'input',
15
- dataType: 'trigger',
16
- required: false,
17
- description: 'Control flow input'
18
- };
19
- /** Standard trigger output port shared by most nodes */
20
- const TRIGGER_OUTPUT = {
21
- id: 'trigger',
22
- name: 'Trigger',
23
- type: 'output',
24
- dataType: 'trigger',
25
- required: false,
26
- description: 'Control flow output'
27
- };
21
+ import { AGENTSPEC_NAMESPACE as AGENTSPEC_NS, TRIGGER_INPUT, TRIGGER_OUTPUT } from './componentTypeDefaults.js';
28
22
  /**
29
23
  * Build the full registry of Agent Spec node types.
30
24
  */
@@ -51,6 +45,7 @@ function buildRegistry() {
51
45
  type: 'object',
52
46
  properties: {}
53
47
  },
48
+ formats: ['agentspec'],
54
49
  extensions: { 'agentspec:component_type': 'start_node' }
55
50
  }
56
51
  });
@@ -75,6 +70,7 @@ function buildRegistry() {
75
70
  type: 'object',
76
71
  properties: {}
77
72
  },
73
+ formats: ['agentspec'],
78
74
  extensions: { 'agentspec:component_type': 'end_node' }
79
75
  }
80
76
  });
@@ -139,6 +135,7 @@ function buildRegistry() {
139
135
  }
140
136
  }
141
137
  },
138
+ formats: ['agentspec'],
142
139
  extensions: { 'agentspec:component_type': 'llm_node' }
143
140
  }
144
141
  });
@@ -206,6 +203,7 @@ function buildRegistry() {
206
203
  }
207
204
  }
208
205
  },
206
+ formats: ['agentspec'],
209
207
  extensions: { 'agentspec:component_type': 'branching_node' }
210
208
  }
211
209
  });
@@ -263,6 +261,7 @@ function buildRegistry() {
263
261
  }
264
262
  }
265
263
  },
264
+ formats: ['agentspec'],
266
265
  extensions: { 'agentspec:component_type': 'tool_node' }
267
266
  }
268
267
  });
@@ -333,6 +332,7 @@ function buildRegistry() {
333
332
  }
334
333
  }
335
334
  },
335
+ formats: ['agentspec'],
336
336
  extensions: { 'agentspec:component_type': 'api_node' }
337
337
  }
338
338
  });
@@ -390,6 +390,7 @@ function buildRegistry() {
390
390
  }
391
391
  }
392
392
  },
393
+ formats: ['agentspec'],
393
394
  extensions: { 'agentspec:component_type': 'agent_node' }
394
395
  }
395
396
  });
@@ -440,6 +441,7 @@ function buildRegistry() {
440
441
  }
441
442
  }
442
443
  },
444
+ formats: ['agentspec'],
443
445
  extensions: { 'agentspec:component_type': 'flow_node' }
444
446
  }
445
447
  });
@@ -502,6 +504,7 @@ function buildRegistry() {
502
504
  }
503
505
  }
504
506
  },
507
+ formats: ['agentspec'],
505
508
  extensions: { 'agentspec:component_type': 'map_node' }
506
509
  }
507
510
  });
@@ -528,12 +531,12 @@ export function getAgentSpecNodeMetadata(componentType) {
528
531
  return registry.get(componentType)?.metadata;
529
532
  }
530
533
  /**
531
- * Get all Agent Spec node types as FlowDrop NodeMetadata.
532
- * Useful for populating the node sidebar with Agent Spec node types.
534
+ * Get all default Agent Spec node types as FlowDrop NodeMetadata.
535
+ * These are starter templates users can provide their own node types instead.
533
536
  *
534
- * @returns Array of NodeMetadata for all 9 Agent Spec node types
537
+ * @returns Array of NodeMetadata for all 9 default Agent Spec node types
535
538
  */
536
- export function getAllAgentSpecNodeTypes() {
539
+ export function getDefaultAgentSpecNodeTypes() {
537
540
  return Array.from(registry.values()).map((entry) => entry.metadata);
538
541
  }
539
542
  /**
@@ -556,34 +559,3 @@ export function createAgentSpecNodeMetadata(componentType, inputs, outputs) {
556
559
  outputs: outputs ?? base.outputs
557
560
  };
558
561
  }
559
- /**
560
- * Check if a FlowDrop node ID belongs to an Agent Spec node type.
561
- *
562
- * @example
563
- * ```typescript
564
- * isAgentSpecNodeId('agentspec.llm_node') // true
565
- * isAgentSpecNodeId('calculator') // false
566
- * ```
567
- */
568
- export function isAgentSpecNodeId(nodeId) {
569
- return nodeId.startsWith(`${AGENTSPEC_NS}.`);
570
- }
571
- /**
572
- * Extract the Agent Spec component_type from a FlowDrop node type ID.
573
- *
574
- * @example
575
- * ```typescript
576
- * extractComponentType('agentspec.llm_node') // 'llm_node'
577
- * extractComponentType('calculator') // undefined
578
- * ```
579
- */
580
- export function extractComponentType(nodeTypeId) {
581
- if (!isAgentSpecNodeId(nodeTypeId))
582
- return undefined;
583
- const componentType = nodeTypeId.slice(AGENTSPEC_NS.length + 1);
584
- return registry.has(componentType)
585
- ? componentType
586
- : undefined;
587
- }
588
- /** The namespace prefix used for Agent Spec node type IDs */
589
- export const AGENTSPEC_NAMESPACE = AGENTSPEC_NS;
@@ -28,7 +28,9 @@
28
28
  export { AgentSpecAdapter } from './AgentSpecAdapter.js';
29
29
  export { AgentSpecAgentAdapter } from './agentAdapter.js';
30
30
  export type { AgentConfig, AgentSpecImportResult } from './agentAdapter.js';
31
- export { getAgentSpecNodeMetadata, getAllAgentSpecNodeTypes, createAgentSpecNodeMetadata, isAgentSpecNodeId, extractComponentType, AGENTSPEC_NAMESPACE } from './nodeTypeRegistry.js';
31
+ export { getAgentSpecNodeMetadata, getDefaultAgentSpecNodeTypes, createAgentSpecNodeMetadata } from './defaultNodeTypes.js';
32
+ export { getComponentTypeDefaults, extractComponentType, isAgentSpecNodeId, AGENTSPEC_NAMESPACE } from './componentTypeDefaults.js';
33
+ export type { ComponentTypeDefaults } from './componentTypeDefaults.js';
32
34
  export { validateForAgentSpecExport, validateAgentSpecFlow } from './validator.js';
33
35
  export type { AgentSpecValidationResult } from './validator.js';
34
36
  export { computeAutoLayout } from './autoLayout.js';
@@ -29,8 +29,10 @@
29
29
  export { AgentSpecAdapter } from './AgentSpecAdapter.js';
30
30
  // Agent-level adapter (wraps flow with agent/tools/LLM config)
31
31
  export { AgentSpecAgentAdapter } from './agentAdapter.js';
32
- // Node type registry
33
- export { getAgentSpecNodeMetadata, getAllAgentSpecNodeTypes, createAgentSpecNodeMetadata, isAgentSpecNodeId, extractComponentType, AGENTSPEC_NAMESPACE } from './nodeTypeRegistry.js';
32
+ // Default node types (optional starter templates — users can provide their own)
33
+ export { getAgentSpecNodeMetadata, getDefaultAgentSpecNodeTypes, createAgentSpecNodeMetadata } from './defaultNodeTypes.js';
34
+ // Component type defaults (adapter infrastructure)
35
+ export { getComponentTypeDefaults, extractComponentType, isAgentSpecNodeId, AGENTSPEC_NAMESPACE } from './componentTypeDefaults.js';
34
36
  // Validation
35
37
  export { validateForAgentSpecExport, validateAgentSpecFlow } from './validator.js';
36
38
  // Auto-layout
@@ -22,6 +22,7 @@
22
22
  ConfigSchema,
23
23
  NodeUIExtensions
24
24
  } from '../types/index.js';
25
+ import { DEFAULT_WORKFLOW_FORMAT } from '../types/index.js';
25
26
  import { createEndpointConfig } from '../config/endpoints.js';
26
27
  import type { EndpointConfig } from '../config/endpoints.js';
27
28
  import type { AuthProvider } from '../types/auth.js';
@@ -31,6 +32,7 @@
31
32
  workflowStore,
32
33
  workflowActions,
33
34
  workflowName,
35
+ workflowFormat,
34
36
  markAsSaved
35
37
  } from '../stores/workflowStore.js';
36
38
  import { apiToasts, dismissToast } from '../services/toastService.js';
@@ -38,6 +40,7 @@
38
40
  import { uiSettings } from '../stores/settingsStore.js';
39
41
  import { initializePortCompatibility } from '../utils/connections.js';
40
42
  import { DEFAULT_PORT_CONFIG } from '../config/defaultPortConfig.js';
43
+ import { workflowFormatRegistry } from '../registry/workflowFormatRegistry.js';
41
44
 
42
45
  /**
43
46
  * Configuration props for runtime customization
@@ -143,9 +146,9 @@
143
146
  // Workflow settings sidebar state
144
147
  let isWorkflowSettingsOpen = $state(false);
145
148
 
146
- // Workflow configuration schema
147
- const workflowConfigSchema: ConfigSchema = {
148
- type: 'object',
149
+ // Workflow configuration schema (derived to pick up dynamic format options)
150
+ let workflowConfigSchema: ConfigSchema = $derived({
151
+ type: 'object' as const,
149
152
  properties: {
150
153
  name: {
151
154
  type: 'string',
@@ -159,15 +162,23 @@
159
162
  description: 'A description of the workflow',
160
163
  format: 'multiline',
161
164
  default: ''
165
+ },
166
+ format: {
167
+ type: 'string',
168
+ title: 'Workflow Format',
169
+ description: 'The specification format for this workflow',
170
+ oneOf: workflowFormatRegistry.getOneOfOptions(),
171
+ default: 'flowdrop'
162
172
  }
163
173
  },
164
174
  required: ['name']
165
- };
175
+ });
166
176
 
167
177
  // Workflow configuration values
168
178
  let workflowConfigValues = $derived({
169
179
  name: $workflowName || '',
170
- description: $workflowStore?.description || ''
180
+ description: $workflowStore?.description || '',
181
+ format: $workflowStore?.metadata?.format || 'flowdrop'
171
182
  });
172
183
 
173
184
  // Get the current node from the workflow store
@@ -188,7 +199,11 @@
188
199
  async function fetchNodeTypes(): Promise<void> {
189
200
  // If nodes were provided as props, use them directly (skip API fetch)
190
201
  if (propNodes && propNodes.length > 0) {
191
- nodes = propNodes;
202
+ // Merge format-provided nodes with prop nodes (deduplicate by ID, props take priority)
203
+ const formatNodes = workflowFormatRegistry.getAllFormatNodes();
204
+ const existingIds = new Set(propNodes.map((n) => n.id));
205
+ const uniqueFormatNodes = formatNodes.filter((n) => !existingIds.has(n.id));
206
+ nodes = [...propNodes, ...uniqueFormatNodes];
192
207
  return;
193
208
  }
194
209
 
@@ -205,7 +220,11 @@
205
220
  fetchedNodes = await api.nodes.getNodes();
206
221
  }
207
222
 
208
- nodes = fetchedNodes;
223
+ // Merge format-provided nodes with API nodes (deduplicate by ID, API takes priority)
224
+ const formatNodes = workflowFormatRegistry.getAllFormatNodes();
225
+ const existingIds = new Set(fetchedNodes.map((n) => n.id));
226
+ const uniqueFormatNodes = formatNodes.filter((n) => !existingIds.has(n.id));
227
+ nodes = [...fetchedNodes, ...uniqueFormatNodes];
209
228
  error = null;
210
229
 
211
230
  // Dismiss loading toast
@@ -430,7 +449,7 @@
430
449
  workflowId = uuidv4();
431
450
  }
432
451
 
433
- // Create workflow object for saving
452
+ // Create workflow object for saving (spread existing metadata to preserve format, tags, etc.)
434
453
  const finalWorkflow: Workflow = {
435
454
  id: workflowId,
436
455
  name: workflowToSave.name || 'Untitled Workflow',
@@ -438,7 +457,9 @@
438
457
  nodes: workflowToSave.nodes || [],
439
458
  edges: workflowToSave.edges || [],
440
459
  metadata: {
441
- version: '1.0.0',
460
+ ...workflowToSave.metadata,
461
+ version: workflowToSave.metadata?.version || '1.0.0',
462
+ format: workflowToSave.metadata?.format || DEFAULT_WORKFLOW_FORMAT,
442
463
  createdAt: workflowToSave.metadata?.createdAt || new Date().toISOString(),
443
464
  updatedAt: new Date().toISOString()
444
465
  }
@@ -538,14 +559,16 @@
538
559
  return;
539
560
  }
540
561
 
541
- // Create workflow object for export
562
+ // Create workflow object for export (spread existing metadata to preserve format, tags, etc.)
542
563
  const finalWorkflow = {
543
564
  id: workflowToExport.id || 'untitled-workflow',
544
565
  name: workflowToExport.name || 'Untitled Workflow',
545
566
  nodes: workflowToExport.nodes || [],
546
567
  edges: workflowToExport.edges || [],
547
568
  metadata: {
548
- version: '1.0.0',
569
+ ...workflowToExport.metadata,
570
+ version: workflowToExport.metadata?.version || '1.0.0',
571
+ format: workflowToExport.metadata?.format || DEFAULT_WORKFLOW_FORMAT,
549
572
  createdAt: workflowToExport.metadata?.createdAt || new Date().toISOString(),
550
573
  updatedAt: new Date().toISOString()
551
574
  }
@@ -722,7 +745,7 @@
722
745
 
723
746
  <!-- Left Sidebar: Node Components -->
724
747
  {#snippet leftSidebar()}
725
- <NodeSidebar {nodes} />
748
+ <NodeSidebar {nodes} activeFormat={$workflowFormat} />
726
749
  {/snippet}
727
750
 
728
751
  <!-- Right Sidebar: Configuration or Workflow Settings -->
@@ -746,9 +769,30 @@
746
769
  onChange={(config) => {
747
770
  // Sync workflow settings changes immediately on field blur
748
771
  if ($workflowStore) {
772
+ const newFormat = (config.format as string) || DEFAULT_WORKFLOW_FORMAT;
773
+ const currentFormat = $workflowStore.metadata?.format || DEFAULT_WORKFLOW_FORMAT;
774
+
775
+ // Warn about incompatible nodes when format changes
776
+ if (newFormat !== currentFormat) {
777
+ const incompatibleNodes = $workflowStore.nodes?.filter((node) => {
778
+ const formats = node.data?.metadata?.formats;
779
+ return formats && formats.length > 0 && !formats.includes(newFormat);
780
+ });
781
+ if (incompatibleNodes && incompatibleNodes.length > 0) {
782
+ console.warn(
783
+ `Format changed to '${newFormat}'. ${incompatibleNodes.length} node(s) are not compatible with this format and may not export correctly:`,
784
+ incompatibleNodes.map((n) => n.data?.label || n.type)
785
+ );
786
+ }
787
+ }
788
+
749
789
  workflowActions.batchUpdate({
750
790
  name: config.name as string,
751
- description: config.description as string | undefined
791
+ description: config.description as string | undefined,
792
+ metadata: {
793
+ ...$workflowStore.metadata,
794
+ format: newFormat
795
+ }
752
796
  });
753
797
  }
754
798
  }}
@@ -5,7 +5,7 @@
5
5
  -->
6
6
 
7
7
  <script lang="ts">
8
- import type { NodeMetadata, NodeCategory } from '../types/index.js';
8
+ import type { NodeMetadata, NodeCategory, WorkflowFormat } from '../types/index.js';
9
9
  import LoadingSpinner from './LoadingSpinner.svelte';
10
10
  import Icon from '@iconify/svelte';
11
11
  import { getNodeIcon, getCategoryIcon } from '../utils/icons.js';
@@ -17,6 +17,7 @@
17
17
  interface Props {
18
18
  nodes: NodeMetadata[];
19
19
  selectedCategory?: NodeCategory;
20
+ activeFormat?: WorkflowFormat;
20
21
  }
21
22
 
22
23
  let props: Props = $props();
@@ -31,6 +32,19 @@
31
32
  updateSettings({ ui: { sidebarCollapsed: !$uiSettings.sidebarCollapsed } });
32
33
  }
33
34
 
35
+ /**
36
+ * Check if a node is compatible with the active workflow format.
37
+ * Nodes without formats are universal (compatible with all formats).
38
+ */
39
+ function isNodeCompatibleWithFormat(node: NodeMetadata): boolean {
40
+ if (!props.activeFormat) return true;
41
+ if (!node.formats || node.formats.length === 0) return true;
42
+ return node.formats.includes(props.activeFormat);
43
+ }
44
+
45
+ /** Nodes filtered by format compatibility */
46
+ let formatCompatibleNodes = $derived((props.nodes || []).filter(isNodeCompatibleWithFormat));
47
+
34
48
  let filteredNodes = $derived(getFilteredNodes());
35
49
  let categories = $derived(getCategories());
36
50
 
@@ -39,12 +53,11 @@
39
53
  * Categories appear in the order their first node appears in the API response
40
54
  */
41
55
  function getCategories(): NodeCategory[] {
42
- const nodes = props.nodes || [];
43
- if (nodes.length === 0) return [];
56
+ if (formatCompatibleNodes.length === 0) return [];
44
57
  // Use a Set to track uniqueness while preserving insertion order
45
58
  const seen = new SvelteSet<NodeCategory>();
46
59
  const orderedCategories: NodeCategory[] = [];
47
- for (const node of nodes) {
60
+ for (const node of formatCompatibleNodes) {
48
61
  if (!seen.has(node.category)) {
49
62
  seen.add(node.category);
50
63
  orderedCategories.push(node.category);
@@ -58,8 +71,8 @@
58
71
  * Preserves the API order - no client-side sorting applied
59
72
  */
60
73
  function getFilteredNodes(): NodeMetadata[] {
61
- // Use actual node types from props
62
- let filtered = props.nodes || [];
74
+ // Start with format-compatible nodes
75
+ let filtered = formatCompatibleNodes;
63
76
 
64
77
  // Filter by category
65
78
  if (selectedCategory !== 'all') {
@@ -155,8 +168,7 @@
155
168
  * Preserves the API order - no client-side sorting applied
156
169
  */
157
170
  function getNodesForCategory(category: NodeCategory): NodeMetadata[] {
158
- const nodes = props.nodes || [];
159
- return nodes.filter((node) => node.category === category);
171
+ return formatCompatibleNodes.filter((node) => node.category === category);
160
172
  }
161
173
 
162
174
  /**
@@ -1,7 +1,8 @@
1
- import type { NodeMetadata, NodeCategory } from '../types/index.js';
1
+ import type { NodeMetadata, NodeCategory, WorkflowFormat } from '../types/index.js';
2
2
  interface Props {
3
3
  nodes: NodeMetadata[];
4
4
  selectedCategory?: NodeCategory;
5
+ activeFormat?: WorkflowFormat;
5
6
  }
6
7
  declare const NodeSidebar: import("svelte").Component<Props, {}, "">;
7
8
  type NodeSidebar = ReturnType<typeof NodeSidebar>;
@@ -387,19 +387,20 @@
387
387
 
388
388
  // Find the best compatible edge using port-to-port distance
389
389
  const portCoordinates = getPortCoordinateSnapshot();
390
- const candidates = portCoordinates.size > 0
391
- ? ProximityConnectHelper.findCompatibleEdgesByPortCoordinates(
392
- targetNode.id,
393
- portCoordinates,
394
- baseEdges,
395
- $editorSettings.proximityConnectDistance
396
- )
397
- : ProximityConnectHelper.findCompatibleEdges(
398
- targetNode,
399
- flowNodes,
400
- baseEdges,
401
- $editorSettings.proximityConnectDistance
402
- );
390
+ const candidates =
391
+ portCoordinates.size > 0
392
+ ? ProximityConnectHelper.findCompatibleEdgesByPortCoordinates(
393
+ targetNode.id,
394
+ portCoordinates,
395
+ baseEdges,
396
+ $editorSettings.proximityConnectDistance
397
+ )
398
+ : ProximityConnectHelper.findCompatibleEdges(
399
+ targetNode,
400
+ flowNodes,
401
+ baseEdges,
402
+ $editorSettings.proximityConnectDistance
403
+ );
403
404
 
404
405
  // Create preview edges
405
406
  const previews = ProximityConnectHelper.createPreviewEdges(candidates);