@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
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { Position, Handle } from '@xyflow/svelte';
|
|
11
11
|
import type { ConfigValues, NodeMetadata } from '../../types/index.js';
|
|
12
12
|
import Icon from '@iconify/svelte';
|
|
13
|
+
import NodeConfigButton from './NodeConfigButton.svelte';
|
|
13
14
|
import { getDataTypeColor } from '../../utils/colors.js';
|
|
14
15
|
import { getInstance } from '../../stores/getInstance.svelte.js';
|
|
15
16
|
import { m } from '../../messages/index.js';
|
|
@@ -114,38 +115,19 @@
|
|
|
114
115
|
function handleDoubleClick(): void {
|
|
115
116
|
openConfigSidebar();
|
|
116
117
|
}
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* Handle single click - selection handled by SvelteFlow
|
|
120
|
-
*/
|
|
121
|
-
function handleClick(): void {
|
|
122
|
-
// Node selection is handled by Svelte Flow
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Handles keyboard events for accessibility
|
|
127
|
-
* @param event - The keyboard event
|
|
128
|
-
*/
|
|
129
|
-
function handleKeydown(event: KeyboardEvent): void {
|
|
130
|
-
if (event.key === 'Enter' || event.key === ' ') {
|
|
131
|
-
event.preventDefault();
|
|
132
|
-
handleDoubleClick();
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
118
|
</script>
|
|
136
119
|
|
|
137
120
|
<!-- Idea Node -->
|
|
121
|
+
<!-- Presentational: focus, keyboard and selection live on xyflow's node
|
|
122
|
+
wrapper (see UniversalNode). double-click is a mouse convenience. -->
|
|
123
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
138
124
|
<div
|
|
139
125
|
class="flowdrop-idea-node"
|
|
140
126
|
class:flowdrop-idea-node--selected={props.selected}
|
|
141
127
|
class:flowdrop-idea-node--processing={props.isProcessing}
|
|
142
128
|
class:flowdrop-idea-node--error={props.isError}
|
|
143
129
|
style="--idea-accent-color: {ideaColor};"
|
|
144
|
-
onclick={handleClick}
|
|
145
130
|
ondblclick={handleDoubleClick}
|
|
146
|
-
onkeydown={handleKeydown}
|
|
147
|
-
role="button"
|
|
148
|
-
tabindex="0"
|
|
149
131
|
aria-label={m().nodes.graph.ideaNode({ title: displayTitle })}
|
|
150
132
|
>
|
|
151
133
|
<!-- Left Port (Target/Input): center at top 40px (multiple of 10), 20px connection area -->
|
|
@@ -161,7 +143,7 @@
|
|
|
161
143
|
/>
|
|
162
144
|
{/if}
|
|
163
145
|
|
|
164
|
-
<!-- Top Port (Target/Input): center at left
|
|
146
|
+
<!-- Top Port (Target/Input): center at left 140px (node midpoint, 20px grid), 20px connection area -->
|
|
165
147
|
{#if enableTopPort}
|
|
166
148
|
<Handle
|
|
167
149
|
type="target"
|
|
@@ -169,7 +151,7 @@
|
|
|
169
151
|
style="--fd-handle-fill: {getDataTypeColor(
|
|
170
152
|
checker,
|
|
171
153
|
IDEA_DATA_TYPE
|
|
172
|
-
)}; --fd-handle-border-color: var(--fd-handle-border); left:
|
|
154
|
+
)}; --fd-handle-border-color: var(--fd-handle-border); left: 140px; transform: translateX(-50%); z-index: 30;"
|
|
173
155
|
id={`${props.data.nodeId}-input-top`}
|
|
174
156
|
/>
|
|
175
157
|
{/if}
|
|
@@ -210,9 +192,7 @@
|
|
|
210
192
|
</div>
|
|
211
193
|
|
|
212
194
|
<!-- Config button -->
|
|
213
|
-
<
|
|
214
|
-
<Icon icon="mdi:cog" />
|
|
215
|
-
</button>
|
|
195
|
+
<NodeConfigButton onclick={openConfigSidebar} title="Configure idea" />
|
|
216
196
|
|
|
217
197
|
<!-- Right Port (Source/Output): center at top 40px (multiple of 10), 20px connection area -->
|
|
218
198
|
{#if enableRightPort}
|
|
@@ -227,7 +207,7 @@
|
|
|
227
207
|
/>
|
|
228
208
|
{/if}
|
|
229
209
|
|
|
230
|
-
<!-- Bottom Port (Source/Output): center at left
|
|
210
|
+
<!-- Bottom Port (Source/Output): center at left 140px (node midpoint, 20px grid), 20px connection area -->
|
|
231
211
|
{#if enableBottomPort}
|
|
232
212
|
<Handle
|
|
233
213
|
type="source"
|
|
@@ -235,7 +215,7 @@
|
|
|
235
215
|
style="--fd-handle-fill: {getDataTypeColor(
|
|
236
216
|
checker,
|
|
237
217
|
IDEA_DATA_TYPE
|
|
238
|
-
)}; --fd-handle-border-color: var(--fd-handle-border); left:
|
|
218
|
+
)}; --fd-handle-border-color: var(--fd-handle-border); left: 140px; transform: translateX(-50%); z-index: 30;"
|
|
239
219
|
id={`${props.data.nodeId}-output-bottom`}
|
|
240
220
|
/>
|
|
241
221
|
{/if}
|
|
@@ -245,7 +225,11 @@
|
|
|
245
225
|
.flowdrop-idea-node {
|
|
246
226
|
position: relative;
|
|
247
227
|
width: var(--fd-node-default-width);
|
|
248
|
-
|
|
228
|
+
/* Floor at 80px, then grow in 20px steps. Fixed chrome = accent 4px +
|
|
229
|
+
header 48px + body bottom 6px = 58px, plus the card's 1px×2 border = 60px;
|
|
230
|
+
each description line adds 20px (line-height), so the card lands on
|
|
231
|
+
80 / 100 / 120px gridlines. */
|
|
232
|
+
min-height: 80px;
|
|
249
233
|
cursor: pointer;
|
|
250
234
|
transition: all var(--fd-transition-normal);
|
|
251
235
|
z-index: 10;
|
|
@@ -254,22 +238,21 @@
|
|
|
254
238
|
|
|
255
239
|
.flowdrop-idea-node__card {
|
|
256
240
|
background-color: var(--fd-background);
|
|
257
|
-
border-radius: var(--fd-radius
|
|
241
|
+
border-radius: var(--fd-node-radius);
|
|
258
242
|
border: 1px solid var(--fd-border);
|
|
259
|
-
box-shadow: var(--fd-shadow
|
|
243
|
+
box-shadow: var(--fd-node-shadow);
|
|
260
244
|
overflow: hidden;
|
|
261
245
|
transition: all var(--fd-transition-normal);
|
|
262
246
|
}
|
|
263
247
|
|
|
264
248
|
.flowdrop-idea-node:hover .flowdrop-idea-node__card {
|
|
265
|
-
box-shadow: var(--fd-shadow-
|
|
266
|
-
transform: translateY(-1px);
|
|
249
|
+
box-shadow: var(--fd-node-shadow-hover);
|
|
267
250
|
}
|
|
268
251
|
|
|
269
252
|
.flowdrop-idea-node--selected .flowdrop-idea-node__card {
|
|
270
253
|
border-color: var(--fd-primary);
|
|
271
254
|
box-shadow:
|
|
272
|
-
var(--fd-shadow-
|
|
255
|
+
var(--fd-node-shadow-hover),
|
|
273
256
|
0 0 0 3px color-mix(in srgb, var(--fd-primary) 30%, transparent);
|
|
274
257
|
}
|
|
275
258
|
|
|
@@ -293,52 +276,69 @@
|
|
|
293
276
|
.flowdrop-idea-node__header {
|
|
294
277
|
display: flex;
|
|
295
278
|
align-items: center;
|
|
296
|
-
|
|
297
|
-
|
|
279
|
+
/* px (not rem) on the 20px grid; 8px top/bottom + 32px icon = 48px header */
|
|
280
|
+
gap: 10px;
|
|
281
|
+
padding: 8px 16px;
|
|
298
282
|
}
|
|
299
283
|
|
|
284
|
+
/* Squircle icon wrapper - px (not rem) so the icon stays grid-locked
|
|
285
|
+
regardless of root font-size */
|
|
300
286
|
.flowdrop-idea-node__icon-wrapper {
|
|
301
287
|
display: flex;
|
|
302
288
|
align-items: center;
|
|
303
289
|
justify-content: center;
|
|
304
|
-
width:
|
|
305
|
-
height:
|
|
290
|
+
width: 32px;
|
|
291
|
+
height: 32px;
|
|
306
292
|
background-color: color-mix(
|
|
307
293
|
in srgb,
|
|
308
294
|
var(--idea-accent-color, var(--fd-accent)) var(--fd-node-icon-bg-opacity),
|
|
309
295
|
transparent
|
|
310
296
|
);
|
|
311
|
-
border-radius:
|
|
297
|
+
border-radius: 8px;
|
|
312
298
|
flex-shrink: 0;
|
|
299
|
+
transition: all var(--fd-transition-normal);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/* Icon hover effect — matches SimpleNode/ToolNode/NotesNode */
|
|
303
|
+
.flowdrop-idea-node:hover .flowdrop-idea-node__icon-wrapper {
|
|
304
|
+
background-color: color-mix(
|
|
305
|
+
in srgb,
|
|
306
|
+
var(--idea-accent-color, var(--fd-accent)) var(--fd-node-icon-bg-opacity-hover),
|
|
307
|
+
transparent
|
|
308
|
+
);
|
|
309
|
+
transform: scale(1.05);
|
|
313
310
|
}
|
|
314
311
|
|
|
315
312
|
:global(.flowdrop-idea-node__icon) {
|
|
316
|
-
width:
|
|
317
|
-
height:
|
|
313
|
+
width: 20px;
|
|
314
|
+
height: 20px;
|
|
318
315
|
color: var(--fd-node-icon);
|
|
319
316
|
}
|
|
320
317
|
|
|
321
318
|
.flowdrop-idea-node__title {
|
|
322
|
-
font-size:
|
|
319
|
+
font-size: 15px;
|
|
323
320
|
font-weight: 600;
|
|
324
321
|
color: var(--fd-foreground);
|
|
325
322
|
margin: 0;
|
|
326
|
-
line-height
|
|
323
|
+
/* px line-height so multi-line text stays on the 20px grid */
|
|
324
|
+
line-height: 20px;
|
|
327
325
|
overflow: hidden;
|
|
328
326
|
text-overflow: ellipsis;
|
|
329
327
|
white-space: nowrap;
|
|
330
328
|
}
|
|
331
329
|
|
|
332
|
-
/* Body section
|
|
330
|
+
/* Body section: 6px bottom (not 8px) compensates the card's 1px×2 border
|
|
331
|
+
so the card height stays a multiple of 20px. */
|
|
333
332
|
.flowdrop-idea-node__body {
|
|
334
|
-
padding: 0
|
|
333
|
+
padding: 0 16px 6px;
|
|
335
334
|
}
|
|
336
335
|
|
|
337
336
|
.flowdrop-idea-node__description {
|
|
338
|
-
font-size:
|
|
337
|
+
font-size: 13px;
|
|
339
338
|
color: var(--fd-muted-foreground);
|
|
340
339
|
margin: 0;
|
|
341
|
-
line-height
|
|
340
|
+
/* px line-height so the 3-line clamp lands on the 20px grid (3 × 20px) */
|
|
341
|
+
line-height: 20px;
|
|
342
342
|
display: -webkit-box;
|
|
343
343
|
-webkit-line-clamp: 3;
|
|
344
344
|
line-clamp: 3;
|
|
@@ -350,16 +350,16 @@
|
|
|
350
350
|
.flowdrop-idea-node__processing {
|
|
351
351
|
display: flex;
|
|
352
352
|
align-items: center;
|
|
353
|
-
gap:
|
|
354
|
-
padding:
|
|
353
|
+
gap: 8px;
|
|
354
|
+
padding: 8px 16px;
|
|
355
355
|
font-size: var(--fd-text-xs);
|
|
356
356
|
color: var(--fd-muted-foreground);
|
|
357
357
|
border-top: 1px solid var(--fd-border-muted);
|
|
358
358
|
}
|
|
359
359
|
|
|
360
360
|
.flowdrop-idea-node__spinner {
|
|
361
|
-
width:
|
|
362
|
-
height:
|
|
361
|
+
width: 14px;
|
|
362
|
+
height: 14px;
|
|
363
363
|
border: 2px solid var(--fd-border);
|
|
364
364
|
border-top-color: var(--idea-accent-color, var(--fd-accent));
|
|
365
365
|
border-radius: 50%;
|
|
@@ -370,8 +370,8 @@
|
|
|
370
370
|
.flowdrop-idea-node__error {
|
|
371
371
|
display: flex;
|
|
372
372
|
align-items: center;
|
|
373
|
-
gap:
|
|
374
|
-
padding:
|
|
373
|
+
gap: 8px;
|
|
374
|
+
padding: 8px 16px;
|
|
375
375
|
font-size: var(--fd-text-xs);
|
|
376
376
|
color: var(--fd-error);
|
|
377
377
|
border-top: 1px solid color-mix(in srgb, var(--fd-error) 30%, transparent);
|
|
@@ -379,8 +379,8 @@
|
|
|
379
379
|
}
|
|
380
380
|
|
|
381
381
|
:global(.flowdrop-idea-node__error-icon) {
|
|
382
|
-
width:
|
|
383
|
-
height:
|
|
382
|
+
width: 14px;
|
|
383
|
+
height: 14px;
|
|
384
384
|
}
|
|
385
385
|
|
|
386
386
|
@keyframes idea-spin {
|
|
@@ -389,37 +389,9 @@
|
|
|
389
389
|
}
|
|
390
390
|
}
|
|
391
391
|
|
|
392
|
-
/*
|
|
393
|
-
.flowdrop-idea-
|
|
394
|
-
|
|
395
|
-
top: 0.625rem;
|
|
396
|
-
right: 0.625rem;
|
|
397
|
-
width: 1.5rem;
|
|
398
|
-
height: 1.5rem;
|
|
399
|
-
background-color: var(--fd-backdrop);
|
|
400
|
-
border: 1px solid var(--fd-border);
|
|
401
|
-
border-radius: var(--fd-radius-md);
|
|
402
|
-
color: var(--fd-muted-foreground);
|
|
403
|
-
cursor: pointer;
|
|
404
|
-
display: flex;
|
|
405
|
-
align-items: center;
|
|
406
|
-
justify-content: center;
|
|
407
|
-
opacity: 0;
|
|
408
|
-
transition: all var(--fd-transition-normal);
|
|
409
|
-
backdrop-filter: var(--fd-backdrop-blur);
|
|
410
|
-
z-index: 15;
|
|
411
|
-
font-size: var(--fd-text-sm);
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
.flowdrop-idea-node:hover .flowdrop-idea-node__config-btn {
|
|
415
|
-
opacity: 1;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
.flowdrop-idea-node__config-btn:hover {
|
|
419
|
-
background-color: var(--fd-muted);
|
|
420
|
-
border-color: var(--fd-border-strong);
|
|
421
|
-
color: var(--fd-foreground);
|
|
422
|
-
transform: scale(1.05);
|
|
392
|
+
/* Reveal the NodeConfigButton (gear) when the node is hovered. */
|
|
393
|
+
.flowdrop-idea-node:hover {
|
|
394
|
+
--fd-config-btn-opacity: 1;
|
|
423
395
|
}
|
|
424
396
|
|
|
425
397
|
/* Handle: 20px/12px from base.css; position offsets for 20px handle */
|
|
@@ -441,15 +413,15 @@
|
|
|
441
413
|
/* Responsive design */
|
|
442
414
|
@media (max-width: 640px) {
|
|
443
415
|
.flowdrop-idea-node {
|
|
444
|
-
width:
|
|
416
|
+
width: 256px;
|
|
445
417
|
}
|
|
446
418
|
|
|
447
419
|
.flowdrop-idea-node__header {
|
|
448
|
-
padding:
|
|
420
|
+
padding: 8px 12px;
|
|
449
421
|
}
|
|
450
422
|
|
|
451
423
|
.flowdrop-idea-node__body {
|
|
452
|
-
padding: 0
|
|
424
|
+
padding: 0 12px 6px;
|
|
453
425
|
}
|
|
454
426
|
|
|
455
427
|
.flowdrop-idea-node__title {
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import CogIcon from '../icons/CogIcon.svelte';
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
/** Click handler — typically opens the node's config sidebar. */
|
|
6
|
+
onclick: (event: MouseEvent) => void;
|
|
7
|
+
/** Accessible label / tooltip. */
|
|
8
|
+
title?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Where the button sits relative to the node.
|
|
11
|
+
* - `corner` (default): top-right corner, used by most nodes.
|
|
12
|
+
* - `top-center`: circular badge above the node, used by TerminalNode.
|
|
13
|
+
*/
|
|
14
|
+
placement?: 'corner' | 'top-center';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
let { onclick, title = 'Configure node', placement = 'corner' }: Props = $props();
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<!--
|
|
21
|
+
tabindex="-1" keeps the gear out of the Tab order: the parent node is already
|
|
22
|
+
keyboard-focusable and opens config on Enter/Space, so tabbing moves straight
|
|
23
|
+
from node to node instead of stopping on the gear. The button stays clickable
|
|
24
|
+
and is revealed on node hover via the --fd-config-btn-opacity custom property
|
|
25
|
+
the parent sets.
|
|
26
|
+
-->
|
|
27
|
+
<button
|
|
28
|
+
class="flowdrop-node-config-btn"
|
|
29
|
+
class:flowdrop-node-config-btn--top-center={placement === 'top-center'}
|
|
30
|
+
{onclick}
|
|
31
|
+
{title}
|
|
32
|
+
tabindex="-1"
|
|
33
|
+
>
|
|
34
|
+
<CogIcon />
|
|
35
|
+
</button>
|
|
36
|
+
|
|
37
|
+
<style>
|
|
38
|
+
.flowdrop-node-config-btn {
|
|
39
|
+
position: absolute;
|
|
40
|
+
top: var(--fd-space-xs);
|
|
41
|
+
right: var(--fd-space-xs);
|
|
42
|
+
width: 24px;
|
|
43
|
+
height: 24px;
|
|
44
|
+
background-color: var(--fd-backdrop);
|
|
45
|
+
border: 1px solid var(--fd-border);
|
|
46
|
+
border-radius: var(--fd-radius-sm);
|
|
47
|
+
color: var(--fd-muted-foreground);
|
|
48
|
+
cursor: pointer;
|
|
49
|
+
display: flex;
|
|
50
|
+
align-items: center;
|
|
51
|
+
justify-content: center;
|
|
52
|
+
opacity: var(--fd-config-btn-opacity, 0);
|
|
53
|
+
transition: all var(--fd-transition-normal);
|
|
54
|
+
backdrop-filter: var(--fd-backdrop-blur);
|
|
55
|
+
z-index: 15;
|
|
56
|
+
font-size: var(--fd-text-sm);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.flowdrop-node-config-btn :global(svg) {
|
|
60
|
+
width: 14px;
|
|
61
|
+
height: 14px;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.flowdrop-node-config-btn:hover {
|
|
65
|
+
background-color: var(--fd-muted);
|
|
66
|
+
border-color: var(--fd-border-strong);
|
|
67
|
+
color: var(--fd-foreground);
|
|
68
|
+
transform: scale(1.05);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/* TerminalNode: circular badge centered above the node. */
|
|
72
|
+
.flowdrop-node-config-btn--top-center {
|
|
73
|
+
top: -24px;
|
|
74
|
+
right: auto;
|
|
75
|
+
left: 50%;
|
|
76
|
+
transform: translateX(-50%);
|
|
77
|
+
border-radius: 50%;
|
|
78
|
+
font-size: var(--fd-text-xs);
|
|
79
|
+
box-shadow: var(--fd-shadow-sm);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/* Keep the centering translate while scaling on hover. */
|
|
83
|
+
.flowdrop-node-config-btn--top-center:hover {
|
|
84
|
+
transform: translateX(-50%) scale(1.1);
|
|
85
|
+
}
|
|
86
|
+
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
/** Click handler — typically opens the node's config sidebar. */
|
|
3
|
+
onclick: (event: MouseEvent) => void;
|
|
4
|
+
/** Accessible label / tooltip. */
|
|
5
|
+
title?: string;
|
|
6
|
+
/**
|
|
7
|
+
* Where the button sits relative to the node.
|
|
8
|
+
* - `corner` (default): top-right corner, used by most nodes.
|
|
9
|
+
* - `top-center`: circular badge above the node, used by TerminalNode.
|
|
10
|
+
*/
|
|
11
|
+
placement?: 'corner' | 'top-center';
|
|
12
|
+
}
|
|
13
|
+
declare const NodeConfigButton: import("svelte").Component<Props, {}, "">;
|
|
14
|
+
type NodeConfigButton = ReturnType<typeof NodeConfigButton>;
|
|
15
|
+
export default NodeConfigButton;
|