@flowdrop/flowdrop 2.0.0-beta.2 → 2.0.0-beta.3

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 (85) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/MIGRATION-2.0.md +13 -0
  3. package/dist/components/App.svelte +21 -45
  4. package/dist/components/App.svelte.d.ts +2 -7
  5. package/dist/components/CanvasIconButton.svelte +76 -0
  6. package/dist/components/CanvasIconButton.svelte.d.ts +18 -0
  7. package/dist/components/ConfigForm.svelte +0 -19
  8. package/dist/components/ConfigPanel.svelte +4 -3
  9. package/dist/components/LogoWordmark.svelte +113 -0
  10. package/dist/components/LogoWordmark.svelte.d.ts +26 -0
  11. package/dist/components/Navbar.svelte +8 -59
  12. package/dist/components/NodeSidebar.svelte +4 -11
  13. package/dist/components/NodeSwapPicker.svelte +0 -2
  14. package/dist/components/PortMappingRow.svelte +0 -2
  15. package/dist/components/SchemaForm.svelte +0 -12
  16. package/dist/components/SettingsModal.svelte +0 -5
  17. package/dist/components/SettingsPanel.svelte +2 -6
  18. package/dist/components/ThemeToggle.svelte +0 -5
  19. package/dist/components/UniversalNode.svelte +32 -1
  20. package/dist/components/WorkflowEditor.svelte +62 -51
  21. package/dist/components/WorkflowEditor.svelte.d.ts +18 -0
  22. package/dist/components/chat/AIChatPanel.svelte +1 -1
  23. package/dist/components/console/ConsoleAutocomplete.svelte +1 -1
  24. package/dist/components/console/ConsoleOutput.svelte +2 -2
  25. package/dist/components/form/FormArray.svelte +0 -16
  26. package/dist/components/form/FormAutocomplete.svelte +10 -6
  27. package/dist/components/form/FormCheckboxGroup.svelte +0 -4
  28. package/dist/components/form/FormCodeEditor.svelte +9 -7
  29. package/dist/components/form/FormFieldLight.svelte +3 -3
  30. package/dist/components/form/FormMarkdownEditor.svelte +8 -5
  31. package/dist/components/form/FormNumberField.svelte +0 -4
  32. package/dist/components/form/FormRangeField.svelte +1 -20
  33. package/dist/components/form/FormSelect.svelte +10 -6
  34. package/dist/components/form/FormTemplateEditor.svelte +6 -4
  35. package/dist/components/form/FormTextField.svelte +10 -6
  36. package/dist/components/form/FormTextarea.svelte +10 -6
  37. package/dist/components/form/FormToggle.svelte +0 -4
  38. package/dist/components/icons/CommandLineIcon.svelte +15 -0
  39. package/dist/components/icons/CommandLineIcon.svelte.d.ts +26 -0
  40. package/dist/components/icons/MenuIcon.svelte +4 -0
  41. package/dist/components/icons/MenuIcon.svelte.d.ts +26 -0
  42. package/dist/components/icons/MenuOpenIcon.svelte +6 -0
  43. package/dist/components/icons/MenuOpenIcon.svelte.d.ts +26 -0
  44. package/dist/components/interrupt/ChoicePrompt.svelte +0 -10
  45. package/dist/components/interrupt/ConfirmationPrompt.svelte +0 -5
  46. package/dist/components/interrupt/InterruptBubble.svelte +0 -10
  47. package/dist/components/interrupt/ReviewPrompt.svelte +0 -20
  48. package/dist/components/interrupt/TextInputPrompt.svelte +0 -6
  49. package/dist/components/layouts/MainLayout.svelte +4 -5
  50. package/dist/components/nodes/AtomNode.svelte +46 -34
  51. package/dist/components/nodes/GatewayNode.svelte +91 -99
  52. package/dist/components/nodes/IdeaNode.svelte +62 -90
  53. package/dist/components/nodes/NodeConfigButton.svelte +86 -0
  54. package/dist/components/nodes/NodeConfigButton.svelte.d.ts +15 -0
  55. package/dist/components/nodes/NotesNode.svelte +70 -81
  56. package/dist/components/nodes/SimpleNode.svelte +28 -78
  57. package/dist/components/nodes/SquareNode.svelte +79 -109
  58. package/dist/components/nodes/TerminalNode.svelte +28 -86
  59. package/dist/components/nodes/ToolNode.svelte +82 -95
  60. package/dist/components/nodes/WorkflowNode.svelte +91 -100
  61. package/dist/components/playground/ChatInput.svelte +0 -1
  62. package/dist/components/playground/InputCollector.svelte +0 -2
  63. package/dist/components/playground/PlaygroundApp.svelte +1 -1
  64. package/dist/components/playground/PlaygroundStudio.svelte +0 -5
  65. package/dist/playground/mount.d.ts +9 -5
  66. package/dist/playground/mount.js +9 -5
  67. package/dist/skins/drafter.d.ts +30 -0
  68. package/dist/skins/drafter.js +185 -0
  69. package/dist/skins/index.d.ts +2 -1
  70. package/dist/skins/index.js +4 -2
  71. package/dist/styles/base.css +38 -9
  72. package/dist/styles/tokens.css +54 -2
  73. package/dist/svelte-app.d.ts +6 -0
  74. package/dist/svelte-app.js +3 -2
  75. package/dist/themes/drafter.d.ts +2 -0
  76. package/dist/themes/drafter.js +15 -0
  77. package/dist/themes/index.d.ts +2 -1
  78. package/dist/themes/index.js +8 -2
  79. package/dist/types/events.d.ts +18 -0
  80. package/dist/types/events.js +2 -1
  81. package/dist/types/settings.d.ts +1 -1
  82. package/dist/types/settings.js +1 -1
  83. package/dist/types/skin.d.ts +1 -1
  84. package/dist/types/theme.d.ts +16 -2
  85. package/package.json +1 -1
@@ -232,7 +232,6 @@
232
232
 
233
233
  .chat-input__wrapper:focus-within {
234
234
  border-color: var(--fd-primary);
235
- box-shadow: 0 0 0 3px var(--fd-primary-muted);
236
235
  }
237
236
 
238
237
  .chat-input__textarea {
@@ -369,9 +369,7 @@
369
369
  .input-collector__input:focus,
370
370
  .input-collector__select:focus,
371
371
  .input-collector__textarea:focus {
372
- outline: none;
373
372
  border-color: var(--fd-primary);
374
- box-shadow: 0 0 0 3px var(--fd-primary-muted);
375
373
  }
376
374
 
377
375
  .input-collector__input::placeholder,
@@ -52,7 +52,7 @@
52
52
  endpointConfig,
53
53
  authProvider,
54
54
  config = {},
55
- showNavbar = true,
55
+ showNavbar = false,
56
56
  navbarTitle,
57
57
  primaryActions = [],
58
58
  showSettings = true,
@@ -463,11 +463,6 @@
463
463
  .playground-studio__back-to-chat:hover {
464
464
  background-color: var(--fd-muted);
465
465
  }
466
-
467
- .playground-studio__back-to-chat:focus-visible {
468
- outline: 2px solid var(--fd-ring);
469
- outline-offset: 2px;
470
- }
471
466
  }
472
467
 
473
468
  @media (prefers-reduced-motion: reduce) {
@@ -252,7 +252,7 @@ export interface PlaygroundAppMountOptions extends Omit<PlaygroundStudioMountOpt
252
252
  * @default "standalone"
253
253
  */
254
254
  mode?: 'standalone' | 'embedded';
255
- /** Render the FlowDrop Navbar above the playground (default: true). */
255
+ /** Render the FlowDrop Navbar above the playground (default: false). */
256
256
  showNavbar?: boolean;
257
257
  /** Title shown in the navbar. Falls back to the workflow name, then "Playground". */
258
258
  navbarTitle?: string;
@@ -268,17 +268,21 @@ export interface PlaygroundAppMountOptions extends Omit<PlaygroundStudioMountOpt
268
268
  showSettingsResetButton?: boolean;
269
269
  }
270
270
  /**
271
- * Mount the full-page PlaygroundApp (Navbar + PlaygroundStudio) into a container.
271
+ * Mount the full-page PlaygroundApp (PlaygroundStudio, optionally wrapped in the
272
+ * FlowDrop Navbar) into a container.
272
273
  *
273
- * Use this when you want the same chrome as the FlowDrop editor logo,
274
- * branding, and settings modal wrapped around the playground. For an
275
- * embeddable split-pane without the navbar, use mountPlaygroundStudio().
274
+ * The navbar is opt-in (`showNavbar: true`) matching the editor mount, so
275
+ * embedding into a page that already has its own header never double-stacks a
276
+ * header. Pass `showNavbar: true` when FlowDrop owns the whole page and you want
277
+ * its chrome (logo, branding, settings modal). For a leaner embeddable
278
+ * split-pane, mountPlaygroundStudio() omits the navbar wrapper entirely.
276
279
  *
277
280
  * @example
278
281
  * ```typescript
279
282
  * const app = await mountPlaygroundApp(container, {
280
283
  * workflowId: 'wf-123',
281
284
  * endpointConfig: createEndpointConfig('/api/flowdrop'),
285
+ * showNavbar: true,
282
286
  * navbarTitle: 'My Workflow',
283
287
  * primaryActions: [
284
288
  * { label: 'Edit', href: '/workflows/wf-123/edit', icon: 'mdi:pencil-outline', variant: 'secondary' },
@@ -287,17 +287,21 @@ export async function mountPlaygroundStudio(container, options) {
287
287
  return buildMountedPlayground(svelteApp, workflowId, config, fd, ownsInstance, onSessionStatusChange);
288
288
  }
289
289
  /**
290
- * Mount the full-page PlaygroundApp (Navbar + PlaygroundStudio) into a container.
290
+ * Mount the full-page PlaygroundApp (PlaygroundStudio, optionally wrapped in the
291
+ * FlowDrop Navbar) into a container.
291
292
  *
292
- * Use this when you want the same chrome as the FlowDrop editor logo,
293
- * branding, and settings modal wrapped around the playground. For an
294
- * embeddable split-pane without the navbar, use mountPlaygroundStudio().
293
+ * The navbar is opt-in (`showNavbar: true`) matching the editor mount, so
294
+ * embedding into a page that already has its own header never double-stacks a
295
+ * header. Pass `showNavbar: true` when FlowDrop owns the whole page and you want
296
+ * its chrome (logo, branding, settings modal). For a leaner embeddable
297
+ * split-pane, mountPlaygroundStudio() omits the navbar wrapper entirely.
295
298
  *
296
299
  * @example
297
300
  * ```typescript
298
301
  * const app = await mountPlaygroundApp(container, {
299
302
  * workflowId: 'wf-123',
300
303
  * endpointConfig: createEndpointConfig('/api/flowdrop'),
304
+ * showNavbar: true,
301
305
  * navbarTitle: 'My Workflow',
302
306
  * primaryActions: [
303
307
  * { label: 'Edit', href: '/workflows/wf-123/edit', icon: 'mdi:pencil-outline', variant: 'secondary' },
@@ -307,7 +311,7 @@ export async function mountPlaygroundStudio(container, options) {
307
311
  * ```
308
312
  */
309
313
  export async function mountPlaygroundApp(container, options) {
310
- const { workflowId, workflow, mode = 'standalone', initialSessionId, endpointConfig, authProvider, config = {}, height, width, showNavbar = true, navbarTitle, primaryActions, showSettings = true, settingsCategories, showSettingsSyncButton, showSettingsResetButton, initialPipelineOpen, minChatWidth, initialPipelineWidth, settings: initialSettings, onClose, onSessionNavigate, onSessionStatusChange, instanceId } = options;
314
+ const { workflowId, workflow, mode = 'standalone', initialSessionId, endpointConfig, authProvider, config = {}, height, width, showNavbar = false, navbarTitle, primaryActions, showSettings = true, settingsCategories, showSettingsSyncButton, showSettingsResetButton, initialPipelineOpen, minChatWidth, initialPipelineWidth, settings: initialSettings, onClose, onSessionNavigate, onSessionStatusChange, instanceId } = options;
311
315
  if (!workflowId) {
312
316
  throw new Error('workflowId is required for mountPlaygroundApp()');
313
317
  }
@@ -0,0 +1,30 @@
1
+ import type { FlowDropSkin } from '../types/skin';
2
+ /**
3
+ * Drafter — a fresh, modern "drafting workspace" skin for the whole editor
4
+ * environment (see ref-image.png): a fresh white shell around a mint/aqua
5
+ * canvas with soft cyan/teal technical grid lines, crisp engineering geometry
6
+ * and clean teal-ink text — not a neutral admin UI and not an all-cyan shell.
7
+ *
8
+ * Unlike a canvas-only skin, Drafter themes the entire shell so it reads as one
9
+ * designed environment:
10
+ * - App chrome (navbar, sidebars, inspector, status bars, form fields) stays
11
+ * white/near-white for a clean fresh product feel.
12
+ * - The mint/aqua personality lives in the canvas, node glass, focus rings,
13
+ * selected states and small technical accents.
14
+ * - Disabled/read-only surfaces use quiet light grey so state remains obvious.
15
+ * - Borders are mostly neutral hairlines; strong/focus borders + node outlines
16
+ * are teal/cyan ink (--fd-ring / --fd-border-strong / --fd-node-border).
17
+ * - Focus rings are cyan (--fd-ring), not the default blue.
18
+ * - Nodes are frosted glass with a faint inner highlight; the minimap + zoom
19
+ * controls share the same vocabulary.
20
+ * - Note/instruction cards read as cool annotations (translucent tint + slate
21
+ * ink border), never as a filled "success" card.
22
+ * - Emerald/green is reserved for primary actions, selection and live edges
23
+ * (--fd-primary) — it is not used for every outline.
24
+ *
25
+ * Data-type port colors and category icon colors are left untouched so they keep
26
+ * their full color against the draft surface. The square grid is rendered by
27
+ * WorkflowEditor via config.canvas.grid = 'lines'; --fd-grid-pattern-color
28
+ * colors it. Ships light + dark variants.
29
+ */
30
+ export declare const drafterSkin: FlowDropSkin;
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Drafter — a fresh, modern "drafting workspace" skin for the whole editor
3
+ * environment (see ref-image.png): a fresh white shell around a mint/aqua
4
+ * canvas with soft cyan/teal technical grid lines, crisp engineering geometry
5
+ * and clean teal-ink text — not a neutral admin UI and not an all-cyan shell.
6
+ *
7
+ * Unlike a canvas-only skin, Drafter themes the entire shell so it reads as one
8
+ * designed environment:
9
+ * - App chrome (navbar, sidebars, inspector, status bars, form fields) stays
10
+ * white/near-white for a clean fresh product feel.
11
+ * - The mint/aqua personality lives in the canvas, node glass, focus rings,
12
+ * selected states and small technical accents.
13
+ * - Disabled/read-only surfaces use quiet light grey so state remains obvious.
14
+ * - Borders are mostly neutral hairlines; strong/focus borders + node outlines
15
+ * are teal/cyan ink (--fd-ring / --fd-border-strong / --fd-node-border).
16
+ * - Focus rings are cyan (--fd-ring), not the default blue.
17
+ * - Nodes are frosted glass with a faint inner highlight; the minimap + zoom
18
+ * controls share the same vocabulary.
19
+ * - Note/instruction cards read as cool annotations (translucent tint + slate
20
+ * ink border), never as a filled "success" card.
21
+ * - Emerald/green is reserved for primary actions, selection and live edges
22
+ * (--fd-primary) — it is not used for every outline.
23
+ *
24
+ * Data-type port colors and category icon colors are left untouched so they keep
25
+ * their full color against the draft surface. The square grid is rendered by
26
+ * WorkflowEditor via config.canvas.grid = 'lines'; --fd-grid-pattern-color
27
+ * colors it. Ships light + dark variants.
28
+ */
29
+ export const drafterSkin = {
30
+ tokens: {
31
+ /* ----- Shell surfaces: fresh white chrome, not all-cyan ----- */
32
+ background: '#ffffff',
33
+ foreground: '#10201c',
34
+ muted: '#f4f6f7',
35
+ 'muted-foreground': '#5f6f6b',
36
+ subtle: '#eef3f2',
37
+ card: '#ffffff',
38
+ 'card-foreground': '#10201c',
39
+ header: '#ffffff',
40
+ 'header-foreground': '#10201c',
41
+ 'header-gradient': 'linear-gradient(180deg, #ffffff 0%, #fbfefd 100%)',
42
+ 'surface-tint': 'rgba(20, 184, 166, 0.015)',
43
+ /* White sidebars/inspector with only a whisper of technical glass */
44
+ 'panel-bg': 'rgba(255, 255, 255, 0.94)',
45
+ 'panel-backdrop-filter': 'blur(10px) saturate(1.04)',
46
+ backdrop: 'rgba(255, 255, 255, 0.92)',
47
+ /* ----- Borders: neutral chrome; strong/focus = teal-cyan accent ----- */
48
+ border: '#e3e8e7',
49
+ 'border-muted': '#eef2f2',
50
+ 'border-strong': 'rgba(15, 118, 110, 0.42)',
51
+ ring: '#06b6d4',
52
+ /* ----- Canvas: fresh aqua-mint, soft cyan/teal square grid ----- */
53
+ 'canvas-bg': '#fbfefd',
54
+ 'grid-pattern-color': 'rgba(20, 184, 166, 0.08)',
55
+ /* ----- Nodes: frosted glass, faint inner highlight ----- */
56
+ 'node-bg': 'rgba(247, 252, 250, 0.7)',
57
+ 'node-header-bg': 'rgba(214, 245, 236, 0.6)',
58
+ 'node-backdrop-filter': 'blur(10px) saturate(1.15)',
59
+ 'node-radius': '2px',
60
+ 'node-shadow': 'inset 0 1px 0 0 rgba(255, 255, 255, 0.6)',
61
+ 'node-shadow-hover': 'inset 0 1px 0 0 rgba(255, 255, 255, 0.85)',
62
+ 'node-border': '#0f766e',
63
+ 'node-border-hover': '#0c5f59',
64
+ 'node-border-width': '1.25px',
65
+ /* Header divider matches the node outline ink (tracks light/dark node-border) */
66
+ 'node-header-divider-color': 'var(--fd-node-border)',
67
+ 'handle-border': '#ffffff',
68
+ /* Notes read as cool annotations, not filled success cards */
69
+ 'note-border': '#5b7891',
70
+ 'note-border-hover': '#48617a',
71
+ /* Translucent status tints so note/instruction cards stay light + glassy */
72
+ /* Status hues tuned to the cool palette: danger = rose (teal's warm
73
+ complement, not a generic red), warning = golden amber. Success/info stay
74
+ on the emerald/cyan family so they read as part of the theme. */
75
+ success: '#0d9488',
76
+ 'success-hover': '#0f766e',
77
+ info: '#0891b2',
78
+ 'info-hover': '#0e7490',
79
+ warning: '#d97706',
80
+ 'warning-hover': '#b45309',
81
+ error: '#e11d48',
82
+ 'error-hover': '#be123c',
83
+ 'info-muted': 'rgba(8, 145, 178, 0.1)',
84
+ 'success-muted': 'rgba(13, 148, 136, 0.1)',
85
+ 'warning-muted': 'rgba(217, 119, 6, 0.12)',
86
+ 'error-muted': 'rgba(225, 29, 72, 0.1)',
87
+ /* ----- Crisp drafting geometry + flat chrome (2–6px radius, no soft shadow) ----- */
88
+ 'radius-sm': '2px',
89
+ 'radius-md': '3px',
90
+ 'radius-lg': '4px',
91
+ 'radius-xl': '6px',
92
+ 'scrollbar-radius': '0',
93
+ 'shadow-sm': 'none',
94
+ 'shadow-md': 'none',
95
+ /* ----- Canvas overlays: light, instrument-like ----- */
96
+ 'minimap-bg': 'rgba(255, 255, 255, 0.72)',
97
+ 'minimap-mask-bg': 'rgba(15, 118, 110, 0.08)',
98
+ 'minimap-mask-stroke': 'rgba(15, 118, 110, 0.35)',
99
+ 'minimap-node-bg': 'rgba(15, 118, 110, 0.3)',
100
+ 'minimap-node-stroke': 'rgba(15, 118, 110, 0.45)',
101
+ 'controls-button-bg': 'rgba(255, 255, 255, 0.86)',
102
+ 'controls-button-bg-hover': 'rgba(204, 251, 241, 0.9)',
103
+ 'controls-button-color': '#0f766e',
104
+ 'controls-button-color-hover': '#0c5f59',
105
+ 'controls-button-border': 'rgba(15, 118, 110, 0.25)',
106
+ /* ----- Secondary = mint, accent = cyan, primary = the one allowed green ----- */
107
+ secondary: 'rgba(206, 230, 223, 0.55)',
108
+ 'secondary-hover': 'rgba(186, 219, 210, 0.7)',
109
+ 'secondary-foreground': '#0f3d36',
110
+ accent: '#06b6d4',
111
+ 'accent-hover': '#0891b2',
112
+ 'accent-foreground': '#ffffff',
113
+ 'accent-muted': 'rgba(6, 182, 212, 0.12)',
114
+ primary: '#10b981',
115
+ 'primary-hover': '#059669',
116
+ 'primary-foreground': '#ffffff',
117
+ 'primary-muted': 'rgba(16, 185, 129, 0.14)'
118
+ },
119
+ darkTokens: {
120
+ /* ----- Shell surfaces: deep teal-slate glass ----- */
121
+ background: '#0e2421',
122
+ foreground: '#d8f0ea',
123
+ muted: 'rgba(20, 60, 54, 0.6)',
124
+ 'muted-foreground': '#8fb3aa',
125
+ subtle: 'rgba(13, 47, 44, 0.7)',
126
+ card: 'rgba(18, 42, 38, 0.96)',
127
+ 'card-foreground': '#d8f0ea',
128
+ header: 'rgba(13, 40, 37, 0.7)',
129
+ 'header-foreground': '#d8f0ea',
130
+ 'header-gradient': 'linear-gradient(180deg, rgba(17, 42, 38, 0.9) 0%, rgba(12, 33, 30, 0.9) 100%)',
131
+ 'surface-tint': 'rgba(45, 212, 191, 0.04)',
132
+ 'panel-bg': 'rgba(14, 36, 33, 0.8)',
133
+ 'panel-backdrop-filter': 'blur(14px) saturate(1.2)',
134
+ backdrop: 'rgba(11, 31, 28, 0.8)',
135
+ border: 'rgba(45, 212, 191, 0.22)',
136
+ 'border-muted': 'rgba(45, 212, 191, 0.12)',
137
+ 'border-strong': 'rgba(45, 212, 191, 0.4)',
138
+ ring: '#22d3ee',
139
+ 'canvas-bg': '#0b1f1c',
140
+ 'grid-pattern-color': 'rgba(45, 212, 191, 0.16)',
141
+ 'node-bg': 'rgba(17, 38, 35, 0.62)',
142
+ 'node-header-bg': 'rgba(13, 47, 44, 0.6)',
143
+ 'node-backdrop-filter': 'blur(10px) saturate(1.2)',
144
+ 'node-shadow': 'inset 0 1px 0 0 rgba(255, 255, 255, 0.08)',
145
+ 'node-shadow-hover': 'inset 0 1px 0 0 rgba(255, 255, 255, 0.14)',
146
+ 'node-border': '#0d9488',
147
+ 'node-border-hover': '#2dd4bf',
148
+ 'handle-border': '#0b1f1c',
149
+ 'note-border': '#7d96b0',
150
+ 'note-border-hover': '#9fb4cb',
151
+ success: '#2dd4bf',
152
+ 'success-hover': '#5eead4',
153
+ info: '#22d3ee',
154
+ 'info-hover': '#67e8f9',
155
+ warning: '#fbbf24',
156
+ 'warning-hover': '#fcd34d',
157
+ error: '#fb7185',
158
+ 'error-hover': '#fda4af',
159
+ 'info-muted': 'rgba(34, 211, 238, 0.12)',
160
+ 'success-muted': 'rgba(45, 212, 191, 0.12)',
161
+ 'warning-muted': 'rgba(251, 191, 36, 0.14)',
162
+ 'error-muted': 'rgba(251, 113, 133, 0.12)',
163
+ 'minimap-bg': 'rgba(11, 31, 28, 0.7)',
164
+ 'minimap-mask-bg': 'rgba(45, 212, 191, 0.06)',
165
+ 'minimap-mask-stroke': 'rgba(45, 212, 191, 0.3)',
166
+ 'minimap-node-bg': 'rgba(45, 212, 191, 0.28)',
167
+ 'minimap-node-stroke': 'rgba(45, 212, 191, 0.45)',
168
+ 'controls-button-bg': 'rgba(17, 38, 35, 0.8)',
169
+ 'controls-button-bg-hover': 'rgba(13, 47, 44, 0.9)',
170
+ 'controls-button-color': '#2dd4bf',
171
+ 'controls-button-color-hover': '#5eead4',
172
+ 'controls-button-border': 'rgba(45, 212, 191, 0.3)',
173
+ secondary: 'rgba(13, 47, 44, 0.8)',
174
+ 'secondary-hover': 'rgba(20, 60, 54, 0.9)',
175
+ 'secondary-foreground': '#d8f0ea',
176
+ accent: '#22d3ee',
177
+ 'accent-hover': '#67e8f9',
178
+ 'accent-foreground': '#03291c',
179
+ 'accent-muted': 'rgba(34, 211, 238, 0.14)',
180
+ primary: '#34d399',
181
+ 'primary-hover': '#6ee7b7',
182
+ 'primary-foreground': '#03291c',
183
+ 'primary-muted': 'rgba(52, 211, 153, 0.16)'
184
+ }
185
+ };
@@ -1,6 +1,7 @@
1
1
  import type { FlowDropSkin, FlowDropSkinName } from '../types/skin';
2
2
  import { defaultSkin } from './default';
3
3
  import { slateSkin } from './slate';
4
+ import { drafterSkin } from './drafter';
4
5
  /**
5
6
  * Resolve a skin prop to a complete FlowDropSkin object.
6
7
  *
@@ -10,4 +11,4 @@ import { slateSkin } from './slate';
10
11
  * → minimal skin tokens + { primary: '#e11d48' }
11
12
  */
12
13
  export declare function resolveSkin(skin: FlowDropSkin | FlowDropSkinName | undefined): FlowDropSkin;
13
- export { defaultSkin, slateSkin };
14
+ export { defaultSkin, slateSkin, drafterSkin };
@@ -1,8 +1,10 @@
1
1
  import { defaultSkin } from './default';
2
2
  import { slateSkin } from './slate';
3
+ import { drafterSkin } from './drafter';
3
4
  const builtinSkins = {
4
5
  default: defaultSkin,
5
- slate: slateSkin
6
+ slate: slateSkin,
7
+ drafter: drafterSkin
6
8
  };
7
9
  /**
8
10
  * Resolve a skin prop to a complete FlowDropSkin object.
@@ -27,4 +29,4 @@ export function resolveSkin(skin) {
27
29
  }
28
30
  return skin;
29
31
  }
30
- export { defaultSkin, slateSkin };
32
+ export { defaultSkin, slateSkin, drafterSkin };
@@ -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 */
@@ -135,10 +167,7 @@
135
167
  border-color: var(--fd-border);
136
168
  }
137
169
 
138
- .flowdrop-btn:focus {
139
- outline: 2px solid var(--fd-ring);
140
- outline-offset: 2px;
141
- }
170
+ /* Focus ring is centralized (see top of file). */
142
171
 
143
172
  .flowdrop-btn--primary {
144
173
  background-color: var(--fd-primary);
@@ -211,10 +240,9 @@
211
240
  box-shadow var(--fd-transition-normal);
212
241
  }
213
242
 
243
+ /* Active-field hint only; the focus ring itself is centralized (top of file). */
214
244
  .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);
245
+ border-color: var(--fd-ring);
218
246
  }
219
247
 
220
248
  .flowdrop-input--sm {
@@ -1092,6 +1120,7 @@
1092
1120
  --fd-notes-node-width: 500px;
1093
1121
  --fd-notes-node-min-width: 250px;
1094
1122
  --fd-notes-node-max-width: 500px;
1123
+ --fd-notes-node-min-height: 200px;
1095
1124
  --fd-notes-node-backdrop-filter: blur(8px);
1096
1125
  }
1097
1126
 
@@ -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 */
@@ -307,6 +349,7 @@
307
349
  --fd-scrollbar-thumb: var(--_gray-4); /* @internal */
308
350
  --fd-scrollbar-thumb-hover: var(--_gray-5); /* @internal */
309
351
  --fd-scrollbar-track: var(--_gray-2); /* @internal */
352
+ --fd-scrollbar-radius: 4px; /* @public scrollbar thumb/track corner radius; 0 for square */
310
353
 
311
354
  /* ----- BACKDROP/OVERLAY ----- */
312
355
  --fd-backdrop: rgba(255, 255, 255, 0.8); /* @internal */
@@ -324,11 +367,17 @@
324
367
 
325
368
  /* ----- NODE LAYOUT (Dimensions and port alignment; multiples of 10 for grid) ----- */
326
369
  --fd-node-grid-step: 10; /* @internal — layout algorithm detail */
327
- --fd-node-default-width: 290px; /* @public */
370
+ --fd-node-default-width: 280px; /* @public */
328
371
  --fd-node-header-height: 60px; /* @public */
329
- --fd-node-header-title-height: 40px; /* @internal */
372
+ --fd-node-header-title-height: 40px; /* @internal — fits icon + up to 2 text lines */
330
373
  --fd-node-header-desc-line: 20px; /* @internal */
331
374
  --fd-node-header-gap: 10px; /* @internal */
375
+ /* Divider absorbed into header bottom padding so header height stays on the
376
+ 20px grid regardless of border thickness. */
377
+ --fd-node-header-divider-width: 1px; /* @public */
378
+ --fd-node-header-divider-color: var(
379
+ --fd-border-muted
380
+ ); /* @public — header bottom divider color */
332
381
  --fd-node-port-row-height: 20px; /* @internal */
333
382
  --fd-node-terminal-size: 80px; /* @public */
334
383
  --fd-node-square-size: 80px; /* @public */
@@ -395,6 +444,9 @@
395
444
  --fd-node-border: #4a4a52;
396
445
  --fd-node-border-hover: #5a5a62;
397
446
 
447
+ /* ----- CANVAS GRID (matches xyflow's dark dot-grid color) ----- */
448
+ --fd-grid-pattern-color: #777;
449
+
398
450
  /* ----- NODE COLORS (port type labels/badges - lighter for readability on dark surfaces) ----- */
399
451
  --fd-node-emerald: #34d399;
400
452
  --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
@@ -335,7 +335,7 @@ export async function mountFlowDropApp(container, options = {}) {
335
335
  * @returns Promise resolving to a MountedFlowDropApp instance
336
336
  */
337
337
  export async function mountWorkflowEditor(container, options = {}) {
338
- const { workflow, endpointConfig, portConfig, categories, authProvider, instanceId } = options;
338
+ const { workflow, endpointConfig, portConfig, categories, authProvider, instanceId, builtinEditors } = options;
339
339
  // Per-instance state container (see mountFlowDropApp)
340
340
  const { fd, isDefault } = acquireInstance(instanceId);
341
341
  // Create endpoint configuration
@@ -401,7 +401,8 @@ export async function mountWorkflowEditor(container, options = {}) {
401
401
  props: {
402
402
  instance: fd,
403
403
  endpointConfig: config,
404
- authProvider
404
+ authProvider,
405
+ builtinEditors
405
406
  }
406
407
  });
407
408
  // 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;
@@ -0,0 +1,15 @@
1
+ import { drafterSkin } from '../skins/drafter.js';
2
+ export const drafterTheme = {
3
+ name: 'drafter',
4
+ skin: drafterSkin,
5
+ config: {
6
+ sidebar: {
7
+ defaultOpen: true,
8
+ categoriesDefaultOpen: false
9
+ },
10
+ // Blueprint square line grid (any theme can opt into a grid variant here)
11
+ canvas: {
12
+ grid: 'lines'
13
+ }
14
+ }
15
+ };
@@ -1,6 +1,7 @@
1
1
  import type { FlowDropTheme, FlowDropThemeName } from '../types/theme.js';
2
2
  import { defaultTheme } from './default.js';
3
3
  import { minimalTheme } from './minimal.js';
4
+ import { drafterTheme } from './drafter.js';
4
5
  /**
5
6
  * Resolve a theme prop to a complete FlowDropTheme object.
6
7
  *
@@ -10,4 +11,4 @@ import { minimalTheme } from './minimal.js';
10
11
  * → minimal theme + { skin.tokens.primary: '#e11d48' }
11
12
  */
12
13
  export declare function resolveTheme(theme: FlowDropTheme | FlowDropThemeName | undefined): FlowDropTheme;
13
- export { defaultTheme, minimalTheme };
14
+ export { defaultTheme, minimalTheme, drafterTheme };
@@ -1,8 +1,10 @@
1
1
  import { defaultTheme } from './default.js';
2
2
  import { minimalTheme } from './minimal.js';
3
+ import { drafterTheme } from './drafter.js';
3
4
  const builtinThemes = {
4
5
  default: defaultTheme,
5
- minimal: minimalTheme
6
+ minimal: minimalTheme,
7
+ drafter: drafterTheme
6
8
  };
7
9
  /**
8
10
  * Resolve a theme prop to a complete FlowDropTheme object.
@@ -35,10 +37,14 @@ export function resolveTheme(theme) {
35
37
  sidebar: {
36
38
  ...base.config?.sidebar,
37
39
  ...theme.config?.sidebar
40
+ },
41
+ canvas: {
42
+ ...base.config?.canvas,
43
+ ...theme.config?.canvas
38
44
  }
39
45
  }
40
46
  };
41
47
  }
42
48
  return theme;
43
49
  }
44
- export { defaultTheme, minimalTheme };
50
+ export { defaultTheme, minimalTheme, drafterTheme };