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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +5 -5
  3. package/dist/adapters/WorkflowAdapter.js +4 -5
  4. package/dist/adapters/agentspec/AgentSpecAdapter.js +3 -3
  5. package/dist/adapters/agentspec/defaultNodeTypes.js +9 -9
  6. package/dist/commands/executor.js +5 -6
  7. package/dist/commands/types.js +5 -5
  8. package/dist/components/App.svelte +19 -150
  9. package/dist/components/Button.stories.svelte +65 -0
  10. package/dist/components/Button.stories.svelte.d.ts +19 -0
  11. package/dist/components/Button.svelte +62 -0
  12. package/dist/components/Button.svelte.d.ts +24 -0
  13. package/dist/components/ConfigForm.svelte +4 -4
  14. package/dist/components/EditorStatusBar.stories.svelte +44 -0
  15. package/dist/components/EditorStatusBar.stories.svelte.d.ts +27 -0
  16. package/dist/components/EditorStatusBar.svelte +99 -0
  17. package/dist/components/EditorStatusBar.svelte.d.ts +15 -0
  18. package/dist/components/IconButton.svelte +80 -0
  19. package/dist/components/IconButton.svelte.d.ts +30 -0
  20. package/dist/components/Input.svelte +74 -0
  21. package/dist/components/Input.svelte.d.ts +17 -0
  22. package/dist/components/Navbar.svelte +9 -4
  23. package/dist/components/Navbar.svelte.d.ts +3 -0
  24. package/dist/components/NodeSidebar.svelte +17 -115
  25. package/dist/components/NodeSwapPicker.svelte +12 -28
  26. package/dist/components/Select.svelte +53 -0
  27. package/dist/components/Select.svelte.d.ts +15 -0
  28. package/dist/components/Textarea.svelte +39 -0
  29. package/dist/components/Textarea.svelte.d.ts +12 -0
  30. package/dist/components/ThemeToggle.svelte +15 -89
  31. package/dist/components/UniversalNode.svelte +5 -4
  32. package/dist/components/UniversalNode.svelte.d.ts +1 -1
  33. package/dist/components/console/ConsoleInput.svelte +3 -3
  34. package/dist/components/form/FormArray.svelte +37 -157
  35. package/dist/components/form/FormCheckboxGroup.svelte +1 -1
  36. package/dist/components/form/FormField.svelte +5 -44
  37. package/dist/components/form/FormFieldLight.svelte +5 -44
  38. package/dist/components/form/FormFieldset.svelte +1 -1
  39. package/dist/components/form/FormNumberField.svelte +4 -32
  40. package/dist/components/form/FormRangeField.svelte +17 -7
  41. package/dist/components/form/FormSelect.svelte +13 -79
  42. package/dist/components/form/FormTextField.svelte +3 -39
  43. package/dist/components/form/FormTextarea.svelte +4 -43
  44. package/dist/components/form/resolveFieldType.d.ts +24 -0
  45. package/dist/components/form/resolveFieldType.js +55 -0
  46. package/dist/components/icons/CloseIcon.svelte +6 -0
  47. package/dist/components/icons/CloseIcon.svelte.d.ts +26 -0
  48. package/dist/components/nodes/AtomNode.svelte +3 -3
  49. package/dist/components/nodes/AtomNode.svelte.d.ts +1 -1
  50. package/dist/components/nodes/GatewayNode.svelte +8 -11
  51. package/dist/components/nodes/GatewayNode.svelte.d.ts +1 -1
  52. package/dist/components/nodes/IdeaNode.svelte +10 -8
  53. package/dist/components/nodes/IdeaNode.svelte.d.ts +8 -4
  54. package/dist/components/nodes/NotesNode.svelte +6 -4
  55. package/dist/components/nodes/NotesNode.svelte.d.ts +8 -4
  56. package/dist/components/nodes/SimpleNode.svelte +10 -8
  57. package/dist/components/nodes/SimpleNode.svelte.d.ts +4 -4
  58. package/dist/components/nodes/SquareNode.svelte +10 -8
  59. package/dist/components/nodes/SquareNode.svelte.d.ts +4 -4
  60. package/dist/components/nodes/TerminalNode.svelte +10 -8
  61. package/dist/components/nodes/TerminalNode.svelte.d.ts +4 -4
  62. package/dist/components/nodes/ToolNode.svelte +10 -8
  63. package/dist/components/nodes/ToolNode.svelte.d.ts +6 -6
  64. package/dist/components/nodes/WorkflowNode.svelte +7 -10
  65. package/dist/components/nodes/WorkflowNode.svelte.d.ts +1 -1
  66. package/dist/components/playground/InputCollector.svelte +11 -46
  67. package/dist/components/playground/PipelineKanbanView.svelte +2 -2
  68. package/dist/components/playground/PipelineTableView.svelte +2 -2
  69. package/dist/helpers/workflowEditorHelper.js +4 -5
  70. package/dist/messages/index.d.ts +1 -1
  71. package/dist/messages/index.js +1 -1
  72. package/dist/openapi/v1/openapi.yaml +2 -2
  73. package/dist/registry/nodeComponentRegistry.d.ts +2 -1
  74. package/dist/services/dynamicSchemaService.d.ts +2 -2
  75. package/dist/services/dynamicSchemaService.js +8 -8
  76. package/dist/skins/drafter.js +41 -28
  77. package/dist/stores/playgroundStore.svelte.js +1 -1
  78. package/dist/stores/workflowStore.svelte.js +0 -18
  79. package/dist/styles/base.css +247 -5
  80. package/dist/styles/tokens.css +6 -0
  81. package/dist/svelte-app.js +68 -107
  82. package/dist/types/index.d.ts +6 -7
  83. package/dist/utils/connections.js +20 -56
  84. package/dist/utils/nodeIds.d.ts +1 -1
  85. package/dist/utils/nodeIds.js +1 -1
  86. package/dist/utils/nodeSwap.js +3 -6
  87. package/package.json +1 -1
@@ -7,6 +7,7 @@
7
7
  <script lang="ts">
8
8
  import type { NodeMetadata, NodeCategory, WorkflowFormat } from '../types/index.js';
9
9
  import LoadingSpinner from './LoadingSpinner.svelte';
10
+ import Input from './Input.svelte';
10
11
  import Icon from '@iconify/svelte';
11
12
  import { getNodeIcon, getCategoryIcon } from '../utils/icons.js';
12
13
  import { getCategoryColorToken } from '../utils/colors.js';
@@ -120,7 +121,7 @@
120
121
  // Create a new node instance from the node type
121
122
  const newNodeData = {
122
123
  type: 'node',
123
- nodeType: nodeType.id,
124
+ nodeType: nodeType.node_type_id,
124
125
  nodeData: {
125
126
  label: nodeType.name,
126
127
  config: extractConfigDefaults(nodeType.configSchema),
@@ -161,19 +162,17 @@
161
162
  >
162
163
  <!-- Search Section — visibility controlled by --fd-sidebar-search-display -->
163
164
  <div class="flowdrop-sidebar__search">
164
- <div class="flowdrop-join flowdrop-w--full">
165
- <div class="flowdrop-join__item flowdrop-flex--1">
166
- <input
167
- type="text"
168
- placeholder={m().layout.searchComponents}
169
- class="flowdrop-input flowdrop-join__item flowdrop-w--full"
170
- bind:value={searchInput}
171
- />
172
- </div>
173
- <button class="flowdrop-btn flowdrop-join__item" aria-label={m().layout.searchComponents}>
174
- <Icon icon="mdi:magnify" class="flowdrop-icon" />
175
- </button>
176
- </div>
165
+ <Input
166
+ type="text"
167
+ placeholder={m().layout.searchComponents}
168
+ aria-label={m().layout.searchComponents}
169
+ value={searchInput}
170
+ oninput={(e) => (searchInput = e.currentTarget.value)}
171
+ >
172
+ {#snippet leading()}
173
+ <Icon icon="mdi:magnify" />
174
+ {/snippet}
175
+ </Input>
177
176
  </div>
178
177
 
179
178
  <!-- Node Types List -->
@@ -247,7 +246,7 @@
247
246
  </div>
248
247
  {:else}
249
248
  <div class="flowdrop-node-list">
250
- {#each filteredNodes as nodeType (nodeType.id)}
249
+ {#each filteredNodes as nodeType (nodeType.node_type_id)}
251
250
  <div
252
251
  class="flowdrop-card flowdrop-card--compact flowdrop-node-item"
253
252
  draggable="true"
@@ -300,7 +299,7 @@
300
299
  {getCategoryDisplayName(category).toUpperCase()}
301
300
  </div>
302
301
  <div class="fd-sidebar-flat-list" role="list">
303
- {#each categoryNodes as nodeType (nodeType.id)}
302
+ {#each categoryNodes as nodeType (nodeType.node_type_id)}
304
303
  <div
305
304
  class="fd-sidebar-flat-item"
306
305
  role="listitem"
@@ -340,7 +339,7 @@
340
339
  </summary>
341
340
  <div class="flowdrop-details__content">
342
341
  <div class="flowdrop-node-list" role="list">
343
- {#each categoryNodes as nodeType (nodeType.id)}
342
+ {#each categoryNodes as nodeType (nodeType.node_type_id)}
344
343
  <div
345
344
  class="flowdrop-card flowdrop-card--compact flowdrop-node-item"
346
345
  role="listitem"
@@ -594,106 +593,9 @@
594
593
  margin-left: 0;
595
594
  }
596
595
 
597
- /* Form Elements - Matching App Design System */
598
- .flowdrop-input {
599
- padding: 0.625rem 0.75rem;
600
- border: 1px solid var(--fd-border-strong);
601
- border-radius: var(--fd-radius-md);
602
- font-size: var(--fd-text-sm);
603
- color: var(--fd-foreground);
604
- background-color: var(--fd-background);
605
- transition:
606
- border-color var(--fd-transition-normal),
607
- box-shadow var(--fd-transition-normal);
608
- width: 100%;
609
- height: 2.5rem;
610
- box-sizing: border-box;
611
- }
612
-
613
- .flowdrop-input:focus {
614
- border-color: var(--fd-ring);
615
- }
616
-
617
- .flowdrop-input::placeholder {
618
- color: var(--fd-muted-foreground);
619
- }
620
-
621
- .flowdrop-btn {
622
- padding: 0.625rem 0.75rem;
623
- border-radius: var(--fd-radius-md);
624
- font-size: var(--fd-text-sm);
625
- font-weight: 500;
626
- cursor: pointer;
627
- transition: all var(--fd-transition-normal);
628
- border: 1px solid var(--fd-border-strong);
629
- display: flex;
630
- align-items: center;
631
- justify-content: center;
632
- gap: 0.5rem;
633
- background-color: var(--fd-muted);
634
- color: var(--fd-foreground);
635
- height: 2.5rem;
636
- min-width: 2.5rem;
637
- box-sizing: border-box;
638
- }
639
-
640
- .flowdrop-btn:hover {
641
- background-color: var(--fd-subtle);
642
- border-color: var(--fd-border-strong);
643
- }
644
-
645
- .flowdrop-btn:active {
646
- background-color: var(--fd-border);
647
- border-color: var(--fd-muted-foreground);
648
- }
649
-
650
- .flowdrop-btn:disabled {
651
- background-color: var(--fd-muted-foreground);
652
- border-color: var(--fd-muted-foreground);
653
- cursor: not-allowed;
654
- opacity: 0.6;
655
- }
656
-
657
- /* Join component styles - Seamless integration */
658
- .flowdrop-join {
659
- display: flex;
660
- width: 100%;
661
- border-radius: var(--fd-radius-md);
662
- overflow: hidden;
663
- border: 1px solid var(--fd-border-strong);
664
- background-color: var(--fd-background);
665
- }
666
-
667
- .flowdrop-join__item {
668
- border: none;
669
- border-radius: 0;
670
- background-color: transparent;
671
- }
672
-
673
- .flowdrop-join__item:first-child {
674
- border-right: 1px solid var(--fd-border-strong);
675
- flex: 1;
676
- }
677
-
678
- .flowdrop-join__item:last-child {
679
- border-left: none;
680
- background-color: var(--fd-muted);
681
- color: var(--fd-foreground);
682
- }
683
-
684
- .flowdrop-join__item:last-child:hover {
685
- background-color: var(--fd-subtle);
686
- }
687
-
688
- .flowdrop-join:focus-within {
689
- border-color: var(--fd-ring);
690
- }
596
+ /* Search field renders through the shared Input primitive (base.css). */
691
597
 
692
598
  /* Utility classes */
693
- .flowdrop-w--full {
694
- width: 100%;
695
- }
696
-
697
599
  .flowdrop-flex--1 {
698
600
  flex: 1;
699
601
  }
@@ -8,6 +8,7 @@
8
8
  <script lang="ts">
9
9
  import type { NodeMetadata, NodeCategory, WorkflowFormat, WorkflowNode } from '../types/index.js';
10
10
  import Icon from '@iconify/svelte';
11
+ import Input from './Input.svelte';
11
12
  import { getNodeIcon, getCategoryIcon } from '../utils/icons.js';
12
13
  import { getCategoryColorToken } from '../utils/colors.js';
13
14
  import { m } from '../messages/index.js';
@@ -115,12 +116,17 @@
115
116
 
116
117
  <!-- Search (hidden in minimal via --fd-sidebar-search-display) -->
117
118
  <div class="swap-picker__search">
118
- <input
119
+ <Input
119
120
  type="text"
120
121
  placeholder="Search node types..."
121
- class="swap-picker__input"
122
- bind:value={searchInput}
123
- />
122
+ aria-label="Search node types"
123
+ value={searchInput}
124
+ oninput={(e) => (searchInput = e.currentTarget.value)}
125
+ >
126
+ {#snippet leading()}
127
+ <Icon icon="mdi:magnify" />
128
+ {/snippet}
129
+ </Input>
124
130
  </div>
125
131
 
126
132
  <!-- Node list -->
@@ -139,7 +145,7 @@
139
145
  {fd.categories.getLabel(category).toUpperCase()}
140
146
  </div>
141
147
  <div class="swap-picker__flat-list">
142
- {#each categoryNodes as nodeType (nodeType.id)}
148
+ {#each categoryNodes as nodeType (nodeType.node_type_id)}
143
149
  <button class="swap-picker__flat-item" onclick={() => onSelect(nodeType)}>
144
150
  <span
145
151
  class="swap-picker__flat-dot"
@@ -168,7 +174,7 @@
168
174
  </span>
169
175
  </div>
170
176
  <div class="swap-picker__category-items">
171
- {#each categoryNodes as nodeType (nodeType.id)}
177
+ {#each categoryNodes as nodeType (nodeType.node_type_id)}
172
178
  <button class="swap-picker__item" onclick={() => onSelect(nodeType)}>
173
179
  <span
174
180
  class="swap-picker__item-icon"
@@ -298,28 +304,6 @@
298
304
  flex-shrink: 0;
299
305
  }
300
306
 
301
- .swap-picker__input {
302
- width: 100%;
303
- padding: 0.5rem 0.75rem;
304
- border: 1px solid var(--fd-border-strong);
305
- border-radius: var(--fd-radius-md);
306
- font-size: var(--fd-text-sm);
307
- color: var(--fd-foreground);
308
- background-color: var(--fd-background);
309
- box-sizing: border-box;
310
- transition:
311
- border-color var(--fd-transition-normal),
312
- box-shadow var(--fd-transition-normal);
313
- }
314
-
315
- .swap-picker__input:focus {
316
- border-color: var(--fd-ring);
317
- }
318
-
319
- .swap-picker__input::placeholder {
320
- color: var(--fd-muted-foreground);
321
- }
322
-
323
307
  .swap-picker__list {
324
308
  flex: 1;
325
309
  overflow-y: auto;
@@ -0,0 +1,53 @@
1
+ <!--
2
+ Select — typed wrapper over the shared `.flowdrop-input` system (base.css).
3
+
4
+ Renders the field shell (`.flowdrop-input .flowdrop-input--select`) plus a
5
+ built-in chevron overlay (`.flowdrop-select-wrap`), so selects match the exact
6
+ look of Input/Textarea. The native arrow is removed; the chevron tints to
7
+ --fd-primary on focus. Pass <option>/<optgroup> as children. Native attributes
8
+ (value, disabled, id, aria-*, onchange…) forward to the underlying <select>.
9
+
10
+ Internal for now; see Button.svelte / Input.svelte for the pattern.
11
+ -->
12
+
13
+ <script lang="ts">
14
+ import type { Snippet } from 'svelte';
15
+ import type { HTMLSelectAttributes } from 'svelte/elements';
16
+
17
+ // Omit native numeric `size` so our design-token size (matching Button) wins.
18
+ interface Props extends Omit<HTMLSelectAttributes, 'size'> {
19
+ /** Size — `md` is the base; `sm`/`lg` add a modifier */
20
+ size?: 'sm' | 'md' | 'lg';
21
+ /** Renders the error-border state */
22
+ invalid?: boolean;
23
+ /** Extra classes appended to the <select> */
24
+ class?: string;
25
+ /** The <option>/<optgroup> elements */
26
+ children: Snippet;
27
+ }
28
+
29
+ let { size = 'md', invalid = false, class: className = '', children, ...rest }: Props = $props();
30
+
31
+ const selectClass = $derived(
32
+ [
33
+ 'flowdrop-input',
34
+ 'flowdrop-input--select',
35
+ size === 'md' ? '' : `flowdrop-input--${size}`,
36
+ invalid ? 'flowdrop-input--invalid' : '',
37
+ className
38
+ ]
39
+ .filter(Boolean)
40
+ .join(' ')
41
+ );
42
+ </script>
43
+
44
+ <div class="flowdrop-select-wrap">
45
+ <select class={selectClass} {...rest}>
46
+ {@render children()}
47
+ </select>
48
+ <span class="flowdrop-select-wrap__icon" aria-hidden="true">
49
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
50
+ <path stroke-linecap="round" stroke-linejoin="round" d="M6 9l6 6 6-6" />
51
+ </svg>
52
+ </span>
53
+ </div>
@@ -0,0 +1,15 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { HTMLSelectAttributes } from 'svelte/elements';
3
+ interface Props extends Omit<HTMLSelectAttributes, 'size'> {
4
+ /** Size — `md` is the base; `sm`/`lg` add a modifier */
5
+ size?: 'sm' | 'md' | 'lg';
6
+ /** Renders the error-border state */
7
+ invalid?: boolean;
8
+ /** Extra classes appended to the <select> */
9
+ class?: string;
10
+ /** The <option>/<optgroup> elements */
11
+ children: Snippet;
12
+ }
13
+ declare const Select: import("svelte").Component<Props, {}, "">;
14
+ type Select = ReturnType<typeof Select>;
15
+ export default Select;
@@ -0,0 +1,39 @@
1
+ <!--
2
+ Textarea — typed wrapper over the shared `.flowdrop-input` system (base.css),
3
+ with the `.flowdrop-input--textarea` modifier (min-height + vertical resize).
4
+
5
+ Shares the exact field look of Input/Select so multiline fields render
6
+ identically. All styling lives in base.css. Native attributes (value,
7
+ placeholder, rows, disabled, id, aria-*, oninput…) forward to <textarea>.
8
+
9
+ Internal for now; see Button.svelte / Input.svelte for the pattern.
10
+ -->
11
+
12
+ <script lang="ts">
13
+ import type { HTMLTextareaAttributes } from 'svelte/elements';
14
+
15
+ interface Props extends HTMLTextareaAttributes {
16
+ /** Size — `md` is the base; `sm`/`lg` add a modifier */
17
+ size?: 'sm' | 'md' | 'lg';
18
+ /** Renders the error-border state */
19
+ invalid?: boolean;
20
+ /** Extra classes appended to the textarea */
21
+ class?: string;
22
+ }
23
+
24
+ let { size = 'md', invalid = false, class: className = '', ...rest }: Props = $props();
25
+
26
+ const textareaClass = $derived(
27
+ [
28
+ 'flowdrop-input',
29
+ 'flowdrop-input--textarea',
30
+ size === 'md' ? '' : `flowdrop-input--${size}`,
31
+ invalid ? 'flowdrop-input--invalid' : '',
32
+ className
33
+ ]
34
+ .filter(Boolean)
35
+ .join(' ')
36
+ );
37
+ </script>
38
+
39
+ <textarea class={textareaClass} {...rest}></textarea>
@@ -0,0 +1,12 @@
1
+ import type { HTMLTextareaAttributes } from 'svelte/elements';
2
+ interface Props extends HTMLTextareaAttributes {
3
+ /** Size — `md` is the base; `sm`/`lg` add a modifier */
4
+ size?: 'sm' | 'md' | 'lg';
5
+ /** Renders the error-border state */
6
+ invalid?: boolean;
7
+ /** Extra classes appended to the textarea */
8
+ class?: string;
9
+ }
10
+ declare const Textarea: import("svelte").Component<Props, {}, "">;
11
+ type Textarea = ReturnType<typeof Textarea>;
12
+ export default Textarea;
@@ -1,12 +1,15 @@
1
1
  <!--
2
2
  Theme Toggle Component
3
- A button that cycles through light, dark, and auto theme modes
4
- Displays appropriate icon for current theme state
5
- Styled with BEM syntax
3
+ A button that cycles through light, dark, and auto theme modes.
4
+ Displays the icon for the current theme state.
5
+
6
+ Built on the shared Button primitive so it stays visually and dimensionally
7
+ aligned with every other control (height, focus ring, hover) for free.
6
8
  -->
7
9
 
8
10
  <script lang="ts">
9
11
  import Icon from '@iconify/svelte';
12
+ import Button from './Button.svelte';
10
13
  import { getTheme, getResolvedTheme, cycleTheme } from '../stores/settingsStore.svelte.js';
11
14
  import type { ThemePreference } from '../types/settings.js';
12
15
 
@@ -47,7 +50,7 @@
47
50
  }
48
51
 
49
52
  /**
50
- * Get accessible label for the current theme
53
+ * Get the label text for the current theme
51
54
  */
52
55
  const themeLabel = $derived(getThemeLabel(getTheme()));
53
56
 
@@ -80,100 +83,23 @@
80
83
  const next = currentTheme === 'light' ? 'Dark' : 'Auto';
81
84
  return `Theme: ${currentTheme === 'light' ? 'Light' : 'Dark'}. Click to switch to ${next}`;
82
85
  }
83
-
84
- /**
85
- * Handle click to cycle theme
86
- */
87
- function handleClick(): void {
88
- cycleTheme();
89
- }
90
-
91
- /**
92
- * Handle keyboard events for accessibility
93
- */
94
- function handleKeydown(event: KeyboardEvent): void {
95
- if (event.key === 'Enter' || event.key === ' ') {
96
- event.preventDefault();
97
- cycleTheme();
98
- }
99
- }
100
86
  </script>
101
87
 
102
- <button
103
- class="flowdrop-theme-toggle flowdrop-theme-toggle--{size} {className}"
104
- onclick={handleClick}
105
- onkeydown={handleKeydown}
88
+ <Button
89
+ variant="outline"
90
+ {size}
91
+ class={className}
106
92
  title={tooltipText}
107
- aria-label={tooltipText}
108
- type="button"
93
+ ariaLabel={tooltipText}
94
+ onclick={cycleTheme}
109
95
  >
110
- <span class="flowdrop-theme-toggle__icon">
111
- <Icon icon={themeIcon} />
112
- </span>
96
+ <Icon icon={themeIcon} />
113
97
  {#if showLabel}
114
98
  <span class="flowdrop-theme-toggle__label">{themeLabel}</span>
115
99
  {/if}
116
- </button>
100
+ </Button>
117
101
 
118
102
  <style>
119
- .flowdrop-theme-toggle {
120
- display: inline-flex;
121
- align-items: center;
122
- justify-content: center;
123
- gap: var(--fd-space-xs);
124
- border: 1px solid var(--fd-border);
125
- border-radius: var(--fd-radius-md);
126
- background-color: var(--fd-background);
127
- color: var(--fd-foreground);
128
- cursor: pointer;
129
- transition: all var(--fd-transition-normal);
130
- font-family: inherit;
131
- }
132
-
133
- .flowdrop-theme-toggle:hover {
134
- background-color: var(--fd-muted);
135
- border-color: var(--fd-border-strong);
136
- }
137
-
138
- .flowdrop-theme-toggle:active {
139
- transform: scale(0.98);
140
- }
141
-
142
- /* Size variants */
143
- .flowdrop-theme-toggle--sm {
144
- padding: var(--fd-space-3xs) var(--fd-space-xs);
145
- font-size: var(--fd-text-xs);
146
- }
147
-
148
- .flowdrop-theme-toggle--sm .flowdrop-theme-toggle__icon {
149
- font-size: var(--fd-text-sm);
150
- }
151
-
152
- .flowdrop-theme-toggle--md {
153
- padding: var(--fd-space-xs) var(--fd-space-md);
154
- font-size: var(--fd-text-sm);
155
- }
156
-
157
- .flowdrop-theme-toggle--md .flowdrop-theme-toggle__icon {
158
- font-size: var(--fd-text-base);
159
- }
160
-
161
- .flowdrop-theme-toggle--lg {
162
- padding: var(--fd-space-md) var(--fd-space-xl);
163
- font-size: var(--fd-text-base);
164
- }
165
-
166
- .flowdrop-theme-toggle--lg .flowdrop-theme-toggle__icon {
167
- font-size: var(--fd-text-lg);
168
- }
169
-
170
- .flowdrop-theme-toggle__icon {
171
- display: flex;
172
- align-items: center;
173
- justify-content: center;
174
- line-height: 1;
175
- }
176
-
177
103
  .flowdrop-theme-toggle__label {
178
104
  font-weight: 500;
179
105
  }
@@ -21,11 +21,12 @@
21
21
  let universalNodeEl: HTMLDivElement;
22
22
 
23
23
  let {
24
+ id,
24
25
  data,
25
26
  selected = false
26
27
  }: {
28
+ id: string;
27
29
  data: WorkflowNode['data'] & {
28
- nodeId?: string;
29
30
  onConfigOpen?: (node: { id: string; type: string; data: WorkflowNode['data'] }) => void;
30
31
  };
31
32
  selected?: boolean;
@@ -81,7 +82,7 @@
81
82
  if (event.key === 'Enter' || event.key === ' ') {
82
83
  event.preventDefault();
83
84
  data.onConfigOpen?.({
84
- id: data.nodeId ?? 'unknown',
85
+ id,
85
86
  type: resolvedComponentName,
86
87
  data
87
88
  });
@@ -165,13 +166,13 @@
165
166
  {#if nodeComponent}
166
167
  <!-- Svelte 5 dynamic component limitation; reactivity maintained via $derived -->
167
168
  {@const NodeComponent = nodeComponent}
168
- <NodeComponent {data} {selected} />
169
+ <NodeComponent {id} {data} {selected} />
169
170
  {/if}
170
171
 
171
172
  <!-- Status overlay - only show if there's meaningful status information -->
172
173
  {#if shouldShowStatus}
173
174
  <NodeStatusOverlay
174
- nodeId={data.nodeId ?? 'unknown'}
175
+ nodeId={id}
175
176
  {executionInfo}
176
177
  position={getStatusPosition()}
177
178
  size={getStatusSize()}
@@ -1,7 +1,7 @@
1
1
  import type { WorkflowNode } from '../types/index.js';
2
2
  type $$ComponentProps = {
3
+ id: string;
3
4
  data: WorkflowNode['data'] & {
4
- nodeId?: string;
5
5
  onConfigOpen?: (node: {
6
6
  id: string;
7
7
  type: string;
@@ -341,10 +341,10 @@
341
341
  if (nodeTypeContext !== null) {
342
342
  const prefix = nodeTypeContext.toLowerCase();
343
343
  return nodeTypes
344
- .filter((nt) => nt.id.toLowerCase().startsWith(prefix))
344
+ .filter((nt) => nt.node_type_id.toLowerCase().startsWith(prefix))
345
345
  .map((nt) => ({
346
- value: nt.id,
347
- label: nt.id,
346
+ value: nt.node_type_id,
347
+ label: nt.node_type_id,
348
348
  detail: `${nt.name} (${nt.category})`
349
349
  }))
350
350
  .slice(0, 50);