@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.
- package/CHANGELOG.md +38 -0
- package/README.md +5 -5
- package/dist/adapters/WorkflowAdapter.js +4 -5
- package/dist/adapters/agentspec/AgentSpecAdapter.js +3 -3
- package/dist/adapters/agentspec/defaultNodeTypes.js +9 -9
- package/dist/commands/executor.js +5 -6
- package/dist/commands/types.js +5 -5
- package/dist/components/App.svelte +19 -150
- package/dist/components/Button.stories.svelte +65 -0
- package/dist/components/Button.stories.svelte.d.ts +19 -0
- package/dist/components/Button.svelte +62 -0
- package/dist/components/Button.svelte.d.ts +24 -0
- package/dist/components/ConfigForm.svelte +4 -4
- package/dist/components/EditorStatusBar.stories.svelte +44 -0
- package/dist/components/EditorStatusBar.stories.svelte.d.ts +27 -0
- package/dist/components/EditorStatusBar.svelte +99 -0
- package/dist/components/EditorStatusBar.svelte.d.ts +15 -0
- package/dist/components/IconButton.svelte +80 -0
- package/dist/components/IconButton.svelte.d.ts +30 -0
- package/dist/components/Input.svelte +74 -0
- package/dist/components/Input.svelte.d.ts +17 -0
- package/dist/components/Navbar.svelte +9 -4
- package/dist/components/Navbar.svelte.d.ts +3 -0
- package/dist/components/NodeSidebar.svelte +17 -115
- package/dist/components/NodeSwapPicker.svelte +12 -28
- package/dist/components/Select.svelte +53 -0
- package/dist/components/Select.svelte.d.ts +15 -0
- package/dist/components/Textarea.svelte +39 -0
- package/dist/components/Textarea.svelte.d.ts +12 -0
- package/dist/components/ThemeToggle.svelte +15 -89
- package/dist/components/UniversalNode.svelte +5 -4
- package/dist/components/UniversalNode.svelte.d.ts +1 -1
- package/dist/components/console/ConsoleInput.svelte +3 -3
- package/dist/components/form/FormArray.svelte +37 -157
- package/dist/components/form/FormCheckboxGroup.svelte +1 -1
- package/dist/components/form/FormField.svelte +5 -44
- package/dist/components/form/FormFieldLight.svelte +5 -44
- package/dist/components/form/FormFieldset.svelte +1 -1
- package/dist/components/form/FormNumberField.svelte +4 -32
- package/dist/components/form/FormRangeField.svelte +17 -7
- package/dist/components/form/FormSelect.svelte +13 -79
- package/dist/components/form/FormTextField.svelte +3 -39
- package/dist/components/form/FormTextarea.svelte +4 -43
- package/dist/components/form/resolveFieldType.d.ts +24 -0
- package/dist/components/form/resolveFieldType.js +55 -0
- package/dist/components/icons/CloseIcon.svelte +6 -0
- package/dist/components/icons/CloseIcon.svelte.d.ts +26 -0
- package/dist/components/nodes/AtomNode.svelte +3 -3
- package/dist/components/nodes/AtomNode.svelte.d.ts +1 -1
- package/dist/components/nodes/GatewayNode.svelte +8 -11
- package/dist/components/nodes/GatewayNode.svelte.d.ts +1 -1
- package/dist/components/nodes/IdeaNode.svelte +10 -8
- package/dist/components/nodes/IdeaNode.svelte.d.ts +8 -4
- package/dist/components/nodes/NotesNode.svelte +6 -4
- package/dist/components/nodes/NotesNode.svelte.d.ts +8 -4
- package/dist/components/nodes/SimpleNode.svelte +10 -8
- package/dist/components/nodes/SimpleNode.svelte.d.ts +4 -4
- package/dist/components/nodes/SquareNode.svelte +10 -8
- package/dist/components/nodes/SquareNode.svelte.d.ts +4 -4
- package/dist/components/nodes/TerminalNode.svelte +10 -8
- package/dist/components/nodes/TerminalNode.svelte.d.ts +4 -4
- package/dist/components/nodes/ToolNode.svelte +10 -8
- package/dist/components/nodes/ToolNode.svelte.d.ts +6 -6
- package/dist/components/nodes/WorkflowNode.svelte +7 -10
- package/dist/components/nodes/WorkflowNode.svelte.d.ts +1 -1
- package/dist/components/playground/InputCollector.svelte +11 -46
- package/dist/components/playground/PipelineKanbanView.svelte +2 -2
- package/dist/components/playground/PipelineTableView.svelte +2 -2
- package/dist/helpers/workflowEditorHelper.js +4 -5
- package/dist/messages/index.d.ts +1 -1
- package/dist/messages/index.js +1 -1
- package/dist/openapi/v1/openapi.yaml +2 -2
- package/dist/registry/nodeComponentRegistry.d.ts +2 -1
- package/dist/services/dynamicSchemaService.d.ts +2 -2
- package/dist/services/dynamicSchemaService.js +8 -8
- package/dist/skins/drafter.js +41 -28
- package/dist/stores/playgroundStore.svelte.js +1 -1
- package/dist/stores/workflowStore.svelte.js +0 -18
- package/dist/styles/base.css +247 -5
- package/dist/styles/tokens.css +6 -0
- package/dist/svelte-app.js +68 -107
- package/dist/types/index.d.ts +6 -7
- package/dist/utils/connections.js +20 -56
- package/dist/utils/nodeIds.d.ts +1 -1
- package/dist/utils/nodeIds.js +1 -1
- package/dist/utils/nodeSwap.js +3 -6
- 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.
|
|
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
|
-
<
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
-
/*
|
|
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
|
-
<
|
|
119
|
+
<Input
|
|
119
120
|
type="text"
|
|
120
121
|
placeholder="Search node types..."
|
|
121
|
-
|
|
122
|
-
|
|
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.
|
|
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.
|
|
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
|
|
5
|
-
|
|
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
|
|
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
|
-
<
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
88
|
+
<Button
|
|
89
|
+
variant="outline"
|
|
90
|
+
{size}
|
|
91
|
+
class={className}
|
|
106
92
|
title={tooltipText}
|
|
107
|
-
|
|
108
|
-
|
|
93
|
+
ariaLabel={tooltipText}
|
|
94
|
+
onclick={cycleTheme}
|
|
109
95
|
>
|
|
110
|
-
<
|
|
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
|
-
</
|
|
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
|
|
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={
|
|
175
|
+
nodeId={id}
|
|
175
176
|
{executionInfo}
|
|
176
177
|
position={getStatusPosition()}
|
|
177
178
|
size={getStatusSize()}
|
|
@@ -341,10 +341,10 @@
|
|
|
341
341
|
if (nodeTypeContext !== null) {
|
|
342
342
|
const prefix = nodeTypeContext.toLowerCase();
|
|
343
343
|
return nodeTypes
|
|
344
|
-
.filter((nt) => nt.
|
|
344
|
+
.filter((nt) => nt.node_type_id.toLowerCase().startsWith(prefix))
|
|
345
345
|
.map((nt) => ({
|
|
346
|
-
value: nt.
|
|
347
|
-
label: nt.
|
|
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);
|