@flowdrop/flowdrop 1.1.0 → 1.2.0

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.
@@ -137,7 +137,7 @@
137
137
  resolveTheme(themeProp ?? getUiSettings().theme),
138
138
  );
139
139
  let themeConfig = $derived(resolvedTheme.config);
140
-
140
+
141
141
  // Inject skin tokens as a style tag so light/dark palettes can coexist.
142
142
  // tokens → :root { ... } (light mode / base)
143
143
  // darkTokens → [data-theme='dark'] { ... } (dark mode override)
@@ -180,6 +180,7 @@
180
180
  });
181
181
 
182
182
  let nodes = $state<NodeMetadata[]>([]);
183
+ let nodeTypesLoading = $state<boolean>(true);
183
184
  // Remove workflow prop - use global store directly
184
185
  // let workflow = $derived($workflowStore || initialWorkflow);
185
186
  let error = $state<string | null>(null);
@@ -259,6 +260,7 @@
259
260
  (n) => !existingIds.has(n.id),
260
261
  );
261
262
  nodes = [...propNodes, ...uniqueFormatNodes];
263
+ nodeTypesLoading = false;
262
264
  return;
263
265
  }
264
266
 
@@ -285,6 +287,7 @@
285
287
  );
286
288
  nodes = [...fetchedNodes, ...uniqueFormatNodes];
287
289
  error = null;
290
+ nodeTypesLoading = false;
288
291
 
289
292
  // Dismiss loading toast
290
293
  if (loadingToast) {
@@ -307,6 +310,7 @@
307
310
  if (suppressToast) {
308
311
  // Parent handled the error, keep nodes empty
309
312
  nodes = [];
313
+ nodeTypesLoading = false;
310
314
  return;
311
315
  }
312
316
  }
@@ -319,6 +323,7 @@
319
323
 
320
324
  // Set empty nodes array instead of fallback data
321
325
  nodes = [];
326
+ nodeTypesLoading = false;
322
327
  }
323
328
  }
324
329
 
@@ -765,6 +770,7 @@
765
770
  {#snippet leftSidebar()}
766
771
  <NodeSidebar
767
772
  {nodes}
773
+ loading={nodeTypesLoading}
768
774
  activeFormat={getWorkflowFormat()}
769
775
  categoriesDefaultOpen={themeConfig?.sidebar?.categoriesDefaultOpen ??
770
776
  false}
@@ -960,6 +966,9 @@
960
966
  <div
961
967
  class="flowdrop-editor-main"
962
968
  class:pipeline-view={!!pipelineId}
969
+ style="--fd-canvas-left-offset: {!disableSidebar
970
+ ? leftSidebarWidth + 'px'
971
+ : '0px'}"
963
972
  onclick={handleCanvasClick}
964
973
  onkeydown={(e) => e.key === "Escape" && closeConfigSidebar()}
965
974
  role="region"
@@ -35,6 +35,12 @@
35
35
  pointer-events: none;
36
36
  }
37
37
 
38
+ @media (max-width: 768px) {
39
+ .flowdrop-canvas-banner {
40
+ left: var(--fd-canvas-left-offset, 0px);
41
+ }
42
+ }
43
+
38
44
  .flowdrop-canvas-banner__icon {
39
45
  font-size: 3.75rem;
40
46
  margin-bottom: 1rem;
@@ -23,6 +23,8 @@
23
23
 
24
24
  interface Props {
25
25
  nodes: NodeMetadata[];
26
+ /** Whether node types are still being fetched. Default: false */
27
+ loading?: boolean;
26
28
  selectedCategory?: NodeCategory;
27
29
  activeFormat?: WorkflowFormat;
28
30
  /** Whether category <details> accordions start open (card mode). Default: false */
@@ -268,14 +270,17 @@
268
270
  <!-- No node types available -->
269
271
  <div class="flowdrop-hero">
270
272
  <div class="flowdrop-hero__content">
271
- <div class="flowdrop-hero__icon">📦</div>
272
- <h3 class="flowdrop-hero__title">No node types available</h3>
273
- <p class="flowdrop-hero__description">
274
- Node type definitions will appear here
275
- </p>
276
- <div class="flowdrop-mb--4">
277
- <LoadingSpinner size="md" text="Loading from server..." />
278
- </div>
273
+ {#if props.loading}
274
+ <div class="flowdrop-mb--4">
275
+ <LoadingSpinner size="md" text="Loading from server..." />
276
+ </div>
277
+ {:else}
278
+ <div class="flowdrop-hero__icon">📦</div>
279
+ <h3 class="flowdrop-hero__title">No node types available</h3>
280
+ <p class="flowdrop-hero__description">
281
+ Node type definitions will appear here
282
+ </p>
283
+ {/if}
279
284
  </div>
280
285
  </div>
281
286
  {:else if searchInput.trim()}
@@ -1,6 +1,8 @@
1
1
  import type { NodeMetadata, NodeCategory, WorkflowFormat } from "../types/index.js";
2
2
  interface Props {
3
3
  nodes: NodeMetadata[];
4
+ /** Whether node types are still being fetched. Default: false */
5
+ loading?: boolean;
4
6
  selectedCategory?: NodeCategory;
5
7
  activeFormat?: WorkflowFormat;
6
8
  /** Whether category <details> accordions start open (card mode). Default: false */
@@ -38,7 +38,13 @@
38
38
  "$ref": "#/$defs/WorkflowMetadata"
39
39
  }
40
40
  },
41
- "required": ["id", "name", "nodes", "edges", "metadata"],
41
+ "required": [
42
+ "id",
43
+ "name",
44
+ "nodes",
45
+ "edges",
46
+ "metadata"
47
+ ],
42
48
  "$defs": {
43
49
  "AutocompleteConfig": {
44
50
  "type": "object",
@@ -89,7 +95,9 @@
89
95
  "description": "Whether to allow multiple selections.\nWhen true, users can select multiple values displayed as tags.\n"
90
96
  }
91
97
  },
92
- "required": ["url"]
98
+ "required": [
99
+ "url"
100
+ ]
93
101
  },
94
102
  "Branch": {
95
103
  "type": "object",
@@ -117,7 +125,10 @@
117
125
  "description": "Whether this is the default/fallback branch"
118
126
  }
119
127
  },
120
- "required": ["name", "label"]
128
+ "required": [
129
+ "name",
130
+ "label"
131
+ ]
121
132
  },
122
133
  "ConfigProperty": {
123
134
  "type": "object",
@@ -125,7 +136,14 @@
125
136
  "properties": {
126
137
  "type": {
127
138
  "type": "string",
128
- "enum": ["string", "number", "boolean", "array", "object", "integer"],
139
+ "enum": [
140
+ "string",
141
+ "number",
142
+ "boolean",
143
+ "array",
144
+ "object",
145
+ "integer"
146
+ ],
129
147
  "description": "JSON Schema type"
130
148
  },
131
149
  "title": {
@@ -251,14 +269,18 @@
251
269
  ]
252
270
  }
253
271
  },
254
- "required": ["type"]
272
+ "required": [
273
+ "type"
274
+ ]
255
275
  },
256
276
  "ConfigSchema": {
257
277
  "type": "object",
258
278
  "properties": {
259
279
  "type": {
260
280
  "type": "string",
261
- "enum": ["object"]
281
+ "enum": [
282
+ "object"
283
+ ]
262
284
  },
263
285
  "properties": {
264
286
  "type": "object",
@@ -279,7 +301,10 @@
279
301
  "default": false
280
302
  }
281
303
  },
282
- "required": ["type", "properties"]
304
+ "required": [
305
+ "type",
306
+ "properties"
307
+ ]
283
308
  },
284
309
  "DynamicPort": {
285
310
  "type": "object",
@@ -313,7 +338,11 @@
313
338
  "description": "Whether this port is required for execution"
314
339
  }
315
340
  },
316
- "required": ["name", "label", "dataType"]
341
+ "required": [
342
+ "name",
343
+ "label",
344
+ "dataType"
345
+ ]
317
346
  },
318
347
  "NodeCategory": {
319
348
  "type": "string",
@@ -404,7 +433,11 @@
404
433
  "description": "Whether the node is currently being executed"
405
434
  }
406
435
  },
407
- "required": ["status", "executionCount", "isExecuting"]
436
+ "required": [
437
+ "status",
438
+ "executionCount",
439
+ "isExecuting"
440
+ ]
408
441
  },
409
442
  "NodeExecutionStatus": {
410
443
  "type": "string",
@@ -548,7 +581,11 @@
548
581
  },
549
582
  "type": {
550
583
  "type": "string",
551
- "enum": ["input", "output", "metadata"],
584
+ "enum": [
585
+ "input",
586
+ "output",
587
+ "metadata"
588
+ ],
552
589
  "description": "Port direction (input receives data, output sends data)"
553
590
  },
554
591
  "dataType": {
@@ -577,7 +614,12 @@
577
614
  ]
578
615
  }
579
616
  },
580
- "required": ["id", "name", "type", "dataType"]
617
+ "required": [
618
+ "id",
619
+ "name",
620
+ "type",
621
+ "dataType"
622
+ ]
581
623
  },
582
624
  "NodeType": {
583
625
  "type": "string",
@@ -635,7 +677,9 @@
635
677
  "description": "Optional description for this option"
636
678
  }
637
679
  },
638
- "required": ["const"]
680
+ "required": [
681
+ "const"
682
+ ]
639
683
  },
640
684
  "PortDataSchema": {
641
685
  "type": "object",
@@ -643,7 +687,14 @@
643
687
  "properties": {
644
688
  "type": {
645
689
  "type": "string",
646
- "enum": ["object", "array", "string", "number", "integer", "boolean"],
690
+ "enum": [
691
+ "object",
692
+ "array",
693
+ "string",
694
+ "number",
695
+ "integer",
696
+ "boolean"
697
+ ],
647
698
  "description": "The JSON Schema type. Use `object` for nested properties,\n`array` for lists with `items` schema.\n"
648
699
  },
649
700
  "title": {
@@ -692,7 +743,10 @@
692
743
  "description": "Y coordinate"
693
744
  }
694
745
  },
695
- "required": ["x", "y"]
746
+ "required": [
747
+ "x",
748
+ "y"
749
+ ]
696
750
  },
697
751
  "TemplateVariable": {
698
752
  "type": "object",
@@ -750,7 +804,10 @@
750
804
  "description": "Source node ID"
751
805
  }
752
806
  },
753
- "required": ["name", "type"]
807
+ "required": [
808
+ "name",
809
+ "type"
810
+ ]
754
811
  },
755
812
  "TemplateVariablesConfig": {
756
813
  "type": "object",
@@ -797,7 +854,9 @@
797
854
  "description": "Map of available variables keyed by variable name"
798
855
  }
799
856
  },
800
- "required": ["variables"]
857
+ "required": [
858
+ "variables"
859
+ ]
801
860
  },
802
861
  "WorkflowEdge": {
803
862
  "type": "object",
@@ -828,7 +887,12 @@
828
887
  "type": {
829
888
  "type": "string",
830
889
  "description": "Connection line type",
831
- "enum": ["default", "straight", "step", "smoothstep"]
890
+ "enum": [
891
+ "default",
892
+ "straight",
893
+ "step",
894
+ "smoothstep"
895
+ ]
832
896
  },
833
897
  "selectable": {
834
898
  "type": "boolean",
@@ -855,7 +919,11 @@
855
919
  "properties": {
856
920
  "edgeType": {
857
921
  "type": "string",
858
- "enum": ["trigger", "tool", "data"],
922
+ "enum": [
923
+ "trigger",
924
+ "tool",
925
+ "data"
926
+ ],
859
927
  "description": "Edge type for visual styling"
860
928
  },
861
929
  "sourcePortDataType": {
@@ -879,7 +947,11 @@
879
947
  }
880
948
  }
881
949
  },
882
- "required": ["id", "source", "target"]
950
+ "required": [
951
+ "id",
952
+ "source",
953
+ "target"
954
+ ]
883
955
  },
884
956
  "WorkflowMetadata": {
885
957
  "type": "object",
@@ -923,7 +995,11 @@
923
995
  "default": "flowdrop"
924
996
  }
925
997
  },
926
- "required": ["version", "createdAt", "updatedAt"]
998
+ "required": [
999
+ "version",
1000
+ "createdAt",
1001
+ "updatedAt"
1002
+ ]
927
1003
  },
928
1004
  "WorkflowNode": {
929
1005
  "type": "object",
@@ -984,10 +1060,19 @@
984
1060
  ]
985
1061
  }
986
1062
  },
987
- "required": ["label", "config", "metadata"]
1063
+ "required": [
1064
+ "label",
1065
+ "config",
1066
+ "metadata"
1067
+ ]
988
1068
  }
989
1069
  },
990
- "required": ["id", "type", "position", "data"]
1070
+ "required": [
1071
+ "id",
1072
+ "type",
1073
+ "position",
1074
+ "data"
1075
+ ]
991
1076
  }
992
1077
  }
993
1078
  }
@@ -10,6 +10,7 @@ import type { Workflow, NodeMetadata, PortConfig, CategoryDefinition } from "./t
10
10
  import type { EndpointConfig } from "./config/endpoints.js";
11
11
  import type { AuthProvider } from "./types/auth.js";
12
12
  import type { FlowDropEventHandlers, FlowDropFeatures } from "./types/events.js";
13
+ import type { FlowDropTheme, FlowDropThemeName } from "./types/theme.js";
13
14
  import type { WorkflowFormatAdapter } from "./registry/workflowFormatRegistry.js";
14
15
  import "./registry/builtinFormats.js";
15
16
  import type { PartialSettings } from "./types/settings.js";
@@ -71,6 +72,8 @@ export interface FlowDropMountOptions {
71
72
  draftStorageKey?: string;
72
73
  /** Custom workflow format adapters to register */
73
74
  formatAdapters?: WorkflowFormatAdapter[];
75
+ /** Visual theme — named built-in ('default' | 'minimal') or custom theme object */
76
+ theme?: FlowDropTheme | FlowDropThemeName;
74
77
  }
75
78
  /**
76
79
  * Return type for mounted FlowDrop app
@@ -47,7 +47,7 @@ import { globalSaveWorkflow, globalExportWorkflow, } from "./services/globalSave
47
47
  * ```
48
48
  */
49
49
  export async function mountFlowDropApp(container, options = {}) {
50
- const { workflow, nodes, endpointConfig, portConfig, categories, height = "100vh", width = "100%", showNavbar = false, disableSidebar, lockWorkflow, readOnly, nodeStatuses, pipelineId, navbarTitle, navbarActions, showSettings, authProvider, eventHandlers, features: userFeatures, settings: initialSettings, draftStorageKey: customDraftKey, formatAdapters, } = options;
50
+ const { workflow, nodes, endpointConfig, portConfig, categories, height = "100vh", width = "100%", showNavbar = false, disableSidebar, lockWorkflow, readOnly, nodeStatuses, pipelineId, navbarTitle, navbarActions, showSettings, authProvider, eventHandlers, features: userFeatures, settings: initialSettings, draftStorageKey: customDraftKey, formatAdapters, theme, } = options;
51
51
  // Register custom format adapters before mounting
52
52
  if (formatAdapters) {
53
53
  for (const adapter of formatAdapters) {
@@ -136,6 +136,7 @@ export async function mountFlowDropApp(container, options = {}) {
136
136
  authProvider,
137
137
  eventHandlers,
138
138
  features,
139
+ theme,
139
140
  },
140
141
  });
141
142
  // Set up draft auto-save manager
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "A drop-in visual workflow editor for any web application. You own the backend. You own the data. You own the orchestration.",
4
4
  "license": "MIT",
5
5
  "private": false,
6
- "version": "1.1.0",
6
+ "version": "1.2.0",
7
7
  "author": "Shibin Das (D34dMan)",
8
8
  "bugs": {
9
9
  "url": "https://github.com/flowdrop-io/flowdrop/issues"