@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.
Files changed (113) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/MIGRATION-2.0.md +13 -0
  3. package/README.md +5 -5
  4. package/dist/components/App.svelte +36 -191
  5. package/dist/components/App.svelte.d.ts +2 -7
  6. package/dist/components/Button.stories.svelte +65 -0
  7. package/dist/components/Button.stories.svelte.d.ts +19 -0
  8. package/dist/components/Button.svelte +62 -0
  9. package/dist/components/Button.svelte.d.ts +24 -0
  10. package/dist/components/CanvasIconButton.svelte +76 -0
  11. package/dist/components/CanvasIconButton.svelte.d.ts +18 -0
  12. package/dist/components/ConfigForm.svelte +4 -23
  13. package/dist/components/ConfigPanel.svelte +4 -3
  14. package/dist/components/EditorStatusBar.stories.svelte +44 -0
  15. package/dist/components/EditorStatusBar.stories.svelte.d.ts +27 -0
  16. package/dist/components/EditorStatusBar.svelte +99 -0
  17. package/dist/components/EditorStatusBar.svelte.d.ts +15 -0
  18. package/dist/components/IconButton.svelte +80 -0
  19. package/dist/components/IconButton.svelte.d.ts +30 -0
  20. package/dist/components/Input.svelte +74 -0
  21. package/dist/components/Input.svelte.d.ts +17 -0
  22. package/dist/components/LogoWordmark.svelte +113 -0
  23. package/dist/components/LogoWordmark.svelte.d.ts +26 -0
  24. package/dist/components/Navbar.svelte +17 -63
  25. package/dist/components/Navbar.svelte.d.ts +3 -0
  26. package/dist/components/NodeSidebar.svelte +17 -122
  27. package/dist/components/NodeSwapPicker.svelte +10 -28
  28. package/dist/components/PortMappingRow.svelte +0 -2
  29. package/dist/components/SchemaForm.svelte +0 -12
  30. package/dist/components/Select.svelte +53 -0
  31. package/dist/components/Select.svelte.d.ts +15 -0
  32. package/dist/components/SettingsModal.svelte +0 -5
  33. package/dist/components/SettingsPanel.svelte +2 -6
  34. package/dist/components/Textarea.svelte +39 -0
  35. package/dist/components/Textarea.svelte.d.ts +12 -0
  36. package/dist/components/ThemeToggle.svelte +15 -94
  37. package/dist/components/UniversalNode.svelte +32 -1
  38. package/dist/components/WorkflowEditor.svelte +62 -51
  39. package/dist/components/WorkflowEditor.svelte.d.ts +18 -0
  40. package/dist/components/chat/AIChatPanel.svelte +1 -1
  41. package/dist/components/console/ConsoleAutocomplete.svelte +1 -1
  42. package/dist/components/console/ConsoleOutput.svelte +2 -2
  43. package/dist/components/form/FormArray.svelte +37 -173
  44. package/dist/components/form/FormAutocomplete.svelte +10 -6
  45. package/dist/components/form/FormCheckboxGroup.svelte +1 -5
  46. package/dist/components/form/FormCodeEditor.svelte +9 -7
  47. package/dist/components/form/FormField.svelte +5 -44
  48. package/dist/components/form/FormFieldLight.svelte +8 -47
  49. package/dist/components/form/FormFieldset.svelte +1 -1
  50. package/dist/components/form/FormMarkdownEditor.svelte +8 -5
  51. package/dist/components/form/FormNumberField.svelte +4 -36
  52. package/dist/components/form/FormRangeField.svelte +18 -27
  53. package/dist/components/form/FormSelect.svelte +13 -75
  54. package/dist/components/form/FormTemplateEditor.svelte +6 -4
  55. package/dist/components/form/FormTextField.svelte +3 -35
  56. package/dist/components/form/FormTextarea.svelte +4 -39
  57. package/dist/components/form/FormToggle.svelte +0 -4
  58. package/dist/components/form/resolveFieldType.d.ts +24 -0
  59. package/dist/components/form/resolveFieldType.js +55 -0
  60. package/dist/components/icons/CloseIcon.svelte +6 -0
  61. package/dist/components/icons/CloseIcon.svelte.d.ts +26 -0
  62. package/dist/components/icons/CommandLineIcon.svelte +15 -0
  63. package/dist/components/icons/CommandLineIcon.svelte.d.ts +26 -0
  64. package/dist/components/icons/MenuIcon.svelte +4 -0
  65. package/dist/components/icons/MenuIcon.svelte.d.ts +26 -0
  66. package/dist/components/icons/MenuOpenIcon.svelte +6 -0
  67. package/dist/components/icons/MenuOpenIcon.svelte.d.ts +26 -0
  68. package/dist/components/interrupt/ChoicePrompt.svelte +0 -10
  69. package/dist/components/interrupt/ConfirmationPrompt.svelte +0 -5
  70. package/dist/components/interrupt/InterruptBubble.svelte +0 -10
  71. package/dist/components/interrupt/ReviewPrompt.svelte +0 -20
  72. package/dist/components/interrupt/TextInputPrompt.svelte +0 -6
  73. package/dist/components/layouts/MainLayout.svelte +4 -5
  74. package/dist/components/nodes/AtomNode.svelte +46 -34
  75. package/dist/components/nodes/GatewayNode.svelte +91 -99
  76. package/dist/components/nodes/IdeaNode.svelte +62 -90
  77. package/dist/components/nodes/NodeConfigButton.svelte +86 -0
  78. package/dist/components/nodes/NodeConfigButton.svelte.d.ts +15 -0
  79. package/dist/components/nodes/NotesNode.svelte +70 -81
  80. package/dist/components/nodes/SimpleNode.svelte +28 -78
  81. package/dist/components/nodes/SquareNode.svelte +79 -109
  82. package/dist/components/nodes/TerminalNode.svelte +28 -86
  83. package/dist/components/nodes/ToolNode.svelte +82 -95
  84. package/dist/components/nodes/WorkflowNode.svelte +91 -100
  85. package/dist/components/playground/ChatInput.svelte +0 -1
  86. package/dist/components/playground/InputCollector.svelte +11 -48
  87. package/dist/components/playground/PlaygroundApp.svelte +1 -1
  88. package/dist/components/playground/PlaygroundStudio.svelte +0 -5
  89. package/dist/messages/index.d.ts +1 -1
  90. package/dist/messages/index.js +1 -1
  91. package/dist/openapi/v1/openapi.yaml +2 -2
  92. package/dist/playground/mount.d.ts +9 -5
  93. package/dist/playground/mount.js +9 -5
  94. package/dist/skins/drafter.d.ts +30 -0
  95. package/dist/skins/drafter.js +198 -0
  96. package/dist/skins/index.d.ts +2 -1
  97. package/dist/skins/index.js +4 -2
  98. package/dist/styles/base.css +285 -14
  99. package/dist/styles/tokens.css +60 -2
  100. package/dist/svelte-app.d.ts +6 -0
  101. package/dist/svelte-app.js +71 -109
  102. package/dist/themes/drafter.d.ts +2 -0
  103. package/dist/themes/drafter.js +15 -0
  104. package/dist/themes/index.d.ts +2 -1
  105. package/dist/themes/index.js +8 -2
  106. package/dist/types/events.d.ts +18 -0
  107. package/dist/types/events.js +2 -1
  108. package/dist/types/settings.d.ts +1 -1
  109. package/dist/types/settings.js +1 -1
  110. package/dist/types/skin.d.ts +1 -1
  111. package/dist/types/theme.d.ts +16 -2
  112. package/dist/utils/connections.js +14 -50
  113. package/package.json +1 -1
@@ -8,6 +8,36 @@
8
8
  box-sizing: border-box;
9
9
  }
10
10
 
11
+ /* Drop the UA default margin on paragraphs so block text sits on the grid;
12
+ contexts that want spacing (e.g. .markdown-display p) opt back in. */
13
+ p {
14
+ margin: 0;
15
+ }
16
+
17
+ /* ───────────────────────────────────────────────────────────────────────────
18
+ Standardized focus ring — THE single source of truth.
19
+
20
+ The entire library draws ONE focus ring: a solid outline in --fd-ring, sized
21
+ by --fd-ring-width / --fd-ring-offset. Components must NOT declare their own
22
+ focus rings (no per-element :focus outline/box-shadow). :focus-visible keeps
23
+ it to keyboard navigation; browsers still surface it for text fields on
24
+ click. Scoped to the library roots so it never leaks into the host app.
25
+ ─────────────────────────────────────────────────────────────────────────── */
26
+ .flowdrop-root :focus-visible,
27
+ .svelte-flow :focus-visible {
28
+ outline: var(--fd-ring-width) solid var(--fd-ring);
29
+ outline-offset: var(--fd-ring-offset);
30
+ }
31
+
32
+ /* xyflow hard-disables the node wrapper outline
33
+ (.svelte-flow__node.selectable:focus-visible { outline: none }). That wrapper
34
+ is our single focusable node element, so re-assert the standard ring at
35
+ matching specificity. */
36
+ .svelte-flow .svelte-flow__node.selectable:focus-visible {
37
+ outline: var(--fd-ring-width) solid var(--fd-ring);
38
+ outline-offset: var(--fd-ring-offset);
39
+ }
40
+
11
41
  /* Layout utilities */
12
42
  .flowdrop-layout {
13
43
  display: flex;
@@ -93,9 +123,11 @@
93
123
  background-color: var(--fd-primary);
94
124
  }
95
125
 
126
+ /* Handles are tabindex="-1" (programmatic focus only, so :focus-visible won't
127
+ fire) — keep a :focus ring, but draw it from the same tokens. */
96
128
  .svelte-flow .svelte-flow__handle:focus {
97
- outline: 2px solid var(--fd-ring);
98
- outline-offset: 2px;
129
+ outline: var(--fd-ring-width) solid var(--fd-ring);
130
+ outline-offset: var(--fd-ring-offset);
99
131
  }
100
132
 
101
133
  /* Centralized handle edge positioning — offset derived from --fd-handle-size */
@@ -117,6 +149,7 @@
117
149
  display: inline-flex;
118
150
  align-items: center;
119
151
  justify-content: center;
152
+ gap: var(--fd-space-xs);
120
153
  padding: var(--fd-space-xs) var(--fd-space-xl);
121
154
  border: 1px solid transparent;
122
155
  border-radius: var(--fd-radius-md);
@@ -135,10 +168,7 @@
135
168
  border-color: var(--fd-border);
136
169
  }
137
170
 
138
- .flowdrop-btn:focus {
139
- outline: 2px solid var(--fd-ring);
140
- outline-offset: 2px;
141
- }
171
+ /* Focus ring is centralized (see top of file). */
142
172
 
143
173
  .flowdrop-btn--primary {
144
174
  background-color: var(--fd-primary);
@@ -195,38 +225,278 @@
195
225
  min-height: var(--fd-space-6xl);
196
226
  }
197
227
 
198
- /* Input styles */
228
+ /* ───────────────────────────────────────────────────────────────────────────
229
+ Icon buttons — square, icon-only. The typed primitive IconButton.svelte
230
+ routes here (the same way Button.svelte routes through .flowdrop-btn). It
231
+ composes onto .flowdrop-btn, then overrides geometry to a fixed square and
232
+ layers a tint variant. Corners follow --fd-control-radius so the Drafter
233
+ theme gets crisp icon buttons alongside its form controls.
234
+
235
+ Sizes: md (default) is 32px with a 16px glyph — the dominant size across the
236
+ library (form-array actions, modal closes, toolbars). sm maps to the
237
+ canonical --fd-size-icon-btn token (28px); lg is 36px (canvas-scale). */
238
+ .flowdrop-btn--icon {
239
+ width: 2rem;
240
+ height: 2rem;
241
+ min-height: 0;
242
+ padding: 0;
243
+ border-radius: var(--fd-control-radius);
244
+ color: var(--fd-muted-foreground);
245
+ }
246
+
247
+ .flowdrop-btn--icon svg {
248
+ width: 1rem;
249
+ height: 1rem;
250
+ }
251
+
252
+ .flowdrop-btn--icon.flowdrop-btn--sm {
253
+ width: var(--fd-size-icon-btn);
254
+ height: var(--fd-size-icon-btn);
255
+ padding: 0;
256
+ }
257
+
258
+ .flowdrop-btn--icon.flowdrop-btn--sm svg {
259
+ width: 0.875rem;
260
+ height: 0.875rem;
261
+ }
262
+
263
+ .flowdrop-btn--icon.flowdrop-btn--lg {
264
+ width: 2.25rem;
265
+ height: 2.25rem;
266
+ padding: 0;
267
+ }
268
+
269
+ .flowdrop-btn--icon.flowdrop-btn--lg svg {
270
+ width: 1.125rem;
271
+ height: 1.125rem;
272
+ }
273
+
274
+ /* Ghost (default for icon buttons) — transparent until hover. */
275
+ .flowdrop-btn--icon.flowdrop-btn--ghost:hover:not(:disabled) {
276
+ background-color: var(--fd-muted);
277
+ color: var(--fd-foreground);
278
+ border-color: transparent;
279
+ }
280
+
281
+ /* Default — flat --fd-background surface with a resting border. */
282
+ .flowdrop-btn--icon-default {
283
+ background-color: var(--fd-background);
284
+ border-color: var(--fd-border);
285
+ }
286
+
287
+ .flowdrop-btn--icon-default:hover:not(:disabled) {
288
+ background-color: var(--fd-muted);
289
+ color: var(--fd-foreground);
290
+ }
291
+
292
+ /* Tinted semantic variants — muted fill + semantic border/text, solid on press.
293
+ Unlike the solid text-button --primary, the icon flavour stays a quiet tint
294
+ so a row of action buttons reads as a group, not a wall of colour. */
295
+ .flowdrop-btn--icon-primary {
296
+ background-color: var(--fd-primary-muted);
297
+ border-color: var(--fd-primary);
298
+ color: var(--fd-primary-hover);
299
+ }
300
+
301
+ .flowdrop-btn--icon-primary:hover:not(:disabled) {
302
+ border-color: var(--fd-primary-hover);
303
+ color: var(--fd-primary-hover);
304
+ }
305
+
306
+ .flowdrop-btn--icon-primary:active:not(:disabled) {
307
+ background-color: var(--fd-primary);
308
+ }
309
+
310
+ .flowdrop-btn--icon-danger {
311
+ background-color: var(--fd-error-muted);
312
+ border-color: var(--fd-error);
313
+ color: var(--fd-error);
314
+ }
315
+
316
+ .flowdrop-btn--icon-danger:hover:not(:disabled) {
317
+ border-color: var(--fd-error-hover);
318
+ color: var(--fd-error-hover);
319
+ }
320
+
321
+ .flowdrop-btn--icon-danger:active:not(:disabled) {
322
+ background-color: var(--fd-error);
323
+ }
324
+
325
+ .flowdrop-btn--icon-success {
326
+ background-color: var(--fd-success-muted);
327
+ border-color: var(--fd-success);
328
+ color: var(--fd-success);
329
+ }
330
+
331
+ .flowdrop-btn--icon-success:hover:not(:disabled) {
332
+ border-color: var(--fd-success-hover);
333
+ color: var(--fd-success-hover);
334
+ }
335
+
336
+ .flowdrop-btn--icon-success:active:not(:disabled) {
337
+ background-color: var(--fd-success);
338
+ }
339
+
340
+ /* Active / toggled state (e.g. a pressed canvas control) — primary tint. */
341
+ .flowdrop-btn--icon.is-active {
342
+ color: var(--fd-primary);
343
+ background-color: var(--fd-primary-muted);
344
+ border-color: var(--fd-primary);
345
+ }
346
+
347
+ .flowdrop-btn--icon:disabled {
348
+ opacity: 0.35;
349
+ cursor: not-allowed;
350
+ }
351
+
352
+ /* ───────────────────────────────────────────────────────────────────────────
353
+ Form controls — THE single source of truth for input/select/textarea look.
354
+
355
+ The typed primitives Input.svelte / Select.svelte / Textarea.svelte route
356
+ here (the same way Button.svelte routes through .flowdrop-btn) so every field
357
+ across the library — config form, sidebar search, playground, prompts —
358
+ renders identically. Resting fields are ALWAYS the flat --fd-background
359
+ surface; `:disabled` is the ONLY muted state. Components must not re-declare
360
+ control backgrounds/borders locally. */
199
361
  .flowdrop-input {
200
362
  display: block;
201
363
  width: 100%;
202
- padding: var(--fd-space-xs) var(--fd-space-md);
364
+ padding: 0.625rem 0.875rem;
203
365
  border: 1px solid var(--fd-border);
204
- border-radius: var(--fd-radius-md);
366
+ border-radius: var(--fd-control-radius);
205
367
  font-size: var(--fd-text-sm);
368
+ font-family: inherit;
206
369
  line-height: 1.25rem;
207
370
  color: var(--fd-foreground);
208
371
  background-color: var(--fd-background);
372
+ box-shadow: var(--fd-shadow-sm);
209
373
  transition:
210
374
  border-color var(--fd-transition-normal),
211
375
  box-shadow var(--fd-transition-normal);
212
376
  }
213
377
 
378
+ .flowdrop-input::placeholder {
379
+ color: var(--fd-muted-foreground);
380
+ }
381
+
382
+ /* Active-field hint only; the focus ring itself is centralized (top of file). */
383
+ .flowdrop-input:hover:not(:disabled):not(:focus) {
384
+ border-color: var(--fd-border-strong);
385
+ }
386
+
214
387
  .flowdrop-input:focus {
215
- outline: none;
216
- border-color: var(--fd-primary);
217
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
388
+ border-color: var(--fd-ring);
389
+ }
390
+
391
+ .flowdrop-input:disabled {
392
+ background-color: var(--fd-muted);
393
+ border-color: var(--fd-border-muted);
394
+ color: var(--fd-muted-foreground);
395
+ cursor: not-allowed;
396
+ }
397
+
398
+ /* Invalid keeps its error border even on hover. */
399
+ .flowdrop-input--invalid,
400
+ .flowdrop-input--invalid:hover:not(:disabled) {
401
+ border-color: var(--fd-error);
218
402
  }
219
403
 
404
+ /* Sizes */
220
405
  .flowdrop-input--sm {
221
- padding: var(--fd-space-2xs) var(--fd-space-xs);
406
+ padding: 0.375rem 0.625rem;
222
407
  font-size: var(--fd-text-xs);
223
408
  }
224
409
 
225
410
  .flowdrop-input--lg {
226
- padding: var(--fd-space-md) var(--fd-space-xl);
411
+ padding: 0.75rem 1rem;
227
412
  font-size: var(--fd-text-base);
228
413
  }
229
414
 
415
+ /* Tabular figures for numeric entry (aligned digits). */
416
+ .flowdrop-input--numeric {
417
+ font-variant-numeric: tabular-nums;
418
+ }
419
+
420
+ /* Multiline */
421
+ .flowdrop-input--textarea {
422
+ min-height: 5rem;
423
+ line-height: 1.5;
424
+ resize: vertical;
425
+ }
426
+
427
+ /* Select: room for the chevron overlay; native arrow removed. */
428
+ .flowdrop-input--select {
429
+ padding-right: 2.5rem;
430
+ cursor: pointer;
431
+ appearance: none;
432
+ -webkit-appearance: none;
433
+ }
434
+
435
+ /* Select shell carries the chevron; the <select> keeps the field look. */
436
+ .flowdrop-select-wrap {
437
+ position: relative;
438
+ width: 100%;
439
+ }
440
+
441
+ .flowdrop-select-wrap__icon {
442
+ position: absolute;
443
+ right: 0.75rem;
444
+ top: 50%;
445
+ transform: translateY(-50%);
446
+ display: flex;
447
+ pointer-events: none;
448
+ color: var(--fd-muted-foreground);
449
+ transition: color var(--fd-transition-fast);
450
+ }
451
+
452
+ .flowdrop-select-wrap:focus-within .flowdrop-select-wrap__icon {
453
+ color: var(--fd-primary);
454
+ }
455
+
456
+ .flowdrop-select-wrap__icon svg {
457
+ width: 1rem;
458
+ height: 1rem;
459
+ }
460
+
461
+ /* Input with a leading/trailing affordance (e.g. a search magnifier). */
462
+ .flowdrop-input-wrap {
463
+ position: relative;
464
+ width: 100%;
465
+ display: flex;
466
+ align-items: center;
467
+ }
468
+
469
+ .flowdrop-input-wrap__icon {
470
+ position: absolute;
471
+ top: 50%;
472
+ transform: translateY(-50%);
473
+ display: flex;
474
+ align-items: center;
475
+ pointer-events: none;
476
+ color: var(--fd-muted-foreground);
477
+ }
478
+
479
+ .flowdrop-input-wrap__icon--leading {
480
+ left: 0.75rem;
481
+ }
482
+
483
+ .flowdrop-input-wrap__icon--trailing {
484
+ right: 0.75rem;
485
+ }
486
+
487
+ .flowdrop-input-wrap__icon svg {
488
+ width: 1rem;
489
+ height: 1rem;
490
+ }
491
+
492
+ .flowdrop-input--has-leading {
493
+ padding-left: 2.25rem;
494
+ }
495
+
496
+ .flowdrop-input--has-trailing {
497
+ padding-right: 2.25rem;
498
+ }
499
+
230
500
  /* Card styles */
231
501
  .flowdrop-card {
232
502
  background-color: var(--fd-card);
@@ -1092,6 +1362,7 @@
1092
1362
  --fd-notes-node-width: 500px;
1093
1363
  --fd-notes-node-min-width: 250px;
1094
1364
  --fd-notes-node-max-width: 500px;
1365
+ --fd-notes-node-min-height: 200px;
1095
1366
  --fd-notes-node-backdrop-filter: blur(8px);
1096
1367
  }
1097
1368
 
@@ -127,6 +127,13 @@
127
127
  --fd-card: #ffffff; /* @public */
128
128
  --fd-card-foreground: var(--_gray-9); /* @public */
129
129
 
130
+ /* ----- CHROME PANELS (sidebar + config/inspector panel) -----
131
+ Large editor-shell panels read from these so a theme can make them
132
+ glassy/translucent without touching every other surface. Default to the
133
+ opaque app background + no blur, so existing themes are unchanged. */
134
+ --fd-panel-bg: var(--fd-background); /* @public sidebar + config panel surface */
135
+ --fd-panel-backdrop-filter: none; /* @public glass/frost behind translucent panels; e.g. blur(14px) */
136
+
130
137
  /* ----- HEADER (Distinct header styling) ----- */
131
138
  --fd-header: #f5f7fa; /* @public */
132
139
  --fd-header-foreground: var(--_gray-8); /* @public */
@@ -140,10 +147,45 @@
140
147
  --fd-border-muted: var(--_gray-3); /* @public */
141
148
  --fd-border-strong: var(--_gray-5); /* @public */
142
149
  --fd-ring: var(--_blue-2); /* @public */
150
+ /* Focus-ring geometry. The whole library draws ONE focus ring from these
151
+ (see base.css). Color is theme-aware (--fd-ring); width/offset are not, so
152
+ they live only here. */
153
+ --fd-ring-width: 2px; /* @public */
154
+ --fd-ring-offset: 2px; /* @public */
155
+
156
+ /* ----- EDITOR CANVAS & NODE SURFACES -----
157
+ Scoped surfaces for the graph editor, kept separate from the general app
158
+ "chrome" (navbar, sidebars, panels) so a theme can restyle the canvas/nodes
159
+ without tinting the rest of the UI. Each defaults to its chrome equivalent,
160
+ so overriding the base token (e.g. --fd-card) still cascades here. */
161
+ --fd-canvas-bg: var(--fd-background); /* @public editor canvas (grid) background */
162
+ --fd-node-bg: var(--fd-card); /* @public node body surface */
163
+ --fd-node-header-bg: var(--fd-header); /* @public node header surface */
164
+ --fd-node-radius: var(
165
+ --fd-radius-xl
166
+ ); /* @public node card corner radius; lower for sharper corners */
167
+ --fd-node-shadow: var(
168
+ --fd-shadow-md
169
+ ); /* @public node resting elevation; 'none' for a flat look */
170
+ --fd-node-shadow-hover: var(
171
+ --fd-shadow-lg
172
+ ); /* @public node hover/selected elevation; 'none' for a flat look */
173
+ --fd-node-backdrop-filter: none; /* @public glass/frost effect behind translucent node bodies; e.g. blur(10px) */
143
174
 
144
175
  /* ----- NODE BORDERS (Higher contrast for visibility when zoomed out) ----- */
145
176
  --fd-node-border: var(--_gray-5); /* @public */
146
177
  --fd-node-border-hover: var(--_gray-6); /* @public */
178
+ --fd-node-border-width: 1.5px; /* @public node outline thickness; lower for a thinner look */
179
+ /* Note nodes can carry their own outline so themes can read them as
180
+ informational/annotation rather than a process node. Defaults to the
181
+ shared node border so existing themes are unchanged. */
182
+ --fd-note-border: var(--fd-node-border); /* @public notes-node outline */
183
+ --fd-note-border-hover: var(--fd-node-border-hover); /* @public notes-node outline (hover) */
184
+
185
+ /* ----- CANVAS GRID (pattern color for the editor background grid; any theme
186
+ can recolor whichever grid variant it picks via config.canvas.grid).
187
+ Default matches xyflow's dot-grid color so the default theme is unchanged. */
188
+ --fd-grid-pattern-color: #91919a; /* @public */
147
189
 
148
190
  /* ----- PRIMARY (Interactive/Brand) ----- */
149
191
  --fd-primary: var(--_blue-2); /* @public */
@@ -211,6 +253,12 @@
211
253
  --fd-radius-2xl: 1rem; /* @public 16px */
212
254
  --fd-radius-full: 9999px; /* @public */
213
255
 
256
+ /* Corner radius shared by form controls (input/select/textarea) and their
257
+ group containers (array item boxes, fieldsets, checkbox groups, config
258
+ sections). Defaults to --fd-radius-lg; themes can tighten it independently
259
+ of cards/panels — e.g. Drafter sets 2px for crisp drafting corners. */
260
+ --fd-control-radius: var(--fd-radius-lg); /* @public */
261
+
214
262
  /* ----- SHADOWS (Refined layered shadows for modern depth) ----- */
215
263
  --fd-shadow-sm: 0 1px 2px rgb(0 0 0 / 0.04), 0 1px 3px rgb(0 0 0 / 0.06); /* @public */
216
264
  --fd-shadow-md: 0 4px 8px rgb(0 0 0 / 0.06), 0 2px 4px rgb(0 0 0 / 0.04); /* @public */
@@ -307,6 +355,7 @@
307
355
  --fd-scrollbar-thumb: var(--_gray-4); /* @internal */
308
356
  --fd-scrollbar-thumb-hover: var(--_gray-5); /* @internal */
309
357
  --fd-scrollbar-track: var(--_gray-2); /* @internal */
358
+ --fd-scrollbar-radius: 4px; /* @public scrollbar thumb/track corner radius; 0 for square */
310
359
 
311
360
  /* ----- BACKDROP/OVERLAY ----- */
312
361
  --fd-backdrop: rgba(255, 255, 255, 0.8); /* @internal */
@@ -324,11 +373,17 @@
324
373
 
325
374
  /* ----- NODE LAYOUT (Dimensions and port alignment; multiples of 10 for grid) ----- */
326
375
  --fd-node-grid-step: 10; /* @internal — layout algorithm detail */
327
- --fd-node-default-width: 290px; /* @public */
376
+ --fd-node-default-width: 280px; /* @public */
328
377
  --fd-node-header-height: 60px; /* @public */
329
- --fd-node-header-title-height: 40px; /* @internal */
378
+ --fd-node-header-title-height: 40px; /* @internal — fits icon + up to 2 text lines */
330
379
  --fd-node-header-desc-line: 20px; /* @internal */
331
380
  --fd-node-header-gap: 10px; /* @internal */
381
+ /* Divider absorbed into header bottom padding so header height stays on the
382
+ 20px grid regardless of border thickness. */
383
+ --fd-node-header-divider-width: 1px; /* @public */
384
+ --fd-node-header-divider-color: var(
385
+ --fd-border-muted
386
+ ); /* @public — header bottom divider color */
332
387
  --fd-node-port-row-height: 20px; /* @internal */
333
388
  --fd-node-terminal-size: 80px; /* @public */
334
389
  --fd-node-square-size: 80px; /* @public */
@@ -395,6 +450,9 @@
395
450
  --fd-node-border: #4a4a52;
396
451
  --fd-node-border-hover: #5a5a62;
397
452
 
453
+ /* ----- CANVAS GRID (matches xyflow's dark dot-grid color) ----- */
454
+ --fd-grid-pattern-color: #777;
455
+
398
456
  /* ----- NODE COLORS (port type labels/badges - lighter for readability on dark surfaces) ----- */
399
457
  --fd-node-emerald: #34d399;
400
458
  --fd-node-blue: #60a5fa;
@@ -204,6 +204,12 @@ export declare function mountWorkflowEditor(container: HTMLElement, options?: {
204
204
  authProvider?: AuthProvider;
205
205
  /** Instance identifier — see {@link FlowDropMountOptions.instanceId}. */
206
206
  instanceId?: string;
207
+ /**
208
+ * Register the built-in markdown/code/template editors. Batteries-included
209
+ * by default (chunks load lazily). See {@link FlowDropFeatures.builtinEditors}.
210
+ * @default true
211
+ */
212
+ builtinEditors?: boolean;
207
213
  }): Promise<MountedFlowDropApp>;
208
214
  /**
209
215
  * Unmount a FlowDrop app
@@ -55,6 +55,58 @@ function releaseInstance(fd, isDefault) {
55
55
  fd.destroy();
56
56
  }
57
57
  }
58
+ /**
59
+ * Resolve endpoint config, port config and categories from mount options and
60
+ * apply them to the given instance (API context, port-compatibility checker,
61
+ * categories). Shared by `mountFlowDropApp` and `mountWorkflowEditor`.
62
+ *
63
+ * @returns the resolved {@link EndpointConfig} (merged with defaults), which the
64
+ * callers forward to their mounted component.
65
+ */
66
+ async function configureInstance(fd, options) {
67
+ const { endpointConfig, portConfig, categories, authProvider } = options;
68
+ // Create endpoint configuration, merging with defaults so all required
69
+ // endpoints are present.
70
+ const { defaultEndpointConfig } = await import('./config/endpoints.js');
71
+ const config = endpointConfig
72
+ ? {
73
+ ...defaultEndpointConfig,
74
+ ...endpointConfig,
75
+ endpoints: {
76
+ ...defaultEndpointConfig.endpoints,
77
+ ...endpointConfig.endpoints
78
+ }
79
+ }
80
+ : defaultEndpointConfig;
81
+ // Initialize port configuration (fetch from API when not supplied).
82
+ let finalPortConfig = portConfig;
83
+ if (!finalPortConfig) {
84
+ try {
85
+ finalPortConfig = await fetchPortConfig(config, authProvider);
86
+ }
87
+ catch (error) {
88
+ logger.warn('Failed to fetch port config from API, using default:', error);
89
+ finalPortConfig = DEFAULT_PORT_CONFIG;
90
+ }
91
+ }
92
+ // Configure this instance's API context and port compatibility checker.
93
+ fd.api.configure(config, authProvider);
94
+ fd.portCompatibility.reinitialize(finalPortConfig);
95
+ // Initialize this instance's categories (fetch from API when not supplied).
96
+ if (categories) {
97
+ fd.categories.initialize(categories);
98
+ }
99
+ else {
100
+ try {
101
+ const fetchedCategories = await fetchCategories(config, authProvider);
102
+ fd.categories.initialize(fetchedCategories);
103
+ }
104
+ catch (error) {
105
+ logger.warn('Failed to fetch categories from API, using defaults:', error);
106
+ }
107
+ }
108
+ return config;
109
+ }
58
110
  /**
59
111
  * Mount the full FlowDrop App with navbar, sidebars, and workflow editor
60
112
  *
@@ -103,61 +155,14 @@ export async function mountFlowDropApp(container, options = {}) {
103
155
  await initializeSettings({
104
156
  defaults: initialSettings
105
157
  });
106
- // Create endpoint configuration
107
- let config;
108
- if (endpointConfig) {
109
- // Merge with default configuration to ensure all required endpoints are present
110
- const { defaultEndpointConfig } = await import('./config/endpoints.js');
111
- config = {
112
- ...defaultEndpointConfig,
113
- ...endpointConfig,
114
- endpoints: {
115
- ...defaultEndpointConfig.endpoints,
116
- ...endpointConfig.endpoints
117
- }
118
- };
119
- }
120
- else {
121
- // Use default configuration if none provided
122
- const { defaultEndpointConfig } = await import('./config/endpoints.js');
123
- config = defaultEndpointConfig;
124
- }
125
- // Initialize port configuration
126
- let finalPortConfig = portConfig;
127
- if (!finalPortConfig && config) {
128
- // Try to fetch port configuration from API
129
- try {
130
- finalPortConfig = await fetchPortConfig(config, authProvider);
131
- }
132
- catch (error) {
133
- logger.warn('Failed to fetch port config from API, using default:', error);
134
- finalPortConfig = DEFAULT_PORT_CONFIG;
135
- }
136
- }
137
- else if (!finalPortConfig) {
138
- finalPortConfig = DEFAULT_PORT_CONFIG;
139
- }
140
- // Configure this instance's API context (endpoints + auth provider) so
141
- // <App> and services resolve it via getInstance().api.
142
- if (config) {
143
- fd.api.configure(config, authProvider);
144
- }
145
- // Re-initialize this instance's port compatibility checker with the resolved
146
- // config (it was seeded with DEFAULT_PORT_CONFIG at construction).
147
- fd.portCompatibility.reinitialize(finalPortConfig);
148
- // Initialize this instance's categories
149
- if (categories) {
150
- fd.categories.initialize(categories);
151
- }
152
- else if (config) {
153
- try {
154
- const fetchedCategories = await fetchCategories(config, authProvider);
155
- fd.categories.initialize(fetchedCategories);
156
- }
157
- catch (error) {
158
- logger.warn('Failed to fetch categories from API, using defaults:', error);
159
- }
160
- }
158
+ // Resolve and apply endpoint config, port config and categories to this
159
+ // instance (see configureInstance).
160
+ const config = await configureInstance(fd, {
161
+ endpointConfig,
162
+ portConfig,
163
+ categories,
164
+ authProvider
165
+ });
161
166
  // Set up event handler callbacks in this instance's store
162
167
  if (eventHandlers?.onDirtyStateChange) {
163
168
  fd.workflow.setOnDirtyStateChange(eventHandlers.onDirtyStateChange);
@@ -335,61 +340,17 @@ export async function mountFlowDropApp(container, options = {}) {
335
340
  * @returns Promise resolving to a MountedFlowDropApp instance
336
341
  */
337
342
  export async function mountWorkflowEditor(container, options = {}) {
338
- const { workflow, endpointConfig, portConfig, categories, authProvider, instanceId } = options;
343
+ const { workflow, endpointConfig, portConfig, categories, authProvider, instanceId, builtinEditors } = options;
339
344
  // Per-instance state container (see mountFlowDropApp)
340
345
  const { fd, isDefault } = acquireInstance(instanceId);
341
- // Create endpoint configuration
342
- let config;
343
- if (endpointConfig) {
344
- // Merge with default configuration to ensure all required endpoints are present
345
- const { defaultEndpointConfig } = await import('./config/endpoints.js');
346
- config = {
347
- ...defaultEndpointConfig,
348
- ...endpointConfig,
349
- endpoints: {
350
- ...defaultEndpointConfig.endpoints,
351
- ...endpointConfig.endpoints
352
- }
353
- };
354
- }
355
- else {
356
- // Use default configuration if none provided
357
- const { defaultEndpointConfig } = await import('./config/endpoints.js');
358
- config = defaultEndpointConfig;
359
- }
360
- // Initialize port configuration
361
- let finalPortConfig = portConfig;
362
- if (!finalPortConfig && config) {
363
- // Try to fetch port configuration from API
364
- try {
365
- finalPortConfig = await fetchPortConfig(config, authProvider);
366
- }
367
- catch (error) {
368
- logger.warn('Failed to fetch port config from API, using default:', error);
369
- finalPortConfig = DEFAULT_PORT_CONFIG;
370
- }
371
- }
372
- else if (!finalPortConfig) {
373
- finalPortConfig = DEFAULT_PORT_CONFIG;
374
- }
375
- // Configure this instance's API context and port compatibility checker.
376
- if (config) {
377
- fd.api.configure(config, authProvider);
378
- }
379
- fd.portCompatibility.reinitialize(finalPortConfig);
380
- // Initialize this instance's categories
381
- if (categories) {
382
- fd.categories.initialize(categories);
383
- }
384
- else if (config) {
385
- try {
386
- const fetchedCategories = await fetchCategories(config, authProvider);
387
- fd.categories.initialize(fetchedCategories);
388
- }
389
- catch (error) {
390
- logger.warn('Failed to fetch categories from API, using defaults:', error);
391
- }
392
- }
346
+ // Resolve and apply endpoint config, port config and categories to this
347
+ // instance (see configureInstance).
348
+ const config = await configureInstance(fd, {
349
+ endpointConfig,
350
+ portConfig,
351
+ categories,
352
+ authProvider
353
+ });
393
354
  // Seed the instance's workflow before mounting so the editor renders it
394
355
  // immediately. (1.x accepted this option but silently ignored it.)
395
356
  if (workflow) {
@@ -401,7 +362,8 @@ export async function mountWorkflowEditor(container, options = {}) {
401
362
  props: {
402
363
  instance: fd,
403
364
  endpointConfig: config,
404
- authProvider
365
+ authProvider,
366
+ builtinEditors
405
367
  }
406
368
  });
407
369
  // Create the mounted app interface (simpler version)
@@ -0,0 +1,2 @@
1
+ import type { FlowDropTheme } from '../types/theme.js';
2
+ export declare const drafterTheme: FlowDropTheme;