@flowdrop/flowdrop 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/README.md +68 -24
  2. package/dist/adapters/WorkflowAdapter.js +2 -22
  3. package/dist/adapters/agentspec/autoLayout.d.ts +51 -5
  4. package/dist/adapters/agentspec/autoLayout.js +120 -23
  5. package/dist/chat/commandClassifier.d.ts +19 -0
  6. package/dist/chat/commandClassifier.js +30 -0
  7. package/dist/chat/index.d.ts +27 -0
  8. package/dist/chat/index.js +32 -0
  9. package/dist/chat/responseParser.d.ts +21 -0
  10. package/dist/chat/responseParser.js +87 -0
  11. package/dist/commands/batch.d.ts +18 -0
  12. package/dist/commands/batch.js +56 -0
  13. package/dist/commands/executor.d.ts +37 -0
  14. package/dist/commands/executor.js +1044 -0
  15. package/dist/commands/index.d.ts +14 -0
  16. package/dist/commands/index.js +17 -0
  17. package/dist/commands/parser.d.ts +16 -0
  18. package/dist/commands/parser.js +278 -0
  19. package/dist/commands/positioner.d.ts +19 -0
  20. package/dist/commands/positioner.js +33 -0
  21. package/dist/commands/storeIntegration.svelte.d.ts +16 -0
  22. package/dist/commands/storeIntegration.svelte.js +67 -0
  23. package/dist/commands/types.d.ts +343 -0
  24. package/dist/commands/types.js +45 -0
  25. package/dist/components/App.svelte +351 -12
  26. package/dist/components/App.svelte.d.ts +3 -0
  27. package/dist/components/CanvasController.svelte +38 -0
  28. package/dist/components/CanvasController.svelte.d.ts +32 -0
  29. package/dist/components/ConfigMappingRow.svelte +130 -0
  30. package/dist/components/ConfigMappingRow.svelte.d.ts +8 -0
  31. package/dist/components/ConfigPanel.svelte +56 -7
  32. package/dist/components/ConfigPanel.svelte.d.ts +2 -0
  33. package/dist/components/FlowDropEdge.svelte +2 -10
  34. package/dist/components/LogsSidebar.svelte +5 -5
  35. package/dist/components/NodeSidebar.svelte +15 -49
  36. package/dist/components/NodeSwapPicker.svelte +537 -0
  37. package/dist/components/NodeSwapPicker.svelte.d.ts +16 -0
  38. package/dist/components/PortMappingRow.svelte +209 -0
  39. package/dist/components/PortMappingRow.svelte.d.ts +12 -0
  40. package/dist/components/SwapMappingEditor.svelte +550 -0
  41. package/dist/components/SwapMappingEditor.svelte.d.ts +12 -0
  42. package/dist/components/WorkflowEditor.svelte +99 -4
  43. package/dist/components/WorkflowEditor.svelte.d.ts +8 -0
  44. package/dist/components/chat/AIChatPanel.svelte +658 -0
  45. package/dist/components/chat/AIChatPanel.svelte.d.ts +13 -0
  46. package/dist/components/chat/CommandPreview.svelte +184 -0
  47. package/dist/components/chat/CommandPreview.svelte.d.ts +9 -0
  48. package/dist/components/console/CommandConsole.stories.svelte +93 -0
  49. package/dist/components/console/CommandConsole.stories.svelte.d.ts +27 -0
  50. package/dist/components/console/CommandConsole.svelte +259 -0
  51. package/dist/components/console/CommandConsole.svelte.d.ts +11 -0
  52. package/dist/components/console/ConsoleAutocomplete.svelte +139 -0
  53. package/dist/components/console/ConsoleAutocomplete.svelte.d.ts +21 -0
  54. package/dist/components/console/ConsoleInput.svelte +712 -0
  55. package/dist/components/console/ConsoleInput.svelte.d.ts +16 -0
  56. package/dist/components/console/ConsoleOutput.svelte +121 -0
  57. package/dist/components/console/ConsoleOutput.svelte.d.ts +11 -0
  58. package/dist/components/console/formatters.d.ts +26 -0
  59. package/dist/components/console/formatters.js +118 -0
  60. package/dist/components/interrupt/index.d.ts +1 -0
  61. package/dist/components/interrupt/index.js +1 -0
  62. package/dist/config/endpoints.d.ts +8 -0
  63. package/dist/config/endpoints.js +5 -0
  64. package/dist/core/index.d.ts +5 -0
  65. package/dist/core/index.js +9 -0
  66. package/dist/editor/index.d.ts +3 -1
  67. package/dist/editor/index.js +4 -2
  68. package/dist/helpers/proximityConnect.js +8 -1
  69. package/dist/helpers/workflowEditorHelper.d.ts +3 -53
  70. package/dist/helpers/workflowEditorHelper.js +13 -228
  71. package/dist/playground/index.d.ts +1 -1
  72. package/dist/playground/index.js +1 -1
  73. package/dist/schemas/v1/workflow.schema.json +107 -22
  74. package/dist/services/chatService.d.ts +65 -0
  75. package/dist/services/chatService.js +131 -0
  76. package/dist/services/historyService.d.ts +6 -4
  77. package/dist/services/historyService.js +21 -6
  78. package/dist/stores/interruptStore.svelte.js +6 -1
  79. package/dist/stores/playgroundStore.svelte.d.ts +1 -1
  80. package/dist/stores/playgroundStore.svelte.js +11 -2
  81. package/dist/stores/portCoordinateStore.svelte.d.ts +4 -0
  82. package/dist/stores/portCoordinateStore.svelte.js +20 -26
  83. package/dist/stores/workflowStore.svelte.d.ts +31 -2
  84. package/dist/stores/workflowStore.svelte.js +84 -64
  85. package/dist/types/chat.d.ts +63 -0
  86. package/dist/types/chat.js +9 -0
  87. package/dist/types/events.d.ts +28 -2
  88. package/dist/types/events.js +1 -0
  89. package/dist/types/index.d.ts +8 -0
  90. package/dist/types/settings.d.ts +6 -0
  91. package/dist/types/settings.js +3 -0
  92. package/dist/utils/edgeStyling.d.ts +42 -0
  93. package/dist/utils/edgeStyling.js +176 -0
  94. package/dist/utils/nodeIds.d.ts +31 -0
  95. package/dist/utils/nodeIds.js +42 -0
  96. package/dist/utils/nodeSwap.d.ts +221 -0
  97. package/dist/utils/nodeSwap.js +686 -0
  98. package/package.json +6 -1
  99. package/dist/helpers/nodeLayoutHelper.d.ts +0 -14
  100. package/dist/helpers/nodeLayoutHelper.js +0 -19
@@ -0,0 +1,550 @@
1
+ <!--
2
+ SwapMappingEditor Component
3
+ Interactive mapping editor for node swap with connections and config sections.
4
+ Replaces the read-only SwapPreview component.
5
+ Styled with BEM syntax.
6
+ -->
7
+
8
+ <script lang="ts">
9
+ import { untrack } from "svelte";
10
+ import type { InteractiveSwapState } from "../utils/nodeSwap.js";
11
+ import type { PortCompatibilityChecker } from "../utils/connections.js";
12
+ import Icon from "@iconify/svelte";
13
+ import { getNodeIcon } from "../utils/icons.js";
14
+ import { getCategoryColorToken } from "../utils/colors.js";
15
+ import PortMappingRow from "./PortMappingRow.svelte";
16
+ import ConfigMappingRow from "./ConfigMappingRow.svelte";
17
+
18
+ interface Props {
19
+ interactiveState: InteractiveSwapState;
20
+ checker: PortCompatibilityChecker | null;
21
+ onConfirm: (state: InteractiveSwapState) => void;
22
+ onCancel: () => void;
23
+ onBack: () => void;
24
+ }
25
+
26
+ const { interactiveState, checker, onConfirm, onCancel, onBack }: Props =
27
+ $props();
28
+
29
+ // Local mutable copy of the interactive state
30
+ // JSON round-trip is intentional: structuredClone fails on Svelte 5 proxies
31
+ let localState = $state<InteractiveSwapState>(
32
+ untrack(() => JSON.parse(JSON.stringify(interactiveState))),
33
+ );
34
+
35
+ // Reinit when interactiveState changes
36
+ $effect(() => {
37
+ localState = JSON.parse(JSON.stringify(interactiveState));
38
+ });
39
+
40
+ // Derived counts
41
+ let inputMappings = $derived(
42
+ localState.portMappings.filter((m) => m.direction === "input"),
43
+ );
44
+ let outputMappings = $derived(
45
+ localState.portMappings.filter((m) => m.direction === "output"),
46
+ );
47
+ let droppedCount = $derived(
48
+ localState.portMappings.filter((m) => !m.selectedNewPortId).length,
49
+ );
50
+ let connectionCount = $derived(localState.portMappings.length);
51
+ let hasDataLoss = $derived(droppedCount > 0);
52
+
53
+ // Used port IDs per direction
54
+ let usedInputPortIds = $derived.by(() => {
55
+ const set = new Set<string>();
56
+ for (const m of localState.portMappings) {
57
+ if (m.direction === "input" && m.selectedNewPortId) {
58
+ set.add(m.selectedNewPortId);
59
+ }
60
+ }
61
+ return set;
62
+ });
63
+
64
+ let usedOutputPortIds = $derived.by(() => {
65
+ const set = new Set<string>();
66
+ for (const m of localState.portMappings) {
67
+ if (m.direction === "output" && m.selectedNewPortId) {
68
+ set.add(m.selectedNewPortId);
69
+ }
70
+ }
71
+ return set;
72
+ });
73
+
74
+ // Trivial swap: no connections and no config
75
+ let isTrivial = $derived(
76
+ connectionCount === 0 && localState.configMappings.length === 0,
77
+ );
78
+
79
+ function handlePortUpdate(index: number, newPortId: string | null): void {
80
+ const mapping = localState.portMappings[index];
81
+ if (!mapping) return;
82
+
83
+ // For input ports: if this port is already used by another mapping, unmap the other
84
+ if (newPortId && mapping.direction === "input") {
85
+ for (let i = 0; i < localState.portMappings.length; i++) {
86
+ if (i === index) continue;
87
+ const other = localState.portMappings[i];
88
+ if (other.direction === "input" && other.selectedNewPortId === newPortId) {
89
+ localState.portMappings[i] = {
90
+ ...other,
91
+ selectedNewPortId: null,
92
+ matchQuality: "unmapped",
93
+ isOverridden: true,
94
+ };
95
+ }
96
+ }
97
+ }
98
+
99
+ localState.portMappings[index] = {
100
+ ...mapping,
101
+ selectedNewPortId: newPortId,
102
+ matchQuality: newPortId ? "manual" : "unmapped",
103
+ isOverridden: true,
104
+ };
105
+ }
106
+
107
+ function handlePortReset(index: number): void {
108
+ const mapping = localState.portMappings[index];
109
+ if (!mapping) return;
110
+
111
+ localState.portMappings[index] = {
112
+ ...mapping,
113
+ selectedNewPortId: mapping.autoSuggestedPortId,
114
+ matchQuality: mapping.autoSuggestedPortId
115
+ ? (interactiveState.portMappings[index]?.matchQuality ?? "type")
116
+ : "unmapped",
117
+ isOverridden: false,
118
+ };
119
+ }
120
+
121
+ function handleConfigToggle(key: string): void {
122
+ const idx = localState.configMappings.findIndex((m) => m.key === key);
123
+ if (idx < 0) return;
124
+ const mapping = localState.configMappings[idx];
125
+ if (!mapping.isFlat) return;
126
+
127
+ localState.configMappings[idx] = {
128
+ ...mapping,
129
+ carryOver: !mapping.carryOver,
130
+ };
131
+ }
132
+
133
+ function handleConfirm(): void {
134
+ onConfirm(localState);
135
+ }
136
+ </script>
137
+
138
+ <div class="swap-editor">
139
+ <!-- Header -->
140
+ <div class="swap-editor__header">
141
+ <button
142
+ class="swap-editor__back"
143
+ onclick={onBack}
144
+ aria-label="Back to node selection"
145
+ >
146
+ <Icon icon="heroicons:arrow-left" />
147
+ </button>
148
+ <h2 class="swap-editor__title">Swap Mapping</h2>
149
+ </div>
150
+
151
+ <!-- Summary bar -->
152
+ <div class="swap-editor__summary">
153
+ <div class="swap-editor__node-info">
154
+ <span class="swap-editor__label">From</span>
155
+ <span class="swap-editor__node-name">{localState.oldNode.data.label}</span>
156
+ </div>
157
+ <Icon icon="heroicons:arrow-right" />
158
+ <div class="swap-editor__node-info">
159
+ <span class="swap-editor__label">To</span>
160
+ <div class="swap-editor__node-target">
161
+ <span
162
+ class="swap-editor__node-icon"
163
+ style="--_icon-color: {getCategoryColorToken(localState.newMetadata.category)}"
164
+ >
165
+ <Icon icon={getNodeIcon(localState.newMetadata.icon, localState.newMetadata.category)} />
166
+ </span>
167
+ <span class="swap-editor__node-name">{localState.newMetadata.name}</span>
168
+ </div>
169
+ </div>
170
+ </div>
171
+
172
+ {#if isTrivial}
173
+ <div class="swap-editor__trivial">
174
+ <p>No connections or config to map.</p>
175
+ </div>
176
+ {:else}
177
+ <div class="swap-editor__content">
178
+ <!-- Connections section -->
179
+ {#if connectionCount > 0}
180
+ <div class="swap-editor__section-heading">
181
+ <Icon icon="heroicons:arrows-right-left" />
182
+ Connections
183
+ </div>
184
+
185
+ {#if inputMappings.length > 0}
186
+ <div class="swap-editor__section-label">Inputs</div>
187
+ {#each inputMappings as mapping, i (mapping.edge.id)}
188
+ {@const globalIndex = localState.portMappings.indexOf(mapping)}
189
+ <PortMappingRow
190
+ {mapping}
191
+ availablePorts={localState.availableNewInputs}
192
+ usedPortIds={usedInputPortIds}
193
+ onUpdate={(newPortId) => handlePortUpdate(globalIndex, newPortId)}
194
+ onReset={() => handlePortReset(globalIndex)}
195
+ />
196
+ {/each}
197
+ {/if}
198
+
199
+ {#if outputMappings.length > 0}
200
+ <div class="swap-editor__section-label">Outputs</div>
201
+ {#each outputMappings as mapping, i (mapping.edge.id)}
202
+ {@const globalIndex = localState.portMappings.indexOf(mapping)}
203
+ <PortMappingRow
204
+ {mapping}
205
+ availablePorts={localState.availableNewOutputs}
206
+ usedPortIds={usedOutputPortIds}
207
+ onUpdate={(newPortId) => handlePortUpdate(globalIndex, newPortId)}
208
+ onReset={() => handlePortReset(globalIndex)}
209
+ />
210
+ {/each}
211
+ {/if}
212
+ {/if}
213
+
214
+ <!-- Config section -->
215
+ {#if localState.configMappings.length > 0}
216
+ <div
217
+ class="swap-editor__section-heading"
218
+ class:swap-editor__section-heading--spaced={connectionCount > 0}
219
+ >
220
+ <Icon icon="heroicons:cog-6-tooth" />
221
+ Configuration
222
+ </div>
223
+ <p class="swap-editor__help">
224
+ <strong>Carry over</strong> keeps the value from your current node.
225
+ <strong>Use default</strong> resets to the new node's default value.
226
+ </p>
227
+
228
+ {#each localState.configMappings as mapping (mapping.key)}
229
+ <ConfigMappingRow {mapping} onToggle={handleConfigToggle} />
230
+ {/each}
231
+
232
+ {#if localState.configMappings.some((m) => !m.isFlat)}
233
+ <div class="swap-editor__info-row">
234
+ Dynamic port config will not be carried over.
235
+ </div>
236
+ {/if}
237
+ {/if}
238
+ </div>
239
+ {/if}
240
+
241
+ <!-- Warning banner -->
242
+ {#if hasDataLoss}
243
+ <div class="swap-editor__warning" role="alert">
244
+ <Icon icon="heroicons:exclamation-triangle" />
245
+ <span>{droppedCount} connection{droppedCount !== 1 ? "s" : ""} will be lost</span>
246
+ </div>
247
+ {/if}
248
+
249
+ <!-- Actions -->
250
+ <div class="swap-editor__actions">
251
+ <button class="swap-editor__btn swap-editor__btn--cancel" onclick={onCancel} type="button">
252
+ Cancel
253
+ </button>
254
+ <button
255
+ class="swap-editor__btn swap-editor__btn--confirm"
256
+ class:swap-editor__btn--danger={hasDataLoss}
257
+ onclick={handleConfirm}
258
+ type="button"
259
+ aria-label={hasDataLoss ? `Swap anyway — ${droppedCount} connections will be lost` : "Confirm swap"}
260
+ >
261
+ {hasDataLoss ? "Swap Anyway" : "Confirm Swap"}
262
+ </button>
263
+ </div>
264
+ </div>
265
+
266
+ <style>
267
+ .swap-editor {
268
+ height: 100%;
269
+ display: flex;
270
+ flex-direction: column;
271
+ background-color: var(--fd-background);
272
+ }
273
+
274
+ .swap-editor__header {
275
+ display: flex;
276
+ align-items: center;
277
+ gap: 0.5rem;
278
+ padding: 0.875rem 1rem;
279
+ border-bottom: 1px solid var(--fd-border);
280
+ background-color: var(--fd-muted);
281
+ flex-shrink: 0;
282
+ }
283
+
284
+ .swap-editor__back {
285
+ background: none;
286
+ border: none;
287
+ cursor: pointer;
288
+ color: var(--fd-muted-foreground);
289
+ padding: 0.25rem;
290
+ border-radius: var(--fd-radius-sm);
291
+ display: flex;
292
+ align-items: center;
293
+ transition:
294
+ color var(--fd-transition-fast),
295
+ background-color var(--fd-transition-fast);
296
+ }
297
+
298
+ .swap-editor__back:hover {
299
+ color: var(--fd-foreground);
300
+ background-color: var(--fd-subtle);
301
+ }
302
+
303
+ .swap-editor__title {
304
+ margin: 0;
305
+ font-size: 1rem;
306
+ font-weight: 600;
307
+ color: var(--fd-foreground);
308
+ }
309
+
310
+ .swap-editor__summary {
311
+ display: flex;
312
+ align-items: center;
313
+ gap: 0.75rem;
314
+ padding: 0.75rem 1rem;
315
+ border-bottom: 1px solid var(--fd-border);
316
+ background-color: var(--fd-muted);
317
+ flex-shrink: 0;
318
+ color: var(--fd-muted-foreground);
319
+ }
320
+
321
+ .swap-editor__node-info {
322
+ flex: 1;
323
+ display: flex;
324
+ flex-direction: column;
325
+ gap: 0.125rem;
326
+ min-width: 0;
327
+ }
328
+
329
+ .swap-editor__label {
330
+ font-size: var(--fd-text-xs);
331
+ color: var(--fd-muted-foreground);
332
+ text-transform: uppercase;
333
+ letter-spacing: 0.05em;
334
+ font-weight: 600;
335
+ }
336
+
337
+ .swap-editor__node-name {
338
+ font-size: var(--fd-text-sm);
339
+ font-weight: 500;
340
+ color: var(--fd-foreground);
341
+ overflow: hidden;
342
+ text-overflow: ellipsis;
343
+ white-space: nowrap;
344
+ }
345
+
346
+ .swap-editor__node-target {
347
+ display: flex;
348
+ align-items: center;
349
+ gap: 0.375rem;
350
+ }
351
+
352
+ .swap-editor__node-icon {
353
+ width: 1.25rem;
354
+ height: 1.25rem;
355
+ border-radius: 0.25rem;
356
+ background: color-mix(
357
+ in srgb,
358
+ var(--_icon-color) var(--fd-node-icon-bg-opacity, 15%),
359
+ transparent
360
+ );
361
+ color: var(--fd-node-icon);
362
+ font-size: 0.5rem;
363
+ display: flex;
364
+ align-items: center;
365
+ justify-content: center;
366
+ flex-shrink: 0;
367
+ }
368
+
369
+ .swap-editor__content {
370
+ flex: 1;
371
+ overflow-y: auto;
372
+ padding: var(--fd-space-md);
373
+ scrollbar-width: thin;
374
+ scrollbar-color: var(--fd-scrollbar-thumb) var(--fd-scrollbar-track);
375
+ }
376
+
377
+ .swap-editor__section-heading {
378
+ display: flex;
379
+ align-items: center;
380
+ gap: var(--fd-space-xs);
381
+ font-size: 0.8125rem;
382
+ font-weight: 600;
383
+ color: var(--fd-foreground);
384
+ padding: var(--fd-space-xs) 0;
385
+ border-bottom: 1px solid var(--fd-border);
386
+ margin-bottom: var(--fd-space-xs);
387
+ }
388
+
389
+ .swap-editor__section-heading :global(svg) {
390
+ width: 1rem;
391
+ height: 1rem;
392
+ color: var(--fd-muted-foreground);
393
+ }
394
+
395
+ .swap-editor__section-heading--spaced {
396
+ margin-top: var(--fd-space-md);
397
+ padding-top: var(--fd-space-md);
398
+ border-top: 1px solid var(--fd-border-muted);
399
+ }
400
+
401
+ .swap-editor__help {
402
+ margin: 0 0 var(--fd-space-xs);
403
+ font-size: var(--fd-text-xs);
404
+ line-height: 1.5;
405
+ color: var(--fd-muted-foreground);
406
+ }
407
+
408
+ .swap-editor__help strong {
409
+ color: var(--fd-foreground);
410
+ font-weight: 600;
411
+ }
412
+
413
+ .swap-editor__section-label {
414
+ font-size: var(--fd-text-xs);
415
+ font-weight: 600;
416
+ color: var(--fd-muted-foreground);
417
+ text-transform: uppercase;
418
+ letter-spacing: 0.05em;
419
+ padding: var(--fd-space-xs) 0 var(--fd-space-3xs);
420
+ margin-bottom: var(--fd-space-3xs);
421
+ }
422
+
423
+ .swap-editor__section-label:first-child {
424
+ padding-top: 0;
425
+ }
426
+
427
+ .swap-editor__info-row {
428
+ font-size: var(--fd-text-xs);
429
+ color: var(--fd-muted-foreground);
430
+ font-style: italic;
431
+ padding: var(--fd-space-xs) 0;
432
+ border-top: 1px solid var(--fd-border-muted);
433
+ margin-top: var(--fd-space-xs);
434
+ }
435
+
436
+ .swap-editor__trivial {
437
+ flex: 1;
438
+ display: flex;
439
+ flex-direction: column;
440
+ align-items: center;
441
+ justify-content: center;
442
+ gap: var(--fd-space-3xs);
443
+ color: var(--fd-muted-foreground);
444
+ font-size: var(--fd-text-sm);
445
+ padding: var(--fd-space-2xl);
446
+ }
447
+
448
+ .swap-editor__trivial p {
449
+ margin: 0;
450
+ }
451
+
452
+ .swap-editor__warning {
453
+ display: flex;
454
+ align-items: center;
455
+ gap: var(--fd-space-xs);
456
+ padding: var(--fd-space-xs) var(--fd-space-md);
457
+ background-color: color-mix(in srgb, var(--fd-warning) 8%, transparent);
458
+ border-top: 1px solid color-mix(in srgb, var(--fd-warning) 25%, transparent);
459
+ color: var(--fd-warning);
460
+ font-size: var(--fd-text-xs);
461
+ font-weight: 500;
462
+ flex-shrink: 0;
463
+ }
464
+
465
+ .swap-editor__actions {
466
+ display: flex;
467
+ gap: var(--fd-space-xs);
468
+ padding: var(--fd-space-md);
469
+ border-top: 1px solid var(--fd-border-muted);
470
+ flex-shrink: 0;
471
+ }
472
+
473
+ .swap-editor__btn {
474
+ flex: 1;
475
+ display: inline-flex;
476
+ align-items: center;
477
+ justify-content: center;
478
+ padding: 0.625rem var(--fd-space-md);
479
+ border-radius: var(--fd-radius-lg);
480
+ font-size: var(--fd-text-sm);
481
+ font-weight: 600;
482
+ font-family: inherit;
483
+ cursor: pointer;
484
+ border: 1px solid transparent;
485
+ transition: all var(--fd-transition-normal);
486
+ }
487
+
488
+ .swap-editor__btn--cancel {
489
+ background-color: var(--fd-background);
490
+ border-color: var(--fd-border);
491
+ color: var(--fd-foreground);
492
+ box-shadow: var(--fd-shadow-sm);
493
+ }
494
+
495
+ .swap-editor__btn--cancel:hover {
496
+ background-color: var(--fd-muted);
497
+ border-color: var(--fd-border-strong);
498
+ }
499
+
500
+ .swap-editor__btn--confirm {
501
+ background: linear-gradient(
502
+ 135deg,
503
+ var(--fd-primary) 0%,
504
+ var(--fd-primary-hover) 100%
505
+ );
506
+ color: var(--fd-primary-foreground);
507
+ box-shadow:
508
+ 0 2px 8px rgba(59, 130, 246, 0.25),
509
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
510
+ }
511
+
512
+ .swap-editor__btn--confirm:hover {
513
+ background: linear-gradient(
514
+ 135deg,
515
+ var(--fd-primary-hover) 0%,
516
+ var(--fd-primary) 100%
517
+ );
518
+ box-shadow:
519
+ 0 4px 12px rgba(59, 130, 246, 0.35),
520
+ inset 0 1px 0 rgba(255, 255, 255, 0.15);
521
+ transform: translateY(-1px);
522
+ }
523
+
524
+ .swap-editor__btn--confirm:active {
525
+ transform: translateY(0);
526
+ }
527
+
528
+ .swap-editor__btn--danger {
529
+ background: linear-gradient(
530
+ 135deg,
531
+ var(--fd-error) 0%,
532
+ var(--fd-error-hover, var(--fd-error)) 100%
533
+ );
534
+ color: var(--fd-error-foreground);
535
+ box-shadow:
536
+ 0 2px 8px color-mix(in srgb, var(--fd-error) 30%, transparent),
537
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
538
+ }
539
+
540
+ .swap-editor__btn--danger:hover {
541
+ box-shadow:
542
+ 0 4px 12px color-mix(in srgb, var(--fd-error) 40%, transparent),
543
+ inset 0 1px 0 rgba(255, 255, 255, 0.15);
544
+ transform: translateY(-1px);
545
+ }
546
+
547
+ .swap-editor__btn--danger:active {
548
+ transform: translateY(0);
549
+ }
550
+ </style>
@@ -0,0 +1,12 @@
1
+ import type { InteractiveSwapState } from "../utils/nodeSwap.js";
2
+ import type { PortCompatibilityChecker } from "../utils/connections.js";
3
+ interface Props {
4
+ interactiveState: InteractiveSwapState;
5
+ checker: PortCompatibilityChecker | null;
6
+ onConfirm: (state: InteractiveSwapState) => void;
7
+ onCancel: () => void;
8
+ onBack: () => void;
9
+ }
10
+ declare const SwapMappingEditor: import("svelte").Component<Props, {}, "">;
11
+ type SwapMappingEditor = ReturnType<typeof SwapMappingEditor>;
12
+ export default SwapMappingEditor;