@flowdrop/flowdrop 2.0.0-beta.1 → 2.0.0-beta.3

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 (149) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/MIGRATION-2.0.md +173 -3
  3. package/dist/api/enhanced-client.js +6 -11
  4. package/dist/components/App.svelte +22 -45
  5. package/dist/components/App.svelte.d.ts +2 -7
  6. package/dist/components/CanvasIconButton.svelte +76 -0
  7. package/dist/components/CanvasIconButton.svelte.d.ts +18 -0
  8. package/dist/components/ConfigForm.svelte +6 -21
  9. package/dist/components/ConfigPanel.svelte +4 -3
  10. package/dist/components/LogoWordmark.svelte +113 -0
  11. package/dist/components/LogoWordmark.svelte.d.ts +26 -0
  12. package/dist/components/Navbar.svelte +8 -59
  13. package/dist/components/NodeSidebar.svelte +4 -11
  14. package/dist/components/NodeSwapPicker.svelte +0 -2
  15. package/dist/components/PipelineStatus.svelte +6 -1
  16. package/dist/components/PipelineStatus.svelte.d.ts +3 -0
  17. package/dist/components/PortMappingRow.svelte +0 -2
  18. package/dist/components/SchemaForm.svelte +4 -14
  19. package/dist/components/SettingsModal.svelte +0 -5
  20. package/dist/components/SettingsPanel.svelte +2 -6
  21. package/dist/components/ThemeToggle.svelte +0 -5
  22. package/dist/components/UniversalNode.svelte +32 -1
  23. package/dist/components/WorkflowEditor.svelte +66 -52
  24. package/dist/components/WorkflowEditor.svelte.d.ts +21 -0
  25. package/dist/components/chat/AIChatPanel.svelte +7 -2
  26. package/dist/components/console/ConsoleAutocomplete.svelte +1 -1
  27. package/dist/components/console/ConsoleOutput.svelte +2 -2
  28. package/dist/components/form/FormArray.svelte +0 -16
  29. package/dist/components/form/FormAutocomplete.svelte +18 -15
  30. package/dist/components/form/FormCheckboxGroup.svelte +0 -4
  31. package/dist/components/form/FormCodeEditor.svelte +9 -7
  32. package/dist/components/form/FormFieldLight.svelte +33 -4
  33. package/dist/components/form/FormFieldLight.svelte.d.ts +12 -0
  34. package/dist/components/form/FormMarkdownEditor.svelte +8 -5
  35. package/dist/components/form/FormNumberField.svelte +0 -4
  36. package/dist/components/form/FormRangeField.svelte +1 -20
  37. package/dist/components/form/FormSelect.svelte +10 -6
  38. package/dist/components/form/FormTemplateEditor.svelte +6 -4
  39. package/dist/components/form/FormTextField.svelte +10 -6
  40. package/dist/components/form/FormTextarea.svelte +10 -6
  41. package/dist/components/form/FormToggle.svelte +0 -4
  42. package/dist/components/form/FormUISchemaRenderer.svelte +3 -1
  43. package/dist/components/icons/CommandLineIcon.svelte +15 -0
  44. package/dist/components/icons/CommandLineIcon.svelte.d.ts +26 -0
  45. package/dist/components/icons/MenuIcon.svelte +4 -0
  46. package/dist/components/icons/MenuIcon.svelte.d.ts +26 -0
  47. package/dist/components/icons/MenuOpenIcon.svelte +6 -0
  48. package/dist/components/icons/MenuOpenIcon.svelte.d.ts +26 -0
  49. package/dist/components/interrupt/ChoicePrompt.svelte +0 -10
  50. package/dist/components/interrupt/ConfirmationPrompt.svelte +0 -5
  51. package/dist/components/interrupt/InterruptBubble.svelte +11 -12
  52. package/dist/components/interrupt/ReviewPrompt.svelte +0 -20
  53. package/dist/components/interrupt/TextInputPrompt.svelte +0 -6
  54. package/dist/components/layouts/MainLayout.svelte +4 -5
  55. package/dist/components/nodes/AtomNode.svelte +46 -34
  56. package/dist/components/nodes/GatewayNode.svelte +91 -99
  57. package/dist/components/nodes/IdeaNode.svelte +62 -90
  58. package/dist/components/nodes/NodeConfigButton.svelte +86 -0
  59. package/dist/components/nodes/NodeConfigButton.svelte.d.ts +15 -0
  60. package/dist/components/nodes/NotesNode.svelte +70 -81
  61. package/dist/components/nodes/SimpleNode.svelte +28 -78
  62. package/dist/components/nodes/SquareNode.svelte +79 -109
  63. package/dist/components/nodes/TerminalNode.svelte +28 -86
  64. package/dist/components/nodes/ToolNode.svelte +82 -95
  65. package/dist/components/nodes/WorkflowNode.svelte +91 -100
  66. package/dist/components/playground/ChatInput.svelte +0 -1
  67. package/dist/components/playground/InputCollector.svelte +0 -2
  68. package/dist/components/playground/PipelineKanbanView.svelte +4 -2
  69. package/dist/components/playground/PipelineKanbanView.svelte.d.ts +2 -0
  70. package/dist/components/playground/PipelinePanel.svelte +20 -3
  71. package/dist/components/playground/PipelinePanel.svelte.d.ts +2 -0
  72. package/dist/components/playground/PipelineTableView.svelte +4 -2
  73. package/dist/components/playground/PipelineTableView.svelte.d.ts +2 -0
  74. package/dist/components/playground/Playground.svelte +76 -25
  75. package/dist/components/playground/Playground.svelte.d.ts +3 -0
  76. package/dist/components/playground/PlaygroundApp.svelte +6 -1
  77. package/dist/components/playground/PlaygroundApp.svelte.d.ts +3 -0
  78. package/dist/components/playground/PlaygroundModal.svelte +5 -0
  79. package/dist/components/playground/PlaygroundModal.svelte.d.ts +3 -0
  80. package/dist/components/playground/PlaygroundStudio.svelte +7 -6
  81. package/dist/components/playground/PlaygroundStudio.svelte.d.ts +3 -0
  82. package/dist/components/playground/pipelineViewUtils.svelte.d.ts +2 -1
  83. package/dist/components/playground/pipelineViewUtils.svelte.js +2 -2
  84. package/dist/config/endpoints.d.ts +23 -0
  85. package/dist/config/endpoints.js +28 -0
  86. package/dist/core/index.d.ts +1 -2
  87. package/dist/core/index.js +2 -6
  88. package/dist/display/index.d.ts +6 -1
  89. package/dist/display/index.js +9 -1
  90. package/dist/editor/index.d.ts +1 -1
  91. package/dist/editor/index.js +1 -1
  92. package/dist/form/full.d.ts +2 -1
  93. package/dist/form/full.js +4 -1
  94. package/dist/form/index.d.ts +0 -1
  95. package/dist/form/index.js +3 -2
  96. package/dist/helpers/workflowEditorHelper.d.ts +4 -2
  97. package/dist/helpers/workflowEditorHelper.js +4 -3
  98. package/dist/playground/index.d.ts +2 -2
  99. package/dist/playground/index.js +2 -2
  100. package/dist/playground/mount.d.ts +19 -5
  101. package/dist/playground/mount.js +16 -8
  102. package/dist/registry/builtinNodeTypes.d.ts +53 -0
  103. package/dist/registry/builtinNodeTypes.js +67 -0
  104. package/dist/registry/builtinNodes.d.ts +2 -39
  105. package/dist/registry/builtinNodes.js +6 -53
  106. package/dist/services/agentSpecExecutionService.d.ts +0 -2
  107. package/dist/services/agentSpecExecutionService.js +0 -2
  108. package/dist/services/apiVariableService.js +12 -26
  109. package/dist/services/categoriesApi.js +3 -6
  110. package/dist/services/chatService.d.ts +4 -3
  111. package/dist/services/chatService.js +13 -18
  112. package/dist/services/interruptService.d.ts +7 -6
  113. package/dist/services/interruptService.js +19 -21
  114. package/dist/services/playgroundService.d.ts +9 -8
  115. package/dist/services/playgroundService.js +23 -25
  116. package/dist/services/portConfigApi.js +3 -6
  117. package/dist/services/settingsService.d.ts +9 -4
  118. package/dist/services/settingsService.js +23 -12
  119. package/dist/skins/drafter.d.ts +30 -0
  120. package/dist/skins/drafter.js +185 -0
  121. package/dist/skins/index.d.ts +2 -1
  122. package/dist/skins/index.js +4 -2
  123. package/dist/stores/apiContext.d.ts +11 -0
  124. package/dist/stores/apiContext.js +15 -0
  125. package/dist/stores/categoriesStore.svelte.js +0 -1
  126. package/dist/stores/playgroundStore.svelte.js +0 -2
  127. package/dist/styles/base.css +38 -9
  128. package/dist/styles/tokens.css +54 -2
  129. package/dist/svelte-app.d.ts +6 -0
  130. package/dist/svelte-app.js +4 -2
  131. package/dist/themes/drafter.d.ts +2 -0
  132. package/dist/themes/drafter.js +15 -0
  133. package/dist/themes/index.d.ts +2 -1
  134. package/dist/themes/index.js +8 -2
  135. package/dist/types/auth.d.ts +9 -51
  136. package/dist/types/auth.js +4 -54
  137. package/dist/types/events.d.ts +18 -0
  138. package/dist/types/events.js +2 -1
  139. package/dist/types/index.d.ts +4 -2
  140. package/dist/types/index.js +0 -1
  141. package/dist/types/settings.d.ts +1 -1
  142. package/dist/types/settings.js +1 -1
  143. package/dist/types/skin.d.ts +1 -1
  144. package/dist/types/theme.d.ts +16 -2
  145. package/dist/utils/edgeStyling.js +9 -5
  146. package/dist/utils/fetchWithAuth.d.ts +36 -15
  147. package/dist/utils/fetchWithAuth.js +53 -23
  148. package/dist/utils/nodeTypes.js +1 -1
  149. package/package.json +2 -1
@@ -24,7 +24,7 @@
24
24
  import { getNodeIcon } from '../../utils/icons.js';
25
25
  import { getInstance } from '../../stores/getInstance.svelte.js';
26
26
  import { applyPortOrder, getPortTop, isPortVisible } from '../../utils/portUtils.js';
27
- import CogIcon from '../icons/CogIcon.svelte';
27
+ import NodeConfigButton from './NodeConfigButton.svelte';
28
28
  import AlertCircleIcon from '../icons/AlertCircleIcon.svelte';
29
29
 
30
30
  const props = $props<{
@@ -102,13 +102,6 @@
102
102
  openConfigSidebar();
103
103
  }
104
104
 
105
- // Handle keyboard events
106
- function handleKeydown(event: KeyboardEvent): void {
107
- if (event.key === 'Enter' || event.key === ' ') {
108
- event.preventDefault();
109
- openConfigSidebar();
110
- }
111
- }
112
105
  const dynamicInputs = $derived(
113
106
  ((props.data.config?.dynamicInputs as DynamicPort[]) || []).map((port) =>
114
107
  dynamicPortToNodePort(port, 'input')
@@ -187,54 +180,54 @@
187
180
  />
188
181
  {/each}
189
182
 
190
- <!-- Square Node -->
183
+ <!-- Square Node: outer is a transparent bounding box (height grows with ports so
184
+ handles anchor in-bounds); the visible square inside stays a fixed 80×80. -->
185
+ <!-- Presentational: focus, keyboard and selection live on xyflow's node wrapper
186
+ (see UniversalNode, which maps Enter/Space to opening config). click/
187
+ double-click are mouse conveniences. -->
188
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
189
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
191
190
  <div
192
- class="flowdrop-square-node flowdrop-square-node--compact"
191
+ class="flowdrop-square-node"
193
192
  class:flowdrop-square-node--selected={props.selected}
194
193
  class:flowdrop-square-node--processing={props.isProcessing}
195
194
  class:flowdrop-square-node--error={props.isError}
196
- style="height: {nodeSize}px; width: {nodeSize}px"
195
+ style="height: {nodeSize}px"
197
196
  onclick={handleClick}
198
197
  ondblclick={handleDoubleClick}
199
- onkeydown={handleKeydown}
200
- role="button"
201
- tabindex="0"
202
198
  >
203
- <!-- Square Layout: Always compact with centered icon in squircle wrapper -->
204
- <div class="flowdrop-square-node__compact-content">
205
- <!-- Squircle icon visibility controlled by --fd-node-icon-display -->
206
- <div class="flowdrop-square-node__icon-wrapper" style="--_icon-color: {squareColor}">
207
- <Icon icon={squareIcon} class="flowdrop-square-node__icon" />
208
- </div>
209
- <!-- Circle dot — visibility controlled by --fd-node-circle-display -->
210
- <span
211
- class="flowdrop-square-node__color-dot"
212
- style="background: {getCategoryColorToken(fd.categories, props.data.metadata?.category)}"
213
- ></span>
214
- </div>
215
-
216
- <!-- Processing indicator -->
217
- {#if props.isProcessing}
218
- <div class="flowdrop-square-node__processing">
219
- <div class="flowdrop-square-node__spinner"></div>
199
+ <!-- The visible, themed square fixed 80×80, vertically centered in the slot -->
200
+ <div class="flowdrop-square-node__square">
201
+ <!-- Square Layout: Always compact with centered icon in squircle wrapper -->
202
+ <div class="flowdrop-square-node__compact-content">
203
+ <!-- Squircle icon — visibility controlled by --fd-node-icon-display -->
204
+ <div class="flowdrop-square-node__icon-wrapper" style="--_icon-color: {squareColor}">
205
+ <Icon icon={squareIcon} class="flowdrop-square-node__icon" />
206
+ </div>
207
+ <!-- Circle dot — visibility controlled by --fd-node-circle-display -->
208
+ <span
209
+ class="flowdrop-square-node__color-dot"
210
+ style="background: {getCategoryColorToken(fd.categories, props.data.metadata?.category)}"
211
+ ></span>
220
212
  </div>
221
- {/if}
222
213
 
223
- <!-- Error indicator -->
224
- {#if props.isError}
225
- <div class="flowdrop-square-node__error">
226
- <AlertCircleIcon />
227
- </div>
228
- {/if}
229
-
230
- <!-- Config button -->
231
- <button
232
- class="flowdrop-square-node__config-btn"
233
- onclick={openConfigSidebar}
234
- title="Configure node"
235
- >
236
- <CogIcon />
237
- </button>
214
+ <!-- Processing indicator -->
215
+ {#if props.isProcessing}
216
+ <div class="flowdrop-square-node__processing">
217
+ <div class="flowdrop-square-node__spinner"></div>
218
+ </div>
219
+ {/if}
220
+
221
+ <!-- Error indicator -->
222
+ {#if props.isError}
223
+ <div class="flowdrop-square-node__error">
224
+ <AlertCircleIcon />
225
+ </div>
226
+ {/if}
227
+
228
+ <!-- Config button -->
229
+ <NodeConfigButton onclick={openConfigSidebar} title="Configure node" />
230
+ </div>
238
231
  </div>
239
232
 
240
233
  <!-- Output Handles: 1 port centered at 40px; N ports at 20px start, 40px gap -->
@@ -254,58 +247,65 @@
254
247
  {/each}
255
248
 
256
249
  <style>
250
+ /* Transparent slot: defines the node's bounding box so handles anchor
251
+ consistently (height grows with port count), while the square sits fixed
252
+ and vertically centered inside. */
257
253
  .flowdrop-square-node {
258
254
  position: relative;
259
- background-color: var(--fd-card);
260
- border: 1.5px solid var(--fd-node-border);
261
- border-radius: var(--fd-radius-xl);
262
255
  display: flex;
263
- flex-direction: column;
256
+ align-items: center;
257
+ justify-content: center;
258
+ width: var(--fd-node-square-size);
264
259
  cursor: pointer;
265
- transition: all var(--fd-transition-fast);
266
- box-shadow: var(--fd-shadow-md);
267
- overflow: visible; /* Changed from hidden to visible to allow handles to be properly accessible */
268
260
  z-index: 10;
269
261
  color: var(--fd-foreground);
270
262
  }
271
263
 
272
- /* Square layout (always compact) */
273
- .flowdrop-square-node--compact {
264
+ /* The visible, themed square — fixed 80×80, never expands. */
265
+ .flowdrop-square-node__square {
266
+ position: relative;
267
+ box-sizing: border-box;
268
+ display: flex;
269
+ align-items: center;
270
+ justify-content: center;
274
271
  width: var(--fd-node-square-size);
275
272
  height: var(--fd-node-square-size);
276
- justify-content: center;
277
- align-items: center;
273
+ background-color: var(--fd-node-bg);
274
+ backdrop-filter: var(--fd-node-backdrop-filter);
275
+ border: var(--fd-node-border-width) solid var(--fd-node-border);
276
+ border-radius: var(--fd-node-radius);
277
+ box-shadow: var(--fd-node-shadow);
278
+ transition: all var(--fd-transition-fast);
279
+ color: var(--fd-foreground);
278
280
  }
279
281
 
280
- .flowdrop-square-node:hover {
281
- box-shadow: var(--fd-shadow-lg);
282
+ .flowdrop-square-node:hover .flowdrop-square-node__square {
283
+ box-shadow: var(--fd-node-shadow-hover);
282
284
  border-color: var(--fd-node-border-hover);
283
285
  }
284
286
 
285
- .flowdrop-square-node--selected {
287
+ .flowdrop-square-node--selected .flowdrop-square-node__square {
286
288
  box-shadow:
287
289
  0 0 0 2px var(--fd-primary-muted),
288
- var(--fd-shadow-lg);
290
+ var(--fd-node-shadow-hover);
289
291
  border-color: var(--fd-primary);
290
292
  }
291
293
 
292
- .flowdrop-square-node--selected:hover {
294
+ .flowdrop-square-node--selected:hover .flowdrop-square-node__square {
293
295
  box-shadow:
294
296
  0 0 0 2px var(--fd-primary-muted),
295
- var(--fd-shadow-lg);
297
+ var(--fd-node-shadow-hover);
296
298
  border-color: var(--fd-primary);
297
299
  }
298
300
 
299
- .flowdrop-square-node:focus-visible {
300
- outline: 2px solid var(--fd-ring);
301
- outline-offset: 2px;
302
- }
301
+ /* Focus ring is centralized in base.css (drawn on the .svelte-flow__node
302
+ wrapper, which is the focusable element). */
303
303
 
304
304
  .flowdrop-square-node--processing {
305
305
  opacity: 0.7;
306
306
  }
307
307
 
308
- .flowdrop-square-node--error {
308
+ .flowdrop-square-node--error .flowdrop-square-node__square {
309
309
  border-color: var(--fd-error) !important;
310
310
  background-color: var(--fd-error-muted) !important;
311
311
  }
@@ -319,14 +319,15 @@
319
319
  height: 100%;
320
320
  }
321
321
 
322
- /* Squircle icon wrapper - matching WorkflowNode style */
322
+ /* Squircle icon wrapper - px (not rem) so the icon stays grid-locked
323
+ regardless of root font-size */
323
324
  .flowdrop-square-node__icon-wrapper {
324
325
  display: var(--fd-node-icon-display, flex);
325
326
  align-items: center;
326
327
  justify-content: center;
327
- width: 3rem;
328
- height: 3rem;
329
- border-radius: 0.625rem;
328
+ width: 48px;
329
+ height: 48px;
330
+ border-radius: 10px;
330
331
  background: color-mix(in srgb, var(--_icon-color) var(--fd-node-icon-bg-opacity), transparent);
331
332
  flex-shrink: 0;
332
333
  transition: all var(--fd-transition-normal);
@@ -342,8 +343,8 @@
342
343
  }
343
344
 
344
345
  .flowdrop-square-node__icon-wrapper :global(.flowdrop-square-node__icon) {
345
- width: 1.75rem;
346
- height: 1.75rem;
346
+ width: 28px;
347
+ height: 28px;
347
348
  color: var(--fd-node-icon);
348
349
  }
349
350
 
@@ -383,40 +384,9 @@
383
384
  height: 12px;
384
385
  }
385
386
 
386
- .flowdrop-square-node__config-btn :global(svg) {
387
- width: 14px;
388
- height: 14px;
389
- }
390
-
391
- .flowdrop-square-node__config-btn {
392
- position: absolute;
393
- top: var(--fd-space-xs);
394
- right: var(--fd-space-xs);
395
- width: 1.5rem;
396
- height: 1.5rem;
397
- background-color: var(--fd-backdrop);
398
- border: 1px solid var(--fd-border);
399
- border-radius: var(--fd-radius-sm);
400
- color: var(--fd-muted-foreground);
401
- cursor: pointer;
402
- display: flex;
403
- align-items: center;
404
- justify-content: center;
405
- opacity: 0;
406
- transition: all var(--fd-transition-normal);
407
- backdrop-filter: var(--fd-backdrop-blur);
408
- z-index: 15;
409
- font-size: var(--fd-text-sm);
410
- }
411
-
412
- .flowdrop-square-node:hover .flowdrop-square-node__config-btn {
413
- opacity: 1;
414
- }
415
-
416
- .flowdrop-square-node__config-btn:hover {
417
- background-color: var(--fd-muted);
418
- border-color: var(--fd-border-strong);
419
- color: var(--fd-foreground);
387
+ /* Reveal the NodeConfigButton (gear) when the node is hovered. */
388
+ .flowdrop-square-node:hover {
389
+ --fd-config-btn-opacity: 1;
420
390
  }
421
391
 
422
392
  @keyframes spin {
@@ -12,6 +12,7 @@
12
12
  import { Position, Handle } from '@xyflow/svelte';
13
13
  import type { ConfigValues, NodeMetadata, NodeExtensions, NodePort } from '../../types/index.js';
14
14
  import Icon from '@iconify/svelte';
15
+ import NodeConfigButton from './NodeConfigButton.svelte';
15
16
  import { getDataTypeColor, getCategoryColorToken } from '../../utils/colors.js';
16
17
  import { getNodeIcon } from '../../utils/icons.js';
17
18
  import { getCircleHandlePosition } from '../../utils/handlePositioning.js';
@@ -311,26 +312,12 @@
311
312
  function handleDoubleClick(): void {
312
313
  openConfigSidebar();
313
314
  }
314
-
315
- /**
316
- * Handle single click - only handle selection
317
- */
318
- function handleClick(): void {
319
- // Node selection is handled by Svelte Flow
320
- }
321
-
322
- /**
323
- * Handle keyboard events for accessibility
324
- */
325
- function handleKeydown(event: KeyboardEvent): void {
326
- if (event.key === 'Enter' || event.key === ' ') {
327
- event.preventDefault();
328
- handleDoubleClick();
329
- }
330
- }
331
315
  </script>
332
316
 
333
317
  <!-- Terminal Node -->
318
+ <!-- Presentational: focus, keyboard and selection live on xyflow's node
319
+ wrapper (see UniversalNode). double-click is a mouse convenience. -->
320
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
334
321
  <div
335
322
  class="flowdrop-terminal-node"
336
323
  class:flowdrop-terminal-node--selected={props.selected}
@@ -340,21 +327,11 @@
340
327
  class:flowdrop-terminal-node--end={variant === 'end'}
341
328
  class:flowdrop-terminal-node--exit={variant === 'exit'}
342
329
  style="--terminal-color: {terminalColor};"
343
- onclick={handleClick}
344
330
  ondblclick={handleDoubleClick}
345
- onkeydown={handleKeydown}
346
- role="button"
347
- tabindex="0"
348
331
  aria-label="{variant} node: {displayTitle}"
349
332
  >
350
333
  <!-- Config button at top -->
351
- <button
352
- class="flowdrop-terminal-node__config-btn"
353
- onclick={openConfigSidebar}
354
- title="Configure node"
355
- >
356
- <Icon icon="mdi:cog" />
357
- </button>
334
+ <NodeConfigButton onclick={openConfigSidebar} title="Configure node" placement="top-center" />
358
335
 
359
336
  <!-- Circle wrapper for proper handle positioning -->
360
337
  <div class="flowdrop-terminal-node__circle-wrapper">
@@ -431,7 +408,8 @@
431
408
  display: flex;
432
409
  flex-direction: column;
433
410
  align-items: center;
434
- gap: var(--fd-space-xs);
411
+ /* px (not rem) on the 20px grid */
412
+ gap: 8px;
435
413
  cursor: pointer;
436
414
  transition: all var(--fd-transition-normal);
437
415
  z-index: 10;
@@ -455,34 +433,32 @@
455
433
  display: flex;
456
434
  align-items: center;
457
435
  justify-content: center;
458
- box-shadow: var(--fd-shadow-md);
436
+ box-shadow: var(--fd-node-shadow);
459
437
  transition: all var(--fd-transition-normal);
460
438
  }
461
439
 
462
440
  .flowdrop-terminal-node:hover .flowdrop-terminal-node__content {
463
- box-shadow: var(--fd-shadow-lg);
441
+ box-shadow: var(--fd-node-shadow-hover);
464
442
  transform: scale(1.05);
465
443
  }
466
444
 
467
445
  .flowdrop-terminal-node--selected .flowdrop-terminal-node__content {
468
446
  box-shadow:
469
- var(--fd-shadow-lg),
447
+ var(--fd-node-shadow-hover),
470
448
  0 0 0 3px color-mix(in srgb, var(--fd-primary) 50%, transparent);
471
449
  border-color: var(--fd-primary);
472
450
  }
473
451
 
474
452
  .flowdrop-terminal-node--selected:hover .flowdrop-terminal-node__content {
475
453
  box-shadow:
476
- var(--fd-shadow-lg),
454
+ var(--fd-node-shadow-hover),
477
455
  0 0 0 3px color-mix(in srgb, var(--fd-primary) 50%, transparent);
478
456
  border-color: var(--fd-primary);
479
457
  transform: scale(1.05);
480
458
  }
481
459
 
482
- .flowdrop-terminal-node:focus-visible .flowdrop-terminal-node__content {
483
- outline: 2px solid var(--fd-ring);
484
- outline-offset: 2px;
485
- }
460
+ /* Focus ring is centralized in base.css (drawn on the .svelte-flow__node
461
+ wrapper, which is the focusable element). */
486
462
 
487
463
  .flowdrop-terminal-node--processing .flowdrop-terminal-node__content {
488
464
  opacity: 0.7;
@@ -534,14 +510,15 @@
534
510
  0 0 0 3px color-mix(in srgb, var(--fd-primary) 50%, transparent);
535
511
  }
536
512
 
537
- /* Squircle icon wrapper - matching WorkflowNode style */
513
+ /* Squircle icon wrapper - px (not rem) so the icon stays grid-locked
514
+ regardless of root font-size */
538
515
  .flowdrop-terminal-node__icon-wrapper {
539
516
  display: flex;
540
517
  align-items: center;
541
518
  justify-content: center;
542
- width: 2.75rem;
543
- height: 2.75rem;
544
- border-radius: 0.625rem;
519
+ width: 44px;
520
+ height: 44px;
521
+ border-radius: 10px;
545
522
  background: color-mix(in srgb, var(--_icon-color) var(--fd-node-icon-bg-opacity), transparent);
546
523
  flex-shrink: 0;
547
524
  transition: all var(--fd-transition-normal);
@@ -556,8 +533,8 @@
556
533
  }
557
534
 
558
535
  .flowdrop-terminal-node__icon-wrapper :global(.flowdrop-terminal-node__icon) {
559
- width: 1.5rem;
560
- height: 1.5rem;
536
+ width: 24px;
537
+ height: 24px;
561
538
  color: var(--fd-node-icon);
562
539
  }
563
540
 
@@ -565,9 +542,9 @@
565
542
  display: flex;
566
543
  flex-direction: column;
567
544
  align-items: center;
568
- gap: 0.125rem;
545
+ gap: 2px;
569
546
  background-color: var(--fd-backdrop);
570
- padding: var(--fd-space-3xs) var(--fd-space-xs);
547
+ padding: 4px 8px;
571
548
  border-radius: var(--fd-radius-sm);
572
549
  box-shadow: var(--fd-shadow-sm);
573
550
  max-width: 140px;
@@ -585,7 +562,7 @@
585
562
  }
586
563
 
587
564
  .flowdrop-terminal-node__description {
588
- font-size: 0.625rem;
565
+ font-size: 10px;
589
566
  color: var(--fd-muted-foreground);
590
567
  text-align: center;
591
568
  overflow: hidden;
@@ -596,7 +573,7 @@
596
573
 
597
574
  .flowdrop-terminal-node__processing {
598
575
  position: absolute;
599
- top: 1.5rem;
576
+ top: 24px;
600
577
  right: 0;
601
578
  }
602
579
 
@@ -611,7 +588,7 @@
611
588
 
612
589
  .flowdrop-terminal-node__error {
613
590
  position: absolute;
614
- top: 1.5rem;
591
+ top: 24px;
615
592
  right: 0;
616
593
  color: var(--fd-error);
617
594
  }
@@ -621,39 +598,9 @@
621
598
  height: 14px;
622
599
  }
623
600
 
624
- /* Config button positioned at top center */
625
- .flowdrop-terminal-node__config-btn {
626
- position: absolute;
627
- top: -1.5rem;
628
- left: 50%;
629
- transform: translateX(-50%);
630
- width: 1.5rem;
631
- height: 1.5rem;
632
- background-color: var(--fd-backdrop);
633
- border: 1px solid var(--fd-border);
634
- border-radius: 50%;
635
- color: var(--fd-muted-foreground);
636
- cursor: pointer;
637
- display: flex;
638
- align-items: center;
639
- justify-content: center;
640
- opacity: 0;
641
- transition: all var(--fd-transition-normal);
642
- backdrop-filter: var(--fd-backdrop-blur);
643
- z-index: 15;
644
- font-size: var(--fd-text-xs);
645
- box-shadow: var(--fd-shadow-sm);
646
- }
647
-
648
- .flowdrop-terminal-node:hover .flowdrop-terminal-node__config-btn {
649
- opacity: 1;
650
- }
651
-
652
- .flowdrop-terminal-node__config-btn:hover {
653
- background-color: var(--fd-muted);
654
- border-color: var(--fd-border-strong);
655
- color: var(--fd-foreground);
656
- transform: translateX(-50%) scale(1.1);
601
+ /* Reveal the NodeConfigButton (gear) when the node is hovered. */
602
+ .flowdrop-terminal-node:hover {
603
+ --fd-config-btn-opacity: 1;
657
604
  }
658
605
 
659
606
  @keyframes spin {
@@ -678,11 +625,6 @@
678
625
  transform: translate(-50%, -50%) scale(1.2) !important;
679
626
  }
680
627
 
681
- :global(.flowdrop-terminal-node__circle-wrapper .svelte-flow__handle:focus) {
682
- outline: 2px solid var(--fd-ring) !important;
683
- outline-offset: 2px !important;
684
- }
685
-
686
628
  /* Also keep node-level handle styles for fallback */
687
629
  :global(.svelte-flow__node-terminal .svelte-flow__handle) {
688
630
  z-index: 20 !important;