@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
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
/**
|
|
6
|
+
* The icon to render — an inline-SVG snippet (offline-safe). Pass a local
|
|
7
|
+
* icon component from `$lib/components/icons/`, not a network-fetched one.
|
|
8
|
+
*/
|
|
9
|
+
icon: Snippet;
|
|
10
|
+
/** Accessible label — drives both aria-label and the hover title. */
|
|
11
|
+
label: string;
|
|
12
|
+
/** Renders the active/toggled-on visual state (e.g. the panel it controls is open). */
|
|
13
|
+
active?: boolean;
|
|
14
|
+
onclick: () => void;
|
|
15
|
+
/** Caller-supplied class for positioning (top/left/bottom/z-index). */
|
|
16
|
+
class?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
let { icon, label, active = false, onclick, class: klass = '' }: Props = $props();
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<button
|
|
23
|
+
class="flowdrop-canvas-btn {klass}"
|
|
24
|
+
class:flowdrop-canvas-btn--active={active}
|
|
25
|
+
{onclick}
|
|
26
|
+
aria-label={label}
|
|
27
|
+
title={label}
|
|
28
|
+
type="button"
|
|
29
|
+
>
|
|
30
|
+
{@render icon()}
|
|
31
|
+
</button>
|
|
32
|
+
|
|
33
|
+
<style>
|
|
34
|
+
.flowdrop-canvas-btn {
|
|
35
|
+
position: absolute;
|
|
36
|
+
display: flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
justify-content: center;
|
|
39
|
+
width: 2.25rem;
|
|
40
|
+
height: 2.25rem;
|
|
41
|
+
border: 1px solid var(--fd-border);
|
|
42
|
+
border-radius: var(--fd-radius-md);
|
|
43
|
+
background-color: var(--fd-background);
|
|
44
|
+
color: var(--fd-muted-foreground);
|
|
45
|
+
cursor: pointer;
|
|
46
|
+
box-shadow: var(--fd-shadow-md);
|
|
47
|
+
transition:
|
|
48
|
+
color var(--fd-transition-fast),
|
|
49
|
+
background-color var(--fd-transition-fast),
|
|
50
|
+
box-shadow var(--fd-transition-fast),
|
|
51
|
+
border-color var(--fd-transition-fast);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Size whatever inline SVG the caller renders. */
|
|
55
|
+
.flowdrop-canvas-btn :global(svg) {
|
|
56
|
+
width: 18px;
|
|
57
|
+
height: 18px;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.flowdrop-canvas-btn:hover {
|
|
61
|
+
color: var(--fd-foreground);
|
|
62
|
+
background-color: var(--fd-subtle);
|
|
63
|
+
box-shadow: var(--fd-shadow-lg);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.flowdrop-canvas-btn--active {
|
|
67
|
+
color: var(--fd-primary);
|
|
68
|
+
background-color: var(--fd-primary-muted);
|
|
69
|
+
border-color: var(--fd-primary);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.flowdrop-canvas-btn--active:hover {
|
|
73
|
+
color: var(--fd-primary);
|
|
74
|
+
background-color: var(--fd-primary-muted);
|
|
75
|
+
}
|
|
76
|
+
</style>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
/**
|
|
4
|
+
* The icon to render — an inline-SVG snippet (offline-safe). Pass a local
|
|
5
|
+
* icon component from `$lib/components/icons/`, not a network-fetched one.
|
|
6
|
+
*/
|
|
7
|
+
icon: Snippet;
|
|
8
|
+
/** Accessible label — drives both aria-label and the hover title. */
|
|
9
|
+
label: string;
|
|
10
|
+
/** Renders the active/toggled-on visual state (e.g. the panel it controls is open). */
|
|
11
|
+
active?: boolean;
|
|
12
|
+
onclick: () => void;
|
|
13
|
+
/** Caller-supplied class for positioning (top/left/bottom/z-index). */
|
|
14
|
+
class?: string;
|
|
15
|
+
}
|
|
16
|
+
declare const CanvasIconButton: import("svelte").Component<Props, {}, "">;
|
|
17
|
+
type CanvasIconButton = ReturnType<typeof CanvasIconButton>;
|
|
18
|
+
export default CanvasIconButton;
|
|
@@ -1044,7 +1044,7 @@
|
|
|
1044
1044
|
justify-content: center;
|
|
1045
1045
|
gap: var(--fd-space-xs);
|
|
1046
1046
|
padding: 0.625rem var(--fd-space-xl);
|
|
1047
|
-
border-radius: var(--fd-radius
|
|
1047
|
+
border-radius: var(--fd-control-radius);
|
|
1048
1048
|
font-size: var(--fd-text-sm);
|
|
1049
1049
|
font-weight: 600;
|
|
1050
1050
|
font-family: inherit;
|
|
@@ -1073,11 +1073,6 @@
|
|
|
1073
1073
|
color: var(--fd-foreground);
|
|
1074
1074
|
}
|
|
1075
1075
|
|
|
1076
|
-
.config-form__button--secondary:focus-visible {
|
|
1077
|
-
outline: none;
|
|
1078
|
-
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2);
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
1076
|
.config-form__button--primary {
|
|
1082
1077
|
background: linear-gradient(135deg, var(--fd-primary) 0%, var(--fd-primary-hover) 100%);
|
|
1083
1078
|
color: var(--fd-primary-foreground);
|
|
@@ -1098,13 +1093,6 @@
|
|
|
1098
1093
|
transform: translateY(0);
|
|
1099
1094
|
}
|
|
1100
1095
|
|
|
1101
|
-
.config-form__button--primary:focus-visible {
|
|
1102
|
-
outline: none;
|
|
1103
|
-
box-shadow:
|
|
1104
|
-
0 0 0 3px rgba(59, 130, 246, 0.4),
|
|
1105
|
-
0 4px 12px rgba(59, 130, 246, 0.35);
|
|
1106
|
-
}
|
|
1107
|
-
|
|
1108
1096
|
/* ============================================
|
|
1109
1097
|
UI EXTENSIONS SECTION
|
|
1110
1098
|
============================================ */
|
|
@@ -1112,7 +1100,7 @@
|
|
|
1112
1100
|
.config-form__extensions {
|
|
1113
1101
|
background-color: var(--fd-muted);
|
|
1114
1102
|
border: 1px solid var(--fd-border);
|
|
1115
|
-
border-radius: var(--fd-radius
|
|
1103
|
+
border-radius: var(--fd-control-radius);
|
|
1116
1104
|
overflow: hidden;
|
|
1117
1105
|
margin-top: var(--fd-space-xs);
|
|
1118
1106
|
}
|
|
@@ -1283,7 +1271,7 @@
|
|
|
1283
1271
|
.config-form__debug {
|
|
1284
1272
|
background-color: var(--fd-warning-muted);
|
|
1285
1273
|
border: 1px solid var(--fd-warning);
|
|
1286
|
-
border-radius: var(--fd-radius
|
|
1274
|
+
border-radius: var(--fd-control-radius);
|
|
1287
1275
|
overflow: hidden;
|
|
1288
1276
|
}
|
|
1289
1277
|
|
|
@@ -1437,7 +1425,7 @@
|
|
|
1437
1425
|
.config-form__error {
|
|
1438
1426
|
background-color: var(--fd-error-muted);
|
|
1439
1427
|
border: 1px solid var(--fd-error);
|
|
1440
|
-
border-radius: var(--fd-radius
|
|
1428
|
+
border-radius: var(--fd-control-radius);
|
|
1441
1429
|
overflow: hidden;
|
|
1442
1430
|
}
|
|
1443
1431
|
|
|
@@ -1559,11 +1547,4 @@
|
|
|
1559
1547
|
.config-form__button--external:active {
|
|
1560
1548
|
transform: translateY(0);
|
|
1561
1549
|
}
|
|
1562
|
-
|
|
1563
|
-
.config-form__button--external:focus-visible {
|
|
1564
|
-
outline: none;
|
|
1565
|
-
box-shadow:
|
|
1566
|
-
0 0 0 3px rgba(99, 102, 241, 0.4),
|
|
1567
|
-
0 4px 12px rgba(99, 102, 241, 0.35);
|
|
1568
|
-
}
|
|
1569
1550
|
</style>
|
|
@@ -110,7 +110,8 @@
|
|
|
110
110
|
height: 100%;
|
|
111
111
|
display: flex;
|
|
112
112
|
flex-direction: column;
|
|
113
|
-
background-color: var(--fd-
|
|
113
|
+
background-color: var(--fd-panel-bg);
|
|
114
|
+
backdrop-filter: var(--fd-panel-backdrop-filter);
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
.config-panel__header {
|
|
@@ -119,7 +120,7 @@
|
|
|
119
120
|
align-items: center;
|
|
120
121
|
padding: 0.875rem 1rem;
|
|
121
122
|
border-bottom: 1px solid var(--fd-border);
|
|
122
|
-
background-color: var(--fd-
|
|
123
|
+
background-color: var(--fd-card);
|
|
123
124
|
flex-shrink: 0;
|
|
124
125
|
}
|
|
125
126
|
|
|
@@ -180,7 +181,7 @@
|
|
|
180
181
|
.config-panel__details {
|
|
181
182
|
padding: 0.75rem 1rem;
|
|
182
183
|
border-bottom: 1px solid var(--fd-border-muted);
|
|
183
|
-
background-color: var(--fd-
|
|
184
|
+
background-color: var(--fd-card);
|
|
184
185
|
flex-shrink: 0;
|
|
185
186
|
}
|
|
186
187
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<script module>
|
|
2
|
+
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
3
|
+
import EditorStatusBar from './EditorStatusBar.svelte';
|
|
4
|
+
import { fn } from 'storybook/test';
|
|
5
|
+
|
|
6
|
+
const { Story } = defineMeta({
|
|
7
|
+
title: 'Editor/EditorStatusBar',
|
|
8
|
+
component: EditorStatusBar,
|
|
9
|
+
tags: ['autodocs'],
|
|
10
|
+
parameters: {
|
|
11
|
+
// The banner is full-width editor chrome — show it edge to edge.
|
|
12
|
+
layout: 'fullscreen'
|
|
13
|
+
},
|
|
14
|
+
args: {
|
|
15
|
+
onRetry: fn(),
|
|
16
|
+
onSetApiUrl: fn(),
|
|
17
|
+
onTestApi: fn(),
|
|
18
|
+
onDismiss: fn()
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<Story
|
|
24
|
+
name="Default"
|
|
25
|
+
args={{
|
|
26
|
+
error: 'API Error: Failed to fetch. No node types available.'
|
|
27
|
+
}}
|
|
28
|
+
/>
|
|
29
|
+
|
|
30
|
+
<!-- The real message when the endpoint serves HTML (e.g. a 404 page) instead of JSON. -->
|
|
31
|
+
<Story
|
|
32
|
+
name="Long Message"
|
|
33
|
+
args={{
|
|
34
|
+
error:
|
|
35
|
+
'API Error: Unexpected token \'<\', "<!doctype "... is not valid JSON. No node types available.'
|
|
36
|
+
}}
|
|
37
|
+
/>
|
|
38
|
+
|
|
39
|
+
<Story
|
|
40
|
+
name="Endpoint Unreachable"
|
|
41
|
+
args={{
|
|
42
|
+
error: 'API Error: NetworkError when attempting to fetch resource. No node types available.'
|
|
43
|
+
}}
|
|
44
|
+
/>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export default EditorStatusBar;
|
|
2
|
+
type EditorStatusBar = SvelteComponent<{
|
|
3
|
+
[x: string]: never;
|
|
4
|
+
}, {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
}, {}> & {
|
|
7
|
+
$$bindings?: string | undefined;
|
|
8
|
+
};
|
|
9
|
+
declare const EditorStatusBar: $$__sveltets_2_IsomorphicComponent<{
|
|
10
|
+
[x: string]: never;
|
|
11
|
+
}, {
|
|
12
|
+
[evt: string]: CustomEvent<any>;
|
|
13
|
+
}, {}, {}, string>;
|
|
14
|
+
import EditorStatusBar from './EditorStatusBar.svelte';
|
|
15
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
16
|
+
new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
|
|
17
|
+
$$bindings?: Bindings;
|
|
18
|
+
} & Exports;
|
|
19
|
+
(internal: unknown, props: {
|
|
20
|
+
$$events?: Events;
|
|
21
|
+
$$slots?: Slots;
|
|
22
|
+
}): Exports & {
|
|
23
|
+
$set?: any;
|
|
24
|
+
$on?: any;
|
|
25
|
+
};
|
|
26
|
+
z_$$bindings?: Bindings;
|
|
27
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
EditorStatusBar — the dismissible error banner shown above the editor canvas
|
|
3
|
+
when node types fail to load (endpoint missing or unreachable).
|
|
4
|
+
|
|
5
|
+
Extracted from App.svelte so it can be storied/tested in isolation. The action
|
|
6
|
+
buttons route through the shared Button primitive; all colours come from design
|
|
7
|
+
tokens, so the banner stays in sync with the rest of the editor chrome.
|
|
8
|
+
-->
|
|
9
|
+
<script lang="ts">
|
|
10
|
+
import Button from './Button.svelte';
|
|
11
|
+
import CloseIcon from './icons/CloseIcon.svelte';
|
|
12
|
+
|
|
13
|
+
interface Props {
|
|
14
|
+
/** The error message to display (rendered after an "Error:" prefix). */
|
|
15
|
+
error: string;
|
|
16
|
+
/** Retry loading node types. */
|
|
17
|
+
onRetry: () => void;
|
|
18
|
+
/** Prompt for / set a new backend API URL. */
|
|
19
|
+
onSetApiUrl: () => void;
|
|
20
|
+
/** Run a connectivity test against the configured endpoint. */
|
|
21
|
+
onTestApi: () => void;
|
|
22
|
+
/** Dismiss the banner. */
|
|
23
|
+
onDismiss: () => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let { error, onRetry, onSetApiUrl, onTestApi, onDismiss }: Props = $props();
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<!-- aria-live announces the API error dynamically without requiring focus -->
|
|
30
|
+
<div class="flowdrop-status flowdrop-status--error" aria-live="polite" aria-atomic="true">
|
|
31
|
+
<div class="flowdrop-status__content">
|
|
32
|
+
<div class="flowdrop-status__message">
|
|
33
|
+
<div class="flowdrop-status__indicator"></div>
|
|
34
|
+
<span class="flowdrop-status__text">Error: {error}</span>
|
|
35
|
+
</div>
|
|
36
|
+
<div class="flowdrop-status__actions">
|
|
37
|
+
<Button variant="primary" size="sm" onclick={onRetry}>Retry</Button>
|
|
38
|
+
<Button variant="outline" size="sm" onclick={onSetApiUrl}>Set API URL</Button>
|
|
39
|
+
<Button variant="outline" size="sm" onclick={onTestApi}>Test API</Button>
|
|
40
|
+
<Button variant="ghost" size="sm" ariaLabel="Dismiss error" onclick={onDismiss}>
|
|
41
|
+
<span class="flowdrop-status__dismiss-icon"><CloseIcon /></span>
|
|
42
|
+
</Button>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<style>
|
|
48
|
+
.flowdrop-status {
|
|
49
|
+
padding: var(--fd-space-xl);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.flowdrop-status--error {
|
|
53
|
+
background-color: var(--fd-error-muted);
|
|
54
|
+
border-bottom: 1px solid var(--fd-error);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.flowdrop-status__content {
|
|
58
|
+
display: flex;
|
|
59
|
+
align-items: center;
|
|
60
|
+
justify-content: space-between;
|
|
61
|
+
gap: var(--fd-space-md);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.flowdrop-status__message {
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: center;
|
|
67
|
+
gap: var(--fd-space-md);
|
|
68
|
+
min-width: 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.flowdrop-status__indicator {
|
|
72
|
+
flex-shrink: 0;
|
|
73
|
+
width: 0.5rem;
|
|
74
|
+
height: 0.5rem;
|
|
75
|
+
border-radius: 50%;
|
|
76
|
+
background-color: var(--fd-error);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.flowdrop-status__text {
|
|
80
|
+
font-size: var(--fd-text-sm);
|
|
81
|
+
line-height: 1.25rem;
|
|
82
|
+
font-weight: 500;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.flowdrop-status__actions {
|
|
86
|
+
display: flex;
|
|
87
|
+
gap: var(--fd-space-xs);
|
|
88
|
+
flex-shrink: 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.flowdrop-status__dismiss-icon {
|
|
92
|
+
display: inline-flex;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.flowdrop-status__dismiss-icon :global(svg) {
|
|
96
|
+
width: 0.875rem;
|
|
97
|
+
height: 0.875rem;
|
|
98
|
+
}
|
|
99
|
+
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
/** The error message to display (rendered after an "Error:" prefix). */
|
|
3
|
+
error: string;
|
|
4
|
+
/** Retry loading node types. */
|
|
5
|
+
onRetry: () => void;
|
|
6
|
+
/** Prompt for / set a new backend API URL. */
|
|
7
|
+
onSetApiUrl: () => void;
|
|
8
|
+
/** Run a connectivity test against the configured endpoint. */
|
|
9
|
+
onTestApi: () => void;
|
|
10
|
+
/** Dismiss the banner. */
|
|
11
|
+
onDismiss: () => void;
|
|
12
|
+
}
|
|
13
|
+
declare const EditorStatusBar: import("svelte").Component<Props, {}, "">;
|
|
14
|
+
type EditorStatusBar = ReturnType<typeof EditorStatusBar>;
|
|
15
|
+
export default EditorStatusBar;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
IconButton — typed wrapper over the `.flowdrop-btn--icon` system (base.css).
|
|
3
|
+
|
|
4
|
+
The icon-only sibling of Button.svelte: a square button that holds a single
|
|
5
|
+
glyph (Icon, inline SVG, or character). All geometry, variants, sizes and the
|
|
6
|
+
centralized focus ring live in base.css; this component is the ergonomic,
|
|
7
|
+
type-safe entry point so callers pick `variant`/`size` instead of hand-writing
|
|
8
|
+
class strings and re-declaring widths/tints in scoped styles.
|
|
9
|
+
|
|
10
|
+
Internal for now (not exported from any public entry) so the API isn't frozen
|
|
11
|
+
before GA. Existing hand-rolled square buttons migrate onto it incrementally.
|
|
12
|
+
Canvas-overlay buttons keep their bespoke components (CanvasIconButton,
|
|
13
|
+
NodeConfigButton) — those add absolute positioning, shadows and backdrop blur
|
|
14
|
+
this primitive deliberately stays out of.
|
|
15
|
+
-->
|
|
16
|
+
|
|
17
|
+
<script lang="ts">
|
|
18
|
+
import type { Snippet } from 'svelte';
|
|
19
|
+
|
|
20
|
+
interface Props {
|
|
21
|
+
/**
|
|
22
|
+
* Visual style. `ghost` (default) is transparent until hover; `default` is a
|
|
23
|
+
* flat surface with a resting border; `primary`/`danger`/`success` are quiet
|
|
24
|
+
* semantic tints (muted fill + coloured border) that go solid on press.
|
|
25
|
+
*/
|
|
26
|
+
variant?: 'ghost' | 'default' | 'primary' | 'danger' | 'success';
|
|
27
|
+
/** Square size — `md` (32px) is the base; `sm` (28px) / `lg` (36px) add a modifier */
|
|
28
|
+
size?: 'sm' | 'md' | 'lg';
|
|
29
|
+
/** Native button type */
|
|
30
|
+
type?: 'button' | 'submit' | 'reset';
|
|
31
|
+
/** Tooltip text */
|
|
32
|
+
title?: string;
|
|
33
|
+
/** Accessible label — required, since the button is icon-only */
|
|
34
|
+
ariaLabel: string;
|
|
35
|
+
/** Toggle/pressed state — applies the active tint and sets `aria-pressed` */
|
|
36
|
+
active?: boolean;
|
|
37
|
+
/** Disabled state */
|
|
38
|
+
disabled?: boolean;
|
|
39
|
+
/** Extra classes appended to the root button */
|
|
40
|
+
class?: string;
|
|
41
|
+
/** Click handler */
|
|
42
|
+
onclick?: (event: MouseEvent) => void;
|
|
43
|
+
/** The glyph (icon, svg, or character) */
|
|
44
|
+
children: Snippet;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let {
|
|
48
|
+
variant = 'ghost',
|
|
49
|
+
size = 'md',
|
|
50
|
+
type = 'button',
|
|
51
|
+
title,
|
|
52
|
+
ariaLabel,
|
|
53
|
+
active = false,
|
|
54
|
+
disabled = false,
|
|
55
|
+
class: className = '',
|
|
56
|
+
onclick,
|
|
57
|
+
children
|
|
58
|
+
}: Props = $props();
|
|
59
|
+
|
|
60
|
+
// `ghost` reuses the shared `.flowdrop-btn--ghost`; the other variants have
|
|
61
|
+
// icon-specific tint classes so they don't collide with the solid text buttons.
|
|
62
|
+
const variantClass = $derived(
|
|
63
|
+
variant === 'ghost' ? 'flowdrop-btn--ghost' : `flowdrop-btn--icon-${variant}`
|
|
64
|
+
);
|
|
65
|
+
// 'md' is the unmodified base size; only 'sm'/'lg' need a size modifier.
|
|
66
|
+
const sizeClass = $derived(size === 'md' ? '' : `flowdrop-btn--${size}`);
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<button
|
|
70
|
+
class="flowdrop-btn flowdrop-btn--icon {variantClass} {sizeClass} {className}"
|
|
71
|
+
class:is-active={active}
|
|
72
|
+
{type}
|
|
73
|
+
{title}
|
|
74
|
+
{disabled}
|
|
75
|
+
aria-label={ariaLabel}
|
|
76
|
+
aria-pressed={active ? true : undefined}
|
|
77
|
+
{onclick}
|
|
78
|
+
>
|
|
79
|
+
{@render children()}
|
|
80
|
+
</button>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
/**
|
|
4
|
+
* Visual style. `ghost` (default) is transparent until hover; `default` is a
|
|
5
|
+
* flat surface with a resting border; `primary`/`danger`/`success` are quiet
|
|
6
|
+
* semantic tints (muted fill + coloured border) that go solid on press.
|
|
7
|
+
*/
|
|
8
|
+
variant?: 'ghost' | 'default' | 'primary' | 'danger' | 'success';
|
|
9
|
+
/** Square size — `md` (32px) is the base; `sm` (28px) / `lg` (36px) add a modifier */
|
|
10
|
+
size?: 'sm' | 'md' | 'lg';
|
|
11
|
+
/** Native button type */
|
|
12
|
+
type?: 'button' | 'submit' | 'reset';
|
|
13
|
+
/** Tooltip text */
|
|
14
|
+
title?: string;
|
|
15
|
+
/** Accessible label — required, since the button is icon-only */
|
|
16
|
+
ariaLabel: string;
|
|
17
|
+
/** Toggle/pressed state — applies the active tint and sets `aria-pressed` */
|
|
18
|
+
active?: boolean;
|
|
19
|
+
/** Disabled state */
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
/** Extra classes appended to the root button */
|
|
22
|
+
class?: string;
|
|
23
|
+
/** Click handler */
|
|
24
|
+
onclick?: (event: MouseEvent) => void;
|
|
25
|
+
/** The glyph (icon, svg, or character) */
|
|
26
|
+
children: Snippet;
|
|
27
|
+
}
|
|
28
|
+
declare const IconButton: import("svelte").Component<Props, {}, "">;
|
|
29
|
+
type IconButton = ReturnType<typeof IconButton>;
|
|
30
|
+
export default IconButton;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Input — typed wrapper over the shared `.flowdrop-input` system (base.css).
|
|
3
|
+
|
|
4
|
+
All control styling (surface, border, radius, sizes, focus ring, disabled =
|
|
5
|
+
the only muted state) lives in base.css. This component is the ergonomic,
|
|
6
|
+
type-safe entry point so callers pick `size`/`invalid`/`leading`/`trailing`
|
|
7
|
+
instead of hand-writing class strings — the single place text-like fields
|
|
8
|
+
should route through. Mirrors Button.svelte.
|
|
9
|
+
|
|
10
|
+
Native attributes (type, value, placeholder, disabled, id, aria-*, oninput…)
|
|
11
|
+
are forwarded verbatim to the underlying <input>.
|
|
12
|
+
|
|
13
|
+
Internal for now (not exported from any public entry) so the API isn't frozen
|
|
14
|
+
before GA. Existing hand-rolled inputs migrate onto it incrementally.
|
|
15
|
+
-->
|
|
16
|
+
|
|
17
|
+
<script lang="ts">
|
|
18
|
+
import type { Snippet } from 'svelte';
|
|
19
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
20
|
+
|
|
21
|
+
// Omit native numeric `size` so our design-token size (matching Button) wins.
|
|
22
|
+
interface Props extends Omit<HTMLInputAttributes, 'size'> {
|
|
23
|
+
/** Size — `md` is the base `.flowdrop-input`; `sm`/`lg` add a modifier */
|
|
24
|
+
size?: 'sm' | 'md' | 'lg';
|
|
25
|
+
/** Renders the error-border state */
|
|
26
|
+
invalid?: boolean;
|
|
27
|
+
/** Extra classes appended to the input */
|
|
28
|
+
class?: string;
|
|
29
|
+
/** Optional leading affordance (e.g. a search icon) */
|
|
30
|
+
leading?: Snippet;
|
|
31
|
+
/** Optional trailing affordance */
|
|
32
|
+
trailing?: Snippet;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let {
|
|
36
|
+
size = 'md',
|
|
37
|
+
invalid = false,
|
|
38
|
+
class: className = '',
|
|
39
|
+
leading,
|
|
40
|
+
trailing,
|
|
41
|
+
...rest
|
|
42
|
+
}: Props = $props();
|
|
43
|
+
|
|
44
|
+
const inputClass = $derived(
|
|
45
|
+
[
|
|
46
|
+
'flowdrop-input',
|
|
47
|
+
size === 'md' ? '' : `flowdrop-input--${size}`,
|
|
48
|
+
invalid ? 'flowdrop-input--invalid' : '',
|
|
49
|
+
leading ? 'flowdrop-input--has-leading' : '',
|
|
50
|
+
trailing ? 'flowdrop-input--has-trailing' : '',
|
|
51
|
+
className
|
|
52
|
+
]
|
|
53
|
+
.filter(Boolean)
|
|
54
|
+
.join(' ')
|
|
55
|
+
);
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
{#if leading || trailing}
|
|
59
|
+
<div class="flowdrop-input-wrap">
|
|
60
|
+
{#if leading}
|
|
61
|
+
<span class="flowdrop-input-wrap__icon flowdrop-input-wrap__icon--leading">
|
|
62
|
+
{@render leading()}
|
|
63
|
+
</span>
|
|
64
|
+
{/if}
|
|
65
|
+
<input class={inputClass} {...rest} />
|
|
66
|
+
{#if trailing}
|
|
67
|
+
<span class="flowdrop-input-wrap__icon flowdrop-input-wrap__icon--trailing">
|
|
68
|
+
{@render trailing()}
|
|
69
|
+
</span>
|
|
70
|
+
{/if}
|
|
71
|
+
</div>
|
|
72
|
+
{:else}
|
|
73
|
+
<input class={inputClass} {...rest} />
|
|
74
|
+
{/if}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLInputAttributes } from 'svelte/elements';
|
|
3
|
+
interface Props extends Omit<HTMLInputAttributes, 'size'> {
|
|
4
|
+
/** Size — `md` is the base `.flowdrop-input`; `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 input */
|
|
9
|
+
class?: string;
|
|
10
|
+
/** Optional leading affordance (e.g. a search icon) */
|
|
11
|
+
leading?: Snippet;
|
|
12
|
+
/** Optional trailing affordance */
|
|
13
|
+
trailing?: Snippet;
|
|
14
|
+
}
|
|
15
|
+
declare const Input: import("svelte").Component<Props, {}, "">;
|
|
16
|
+
type Input = ReturnType<typeof Input>;
|
|
17
|
+
export default Input;
|