@flowdrop/flowdrop 2.0.0-beta.3 → 2.0.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/README.md +5 -5
- package/dist/adapters/WorkflowAdapter.js +4 -5
- package/dist/adapters/agentspec/AgentSpecAdapter.js +3 -3
- package/dist/adapters/agentspec/defaultNodeTypes.js +9 -9
- package/dist/commands/executor.js +5 -6
- package/dist/commands/types.js +5 -5
- package/dist/components/App.svelte +19 -150
- package/dist/components/Button.stories.svelte +65 -0
- package/dist/components/Button.stories.svelte.d.ts +19 -0
- package/dist/components/Button.svelte +62 -0
- package/dist/components/Button.svelte.d.ts +24 -0
- package/dist/components/ConfigForm.svelte +4 -4
- package/dist/components/EditorStatusBar.stories.svelte +44 -0
- package/dist/components/EditorStatusBar.stories.svelte.d.ts +27 -0
- package/dist/components/EditorStatusBar.svelte +99 -0
- package/dist/components/EditorStatusBar.svelte.d.ts +15 -0
- package/dist/components/IconButton.svelte +80 -0
- package/dist/components/IconButton.svelte.d.ts +30 -0
- package/dist/components/Input.svelte +74 -0
- package/dist/components/Input.svelte.d.ts +17 -0
- package/dist/components/Navbar.svelte +9 -4
- package/dist/components/Navbar.svelte.d.ts +3 -0
- package/dist/components/NodeSidebar.svelte +17 -115
- package/dist/components/NodeSwapPicker.svelte +12 -28
- package/dist/components/Select.svelte +53 -0
- package/dist/components/Select.svelte.d.ts +15 -0
- package/dist/components/Textarea.svelte +39 -0
- package/dist/components/Textarea.svelte.d.ts +12 -0
- package/dist/components/ThemeToggle.svelte +15 -89
- package/dist/components/UniversalNode.svelte +5 -4
- package/dist/components/UniversalNode.svelte.d.ts +1 -1
- package/dist/components/console/ConsoleInput.svelte +3 -3
- package/dist/components/form/FormArray.svelte +37 -157
- package/dist/components/form/FormCheckboxGroup.svelte +1 -1
- package/dist/components/form/FormField.svelte +5 -44
- package/dist/components/form/FormFieldLight.svelte +5 -44
- package/dist/components/form/FormFieldset.svelte +1 -1
- package/dist/components/form/FormNumberField.svelte +4 -32
- package/dist/components/form/FormRangeField.svelte +17 -7
- package/dist/components/form/FormSelect.svelte +13 -79
- package/dist/components/form/FormTextField.svelte +3 -39
- package/dist/components/form/FormTextarea.svelte +4 -43
- package/dist/components/form/resolveFieldType.d.ts +24 -0
- package/dist/components/form/resolveFieldType.js +55 -0
- package/dist/components/icons/CloseIcon.svelte +6 -0
- package/dist/components/icons/CloseIcon.svelte.d.ts +26 -0
- package/dist/components/nodes/AtomNode.svelte +3 -3
- package/dist/components/nodes/AtomNode.svelte.d.ts +1 -1
- package/dist/components/nodes/GatewayNode.svelte +8 -11
- package/dist/components/nodes/GatewayNode.svelte.d.ts +1 -1
- package/dist/components/nodes/IdeaNode.svelte +10 -8
- package/dist/components/nodes/IdeaNode.svelte.d.ts +8 -4
- package/dist/components/nodes/NotesNode.svelte +6 -4
- package/dist/components/nodes/NotesNode.svelte.d.ts +8 -4
- package/dist/components/nodes/SimpleNode.svelte +10 -8
- package/dist/components/nodes/SimpleNode.svelte.d.ts +4 -4
- package/dist/components/nodes/SquareNode.svelte +10 -8
- package/dist/components/nodes/SquareNode.svelte.d.ts +4 -4
- package/dist/components/nodes/TerminalNode.svelte +10 -8
- package/dist/components/nodes/TerminalNode.svelte.d.ts +4 -4
- package/dist/components/nodes/ToolNode.svelte +10 -8
- package/dist/components/nodes/ToolNode.svelte.d.ts +6 -6
- package/dist/components/nodes/WorkflowNode.svelte +7 -10
- package/dist/components/nodes/WorkflowNode.svelte.d.ts +1 -1
- package/dist/components/playground/InputCollector.svelte +11 -46
- package/dist/components/playground/PipelineKanbanView.svelte +2 -2
- package/dist/components/playground/PipelineTableView.svelte +2 -2
- package/dist/helpers/workflowEditorHelper.js +4 -5
- package/dist/messages/index.d.ts +1 -1
- package/dist/messages/index.js +1 -1
- package/dist/openapi/v1/openapi.yaml +2 -2
- package/dist/registry/nodeComponentRegistry.d.ts +2 -1
- package/dist/services/dynamicSchemaService.d.ts +2 -2
- package/dist/services/dynamicSchemaService.js +8 -8
- package/dist/skins/drafter.js +41 -28
- package/dist/stores/playgroundStore.svelte.js +1 -1
- package/dist/stores/workflowStore.svelte.js +0 -18
- package/dist/styles/base.css +247 -5
- package/dist/styles/tokens.css +6 -0
- package/dist/svelte-app.js +68 -107
- package/dist/types/index.d.ts +6 -7
- package/dist/utils/connections.js +20 -56
- package/dist/utils/nodeIds.d.ts +1 -1
- package/dist/utils/nodeIds.js +1 -1
- package/dist/utils/nodeSwap.js +3 -6
- package/package.json +1 -1
|
@@ -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;
|
|
@@ -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;
|
|
@@ -1100,7 +1100,7 @@
|
|
|
1100
1100
|
.config-form__extensions {
|
|
1101
1101
|
background-color: var(--fd-muted);
|
|
1102
1102
|
border: 1px solid var(--fd-border);
|
|
1103
|
-
border-radius: var(--fd-radius
|
|
1103
|
+
border-radius: var(--fd-control-radius);
|
|
1104
1104
|
overflow: hidden;
|
|
1105
1105
|
margin-top: var(--fd-space-xs);
|
|
1106
1106
|
}
|
|
@@ -1271,7 +1271,7 @@
|
|
|
1271
1271
|
.config-form__debug {
|
|
1272
1272
|
background-color: var(--fd-warning-muted);
|
|
1273
1273
|
border: 1px solid var(--fd-warning);
|
|
1274
|
-
border-radius: var(--fd-radius
|
|
1274
|
+
border-radius: var(--fd-control-radius);
|
|
1275
1275
|
overflow: hidden;
|
|
1276
1276
|
}
|
|
1277
1277
|
|
|
@@ -1425,7 +1425,7 @@
|
|
|
1425
1425
|
.config-form__error {
|
|
1426
1426
|
background-color: var(--fd-error-muted);
|
|
1427
1427
|
border: 1px solid var(--fd-error);
|
|
1428
|
-
border-radius: var(--fd-radius
|
|
1428
|
+
border-radius: var(--fd-control-radius);
|
|
1429
1429
|
overflow: hidden;
|
|
1430
1430
|
}
|
|
1431
1431
|
|
|
@@ -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;
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
-->
|
|
8
8
|
|
|
9
9
|
<script lang="ts">
|
|
10
|
+
import type { Snippet } from 'svelte';
|
|
10
11
|
import Icon from '@iconify/svelte';
|
|
11
12
|
import LogoWordmark from './LogoWordmark.svelte';
|
|
12
13
|
import SettingsModal from './SettingsModal.svelte';
|
|
@@ -37,6 +38,8 @@
|
|
|
37
38
|
showSettingsSyncButton?: boolean;
|
|
38
39
|
/** Show the reset buttons in the settings modal */
|
|
39
40
|
showSettingsResetButton?: boolean;
|
|
41
|
+
/** Custom content rendered in the trailing (right) region, before the settings gear */
|
|
42
|
+
end?: Snippet;
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
let {
|
|
@@ -47,7 +50,8 @@
|
|
|
47
50
|
showSettings = true,
|
|
48
51
|
settingsCategories,
|
|
49
52
|
showSettingsSyncButton,
|
|
50
|
-
showSettingsResetButton
|
|
53
|
+
showSettingsResetButton,
|
|
54
|
+
end
|
|
51
55
|
}: Props = $props();
|
|
52
56
|
|
|
53
57
|
// Dropdown state
|
|
@@ -271,6 +275,7 @@
|
|
|
271
275
|
</div>
|
|
272
276
|
|
|
273
277
|
<div class="flowdrop-navbar__end">
|
|
278
|
+
{@render end?.()}
|
|
274
279
|
{#if showSettings}
|
|
275
280
|
<button
|
|
276
281
|
class="flowdrop-navbar__settings-btn"
|
|
@@ -519,7 +524,7 @@
|
|
|
519
524
|
transition: all var(--fd-transition-normal);
|
|
520
525
|
font-weight: 500;
|
|
521
526
|
font-size: var(--fd-text-sm);
|
|
522
|
-
height:
|
|
527
|
+
height: var(--fd-size-btn-min);
|
|
523
528
|
box-sizing: border-box;
|
|
524
529
|
background-color: var(--fd-background);
|
|
525
530
|
color: var(--fd-foreground);
|
|
@@ -535,7 +540,7 @@
|
|
|
535
540
|
position: relative;
|
|
536
541
|
display: flex;
|
|
537
542
|
align-items: center;
|
|
538
|
-
height:
|
|
543
|
+
height: var(--fd-size-btn-min);
|
|
539
544
|
}
|
|
540
545
|
|
|
541
546
|
.flowdrop-navbar__dropdown-trigger {
|
|
@@ -543,7 +548,7 @@
|
|
|
543
548
|
align-items: center;
|
|
544
549
|
justify-content: center;
|
|
545
550
|
width: 2rem;
|
|
546
|
-
height:
|
|
551
|
+
height: var(--fd-size-btn-min);
|
|
547
552
|
border: 1px solid var(--fd-border-strong);
|
|
548
553
|
border-left: none;
|
|
549
554
|
border-radius: 0 var(--fd-radius-md) var(--fd-radius-md) 0;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
1
2
|
import type { SettingsCategory } from '../types/settings.js';
|
|
2
3
|
import type { NavbarAction } from '../types/navbar.js';
|
|
3
4
|
interface BreadcrumbItem {
|
|
@@ -22,6 +23,8 @@ interface Props {
|
|
|
22
23
|
showSettingsSyncButton?: boolean;
|
|
23
24
|
/** Show the reset buttons in the settings modal */
|
|
24
25
|
showSettingsResetButton?: boolean;
|
|
26
|
+
/** Custom content rendered in the trailing (right) region, before the settings gear */
|
|
27
|
+
end?: Snippet;
|
|
25
28
|
}
|
|
26
29
|
declare const Navbar: import("svelte").Component<Props, {}, "">;
|
|
27
30
|
type Navbar = ReturnType<typeof Navbar>;
|