@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
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,65 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.0.0-beta.4] - 2026-06-13
|
|
11
|
+
|
|
12
|
+
Fourth 2.0 beta, published under the npm `beta` dist-tag (`npm install @flowdrop/flowdrop@beta`). `latest` remains 1.15.0 until 2.0.0 GA. This release is mostly an internal design-system consolidation pass — new shared `Button` / `IconButton` / `Input` / `Select` / `Textarea` primitives route every control through the `base.css` class system as the single source of truth, so themes (including Drafter) style fields and buttons consistently. User-visible changes are a navbar `end` snippet for embedding custom trailing controls, a new `--fd-control-radius` theming token, a range-slider fill fix, and opaque Drafter buttons. The archived Astro docs site is retired in favor of the Mintlify docs at `flowdrop.mintlify.app`.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **`end` snippet on the navbar.** A new `end` snippet prop renders custom trailing content in the navbar (before the settings gear), letting consuming apps inject their own controls — e.g. a theme toggle — without forking the navbar.
|
|
17
|
+
- **`--fd-control-radius` theming token.** Form controls (inputs, selects, textareas, the array action buttons, fieldset/checkbox-group/config-form borders) now read their corner radius from `--fd-control-radius`, so themes can tighten field corners independently of cards and panels. Drafter sets it to `2px` for its crisp blueprint look; other themes inherit the existing radius.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- **Range slider fill now tracks the thumb center.** The colored fill measured 0–100% of the raw track width while the browser keeps the thumb inside the track, so the fill and thumb drifted apart — worst at the extremes and visible on load. The fill now mirrors the thumb's actual travel (`thumb/2` to `100% − thumb/2`) via a new `--fd-range-fill` calc, with the thumb size tokenized.
|
|
22
|
+
- **Drafter buttons are opaque and flat.** Several buttons in the Drafter skin (file-upload node config, canvas toggles) rendered with translucent backgrounds and read as see-through; they are now flat and opaque.
|
|
23
|
+
|
|
24
|
+
### Changed (internal — no API change)
|
|
25
|
+
|
|
26
|
+
- **Shared form-control and button primitives.** New typed `Button`, `IconButton`, `Input`, `Select`, and `Textarea` wrappers sit over the existing `.flowdrop-btn*` / `.flowdrop-input*` / `.flowdrop-btn--icon*` classes in `base.css`, making it the single source for control look (`:disabled` is the only muted state). `ThemeToggle`, the config form, sidebar search, the node swap picker, `FormArray` move/delete buttons, `InputCollector`, and the playground inputs were migrated onto them, dropping their hand-rolled, duplicated CSS. The primitives are internal (not exported), so their APIs aren't frozen before GA; public component prop APIs (e.g. `ThemeToggle`) are unchanged.
|
|
27
|
+
- **`EditorStatusBar` extracted onto the shared button system.** The endpoint-error banner — previously inline in `App.svelte` with its own button CSS and a centered `80rem` layout — is now an `EditorStatusBar` component that routes actions through the `Button` primitive, spans the editor chrome flush, and uses a proper `CloseIcon` for dismissal. Added Storybook stories for `Button` and `EditorStatusBar`.
|
|
28
|
+
- **Navbar control heights from one token.** Three hardcoded `height: 2.5rem` rules now use `var(--fd-size-btn-min)`, sharing a single source of truth with `.flowdrop-btn`.
|
|
29
|
+
- **Extracted shared logic flagged by the duplication review.** `connections.ts` gains a shared `detectCycles()` (used by both `hasCycles` / `hasInvalidCycles`); `svelte-app.ts` extracts a `configureInstance()` shared by `mountFlowDropApp` / `mountWorkflowEditor`; and `FormField` / `FormFieldLight` share a `resolveBaseFieldType()` for the basic-type switch (with a unit test pinning resolution order) while keeping the deliberate full/light rendering split for the bundle-guard contract. No behavioral change.
|
|
30
|
+
|
|
31
|
+
### Docs
|
|
32
|
+
|
|
33
|
+
- **Retired the archived Astro/Starlight docs site (`apps/docs`)** and its docker-publish workflow; the Mintlify site at `flowdrop.mintlify.app` is canonical. All live documentation links (README, AGENTS, quick-start, i18n guide, API README, dev playground navbar, docker-playground landing, interrupt-feature doc) were repointed there. `apps/api-docs` is kept only to back the `api:lint` / `api:bundle` tooling and CI. Corrected the local dev-server port reference to the recommended Express demo.
|
|
34
|
+
|
|
35
|
+
## [2.0.0-beta.3] - 2026-06-12
|
|
36
|
+
|
|
37
|
+
Third 2.0 beta, published under the npm `beta` dist-tag (`npm install @flowdrop/flowdrop@beta`). `latest` remains 1.15.0 until 2.0.0 GA. This release finishes the navbar/theme defaults pass started in beta.2 (navbar opt-in everywhere, light as the default theme, the FlowDrop wordmark in the header), adds the **Drafter** blueprint theme with per-theme canvas grids, and lands a keyboard-navigation and focus-ring overhaul alongside the 20px node-grid alignment.
|
|
38
|
+
|
|
39
|
+
### Breaking Changes
|
|
40
|
+
|
|
41
|
+
- **`mountPlaygroundApp` / `<PlaygroundApp>` no longer render the navbar by default.** `showNavbar` now defaults to `false`, matching `mountFlowDropApp` / `<App>` — so every mount path is navbar-off by default and embedding FlowDrop into a page that already has its own header never double-stacks a header. Pass `showNavbar: true` to opt back into the FlowDrop navbar (logo, branding, settings modal) when FlowDrop owns the whole page.
|
|
42
|
+
|
|
43
|
+
### Added
|
|
44
|
+
|
|
45
|
+
- **Drafter blueprint theme.** A third built-in editor theme (`'drafter'`), shipping light + dark variants: a blueprint aesthetic with a soft mint canvas, a subtle emerald line grid, and translucent green-tinted flat nodes. Data-type port colors and category icon colors are left untouched so they keep popping against the muted draft surface. Selectable from the Settings → UI Theme picker; the `FlowDropSkinName` / theme / skin name unions gain `'drafter'`.
|
|
46
|
+
- **Per-theme canvas grid.** A new `FlowDropGridVariant` type (`'dots' | 'lines' | 'cross'`) and `themeConfig.canvas.grid` config let any theme drive the editor's background grid (previously hardcoded to dots). The grid pattern color is the `--fd-grid-pattern-color` token, whose default matches xyflow's dot color, so the default/minimal themes render unchanged. `resolveTheme` now merges `config.canvas` alongside `config.sidebar`.
|
|
47
|
+
- **`features.builtinEditors` opt-out.** The built-in markdown/code/template editors are batteries-included in the full editor by default. Pass `features: { builtinEditors: false }` to `mountFlowDropApp` (or `builtinEditors: false` to `mountWorkflowEditor` / `<WorkflowEditor>`) to skip registering them — keeping the textarea fallback or leaving room to register your own field components via `instance.fields.register(...)`. The corrected fallback hint now points at the registry-scoped API (`registerMarkdownEditorField(instance.fields)`).
|
|
48
|
+
- **FlowDrop wordmark logo in the navbar.** The header now renders the FlowDrop wordmark in place of the plain text title.
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
|
|
52
|
+
- **The default theme preference is now `'light'` (was `'dark'`).** `DEFAULT_THEME_SETTINGS.preference` was hardcoded to `'dark'`, so any embed with no persisted theme choice rendered dark. Embeds now default to light; hosts that want dark by default should set the preference explicitly.
|
|
53
|
+
- **Editor / node / chrome surface tokens are scoped per surface,** refining how themes (including Drafter) tint the canvas, nodes, and surrounding chrome independently.
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- **Nodes are a single tab stop again.** The node config (gear) button sat in the tab order, so leaving a node required a second `Tab` press. The gear button is removed from the tab order (it stays mouse/Enter-activatable), and node focus defers to xyflow's own node focus — Tab now moves one node per press. `nodesFocusable` redundancy was removed to eliminate the duplicate stop.
|
|
58
|
+
- **The full editor renders markdown/code/config editors out of the box again.** The beta.2 light-entry split made the heavy form editors opt-in everywhere, which inadvertently left `<WorkflowEditor>` / `<App>` / the playground showing the "Editor component not registered" textarea fallback for node config fields with `format: 'markdown' | 'code' | 'template'`. The full editor now registers the built-in editors on its own instance's field registry on mount. Registration uses a dynamic `import()`, so the chunks stay code-split (loaded lazily) and the light `/editor` static bundle is unaffected — the bundle guard still passes. The standalone `@flowdrop/flowdrop/form` primitive is unchanged and remains opt-in.
|
|
59
|
+
- **`<App navbarActions>` accepts the full `NavbarAction` shape.** The component prop was typed with an inline subset that silently dropped `external` and `group`, even though the underlying `<Navbar>` (and the `mountFlowDropApp` option) already supported them. It now uses the canonical `NavbarAction` type, so external-link and grouped actions type-check through the component as they always did through the mount API.
|
|
60
|
+
- **The node header no longer shows a top-accent line.**
|
|
61
|
+
|
|
62
|
+
### Changed (internal — no API change)
|
|
63
|
+
|
|
64
|
+
- **One centralized focus ring across the whole component library.** New `--fd-ring-width` / `--fd-ring-offset` tokens and a single `.flowdrop-root :focus-visible` rule in `base.css` replace ~200 lines of component-local focus CSS (mismatched outlines, hardcoded `rgba(59,130,246)` box-shadow glows, `color-mix` rings) removed across 41 files. CodeMirror editors in `overflow:hidden` containers use a `:focus-within` ring (outline paints outside the box and would clip); range-input thumbs ring on the parent.
|
|
65
|
+
- **Extracted shared `NodeConfigButton` and `CanvasIconButton` components,** replacing per-node config-button and per-canvas floating-button duplication (including an inline-SVG cog) with one keyboard-correct implementation each.
|
|
66
|
+
- **Node geometry converted from `rem` to `px` and snapped to a 20px grid** across all eight node types — header, port rows (fixed 60px), icon sizes, paddings, gaps, and font sizes — so nodes stay aligned to the canvas coordinate grid regardless of the host's root font-size.
|
|
67
|
+
- **The code / markdown / template editors now rest on the shared input surface** instead of carrying their own background.
|
|
68
|
+
|
|
10
69
|
## [2.0.0-beta.2] - 2026-06-09
|
|
11
70
|
|
|
12
71
|
Second 2.0 beta, published under the npm `beta` dist-tag (`npm install @flowdrop/flowdrop@beta`). This release tightens the 2.0 package boundaries, finishes `AuthProvider` propagation across the editor and playground runtime surfaces, and adds a regression guard for light-entry bundle size.
|
package/MIGRATION-2.0.md
CHANGED
|
@@ -295,6 +295,19 @@ import { getInstance } from '@flowdrop/flowdrop/editor';
|
|
|
295
295
|
registerCodeEditorField(getInstance().fields);
|
|
296
296
|
```
|
|
297
297
|
|
|
298
|
+
**You only need this for the standalone `@flowdrop/flowdrop/form` primitive.**
|
|
299
|
+
The full editor is batteries-included: `<WorkflowEditor>` / `<App>` and the
|
|
300
|
+
playground register the built-in markdown, code, and template editors on their
|
|
301
|
+
own instance's `fields` registry on mount, so node config fields with
|
|
302
|
+
`format: 'markdown' | 'code' | 'template'` render real editors out of the box —
|
|
303
|
+
no host call required. Registration is a dynamic `import()`, so the CodeMirror /
|
|
304
|
+
`marked` chunks stay code-split (the light `/editor` static bundle is
|
|
305
|
+
unaffected) and load lazily on first use. To strip them, pass
|
|
306
|
+
`features: { builtinEditors: false }` to `mountFlowDropApp` (or
|
|
307
|
+
`builtinEditors: false` to `mountWorkflowEditor` / `<WorkflowEditor>`) and either
|
|
308
|
+
accept the textarea fallback or register your own field components via
|
|
309
|
+
`instance.fields.register(...)`.
|
|
310
|
+
|
|
298
311
|
Category color/icon helpers likewise take a `CategoriesStore` as an explicit
|
|
299
312
|
parameter — the last global-instance fallback in `utils` is gone.
|
|
300
313
|
|
package/README.md
CHANGED
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
</p>
|
|
24
24
|
|
|
25
25
|
<p align="center">
|
|
26
|
-
<a href="https://
|
|
26
|
+
<a href="https://flowdrop.mintlify.app/docs/quickstart">Quickstart</a> •
|
|
27
27
|
<a href="#features">Features</a> •
|
|
28
28
|
<a href="#integration">Integration</a> •
|
|
29
|
-
<a href="https://
|
|
29
|
+
<a href="https://flowdrop.mintlify.app">Docs</a>
|
|
30
30
|
</p>
|
|
31
31
|
|
|
32
32
|
<p align="center">
|
|
@@ -139,7 +139,7 @@ Every user-facing string flows through a typed `Messages` tree. Pass a callback
|
|
|
139
139
|
<App messages={() => ({ form: { schema: { save: 'Apply' } } })} />
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
-
Wire the callback to your i18n library (paraglide-js, sveltekit-i18n, etc.) — locale changes propagate automatically. See the [i18n & Custom Messages guide](https://
|
|
142
|
+
Wire the callback to your i18n library (paraglide-js, sveltekit-i18n, etc.) — locale changes propagate automatically. See the [i18n & Custom Messages guide](https://flowdrop.mintlify.app/guides/i18n) for the full shape and a paraglide-js worked example.
|
|
143
143
|
|
|
144
144
|
## Sub-Module Exports
|
|
145
145
|
|
|
@@ -283,8 +283,8 @@ Runtime configuration means you build once and deploy to staging, production, or
|
|
|
283
283
|
|
|
284
284
|
| Resource | Description |
|
|
285
285
|
| -------------------------------------------------------------------------------------------- | ------------------------ |
|
|
286
|
-
| [QUICK_START.md](https://
|
|
287
|
-
| [API Documentation](https://
|
|
286
|
+
| [QUICK_START.md](https://flowdrop.mintlify.app/docs/quickstart) | Get running in 5 minutes |
|
|
287
|
+
| [API Documentation](https://flowdrop.mintlify.app/api-reference/introduction) | REST API specification |
|
|
288
288
|
| [CHANGELOG.md](https://github.com/flowdrop-io/flowdrop/blob/main/libs/flowdrop/CHANGELOG.md) | Version history |
|
|
289
289
|
|
|
290
290
|
## Development
|
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
import MainLayout from './layouts/MainLayout.svelte';
|
|
10
10
|
import WorkflowEditor from './WorkflowEditor.svelte';
|
|
11
11
|
import NodeSidebar from './NodeSidebar.svelte';
|
|
12
|
-
import
|
|
12
|
+
import CanvasIconButton from './CanvasIconButton.svelte';
|
|
13
|
+
import EditorStatusBar from './EditorStatusBar.svelte';
|
|
14
|
+
import MenuIcon from './icons/MenuIcon.svelte';
|
|
15
|
+
import MenuOpenIcon from './icons/MenuOpenIcon.svelte';
|
|
13
16
|
import ConfigForm from './ConfigForm.svelte';
|
|
14
17
|
import ConfigPanel from './ConfigPanel.svelte';
|
|
15
18
|
import CommandConsole from './console/CommandConsole.svelte';
|
|
@@ -18,6 +21,7 @@
|
|
|
18
21
|
import NodeSwapPicker from './NodeSwapPicker.svelte';
|
|
19
22
|
import SwapMappingEditor from './SwapMappingEditor.svelte';
|
|
20
23
|
import Navbar from './Navbar.svelte';
|
|
24
|
+
import type { NavbarAction } from '../types/navbar.js';
|
|
21
25
|
import type { NodeMetadata, Workflow, WorkflowNode, ConfigSchema } from '../types/index.js';
|
|
22
26
|
import type { InteractiveSwapState, SwapEventContext } from '../utils/nodeSwap.js';
|
|
23
27
|
import {
|
|
@@ -98,13 +102,7 @@
|
|
|
98
102
|
/** Custom navbar title */
|
|
99
103
|
navbarTitle?: string;
|
|
100
104
|
/** Custom navbar actions */
|
|
101
|
-
navbarActions?:
|
|
102
|
-
label: string;
|
|
103
|
-
href: string;
|
|
104
|
-
icon?: string;
|
|
105
|
-
variant?: 'primary' | 'secondary' | 'outline';
|
|
106
|
-
onclick?: (event: Event) => void;
|
|
107
|
-
}>;
|
|
105
|
+
navbarActions?: NavbarAction[];
|
|
108
106
|
/** Show settings gear icon in navbar */
|
|
109
107
|
showSettings?: boolean;
|
|
110
108
|
/** Show the "Connected" status indicator in the navbar (default: true) */
|
|
@@ -1215,53 +1213,21 @@
|
|
|
1215
1213
|
{/snippet}
|
|
1216
1214
|
|
|
1217
1215
|
<!-- Main Content: Workflow Editor with Error Status -->
|
|
1218
|
-
<!-- Status Display: aria-live announces API errors dynamically without requiring focus -->
|
|
1219
1216
|
{#if error}
|
|
1220
|
-
<
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
<button
|
|
1235
|
-
class="flowdrop-btn flowdrop-btn--sm flowdrop-btn--outline"
|
|
1236
|
-
onclick={() => {
|
|
1237
|
-
const defaultUrl = '/api/flowdrop';
|
|
1238
|
-
const newUrl = prompt('Enter Backend API URL:', defaultUrl);
|
|
1239
|
-
if (newUrl) {
|
|
1240
|
-
configureApi(createEndpointConfig(newUrl));
|
|
1241
|
-
fetchNodeTypes();
|
|
1242
|
-
}
|
|
1243
|
-
}}
|
|
1244
|
-
type="button"
|
|
1245
|
-
>
|
|
1246
|
-
Set API URL
|
|
1247
|
-
</button>
|
|
1248
|
-
<button
|
|
1249
|
-
class="flowdrop-btn flowdrop-btn--sm flowdrop-btn--outline"
|
|
1250
|
-
onclick={testApiConnection}
|
|
1251
|
-
type="button"
|
|
1252
|
-
>
|
|
1253
|
-
Test API
|
|
1254
|
-
</button>
|
|
1255
|
-
<button
|
|
1256
|
-
class="flowdrop-btn flowdrop-btn--ghost flowdrop-btn--sm"
|
|
1257
|
-
onclick={() => (error = null)}
|
|
1258
|
-
type="button"
|
|
1259
|
-
>
|
|
1260
|
-
✕
|
|
1261
|
-
</button>
|
|
1262
|
-
</div>
|
|
1263
|
-
</div>
|
|
1264
|
-
</div>
|
|
1217
|
+
<EditorStatusBar
|
|
1218
|
+
{error}
|
|
1219
|
+
onRetry={retryLoad}
|
|
1220
|
+
onSetApiUrl={() => {
|
|
1221
|
+
const defaultUrl = '/api/flowdrop';
|
|
1222
|
+
const newUrl = prompt('Enter Backend API URL:', defaultUrl);
|
|
1223
|
+
if (newUrl) {
|
|
1224
|
+
configureApi(createEndpointConfig(newUrl));
|
|
1225
|
+
fetchNodeTypes();
|
|
1226
|
+
}
|
|
1227
|
+
}}
|
|
1228
|
+
onTestApi={testApiConnection}
|
|
1229
|
+
onDismiss={() => (error = null)}
|
|
1230
|
+
/>
|
|
1265
1231
|
{/if}
|
|
1266
1232
|
|
|
1267
1233
|
<!-- Main Editor Area -->
|
|
@@ -1278,18 +1244,22 @@
|
|
|
1278
1244
|
>
|
|
1279
1245
|
<!-- Floating sidebar toggle — always visible on the canvas top-left -->
|
|
1280
1246
|
{#if !disableSidebar}
|
|
1281
|
-
<
|
|
1247
|
+
<CanvasIconButton
|
|
1282
1248
|
class="flowdrop-sidebar-fab"
|
|
1283
|
-
|
|
1284
|
-
aria-label={isSidebarCollapsed
|
|
1285
|
-
? mergedMessages.layout.expandSidebar
|
|
1286
|
-
: mergedMessages.layout.collapseSidebar}
|
|
1287
|
-
title={isSidebarCollapsed
|
|
1249
|
+
label={isSidebarCollapsed
|
|
1288
1250
|
? mergedMessages.layout.expandSidebar
|
|
1289
1251
|
: mergedMessages.layout.collapseSidebar}
|
|
1252
|
+
active={!isSidebarCollapsed}
|
|
1253
|
+
onclick={toggleSidebar}
|
|
1290
1254
|
>
|
|
1291
|
-
|
|
1292
|
-
|
|
1255
|
+
{#snippet icon()}
|
|
1256
|
+
{#if isSidebarCollapsed}
|
|
1257
|
+
<MenuIcon />
|
|
1258
|
+
{:else}
|
|
1259
|
+
<MenuOpenIcon />
|
|
1260
|
+
{/if}
|
|
1261
|
+
{/snippet}
|
|
1262
|
+
</CanvasIconButton>
|
|
1293
1263
|
{/if}
|
|
1294
1264
|
|
|
1295
1265
|
<WorkflowEditor
|
|
@@ -1300,6 +1270,8 @@
|
|
|
1300
1270
|
{mode}
|
|
1301
1271
|
{pipelineId}
|
|
1302
1272
|
{refreshTrigger}
|
|
1273
|
+
builtinEditors={features.builtinEditors}
|
|
1274
|
+
gridVariant={themeConfig?.canvas?.grid ?? 'dots'}
|
|
1303
1275
|
consoleOpen={getUiSettings().consoleOpen}
|
|
1304
1276
|
onToggleConsole={toggleConsole}
|
|
1305
1277
|
/>
|
|
@@ -1311,139 +1283,12 @@
|
|
|
1311
1283
|
.flowdrop-root {
|
|
1312
1284
|
display: contents;
|
|
1313
1285
|
}
|
|
1314
|
-
/* Status bar styles */
|
|
1315
|
-
.flowdrop-status {
|
|
1316
|
-
background-color: var(--fd-info-muted);
|
|
1317
|
-
border-bottom: 1px solid var(--fd-info);
|
|
1318
|
-
padding: 1rem;
|
|
1319
|
-
}
|
|
1320
|
-
|
|
1321
|
-
.flowdrop-status--error {
|
|
1322
|
-
background-color: var(--fd-error-muted);
|
|
1323
|
-
border-bottom: 1px solid var(--fd-error);
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
.flowdrop-status__content {
|
|
1327
|
-
max-width: 80rem;
|
|
1328
|
-
margin: 0 auto;
|
|
1329
|
-
display: flex;
|
|
1330
|
-
align-items: center;
|
|
1331
|
-
justify-content: space-between;
|
|
1332
|
-
}
|
|
1333
|
-
|
|
1334
|
-
.flowdrop-status__indicator {
|
|
1335
|
-
width: 0.5rem;
|
|
1336
|
-
height: 0.5rem;
|
|
1337
|
-
border-radius: 50%;
|
|
1338
|
-
}
|
|
1339
|
-
|
|
1340
|
-
.flowdrop-status__indicator--error {
|
|
1341
|
-
background-color: var(--fd-error);
|
|
1342
|
-
}
|
|
1343
|
-
|
|
1344
|
-
/* Button styles */
|
|
1345
|
-
.flowdrop-btn {
|
|
1346
|
-
padding: 0.375rem 0.75rem;
|
|
1347
|
-
border-radius: var(--fd-radius-md);
|
|
1348
|
-
font-size: 0.75rem;
|
|
1349
|
-
font-weight: 500;
|
|
1350
|
-
cursor: pointer;
|
|
1351
|
-
border: 1px solid transparent;
|
|
1352
|
-
transition: all var(--fd-transition-fast);
|
|
1353
|
-
}
|
|
1354
|
-
|
|
1355
|
-
.flowdrop-btn--sm {
|
|
1356
|
-
padding: 0.25rem 0.5rem;
|
|
1357
|
-
font-size: 0.625rem;
|
|
1358
|
-
}
|
|
1359
|
-
|
|
1360
|
-
.flowdrop-btn--outline {
|
|
1361
|
-
background-color: transparent;
|
|
1362
|
-
border-color: var(--fd-border);
|
|
1363
|
-
color: var(--fd-foreground);
|
|
1364
|
-
}
|
|
1365
1286
|
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
border-color: var(--fd-border-strong);
|
|
1369
|
-
}
|
|
1370
|
-
|
|
1371
|
-
.flowdrop-btn--primary {
|
|
1372
|
-
background-color: var(--fd-primary);
|
|
1373
|
-
border-color: var(--fd-primary);
|
|
1374
|
-
color: var(--fd-primary-foreground);
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1377
|
-
.flowdrop-btn--primary:hover {
|
|
1378
|
-
background-color: var(--fd-primary-hover);
|
|
1379
|
-
border-color: var(--fd-primary-hover);
|
|
1380
|
-
}
|
|
1381
|
-
|
|
1382
|
-
.flowdrop-btn--ghost {
|
|
1383
|
-
background-color: transparent;
|
|
1384
|
-
border-color: transparent;
|
|
1385
|
-
color: var(--fd-muted-foreground);
|
|
1386
|
-
}
|
|
1387
|
-
|
|
1388
|
-
.flowdrop-btn--ghost:hover {
|
|
1389
|
-
background-color: var(--fd-muted);
|
|
1390
|
-
color: var(--fd-foreground);
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
|
-
/* Utility classes */
|
|
1394
|
-
.flowdrop-flex {
|
|
1395
|
-
display: flex;
|
|
1396
|
-
}
|
|
1397
|
-
|
|
1398
|
-
.flowdrop-gap--2 {
|
|
1399
|
-
gap: 0.5rem;
|
|
1400
|
-
}
|
|
1401
|
-
|
|
1402
|
-
.flowdrop-gap--3 {
|
|
1403
|
-
gap: 0.75rem;
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
|
-
.flowdrop-text--sm {
|
|
1407
|
-
font-size: 0.875rem;
|
|
1408
|
-
line-height: 1.25rem;
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
.flowdrop-font--medium {
|
|
1412
|
-
font-weight: 500;
|
|
1413
|
-
}
|
|
1414
|
-
|
|
1415
|
-
/* Floating sidebar toggle button */
|
|
1416
|
-
.flowdrop-sidebar-fab {
|
|
1417
|
-
position: absolute;
|
|
1287
|
+
/* Floating sidebar toggle button — placement only; visuals live in CanvasIconButton */
|
|
1288
|
+
:global(.flowdrop-sidebar-fab) {
|
|
1418
1289
|
top: 12px;
|
|
1419
1290
|
left: 12px;
|
|
1420
1291
|
z-index: 50;
|
|
1421
|
-
display: flex;
|
|
1422
|
-
align-items: center;
|
|
1423
|
-
justify-content: center;
|
|
1424
|
-
width: 2.25rem;
|
|
1425
|
-
height: 2.25rem;
|
|
1426
|
-
border: 1px solid var(--fd-border);
|
|
1427
|
-
border-radius: var(--fd-radius-md);
|
|
1428
|
-
background-color: var(--fd-background);
|
|
1429
|
-
color: var(--fd-muted-foreground);
|
|
1430
|
-
cursor: pointer;
|
|
1431
|
-
box-shadow: var(--fd-shadow-md);
|
|
1432
|
-
transition:
|
|
1433
|
-
color var(--fd-transition-fast),
|
|
1434
|
-
background-color var(--fd-transition-fast),
|
|
1435
|
-
box-shadow var(--fd-transition-fast);
|
|
1436
|
-
}
|
|
1437
|
-
|
|
1438
|
-
.flowdrop-sidebar-fab:hover {
|
|
1439
|
-
color: var(--fd-foreground);
|
|
1440
|
-
background-color: var(--fd-subtle);
|
|
1441
|
-
box-shadow: var(--fd-shadow-lg);
|
|
1442
|
-
}
|
|
1443
|
-
|
|
1444
|
-
.flowdrop-sidebar-fab:focus {
|
|
1445
|
-
outline: none;
|
|
1446
|
-
box-shadow: 0 0 0 2px var(--fd-ring);
|
|
1447
1292
|
}
|
|
1448
1293
|
|
|
1449
1294
|
/* Main editor area */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { NavbarAction } from '../types/navbar.js';
|
|
1
2
|
import type { NodeMetadata, Workflow, ConfigSchema } from '../types/index.js';
|
|
2
3
|
import type { SwapStrategy } from '../utils/nodeSwap.js';
|
|
3
4
|
import type { EndpointConfig } from '../config/endpoints.js';
|
|
@@ -53,13 +54,7 @@ interface Props {
|
|
|
53
54
|
/** Custom navbar title */
|
|
54
55
|
navbarTitle?: string;
|
|
55
56
|
/** Custom navbar actions */
|
|
56
|
-
navbarActions?:
|
|
57
|
-
label: string;
|
|
58
|
-
href: string;
|
|
59
|
-
icon?: string;
|
|
60
|
-
variant?: 'primary' | 'secondary' | 'outline';
|
|
61
|
-
onclick?: (event: Event) => void;
|
|
62
|
-
}>;
|
|
57
|
+
navbarActions?: NavbarAction[];
|
|
63
58
|
/** Show settings gear icon in navbar */
|
|
64
59
|
showSettings?: boolean;
|
|
65
60
|
/** Show the "Connected" status indicator in the navbar (default: true) */
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<script module lang="ts">
|
|
2
|
+
import type { ComponentProps } from 'svelte';
|
|
3
|
+
import { defineMeta } from '@storybook/addon-svelte-csf';
|
|
4
|
+
import Button from './Button.svelte';
|
|
5
|
+
import { fn } from 'storybook/test';
|
|
6
|
+
|
|
7
|
+
const { Story } = defineMeta({
|
|
8
|
+
title: 'Display/Button',
|
|
9
|
+
component: Button,
|
|
10
|
+
tags: ['autodocs'],
|
|
11
|
+
parameters: {
|
|
12
|
+
layout: 'centered'
|
|
13
|
+
},
|
|
14
|
+
argTypes: {
|
|
15
|
+
variant: {
|
|
16
|
+
control: { type: 'select' },
|
|
17
|
+
options: ['primary', 'secondary', 'outline', 'ghost']
|
|
18
|
+
},
|
|
19
|
+
size: {
|
|
20
|
+
control: { type: 'select' },
|
|
21
|
+
options: ['sm', 'md', 'lg']
|
|
22
|
+
},
|
|
23
|
+
disabled: { control: 'boolean' }
|
|
24
|
+
},
|
|
25
|
+
args: {
|
|
26
|
+
variant: 'secondary',
|
|
27
|
+
size: 'md',
|
|
28
|
+
disabled: false,
|
|
29
|
+
onclick: fn()
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<!-- Arg-driven template so the Controls panel can tweak variant/size/disabled live. -->
|
|
35
|
+
{#snippet template(args: Omit<ComponentProps<typeof Button>, 'children'>)}
|
|
36
|
+
<Button {...args}>Button</Button>
|
|
37
|
+
{/snippet}
|
|
38
|
+
|
|
39
|
+
<Story name="Primary" args={{ variant: 'primary' }} {template} />
|
|
40
|
+
|
|
41
|
+
<Story name="Secondary" args={{ variant: 'secondary' }} {template} />
|
|
42
|
+
|
|
43
|
+
<Story name="Outline" args={{ variant: 'outline' }} {template} />
|
|
44
|
+
|
|
45
|
+
<Story name="Ghost" args={{ variant: 'ghost' }} {template} />
|
|
46
|
+
|
|
47
|
+
<Story name="Disabled" args={{ variant: 'primary', disabled: true }} {template} />
|
|
48
|
+
|
|
49
|
+
<!-- Static showcases comparing every variant / size side by side. -->
|
|
50
|
+
<Story name="Variants" asChild>
|
|
51
|
+
<div style="display: flex; gap: 0.75rem; align-items: center;">
|
|
52
|
+
<Button variant="primary">Primary</Button>
|
|
53
|
+
<Button variant="secondary">Secondary</Button>
|
|
54
|
+
<Button variant="outline">Outline</Button>
|
|
55
|
+
<Button variant="ghost">Ghost</Button>
|
|
56
|
+
</div>
|
|
57
|
+
</Story>
|
|
58
|
+
|
|
59
|
+
<Story name="Sizes" asChild>
|
|
60
|
+
<div style="display: flex; gap: 0.75rem; align-items: center;">
|
|
61
|
+
<Button variant="primary" size="sm">Small</Button>
|
|
62
|
+
<Button variant="primary" size="md">Medium</Button>
|
|
63
|
+
<Button variant="primary" size="lg">Large</Button>
|
|
64
|
+
</div>
|
|
65
|
+
</Story>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Button from './Button.svelte';
|
|
2
|
+
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> {
|
|
3
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
+
$$bindings?: Bindings;
|
|
5
|
+
} & Exports;
|
|
6
|
+
(internal: unknown, props: {
|
|
7
|
+
$$events?: Events;
|
|
8
|
+
$$slots?: Slots;
|
|
9
|
+
}): Exports & {
|
|
10
|
+
$set?: any;
|
|
11
|
+
$on?: any;
|
|
12
|
+
};
|
|
13
|
+
z_$$bindings?: Bindings;
|
|
14
|
+
}
|
|
15
|
+
declare const Button: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
16
|
+
[evt: string]: CustomEvent<any>;
|
|
17
|
+
}, {}, {}, string>;
|
|
18
|
+
type Button = InstanceType<typeof Button>;
|
|
19
|
+
export default Button;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Button — typed wrapper over the shared `.flowdrop-btn` system (base.css).
|
|
3
|
+
|
|
4
|
+
All button styling (variants, sizes, the --fd-size-btn-min height token and the
|
|
5
|
+
centralized focus ring) lives in base.css. This component is the ergonomic,
|
|
6
|
+
type-safe entry point so callers pick `variant`/`size` instead of hand-writing
|
|
7
|
+
class strings — the single place new buttons should route through.
|
|
8
|
+
|
|
9
|
+
Internal for now (not exported from any public entry) so the API isn't frozen
|
|
10
|
+
before GA. Existing hand-rolled buttons migrate onto it incrementally.
|
|
11
|
+
-->
|
|
12
|
+
|
|
13
|
+
<script lang="ts">
|
|
14
|
+
import type { Snippet } from 'svelte';
|
|
15
|
+
|
|
16
|
+
interface Props {
|
|
17
|
+
/** Visual style — maps to `.flowdrop-btn--{variant}` in base.css */
|
|
18
|
+
variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
|
|
19
|
+
/** Size — `md` is the base `.flowdrop-btn`; `sm`/`lg` add a modifier */
|
|
20
|
+
size?: 'sm' | 'md' | 'lg';
|
|
21
|
+
/** Native button type */
|
|
22
|
+
type?: 'button' | 'submit' | 'reset';
|
|
23
|
+
/** Tooltip text */
|
|
24
|
+
title?: string;
|
|
25
|
+
/** Accessible label (use when the button is icon-only) */
|
|
26
|
+
ariaLabel?: string;
|
|
27
|
+
/** Disabled state */
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
/** Extra classes appended to the root button */
|
|
30
|
+
class?: string;
|
|
31
|
+
/** Click handler */
|
|
32
|
+
onclick?: (event: MouseEvent) => void;
|
|
33
|
+
/** Button contents (icon, label, or both) */
|
|
34
|
+
children: Snippet;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
let {
|
|
38
|
+
variant = 'secondary',
|
|
39
|
+
size = 'md',
|
|
40
|
+
type = 'button',
|
|
41
|
+
title,
|
|
42
|
+
ariaLabel,
|
|
43
|
+
disabled = false,
|
|
44
|
+
class: className = '',
|
|
45
|
+
onclick,
|
|
46
|
+
children
|
|
47
|
+
}: Props = $props();
|
|
48
|
+
|
|
49
|
+
// 'md' is the unmodified base class; only 'sm'/'lg' need a size modifier.
|
|
50
|
+
const sizeClass = $derived(size === 'md' ? '' : `flowdrop-btn--${size}`);
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<button
|
|
54
|
+
class="flowdrop-btn flowdrop-btn--{variant} {sizeClass} {className}"
|
|
55
|
+
{type}
|
|
56
|
+
{title}
|
|
57
|
+
{disabled}
|
|
58
|
+
aria-label={ariaLabel}
|
|
59
|
+
{onclick}
|
|
60
|
+
>
|
|
61
|
+
{@render children()}
|
|
62
|
+
</button>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
/** Visual style — maps to `.flowdrop-btn--{variant}` in base.css */
|
|
4
|
+
variant?: 'primary' | 'secondary' | 'outline' | 'ghost';
|
|
5
|
+
/** Size — `md` is the base `.flowdrop-btn`; `sm`/`lg` add a modifier */
|
|
6
|
+
size?: 'sm' | 'md' | 'lg';
|
|
7
|
+
/** Native button type */
|
|
8
|
+
type?: 'button' | 'submit' | 'reset';
|
|
9
|
+
/** Tooltip text */
|
|
10
|
+
title?: string;
|
|
11
|
+
/** Accessible label (use when the button is icon-only) */
|
|
12
|
+
ariaLabel?: string;
|
|
13
|
+
/** Disabled state */
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
/** Extra classes appended to the root button */
|
|
16
|
+
class?: string;
|
|
17
|
+
/** Click handler */
|
|
18
|
+
onclick?: (event: MouseEvent) => void;
|
|
19
|
+
/** Button contents (icon, label, or both) */
|
|
20
|
+
children: Snippet;
|
|
21
|
+
}
|
|
22
|
+
declare const Button: import("svelte").Component<Props, {}, "">;
|
|
23
|
+
type Button = ReturnType<typeof Button>;
|
|
24
|
+
export default Button;
|