@flowdrop/flowdrop 2.0.0-beta.2 → 2.0.0-beta.4
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 +59 -0
- package/MIGRATION-2.0.md +13 -0
- package/README.md +5 -5
- package/dist/components/App.svelte +36 -191
- package/dist/components/App.svelte.d.ts +2 -7
- 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/CanvasIconButton.svelte +76 -0
- package/dist/components/CanvasIconButton.svelte.d.ts +18 -0
- package/dist/components/ConfigForm.svelte +4 -23
- package/dist/components/ConfigPanel.svelte +4 -3
- 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/LogoWordmark.svelte +113 -0
- package/dist/components/LogoWordmark.svelte.d.ts +26 -0
- package/dist/components/Navbar.svelte +17 -63
- package/dist/components/Navbar.svelte.d.ts +3 -0
- package/dist/components/NodeSidebar.svelte +17 -122
- package/dist/components/NodeSwapPicker.svelte +10 -28
- package/dist/components/PortMappingRow.svelte +0 -2
- package/dist/components/SchemaForm.svelte +0 -12
- package/dist/components/Select.svelte +53 -0
- package/dist/components/Select.svelte.d.ts +15 -0
- package/dist/components/SettingsModal.svelte +0 -5
- package/dist/components/SettingsPanel.svelte +2 -6
- package/dist/components/Textarea.svelte +39 -0
- package/dist/components/Textarea.svelte.d.ts +12 -0
- package/dist/components/ThemeToggle.svelte +15 -94
- package/dist/components/UniversalNode.svelte +32 -1
- package/dist/components/WorkflowEditor.svelte +62 -51
- package/dist/components/WorkflowEditor.svelte.d.ts +18 -0
- package/dist/components/chat/AIChatPanel.svelte +1 -1
- package/dist/components/console/ConsoleAutocomplete.svelte +1 -1
- package/dist/components/console/ConsoleOutput.svelte +2 -2
- package/dist/components/form/FormArray.svelte +37 -173
- package/dist/components/form/FormAutocomplete.svelte +10 -6
- package/dist/components/form/FormCheckboxGroup.svelte +1 -5
- package/dist/components/form/FormCodeEditor.svelte +9 -7
- package/dist/components/form/FormField.svelte +5 -44
- package/dist/components/form/FormFieldLight.svelte +8 -47
- package/dist/components/form/FormFieldset.svelte +1 -1
- package/dist/components/form/FormMarkdownEditor.svelte +8 -5
- package/dist/components/form/FormNumberField.svelte +4 -36
- package/dist/components/form/FormRangeField.svelte +18 -27
- package/dist/components/form/FormSelect.svelte +13 -75
- package/dist/components/form/FormTemplateEditor.svelte +6 -4
- package/dist/components/form/FormTextField.svelte +3 -35
- package/dist/components/form/FormTextarea.svelte +4 -39
- package/dist/components/form/FormToggle.svelte +0 -4
- 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/icons/CommandLineIcon.svelte +15 -0
- package/dist/components/icons/CommandLineIcon.svelte.d.ts +26 -0
- package/dist/components/icons/MenuIcon.svelte +4 -0
- package/dist/components/icons/MenuIcon.svelte.d.ts +26 -0
- package/dist/components/icons/MenuOpenIcon.svelte +6 -0
- package/dist/components/icons/MenuOpenIcon.svelte.d.ts +26 -0
- package/dist/components/interrupt/ChoicePrompt.svelte +0 -10
- package/dist/components/interrupt/ConfirmationPrompt.svelte +0 -5
- package/dist/components/interrupt/InterruptBubble.svelte +0 -10
- package/dist/components/interrupt/ReviewPrompt.svelte +0 -20
- package/dist/components/interrupt/TextInputPrompt.svelte +0 -6
- package/dist/components/layouts/MainLayout.svelte +4 -5
- package/dist/components/nodes/AtomNode.svelte +46 -34
- package/dist/components/nodes/GatewayNode.svelte +91 -99
- package/dist/components/nodes/IdeaNode.svelte +62 -90
- package/dist/components/nodes/NodeConfigButton.svelte +86 -0
- package/dist/components/nodes/NodeConfigButton.svelte.d.ts +15 -0
- package/dist/components/nodes/NotesNode.svelte +70 -81
- package/dist/components/nodes/SimpleNode.svelte +28 -78
- package/dist/components/nodes/SquareNode.svelte +79 -109
- package/dist/components/nodes/TerminalNode.svelte +28 -86
- package/dist/components/nodes/ToolNode.svelte +82 -95
- package/dist/components/nodes/WorkflowNode.svelte +91 -100
- package/dist/components/playground/ChatInput.svelte +0 -1
- package/dist/components/playground/InputCollector.svelte +11 -48
- package/dist/components/playground/PlaygroundApp.svelte +1 -1
- package/dist/components/playground/PlaygroundStudio.svelte +0 -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/playground/mount.d.ts +9 -5
- package/dist/playground/mount.js +9 -5
- package/dist/skins/drafter.d.ts +30 -0
- package/dist/skins/drafter.js +198 -0
- package/dist/skins/index.d.ts +2 -1
- package/dist/skins/index.js +4 -2
- package/dist/styles/base.css +285 -14
- package/dist/styles/tokens.css +60 -2
- package/dist/svelte-app.d.ts +6 -0
- package/dist/svelte-app.js +71 -109
- package/dist/themes/drafter.d.ts +2 -0
- package/dist/themes/drafter.js +15 -0
- package/dist/themes/index.d.ts +2 -1
- package/dist/themes/index.js +8 -2
- package/dist/types/events.d.ts +18 -0
- package/dist/types/events.js +2 -1
- package/dist/types/settings.d.ts +1 -1
- package/dist/types/settings.js +1 -1
- package/dist/types/skin.d.ts +1 -1
- package/dist/types/theme.d.ts +16 -2
- package/dist/utils/connections.js +14 -50
- package/package.json +1 -1
|
@@ -198,7 +198,8 @@
|
|
|
198
198
|
description: 'Visual style and layout of the editor',
|
|
199
199
|
oneOf: [
|
|
200
200
|
{ const: 'default', title: 'Default' },
|
|
201
|
-
{ const: 'minimal', title: 'Minimal' }
|
|
201
|
+
{ const: 'minimal', title: 'Minimal' },
|
|
202
|
+
{ const: 'drafter', title: 'Drafter' }
|
|
202
203
|
],
|
|
203
204
|
default: 'default'
|
|
204
205
|
}
|
|
@@ -538,11 +539,6 @@
|
|
|
538
539
|
color: var(--fd-primary-foreground);
|
|
539
540
|
}
|
|
540
541
|
|
|
541
|
-
.flowdrop-settings-panel__tab:focus {
|
|
542
|
-
outline: none;
|
|
543
|
-
box-shadow: 0 0 0 2px var(--fd-ring);
|
|
544
|
-
}
|
|
545
|
-
|
|
546
542
|
:global(.flowdrop-settings-panel__tab-icon) {
|
|
547
543
|
font-size: var(--fd-text-base);
|
|
548
544
|
}
|
|
@@ -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,105 +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:focus {
|
|
139
|
-
outline: none;
|
|
140
|
-
box-shadow: 0 0 0 2px var(--fd-ring);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
.flowdrop-theme-toggle:active {
|
|
144
|
-
transform: scale(0.98);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/* Size variants */
|
|
148
|
-
.flowdrop-theme-toggle--sm {
|
|
149
|
-
padding: var(--fd-space-3xs) var(--fd-space-xs);
|
|
150
|
-
font-size: var(--fd-text-xs);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
.flowdrop-theme-toggle--sm .flowdrop-theme-toggle__icon {
|
|
154
|
-
font-size: var(--fd-text-sm);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
.flowdrop-theme-toggle--md {
|
|
158
|
-
padding: var(--fd-space-xs) var(--fd-space-md);
|
|
159
|
-
font-size: var(--fd-text-sm);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
.flowdrop-theme-toggle--md .flowdrop-theme-toggle__icon {
|
|
163
|
-
font-size: var(--fd-text-base);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
.flowdrop-theme-toggle--lg {
|
|
167
|
-
padding: var(--fd-space-md) var(--fd-space-xl);
|
|
168
|
-
font-size: var(--fd-text-base);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
.flowdrop-theme-toggle--lg .flowdrop-theme-toggle__icon {
|
|
172
|
-
font-size: var(--fd-text-lg);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
.flowdrop-theme-toggle__icon {
|
|
176
|
-
display: flex;
|
|
177
|
-
align-items: center;
|
|
178
|
-
justify-content: center;
|
|
179
|
-
line-height: 1;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
103
|
.flowdrop-theme-toggle__label {
|
|
183
104
|
font-weight: 500;
|
|
184
105
|
}
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
|
|
18
18
|
const fd = getInstance();
|
|
19
19
|
|
|
20
|
+
// Element ref used only to reach xyflow's node wrapper (our ancestor).
|
|
21
|
+
let universalNodeEl: HTMLDivElement;
|
|
22
|
+
|
|
20
23
|
let {
|
|
21
24
|
data,
|
|
22
25
|
selected = false
|
|
@@ -61,6 +64,34 @@
|
|
|
61
64
|
shouldShowNodeStatus(executionInfo) && resolvedComponentName !== 'note'
|
|
62
65
|
);
|
|
63
66
|
|
|
67
|
+
// Keyboard activation lives on xyflow's node wrapper — the single focusable,
|
|
68
|
+
// arrow-movable element SvelteFlow manages. Because the wrapper is our
|
|
69
|
+
// ancestor, its keydown events never bubble down into our markup, so we bind
|
|
70
|
+
// directly to it. Enter/Space opens the node's config, mirroring the
|
|
71
|
+
// double-click (and single-click for square/atom) mouse paths. Node selection
|
|
72
|
+
// and arrow-key movement remain SvelteFlow's job.
|
|
73
|
+
$effect(() => {
|
|
74
|
+
const wrapper = universalNodeEl?.closest<HTMLElement>('.svelte-flow__node');
|
|
75
|
+
if (!wrapper) return;
|
|
76
|
+
|
|
77
|
+
function onWrapperKeydown(event: KeyboardEvent): void {
|
|
78
|
+
// Only when the node itself is focused — not an inner field (e.g. an
|
|
79
|
+
// editable note) — so we don't hijack typing.
|
|
80
|
+
if (event.target !== wrapper) return;
|
|
81
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
82
|
+
event.preventDefault();
|
|
83
|
+
data.onConfigOpen?.({
|
|
84
|
+
id: data.nodeId ?? 'unknown',
|
|
85
|
+
type: resolvedComponentName,
|
|
86
|
+
data
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
wrapper.addEventListener('keydown', onWrapperKeydown);
|
|
92
|
+
return () => wrapper.removeEventListener('keydown', onWrapperKeydown);
|
|
93
|
+
});
|
|
94
|
+
|
|
64
95
|
/**
|
|
65
96
|
* Get the node component for the given type from the registry.
|
|
66
97
|
*
|
|
@@ -129,7 +160,7 @@
|
|
|
129
160
|
}
|
|
130
161
|
</script>
|
|
131
162
|
|
|
132
|
-
<div class="universal-node">
|
|
163
|
+
<div class="universal-node" bind:this={universalNodeEl}>
|
|
133
164
|
<!-- Render the node component dynamically (Svelte 5 dynamic component syntax) -->
|
|
134
165
|
{#if nodeComponent}
|
|
135
166
|
<!-- Svelte 5 dynamic component limitation; reactivity maintained via $derived -->
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
import CanvasController from './CanvasController.svelte';
|
|
27
27
|
import FlowDropZone from './FlowDropZone.svelte';
|
|
28
28
|
import EdgeRefresher from './EdgeRefresher.svelte';
|
|
29
|
-
import { tick, untrack } from 'svelte';
|
|
29
|
+
import { tick, untrack, onMount } from 'svelte';
|
|
30
30
|
import type { EndpointConfig } from '../config/endpoints.js';
|
|
31
31
|
import type { AuthProvider } from '../types/auth.js';
|
|
32
32
|
import ConnectionLine from './ConnectionLine.svelte';
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
import { m } from '../messages/index.js';
|
|
35
35
|
import { provideInstance } from '../stores/getInstance.svelte.js';
|
|
36
36
|
import type { FlowDropInstance } from '../stores/instanceContainer.svelte.js';
|
|
37
|
+
import type { FlowDropGridVariant } from '../types/theme.js';
|
|
37
38
|
import UniversalNode from './UniversalNode.svelte';
|
|
38
39
|
import {
|
|
39
40
|
EdgeStylingHelper,
|
|
@@ -56,7 +57,8 @@
|
|
|
56
57
|
import { logger } from '../utils/logger.js';
|
|
57
58
|
import { validateWorkflowData } from '../utils/validation.js';
|
|
58
59
|
import { createEditorStateMachine } from '../stores/editorStateMachine.svelte.js';
|
|
59
|
-
import
|
|
60
|
+
import CanvasIconButton from './CanvasIconButton.svelte';
|
|
61
|
+
import CommandLineIcon from './icons/CommandLineIcon.svelte';
|
|
60
62
|
import { DEV } from 'esm-env';
|
|
61
63
|
|
|
62
64
|
interface Props {
|
|
@@ -85,6 +87,23 @@
|
|
|
85
87
|
onToggleConsole?: () => void;
|
|
86
88
|
/** Per-instance state container (created by mount functions). Defaults to the page-default instance. */
|
|
87
89
|
instance?: FlowDropInstance;
|
|
90
|
+
/**
|
|
91
|
+
* Canvas background grid pattern. Supplied by App from the active theme's
|
|
92
|
+
* `config.canvas.grid` default; any theme can opt into 'lines' / 'cross'.
|
|
93
|
+
* Color is driven separately by the `--fd-grid-pattern-color` token.
|
|
94
|
+
* @default 'dots'
|
|
95
|
+
*/
|
|
96
|
+
gridVariant?: FlowDropGridVariant;
|
|
97
|
+
/**
|
|
98
|
+
* Register the built-in heavy form editors (markdown / code / template)
|
|
99
|
+
* on this instance's field registry. Batteries-included by default — node
|
|
100
|
+
* config fields with `format: 'markdown' | 'code' | 'template'` render real
|
|
101
|
+
* CodeMirror editors. The chunks are code-split (loaded lazily here), so
|
|
102
|
+
* the `/editor` static bundle stays light. Set `false` to keep the textarea
|
|
103
|
+
* fallback or register your own field components. See `features.builtinEditors`.
|
|
104
|
+
* @default true
|
|
105
|
+
*/
|
|
106
|
+
builtinEditors?: boolean;
|
|
88
107
|
}
|
|
89
108
|
|
|
90
109
|
let props: Props = $props();
|
|
@@ -95,10 +114,36 @@
|
|
|
95
114
|
// svelte-ignore state_referenced_locally
|
|
96
115
|
const fd = provideInstance(props.instance);
|
|
97
116
|
|
|
117
|
+
// Batteries-included: register the built-in heavy form editors (markdown /
|
|
118
|
+
// code / template) on this instance's field registry so node config fields
|
|
119
|
+
// render real editors out of the box. Dynamic import is deliberate — the
|
|
120
|
+
// bundle guard only inspects *static* imports, and `form/markdown`/`form/code`
|
|
121
|
+
// statically re-export their CodeMirror components, so a static import here
|
|
122
|
+
// would leak CodeMirror into the light `/editor` entry. Importing lazily on
|
|
123
|
+
// mount keeps the static graph clean while the chunks load on demand.
|
|
124
|
+
// register*Field is idempotent per registry, so re-mounts are safe.
|
|
125
|
+
onMount(() => {
|
|
126
|
+
if (props.builtinEditors === false) return;
|
|
127
|
+
void (async () => {
|
|
128
|
+
const [code, markdown] = await Promise.all([
|
|
129
|
+
import('../form/code.js'),
|
|
130
|
+
import('../form/markdown.js')
|
|
131
|
+
]);
|
|
132
|
+
code.registerCodeEditorField(fd.fields);
|
|
133
|
+
code.registerTemplateEditorField(fd.fields);
|
|
134
|
+
markdown.registerMarkdownEditorField(fd.fields);
|
|
135
|
+
})();
|
|
136
|
+
});
|
|
137
|
+
|
|
98
138
|
// `mode` is the public API; the canvas only needs to know whether editing is
|
|
99
139
|
// enabled. 'readonly' and 'locked' both disable interaction identically.
|
|
100
140
|
const canvasEditable = $derived((props.mode ?? 'edit') === 'edit');
|
|
101
141
|
|
|
142
|
+
// Canvas grid pattern, supplied by the active theme's config.canvas.grid
|
|
143
|
+
// (App passes it down). BackgroundVariant's enum values are the same strings
|
|
144
|
+
// ('dots' | 'lines' | 'cross'), so the theme config maps straight through.
|
|
145
|
+
const gridVariant = $derived((props.gridVariant ?? 'dots') as BackgroundVariant);
|
|
146
|
+
|
|
102
147
|
// ---------------------------------------------------------------------------
|
|
103
148
|
// Editor State Machine
|
|
104
149
|
// Centralizes reactive guards — replaces scattered boolean flags
|
|
@@ -875,23 +920,26 @@
|
|
|
875
920
|
>
|
|
876
921
|
<Controls />
|
|
877
922
|
{#if canvasEditable && props.onToggleConsole}
|
|
878
|
-
<
|
|
923
|
+
<CanvasIconButton
|
|
879
924
|
class="flowdrop-console-toggle"
|
|
880
|
-
|
|
925
|
+
label={m().layout.commandConsole}
|
|
926
|
+
active={props.consoleOpen}
|
|
881
927
|
onclick={props.onToggleConsole}
|
|
882
|
-
aria-label={m().layout.commandConsole}
|
|
883
|
-
title={m().layout.commandConsole}
|
|
884
|
-
type="button"
|
|
885
928
|
>
|
|
886
|
-
|
|
887
|
-
|
|
929
|
+
{#snippet icon()}
|
|
930
|
+
<CommandLineIcon />
|
|
931
|
+
{/snippet}
|
|
932
|
+
</CanvasIconButton>
|
|
888
933
|
{/if}
|
|
889
934
|
<!-- Always render Background for consistent bg color in dark/light mode -->
|
|
890
935
|
<Background
|
|
891
936
|
gap={getEditorSettings().gridSize}
|
|
892
|
-
bgColor="var(--fd-
|
|
893
|
-
variant={
|
|
894
|
-
|
|
937
|
+
bgColor="var(--fd-canvas-bg)"
|
|
938
|
+
variant={gridVariant}
|
|
939
|
+
lineWidth={1}
|
|
940
|
+
patternColor={getEditorSettings().showGrid
|
|
941
|
+
? 'var(--fd-grid-pattern-color)'
|
|
942
|
+
: 'transparent'}
|
|
895
943
|
/>
|
|
896
944
|
{#if getEditorSettings().showMinimap}
|
|
897
945
|
<MiniMap />
|
|
@@ -1006,48 +1054,11 @@
|
|
|
1006
1054
|
justify-content: space-between;
|
|
1007
1055
|
}
|
|
1008
1056
|
|
|
1009
|
-
|
|
1010
|
-
|
|
1057
|
+
/* Console toggle — placement only; visuals live in CanvasIconButton */
|
|
1058
|
+
:global(.flowdrop-console-toggle) {
|
|
1011
1059
|
bottom: 140px;
|
|
1012
1060
|
left: 12px;
|
|
1013
1061
|
z-index: 5;
|
|
1014
|
-
display: flex;
|
|
1015
|
-
align-items: center;
|
|
1016
|
-
justify-content: center;
|
|
1017
|
-
width: 2rem;
|
|
1018
|
-
height: 2rem;
|
|
1019
|
-
border: 1px solid var(--fd-border);
|
|
1020
|
-
border-radius: var(--fd-radius-md);
|
|
1021
|
-
background-color: var(--fd-background);
|
|
1022
|
-
color: var(--fd-muted-foreground);
|
|
1023
|
-
cursor: pointer;
|
|
1024
|
-
box-shadow: var(--fd-shadow-sm);
|
|
1025
|
-
transition:
|
|
1026
|
-
color var(--fd-transition-fast),
|
|
1027
|
-
background-color var(--fd-transition-fast),
|
|
1028
|
-
box-shadow var(--fd-transition-fast);
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
.flowdrop-console-toggle:hover {
|
|
1032
|
-
color: var(--fd-foreground);
|
|
1033
|
-
background-color: var(--fd-subtle);
|
|
1034
|
-
box-shadow: var(--fd-shadow-md);
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
.flowdrop-console-toggle:focus {
|
|
1038
|
-
outline: none;
|
|
1039
|
-
box-shadow: 0 0 0 2px var(--fd-ring);
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
.flowdrop-console-toggle--active {
|
|
1043
|
-
color: var(--fd-primary);
|
|
1044
|
-
background-color: var(--fd-primary-muted);
|
|
1045
|
-
border-color: var(--fd-primary);
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
.flowdrop-console-toggle--active:hover {
|
|
1049
|
-
color: var(--fd-primary);
|
|
1050
|
-
background-color: var(--fd-primary-muted);
|
|
1051
1062
|
}
|
|
1052
1063
|
|
|
1053
1064
|
:global(.flowdrop-workflow-editor .svelte-flow__node:hover) {
|
|
@@ -3,6 +3,7 @@ import type { WorkflowNode as WorkflowNodeType } from '../types/index.js';
|
|
|
3
3
|
import type { EndpointConfig } from '../config/endpoints.js';
|
|
4
4
|
import type { AuthProvider } from '../types/auth.js';
|
|
5
5
|
import type { FlowDropInstance } from '../stores/instanceContainer.svelte.js';
|
|
6
|
+
import type { FlowDropGridVariant } from '../types/theme.js';
|
|
6
7
|
interface Props {
|
|
7
8
|
endpointConfig?: EndpointConfig;
|
|
8
9
|
/** Auth provider applied to this instance's API requests. */
|
|
@@ -27,6 +28,23 @@ interface Props {
|
|
|
27
28
|
onToggleConsole?: () => void;
|
|
28
29
|
/** Per-instance state container (created by mount functions). Defaults to the page-default instance. */
|
|
29
30
|
instance?: FlowDropInstance;
|
|
31
|
+
/**
|
|
32
|
+
* Canvas background grid pattern. Supplied by App from the active theme's
|
|
33
|
+
* `config.canvas.grid` default; any theme can opt into 'lines' / 'cross'.
|
|
34
|
+
* Color is driven separately by the `--fd-grid-pattern-color` token.
|
|
35
|
+
* @default 'dots'
|
|
36
|
+
*/
|
|
37
|
+
gridVariant?: FlowDropGridVariant;
|
|
38
|
+
/**
|
|
39
|
+
* Register the built-in heavy form editors (markdown / code / template)
|
|
40
|
+
* on this instance's field registry. Batteries-included by default — node
|
|
41
|
+
* config fields with `format: 'markdown' | 'code' | 'template'` render real
|
|
42
|
+
* CodeMirror editors. The chunks are code-split (loaded lazily here), so
|
|
43
|
+
* the `/editor` static bundle stays light. Set `false` to keep the textarea
|
|
44
|
+
* fallback or register your own field components. See `features.builtinEditors`.
|
|
45
|
+
* @default true
|
|
46
|
+
*/
|
|
47
|
+
builtinEditors?: boolean;
|
|
30
48
|
}
|
|
31
49
|
declare const WorkflowEditor: import("svelte").Component<Props, {
|
|
32
50
|
updateNodeData: (nodeId: string, dataUpdates: Partial<WorkflowNodeType["data"]>) => void;
|
|
@@ -68,12 +68,12 @@
|
|
|
68
68
|
|
|
69
69
|
.console-output::-webkit-scrollbar-track {
|
|
70
70
|
background: var(--fd-scrollbar-track);
|
|
71
|
-
border-radius:
|
|
71
|
+
border-radius: var(--fd-scrollbar-radius);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
.console-output::-webkit-scrollbar-thumb {
|
|
75
75
|
background: var(--fd-scrollbar-thumb);
|
|
76
|
-
border-radius:
|
|
76
|
+
border-radius: var(--fd-scrollbar-radius);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
.console-output::-webkit-scrollbar-thumb:hover {
|