@d34dman/flowdrop 0.0.28 → 0.0.30

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.
@@ -25,25 +25,34 @@
25
25
  let categories = $derived(getCategories());
26
26
 
27
27
  /**
28
- * Get all unique categories from node types
28
+ * Get all unique categories from node types, preserving API order
29
+ * Categories appear in the order their first node appears in the API response
29
30
  */
30
31
  function getCategories(): NodeCategory[] {
31
32
  const nodes = props.nodes || [];
32
33
  if (nodes.length === 0) return [];
33
- const categories = new SvelteSet<NodeCategory>();
34
- nodes.forEach((node) => categories.add(node.category));
35
- return Array.from(categories).sort();
34
+ // Use a Set to track uniqueness while preserving insertion order
35
+ const seen = new SvelteSet<NodeCategory>();
36
+ const orderedCategories: NodeCategory[] = [];
37
+ for (const node of nodes) {
38
+ if (!seen.has(node.category)) {
39
+ seen.add(node.category);
40
+ orderedCategories.push(node.category);
41
+ }
42
+ }
43
+ return orderedCategories;
36
44
  }
37
45
 
38
46
  /**
39
47
  * Filter node types based on search query and selected category
48
+ * Preserves the API order - no client-side sorting applied
40
49
  */
41
50
  function getFilteredNodes(): NodeMetadata[] {
42
51
  // Use actual node types from props
43
52
  let filtered = props.nodes || [];
44
53
 
45
54
  // Filter by category
46
- if (selectedCategory !== 'all') {
55
+ if (selectedCategory !== "all") {
47
56
  filtered = filtered.filter((node) => node.category === selectedCategory);
48
57
  }
49
58
 
@@ -58,8 +67,8 @@
58
67
  );
59
68
  }
60
69
 
61
- // Create a new array and sort it to avoid mutating the original
62
- return [...filtered].sort((a, b) => a.name.localeCompare(b.name));
70
+ // Return filtered results preserving API order
71
+ return filtered;
63
72
  }
64
73
 
65
74
  /**
@@ -149,12 +158,11 @@
149
158
 
150
159
  /**
151
160
  * Get node types for category
161
+ * Preserves the API order - no client-side sorting applied
152
162
  */
153
163
  function getNodesForCategory(category: NodeCategory): NodeMetadata[] {
154
164
  const nodes = props.nodes || [];
155
- return [...nodes]
156
- .filter((node) => node.category === category)
157
- .sort((a, b) => a.name.localeCompare(b.name));
165
+ return nodes.filter((node) => node.category === category);
158
166
  }
159
167
 
160
168
  /**
@@ -37,6 +37,7 @@
37
37
  } from '../helpers/workflowEditorHelper.js';
38
38
  import type { NodeExecutionInfo } from '../types/index.js';
39
39
  import { areNodeArraysEqual, areEdgeArraysEqual, throttle } from '../utils/performanceUtils.js';
40
+ import { Toaster } from 'svelte-5-french-toast';
40
41
 
41
42
  interface Props {
42
43
  nodes?: NodeMetadata[];
@@ -457,6 +458,9 @@
457
458
  </div>
458
459
  </SvelteFlowProvider>
459
460
 
461
+ <!-- Toast notifications container -->
462
+ <Toaster position="bottom-center" />
463
+
460
464
  <style>
461
465
  .flowdrop-workflow-editor {
462
466
  display: flex;
@@ -0,0 +1,422 @@
1
+ <!--
2
+ FormFieldLight Component
3
+ Factory component that renders the appropriate field based on schema type.
4
+
5
+ This is the "light" version that uses the field registry for heavy components
6
+ (code editor, markdown editor, template editor) instead of static imports.
7
+
8
+ Heavy components are only loaded if registered via:
9
+ - `registerCodeEditorField()` from "@d34dman/flowdrop/form/code"
10
+ - `registerMarkdownEditorField()` from "@d34dman/flowdrop/form/markdown"
11
+
12
+ Features:
13
+ - Automatically selects the correct field component based on schema
14
+ - Wraps fields with FormFieldWrapper for consistent layout
15
+ - Supports all basic field types (string, number, boolean, select, checkbox group, range)
16
+ - Heavy editors (code, markdown, template) require explicit registration
17
+ - Shows helpful fallback when heavy editors aren't registered
18
+
19
+ Type Resolution Order:
20
+ 1. Check field registry for custom/heavy components (highest priority)
21
+ 2. format: 'hidden' -> skip rendering (return nothing)
22
+ 3. enum with multiple: true -> FormCheckboxGroup
23
+ 4. enum -> FormSelect
24
+ 5. format: 'multiline' -> FormTextarea
25
+ 6. format: 'range' (number/integer) -> FormRangeField
26
+ 7. type: 'string' -> FormTextField
27
+ 8. type: 'number' or 'integer' -> FormNumberField
28
+ 9. type: 'boolean' -> FormToggle
29
+ 10. type: 'select' or has options -> FormSelect
30
+ 11. type: 'array' -> FormArray
31
+ 12. fallback -> FormTextField
32
+ -->
33
+
34
+ <script lang="ts">
35
+ import FormFieldWrapper from "./FormFieldWrapper.svelte";
36
+ import FormTextField from "./FormTextField.svelte";
37
+ import FormTextarea from "./FormTextarea.svelte";
38
+ import FormNumberField from "./FormNumberField.svelte";
39
+ import FormRangeField from "./FormRangeField.svelte";
40
+ import FormToggle from "./FormToggle.svelte";
41
+ import FormSelect from "./FormSelect.svelte";
42
+ import FormCheckboxGroup from "./FormCheckboxGroup.svelte";
43
+ import FormArray from "./FormArray.svelte";
44
+ import { resolveFieldComponent } from "../../form/fieldRegistry.js";
45
+ import type { FieldSchema, FieldOption } from "./types.js";
46
+
47
+ interface Props {
48
+ /** Unique key/id for the field */
49
+ fieldKey: string;
50
+ /** Field schema definition */
51
+ schema: FieldSchema;
52
+ /** Current field value */
53
+ value: unknown;
54
+ /** Whether the field is required */
55
+ required?: boolean;
56
+ /** Animation delay index for staggered animations */
57
+ animationIndex?: number;
58
+ /** Callback when the field value changes */
59
+ onChange: (value: unknown) => void;
60
+ }
61
+
62
+ let { fieldKey, schema, value, required = false, animationIndex = 0, onChange }: Props = $props();
63
+
64
+ /**
65
+ * Computed description ID for ARIA association
66
+ */
67
+ const descriptionId = $derived(
68
+ schema.description && schema.title ? `${fieldKey}-description` : undefined
69
+ );
70
+
71
+ /**
72
+ * Animation delay based on index
73
+ */
74
+ const animationDelay = $derived(animationIndex * 30);
75
+
76
+ /**
77
+ * Field label - prefer title, fall back to description, then key
78
+ */
79
+ const fieldLabel = $derived(String(schema.title ?? schema.description ?? fieldKey));
80
+
81
+ /**
82
+ * Check if there's a registered custom component for this schema
83
+ */
84
+ const registeredComponent = $derived(resolveFieldComponent(schema));
85
+
86
+ /**
87
+ * Determine the field type to render (for non-registered components)
88
+ */
89
+ const fieldType = $derived.by(() => {
90
+ // If a custom component is registered, use it
91
+ if (registeredComponent) {
92
+ return "registered";
93
+ }
94
+
95
+ // Hidden fields should not be rendered
96
+ if (schema.format === "hidden") {
97
+ return "hidden";
98
+ }
99
+
100
+ // Check for heavy editor formats that need registration
101
+ if (schema.format === "json" || schema.format === "code") {
102
+ return "code-editor-fallback";
103
+ }
104
+
105
+ if (schema.format === "markdown") {
106
+ return "markdown-editor-fallback";
107
+ }
108
+
109
+ if (schema.format === "template") {
110
+ return "template-editor-fallback";
111
+ }
112
+
113
+ // Object type without specific format would use code editor
114
+ if (schema.type === "object" && !schema.format) {
115
+ return "code-editor-fallback";
116
+ }
117
+
118
+ // Enum with multiple selection -> checkbox group
119
+ if (schema.enum && schema.multiple) {
120
+ return "checkbox-group";
121
+ }
122
+
123
+ // Enum with single selection -> select
124
+ if (schema.enum) {
125
+ return "select-enum";
126
+ }
127
+
128
+ // Multiline string -> textarea
129
+ if (schema.type === "string" && schema.format === "multiline") {
130
+ return "textarea";
131
+ }
132
+
133
+ // Range slider for number/integer with format: "range"
134
+ if ((schema.type === "number" || schema.type === "integer") && schema.format === "range") {
135
+ return "range";
136
+ }
137
+
138
+ // String -> text field
139
+ if (schema.type === "string") {
140
+ return "text";
141
+ }
142
+
143
+ // Number or integer -> number field
144
+ if (schema.type === "number" || schema.type === "integer") {
145
+ return "number";
146
+ }
147
+
148
+ // Boolean -> toggle
149
+ if (schema.type === "boolean") {
150
+ return "toggle";
151
+ }
152
+
153
+ // Select type or has options -> select
154
+ if (schema.type === "select" || schema.options) {
155
+ return "select-options";
156
+ }
157
+
158
+ // Array type
159
+ if (schema.type === "array") {
160
+ return "array";
161
+ }
162
+
163
+ // Fallback to text
164
+ return "text";
165
+ });
166
+
167
+ /**
168
+ * Get enum options as string array for select/checkbox components
169
+ */
170
+ const enumOptions = $derived.by((): string[] => {
171
+ if (!schema.enum) return [];
172
+ return schema.enum.map((opt) => String(opt));
173
+ });
174
+
175
+ /**
176
+ * Get select options for select-options type
177
+ */
178
+ const selectOptions = $derived.by((): FieldOption[] => {
179
+ if (!schema.options) return [];
180
+ return schema.options as FieldOption[];
181
+ });
182
+
183
+ /**
184
+ * Get current value as the appropriate type
185
+ */
186
+ const stringValue = $derived(String(value ?? ""));
187
+ const numberValue = $derived(value as number | string);
188
+ const booleanValue = $derived(Boolean(value ?? schema.default ?? false));
189
+ const arrayValue = $derived.by((): string[] => {
190
+ if (Array.isArray(value)) {
191
+ return value.map((v) => String(v));
192
+ }
193
+ return [];
194
+ });
195
+ const arrayItems = $derived.by((): unknown[] => {
196
+ if (Array.isArray(value)) {
197
+ return value;
198
+ }
199
+ return [];
200
+ });
201
+
202
+ /**
203
+ * Get helpful message for missing editor registration
204
+ */
205
+ function getEditorHint(editorType: string): string {
206
+ switch (editorType) {
207
+ case "code-editor-fallback":
208
+ return "Code editor requires: import { registerCodeEditorField } from '@d34dman/flowdrop/form/code'; registerCodeEditorField();";
209
+ case "markdown-editor-fallback":
210
+ return "Markdown editor requires: import { registerMarkdownEditorField } from '@d34dman/flowdrop/form/markdown'; registerMarkdownEditorField();";
211
+ case "template-editor-fallback":
212
+ return "Template editor requires: import { registerTemplateEditorField } from '@d34dman/flowdrop/form/code'; registerTemplateEditorField();";
213
+ default:
214
+ return "This field type requires additional registration.";
215
+ }
216
+ }
217
+ </script>
218
+
219
+ {#if fieldType !== "hidden"}
220
+ <FormFieldWrapper
221
+ id={fieldKey}
222
+ label={fieldLabel}
223
+ {required}
224
+ description={schema.title ? schema.description : undefined}
225
+ {animationDelay}
226
+ >
227
+ {#if fieldType === "registered" && registeredComponent}
228
+ <!-- Render registered custom component -->
229
+ <registeredComponent.component
230
+ id={fieldKey}
231
+ {value}
232
+ placeholder={schema.placeholder ?? ""}
233
+ {required}
234
+ ariaDescribedBy={descriptionId}
235
+ height={schema.height as string | undefined}
236
+ darkTheme={schema.darkTheme as boolean | undefined}
237
+ autoFormat={schema.autoFormat as boolean | undefined}
238
+ showToolbar={schema.showToolbar as boolean | undefined}
239
+ showStatusBar={schema.showStatusBar as boolean | undefined}
240
+ spellChecker={schema.spellChecker as boolean | undefined}
241
+ variableHints={schema.variableHints as string[] | undefined}
242
+ placeholderExample={schema.placeholderExample as string | undefined}
243
+ onChange={(val: unknown) => onChange(val)}
244
+ />
245
+ {:else if fieldType === "checkbox-group"}
246
+ <FormCheckboxGroup
247
+ id={fieldKey}
248
+ value={arrayValue}
249
+ options={enumOptions}
250
+ ariaDescribedBy={descriptionId}
251
+ onChange={(val) => onChange(val)}
252
+ />
253
+ {:else if fieldType === "select-enum"}
254
+ <FormSelect
255
+ id={fieldKey}
256
+ value={stringValue}
257
+ options={enumOptions}
258
+ {required}
259
+ ariaDescribedBy={descriptionId}
260
+ onChange={(val) => onChange(val)}
261
+ />
262
+ {:else if fieldType === "textarea"}
263
+ <FormTextarea
264
+ id={fieldKey}
265
+ value={stringValue}
266
+ placeholder={schema.placeholder ?? ""}
267
+ {required}
268
+ ariaDescribedBy={descriptionId}
269
+ onChange={(val) => onChange(val)}
270
+ />
271
+ {:else if fieldType === "text"}
272
+ <FormTextField
273
+ id={fieldKey}
274
+ value={stringValue}
275
+ placeholder={schema.placeholder ?? ""}
276
+ {required}
277
+ ariaDescribedBy={descriptionId}
278
+ onChange={(val) => onChange(val)}
279
+ />
280
+ {:else if fieldType === "number"}
281
+ <FormNumberField
282
+ id={fieldKey}
283
+ value={numberValue}
284
+ placeholder={schema.placeholder ?? ""}
285
+ min={schema.minimum}
286
+ max={schema.maximum}
287
+ {required}
288
+ ariaDescribedBy={descriptionId}
289
+ onChange={(val) => onChange(val)}
290
+ />
291
+ {:else if fieldType === "range"}
292
+ <FormRangeField
293
+ id={fieldKey}
294
+ value={numberValue}
295
+ min={schema.minimum}
296
+ max={schema.maximum}
297
+ step={schema.step}
298
+ {required}
299
+ ariaDescribedBy={descriptionId}
300
+ onChange={(val) => onChange(val)}
301
+ />
302
+ {:else if fieldType === "toggle"}
303
+ <FormToggle
304
+ id={fieldKey}
305
+ value={booleanValue}
306
+ ariaDescribedBy={descriptionId}
307
+ onChange={(val) => onChange(val)}
308
+ />
309
+ {:else if fieldType === "select-options"}
310
+ <FormSelect
311
+ id={fieldKey}
312
+ value={stringValue}
313
+ options={selectOptions}
314
+ {required}
315
+ ariaDescribedBy={descriptionId}
316
+ onChange={(val) => onChange(val)}
317
+ />
318
+ {:else if fieldType === "array" && schema.items}
319
+ <FormArray
320
+ id={fieldKey}
321
+ value={arrayItems}
322
+ itemSchema={schema.items}
323
+ minItems={schema.minItems}
324
+ maxItems={schema.maxItems}
325
+ addLabel={`Add ${schema.items.title ?? "Item"}`}
326
+ onChange={(val) => onChange(val)}
327
+ />
328
+ {:else if fieldType.endsWith("-fallback")}
329
+ <!-- Fallback for unregistered heavy editors -->
330
+ <div class="form-field-fallback">
331
+ <div class="form-field-fallback__message">
332
+ <svg
333
+ xmlns="http://www.w3.org/2000/svg"
334
+ viewBox="0 0 20 20"
335
+ fill="currentColor"
336
+ class="form-field-fallback__icon"
337
+ >
338
+ <path
339
+ fill-rule="evenodd"
340
+ d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a.75.75 0 000 1.5h.253a.25.25 0 01.244.304l-.459 2.066A1.75 1.75 0 0010.747 15H11a.75.75 0 000-1.5h-.253a.25.25 0 01-.244-.304l.459-2.066A1.75 1.75 0 009.253 9H9z"
341
+ clip-rule="evenodd"
342
+ />
343
+ </svg>
344
+ <span>Editor component not registered</span>
345
+ </div>
346
+ <p class="form-field-fallback__hint">
347
+ {getEditorHint(fieldType)}
348
+ </p>
349
+ <!-- Provide a basic textarea fallback for editing -->
350
+ <FormTextarea
351
+ id={fieldKey}
352
+ value={typeof value === "string" ? value : JSON.stringify(value, null, 2)}
353
+ placeholder={schema.placeholder ?? "Enter value..."}
354
+ {required}
355
+ ariaDescribedBy={descriptionId}
356
+ onChange={(val) => {
357
+ // Try to parse as JSON for object types
358
+ if (schema.type === "object" || schema.format === "json") {
359
+ try {
360
+ onChange(JSON.parse(val));
361
+ } catch {
362
+ onChange(val);
363
+ }
364
+ } else {
365
+ onChange(val);
366
+ }
367
+ }}
368
+ />
369
+ </div>
370
+ {:else}
371
+ <!-- Fallback to text input -->
372
+ <FormTextField
373
+ id={fieldKey}
374
+ value={stringValue}
375
+ placeholder={schema.placeholder ?? ""}
376
+ ariaDescribedBy={descriptionId}
377
+ onChange={(val) => onChange(val)}
378
+ />
379
+ {/if}
380
+ </FormFieldWrapper>
381
+ {/if}
382
+
383
+ <style>
384
+ .form-field-fallback {
385
+ display: flex;
386
+ flex-direction: column;
387
+ gap: 0.5rem;
388
+ }
389
+
390
+ .form-field-fallback__message {
391
+ display: flex;
392
+ align-items: center;
393
+ gap: 0.5rem;
394
+ padding: 0.5rem 0.75rem;
395
+ background-color: var(--color-ref-amber-50, #fffbeb);
396
+ border: 1px solid var(--color-ref-amber-200, #fde68a);
397
+ border-radius: 0.375rem;
398
+ color: var(--color-ref-amber-800, #92400e);
399
+ font-size: 0.8125rem;
400
+ font-weight: 500;
401
+ }
402
+
403
+ .form-field-fallback__icon {
404
+ width: 1rem;
405
+ height: 1rem;
406
+ flex-shrink: 0;
407
+ color: var(--color-ref-amber-500, #f59e0b);
408
+ }
409
+
410
+ .form-field-fallback__hint {
411
+ margin: 0;
412
+ padding: 0.5rem 0.75rem;
413
+ background-color: var(--color-ref-gray-50, #f9fafb);
414
+ border: 1px solid var(--color-ref-gray-200, #e5e7eb);
415
+ border-radius: 0.375rem;
416
+ font-family: "JetBrains Mono", "Fira Code", "Monaco", "Menlo", monospace;
417
+ font-size: 0.6875rem;
418
+ line-height: 1.5;
419
+ color: var(--color-ref-gray-600, #4b5563);
420
+ word-break: break-word;
421
+ }
422
+ </style>
@@ -0,0 +1,18 @@
1
+ import type { FieldSchema } from "./types.js";
2
+ interface Props {
3
+ /** Unique key/id for the field */
4
+ fieldKey: string;
5
+ /** Field schema definition */
6
+ schema: FieldSchema;
7
+ /** Current field value */
8
+ value: unknown;
9
+ /** Whether the field is required */
10
+ required?: boolean;
11
+ /** Animation delay index for staggered animations */
12
+ animationIndex?: number;
13
+ /** Callback when the field value changes */
14
+ onChange: (value: unknown) => void;
15
+ }
16
+ declare const FormFieldLight: import("svelte").Component<Props, {}, "">;
17
+ type FormFieldLight = ReturnType<typeof FormFieldLight>;
18
+ export default FormFieldLight;
@@ -7,7 +7,7 @@
7
7
  <script lang="ts">
8
8
  import { Position, Handle } from '@xyflow/svelte';
9
9
  import Icon from '@iconify/svelte';
10
- import { getDataTypeColor } from '../../utils/colors';
10
+ import { getDataTypeColor, getColorVariants } from '../../utils/colors';
11
11
  import type { NodeMetadata } from '../../types/index.js';
12
12
 
13
13
  interface ToolNodeParameter {
@@ -64,6 +64,19 @@
64
64
  '1.0.0'
65
65
  );
66
66
 
67
+ // Generate color variants for theming (light tint for background, border tint for borders)
68
+ let colorVariants = $derived(getColorVariants(toolColor));
69
+
70
+ // Build inline style string for CSS custom properties
71
+ // This allows per-node color overrides while defaulting to global CSS variables
72
+ let nodeStyle = $derived(
73
+ [
74
+ `--flowdrop-tool-node-color: ${colorVariants.base}`,
75
+ `--flowdrop-tool-node-color-light: ${colorVariants.light}`,
76
+ `--flowdrop-tool-node-color-border: ${colorVariants.border}`
77
+ ].join('; ')
78
+ );
79
+
67
80
  // Check for tool interface ports in metadata
68
81
  let hasToolInputPort = $derived(
69
82
  props.data.metadata?.inputs?.some((port) => port.dataType === 'tool') || false
@@ -128,6 +141,7 @@
128
141
  class:flowdrop-tool-node--selected={props.selected}
129
142
  class:flowdrop-tool-node--processing={props.isProcessing}
130
143
  class:flowdrop-tool-node--error={props.isError}
144
+ style={nodeStyle}
131
145
  onclick={handleClick}
132
146
  ondblclick={handleDoubleClick}
133
147
  onkeydown={handleKeydown}
@@ -138,7 +152,7 @@
138
152
  <div class="flowdrop-tool-node__header">
139
153
  <div class="flowdrop-tool-node__header-content">
140
154
  <!-- Tool Icon -->
141
- <div class="flowdrop-tool-node__icon-container" style="background-color: {toolColor}">
155
+ <div class="flowdrop-tool-node__icon-container">
142
156
  <Icon icon={toolIcon} class="flowdrop-tool-node__icon" />
143
157
  </div>
144
158
 
@@ -214,7 +228,7 @@
214
228
 
215
229
  .flowdrop-tool-node--selected {
216
230
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
217
- border: 2px solid #f59e0b;
231
+ border: 2px solid var(--flowdrop-tool-node-color);
218
232
  }
219
233
 
220
234
  .flowdrop-tool-node--processing {
@@ -228,9 +242,9 @@
228
242
 
229
243
  .flowdrop-tool-node__header {
230
244
  padding: 1rem;
231
- background-color: #fffbeb;
245
+ background-color: var(--flowdrop-tool-node-color-light);
232
246
  border-radius: 0.75rem;
233
- border: 1px solid #fcd34d;
247
+ border: 1px solid var(--flowdrop-tool-node-color-border);
234
248
  }
235
249
 
236
250
  .flowdrop-tool-node__header-content {
@@ -248,6 +262,7 @@
248
262
  height: 2.5rem;
249
263
  border-radius: 0.5rem;
250
264
  flex-shrink: 0;
265
+ background-color: var(--flowdrop-tool-node-color);
251
266
  }
252
267
 
253
268
  .flowdrop-tool-node__info {
@@ -271,7 +286,7 @@
271
286
  }
272
287
 
273
288
  .flowdrop-tool-node__badge {
274
- background-color: #f59e0b;
289
+ background-color: var(--flowdrop-tool-node-color);
275
290
  color: white;
276
291
  font-size: 0.625rem;
277
292
  font-weight: 700;
@@ -375,11 +390,11 @@
375
390
 
376
391
  /* Metadata port hover effects */
377
392
  :global(.svelte-flow__node-tool .svelte-flow__handle:hover) {
378
- box-shadow: 0 0 0 2px rgba(245, 158, 11, 0.3) !important;
393
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--flowdrop-tool-node-color) 30%, transparent) !important;
379
394
  }
380
395
 
381
396
  :global(.svelte-flow__node-tool .svelte-flow__handle:focus) {
382
- outline: 2px solid #f59e0b !important;
397
+ outline: 2px solid var(--flowdrop-tool-node-color) !important;
383
398
  outline-offset: 2px !important;
384
399
  }
385
400
  </style>
@@ -0,0 +1,39 @@
1
+ /**
2
+ * FlowDrop Core Module
3
+ *
4
+ * This module exports types, utilities, and lightweight functionality
5
+ * with zero heavy dependencies. Safe to import without bundling
6
+ * @xyflow/svelte, codemirror, easymde, or marked.
7
+ *
8
+ * @module core
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * // Import types and utilities without heavy dependencies
13
+ * import type { Workflow, WorkflowNode, NodeMetadata } from "@d34dman/flowdrop/core";
14
+ * import { getStatusColor, createDefaultExecutionInfo } from "@d34dman/flowdrop/core";
15
+ * ```
16
+ */
17
+ export type { NodeCategory, NodeDataType, NodePort, DynamicPort, Branch, NodeMetadata, NodeExtensions, NodeUIExtensions, ConfigValues, WorkflowNode, WorkflowEdge, Workflow, ApiResponse, NodesResponse, WorkflowResponse, WorkflowsResponse, ExecutionStatus, ExecutionResult, FlowDropConfig, WorkflowEvents, BuiltinNodeType, PortConfig, PortCompatibilityRule, ConfigSchema, ConfigProperty, HttpMethod, DynamicSchemaEndpoint, ExternalEditLink, ConfigEditOptions } from "../types/index.js";
18
+ export type { WorkflowEditorConfig, EditorFeatures, UIConfig, APIConfig, ExecutionConfig, StorageConfig } from "../types/config.js";
19
+ export type { AuthProvider, StaticAuthConfig, CallbackAuthConfig } from "../types/auth.js";
20
+ export type { WorkflowChangeType, FlowDropEventHandlers, FlowDropFeatures } from "../types/events.js";
21
+ export type { FieldSchema, FieldType, FieldFormat, FieldOption, SchemaFormProps, BaseFieldProps, TextFieldProps, TextareaFieldProps, NumberFieldProps, ToggleFieldProps, RangeFieldProps, SelectFieldProps, CheckboxGroupFieldProps, ArrayFieldProps, CodeEditorFieldProps, MarkdownEditorFieldProps, TemplateEditorFieldProps, FormFieldFactoryProps, FormFieldWrapperProps } from "../components/form/types.js";
22
+ export type { NodeComponentProps, NodeComponentRegistration, NodeComponentCategory, StatusPosition, StatusSize, NodeRegistrationFilter, FlowDropPluginConfig, PluginNodeDefinition, PluginRegistrationResult } from "../registry/index.js";
23
+ export type { ToastType, ToastOptions } from "../services/toastService.js";
24
+ export type { DynamicSchemaResult } from "../services/dynamicSchemaService.js";
25
+ export type { EndpointConfig } from "../config/endpoints.js";
26
+ export type { FlowDropMountOptions, MountedFlowDropApp, NavbarAction } from "../svelte-app.js";
27
+ export { StaticAuthProvider, CallbackAuthProvider, NoAuthProvider } from "../types/auth.js";
28
+ export { DEFAULT_FEATURES, mergeFeatures } from "../types/events.js";
29
+ export { getStatusColor, getStatusIcon, getStatusLabel, getStatusBackgroundColor, getStatusTextColor, createDefaultExecutionInfo, updateExecutionStart, updateExecutionComplete, updateExecutionFailed, resetExecutionInfo, formatExecutionDuration, formatLastExecuted } from "../utils/nodeStatus.js";
30
+ export { createNodeWrapperConfig, shouldShowNodeStatus, getOptimalStatusPosition, getOptimalStatusSize, DEFAULT_NODE_STATUS_CONFIG } from "../utils/nodeWrapper.js";
31
+ export type { NodeStatusConfig } from "../utils/nodeWrapper.js";
32
+ export * from "../utils/colors.js";
33
+ export * from "../utils/icons.js";
34
+ export * from "../utils/config.js";
35
+ export * from "../utils/nodeTypes.js";
36
+ export { isFieldOptionArray, normalizeOptions } from "../components/form/types.js";
37
+ export { DEFAULT_PORT_CONFIG } from "../config/defaultPortConfig.js";
38
+ export { defaultEndpointConfig, createEndpointConfig } from "../config/endpoints.js";
39
+ export * from "../adapters/WorkflowAdapter.js";