@d34dman/flowdrop 0.0.25 → 0.0.27

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 (40) hide show
  1. package/README.md +52 -62
  2. package/dist/components/App.svelte +12 -2
  3. package/dist/components/ConfigForm.svelte +500 -9
  4. package/dist/components/ConfigForm.svelte.d.ts +2 -0
  5. package/dist/components/ConfigModal.svelte +4 -70
  6. package/dist/components/ConfigPanel.svelte +4 -9
  7. package/dist/components/EdgeRefresher.svelte +41 -0
  8. package/dist/components/EdgeRefresher.svelte.d.ts +9 -0
  9. package/dist/components/ReadOnlyDetails.svelte +3 -1
  10. package/dist/components/UniversalNode.svelte +6 -3
  11. package/dist/components/WorkflowEditor.svelte +30 -0
  12. package/dist/components/WorkflowEditor.svelte.d.ts +3 -1
  13. package/dist/components/form/FormCheckboxGroup.svelte +2 -9
  14. package/dist/components/form/FormField.svelte +1 -12
  15. package/dist/components/form/FormFieldWrapper.svelte +2 -10
  16. package/dist/components/form/FormFieldWrapper.svelte.d.ts +1 -1
  17. package/dist/components/form/FormMarkdownEditor.svelte +0 -2
  18. package/dist/components/form/FormNumberField.svelte +5 -6
  19. package/dist/components/form/FormRangeField.svelte +3 -13
  20. package/dist/components/form/FormSelect.svelte +4 -5
  21. package/dist/components/form/FormSelect.svelte.d.ts +1 -1
  22. package/dist/components/form/FormTextField.svelte +3 -4
  23. package/dist/components/form/FormTextarea.svelte +3 -4
  24. package/dist/components/form/FormToggle.svelte +2 -3
  25. package/dist/components/form/index.d.ts +14 -14
  26. package/dist/components/form/index.js +14 -14
  27. package/dist/components/form/types.d.ts +2 -2
  28. package/dist/components/form/types.js +1 -1
  29. package/dist/components/nodes/NotesNode.svelte +39 -45
  30. package/dist/components/nodes/NotesNode.svelte.d.ts +1 -1
  31. package/dist/components/nodes/SimpleNode.svelte +92 -142
  32. package/dist/components/nodes/SquareNode.svelte +75 -58
  33. package/dist/components/nodes/WorkflowNode.svelte +1 -3
  34. package/dist/index.d.ts +3 -1
  35. package/dist/index.js +2 -0
  36. package/dist/services/dynamicSchemaService.d.ts +108 -0
  37. package/dist/services/dynamicSchemaService.js +445 -0
  38. package/dist/styles/base.css +1 -1
  39. package/dist/types/index.d.ts +213 -0
  40. package/package.json +163 -155
@@ -60,13 +60,7 @@
60
60
  <!-- Header -->
61
61
  <div class="config-panel__header">
62
62
  <h2 class="config-panel__title">{title}</h2>
63
- <button
64
- class="config-panel__close"
65
- onclick={onClose}
66
- aria-label="Close panel"
67
- >
68
- ×
69
- </button>
63
+ <button class="config-panel__close" onclick={onClose} aria-label="Close panel"> × </button>
70
64
  </div>
71
65
 
72
66
  <!-- Details Section (between header and content) -->
@@ -121,7 +115,9 @@
121
115
  color: #6b7280;
122
116
  padding: 0.25rem;
123
117
  border-radius: 0.25rem;
124
- transition: color 0.15s, background-color 0.15s;
118
+ transition:
119
+ color 0.15s,
120
+ background-color 0.15s;
125
121
  }
126
122
 
127
123
  .config-panel__close:hover {
@@ -157,4 +153,3 @@
157
153
  letter-spacing: 0.05em;
158
154
  }
159
155
  </style>
160
-
@@ -0,0 +1,41 @@
1
+ <!--
2
+ EdgeRefresher Component
3
+ Helper component that uses useUpdateNodeInternals to force edge recalculation
4
+ Must be rendered inside SvelteFlowProvider context
5
+ -->
6
+
7
+ <script lang="ts">
8
+ import { useUpdateNodeInternals } from '@xyflow/svelte';
9
+
10
+ interface Props {
11
+ /** Node ID to refresh - when this changes, edges are recalculated */
12
+ nodeIdToRefresh: string | null;
13
+ /** Callback when refresh is complete */
14
+ onRefreshComplete?: () => void;
15
+ }
16
+
17
+ let { nodeIdToRefresh, onRefreshComplete }: Props = $props();
18
+
19
+ /**
20
+ * Get the updateNodeInternals function from Svelte Flow context
21
+ * This recalculates handle positions and forces edge path updates
22
+ */
23
+ const updateNodeInternals = useUpdateNodeInternals();
24
+
25
+ /**
26
+ * Watch for nodeIdToRefresh changes and trigger edge recalculation
27
+ */
28
+ $effect(() => {
29
+ if (nodeIdToRefresh) {
30
+ // Tell Svelte Flow to recalculate node internals (handle positions)
31
+ updateNodeInternals(nodeIdToRefresh);
32
+
33
+ // Notify parent that refresh is complete
34
+ if (onRefreshComplete) {
35
+ onRefreshComplete();
36
+ }
37
+ }
38
+ });
39
+ </script>
40
+
41
+ <!-- This component renders nothing - it's just for the hook logic -->
@@ -0,0 +1,9 @@
1
+ interface Props {
2
+ /** Node ID to refresh - when this changes, edges are recalculated */
3
+ nodeIdToRefresh: string | null;
4
+ /** Callback when refresh is complete */
5
+ onRefreshComplete?: () => void;
6
+ }
7
+ declare const EdgeRefresher: import("svelte").Component<Props, {}, "">;
8
+ type EdgeRefresher = ReturnType<typeof EdgeRefresher>;
9
+ export default EdgeRefresher;
@@ -147,7 +147,9 @@
147
147
  display: flex;
148
148
  align-items: center;
149
149
  justify-content: center;
150
- transition: color 0.15s, background-color 0.15s;
150
+ transition:
151
+ color 0.15s,
152
+ background-color 0.15s;
151
153
  }
152
154
 
153
155
  .readonly-details__copy-btn:hover {
@@ -128,9 +128,12 @@
128
128
  </script>
129
129
 
130
130
  <div class="universal-node">
131
- <!-- Render the node component dynamically -->
132
- <!-- svelte-ignore binding_property_non_reactive -->
133
- <svelte:component this={nodeComponent} {data} {selected} />
131
+ <!-- Render the node component dynamically (Svelte 5 dynamic component syntax) -->
132
+ {#if nodeComponent}
133
+ <!-- svelte-ignore binding_property_non_reactive -->
134
+ {@const NodeComponent = nodeComponent}
135
+ <NodeComponent {data} {selected} />
136
+ {/if}
134
137
 
135
138
  <!-- Status overlay - only show if there's meaningful status information -->
136
139
  {#if shouldShowStatus}
@@ -23,6 +23,7 @@
23
23
  } from '../types/index.js';
24
24
  import CanvasBanner from './CanvasBanner.svelte';
25
25
  import FlowDropZone from './FlowDropZone.svelte';
26
+ import EdgeRefresher from './EdgeRefresher.svelte';
26
27
  import { tick } from 'svelte';
27
28
  import type { EndpointConfig } from '../config/endpoints.js';
28
29
  import ConnectionLine from './ConnectionLine.svelte';
@@ -359,9 +360,38 @@
359
360
  console.warn('No currentWorkflow available for new node');
360
361
  }
361
362
  }
363
+
364
+ /**
365
+ * Node ID that needs edge refresh - used to trigger EdgeRefresher component
366
+ */
367
+ let nodeIdToRefresh = $state<string | null>(null);
368
+
369
+ /**
370
+ * Force edge position recalculation after node config changes
371
+ * This should be called after saving gateway/switch node configs where branches are reordered
372
+ * Svelte Flow doesn't automatically recalculate edge paths when handle positions change
373
+ * @param nodeId - The ID of the node whose handles have changed position
374
+ */
375
+ export async function refreshEdgePositions(nodeId: string): Promise<void> {
376
+ // Wait for DOM to update with new handle positions
377
+ await tick();
378
+
379
+ // Trigger the EdgeRefresher component to call updateNodeInternals
380
+ nodeIdToRefresh = nodeId;
381
+ }
382
+
383
+ /**
384
+ * Callback when edge refresh is complete
385
+ */
386
+ function handleEdgeRefreshComplete(): void {
387
+ nodeIdToRefresh = null;
388
+ }
362
389
  </script>
363
390
 
364
391
  <SvelteFlowProvider>
392
+ <!-- EdgeRefresher component - handles updateNodeInternals calls -->
393
+ <EdgeRefresher {nodeIdToRefresh} onRefreshComplete={handleEdgeRefreshComplete} />
394
+
365
395
  <div class="flowdrop-workflow-editor">
366
396
  <!-- Main Editor Area -->
367
397
  <div class="flowdrop-workflow-editor__main">
@@ -15,6 +15,8 @@ interface Props {
15
15
  nodeStatuses?: Record<string, 'pending' | 'running' | 'completed' | 'error'>;
16
16
  pipelineId?: string;
17
17
  }
18
- declare const WorkflowEditor: import("svelte").Component<Props, {}, "">;
18
+ declare const WorkflowEditor: import("svelte").Component<Props, {
19
+ refreshEdgePositions: (nodeId: string) => Promise<void>;
20
+ }, "">;
19
21
  type WorkflowEditor = ReturnType<typeof WorkflowEditor>;
20
22
  export default WorkflowEditor;
@@ -9,7 +9,7 @@
9
9
  -->
10
10
 
11
11
  <script lang="ts">
12
- import Icon from "@iconify/svelte";
12
+ import Icon from '@iconify/svelte';
13
13
 
14
14
  interface Props {
15
15
  /** Field identifier (used for ARIA) */
@@ -24,13 +24,7 @@
24
24
  onChange: (value: string[]) => void;
25
25
  }
26
26
 
27
- let {
28
- id,
29
- value = [],
30
- options = [],
31
- ariaDescribedBy,
32
- onChange
33
- }: Props = $props();
27
+ let { id, value = [], options = [], ariaDescribedBy, onChange }: Props = $props();
34
28
 
35
29
  /**
36
30
  * Handle checkbox toggle
@@ -149,4 +143,3 @@
149
143
  line-height: 1.4;
150
144
  }
151
145
  </style>
152
-
@@ -333,16 +333,5 @@
333
333
  {/if}
334
334
 
335
335
  <style>
336
- .form-field__unsupported {
337
- padding: 0.75rem;
338
- background-color: var(--color-ref-amber-50, #fffbeb);
339
- border: 1px solid var(--color-ref-amber-200, #fde68a);
340
- border-radius: 0.5rem;
341
- color: var(--color-ref-amber-800, #92400e);
342
- font-size: 0.8125rem;
343
- }
344
-
345
- .form-field__unsupported p {
346
- margin: 0;
347
- }
336
+ /* Styles moved to individual form components */
348
337
  </style>
@@ -10,7 +10,7 @@
10
10
  -->
11
11
 
12
12
  <script lang="ts">
13
- import type { Snippet } from "svelte";
13
+ import type { Snippet } from 'svelte';
14
14
 
15
15
  interface Props {
16
16
  /** Field identifier for label association */
@@ -27,14 +27,7 @@
27
27
  children: Snippet;
28
28
  }
29
29
 
30
- let {
31
- id,
32
- label,
33
- required = false,
34
- description,
35
- animationDelay = 0,
36
- children
37
- }: Props = $props();
30
+ let { id, label, required = false, description, animationDelay = 0, children }: Props = $props();
38
31
 
39
32
  /**
40
33
  * Computed description ID for ARIA association
@@ -130,4 +123,3 @@
130
123
  padding-left: 0.125rem;
131
124
  }
132
125
  </style>
133
-
@@ -1,4 +1,4 @@
1
- import type { Snippet } from "svelte";
1
+ import type { Snippet } from 'svelte';
2
2
  interface Props {
3
3
  /** Field identifier for label association */
4
4
  id: string;
@@ -100,8 +100,6 @@
100
100
  'table',
101
101
  '|',
102
102
  'preview',
103
- 'side-by-side',
104
- 'fullscreen',
105
103
  '|',
106
104
  'guide'
107
105
  ] as const;
@@ -32,8 +32,8 @@
32
32
 
33
33
  let {
34
34
  id,
35
- value = "",
36
- placeholder = "",
35
+ value = '',
36
+ placeholder = '',
37
37
  min,
38
38
  max,
39
39
  step,
@@ -50,8 +50,8 @@
50
50
  const target = event.currentTarget as HTMLInputElement;
51
51
  const inputValue = target.value;
52
52
 
53
- if (inputValue === "") {
54
- onChange("");
53
+ if (inputValue === '') {
54
+ onChange('');
55
55
  } else {
56
56
  const numValue = Number(inputValue);
57
57
  onChange(isNaN(numValue) ? inputValue : numValue);
@@ -63,7 +63,7 @@
63
63
  {id}
64
64
  type="number"
65
65
  class="form-number-field"
66
- value={value ?? ""}
66
+ value={value ?? ''}
67
67
  {placeholder}
68
68
  {min}
69
69
  {max}
@@ -106,4 +106,3 @@
106
106
  0 1px 2px rgba(0, 0, 0, 0.04);
107
107
  }
108
108
  </style>
109
-
@@ -46,7 +46,7 @@
46
46
  * Handles string values and defaults
47
47
  */
48
48
  const numericValue = $derived.by((): number => {
49
- if (typeof value === "number") {
49
+ if (typeof value === 'number') {
50
50
  return value;
51
51
  }
52
52
  const parsed = Number(value);
@@ -85,7 +85,6 @@
85
85
  {max}
86
86
  {step}
87
87
  aria-describedby={ariaDescribedBy}
88
- aria-required={required}
89
88
  aria-valuemin={min}
90
89
  aria-valuemax={max}
91
90
  aria-valuenow={numericValue}
@@ -144,11 +143,7 @@
144
143
  width: 18px;
145
144
  height: 18px;
146
145
  border-radius: 50%;
147
- background: linear-gradient(
148
- 135deg,
149
- #ffffff 0%,
150
- var(--color-ref-gray-50, #f9fafb) 100%
151
- );
146
+ background: linear-gradient(135deg, #ffffff 0%, var(--color-ref-gray-50, #f9fafb) 100%);
152
147
  border: 2px solid var(--color-ref-blue-500, #3b82f6);
153
148
  box-shadow:
154
149
  0 2px 6px rgba(59, 130, 246, 0.25),
@@ -189,11 +184,7 @@
189
184
  width: 18px;
190
185
  height: 18px;
191
186
  border-radius: 50%;
192
- background: linear-gradient(
193
- 135deg,
194
- #ffffff 0%,
195
- var(--color-ref-gray-50, #f9fafb) 100%
196
- );
187
+ background: linear-gradient(135deg, #ffffff 0%, var(--color-ref-gray-50, #f9fafb) 100%);
197
188
  border: 2px solid var(--color-ref-blue-500, #3b82f6);
198
189
  box-shadow:
199
190
  0 2px 6px rgba(59, 130, 246, 0.25),
@@ -249,4 +240,3 @@
249
240
  text-align: center;
250
241
  }
251
242
  </style>
252
-
@@ -9,8 +9,8 @@
9
9
  -->
10
10
 
11
11
  <script lang="ts">
12
- import Icon from "@iconify/svelte";
13
- import { normalizeOptions, type FieldOption } from "./types.js";
12
+ import Icon from '@iconify/svelte';
13
+ import { normalizeOptions, type FieldOption } from './types.js';
14
14
 
15
15
  interface Props {
16
16
  /** Field identifier */
@@ -29,7 +29,7 @@
29
29
 
30
30
  let {
31
31
  id,
32
- value = "",
32
+ value = '',
33
33
  options = [],
34
34
  required = false,
35
35
  ariaDescribedBy,
@@ -54,7 +54,7 @@
54
54
  <select
55
55
  {id}
56
56
  class="form-select"
57
- value={value ?? ""}
57
+ value={value ?? ''}
58
58
  aria-describedby={ariaDescribedBy}
59
59
  aria-required={required}
60
60
  onchange={handleChange}
@@ -123,4 +123,3 @@
123
123
  color: var(--color-ref-blue-500, #3b82f6);
124
124
  }
125
125
  </style>
126
-
@@ -1,4 +1,4 @@
1
- import { type FieldOption } from "./types.js";
1
+ import { type FieldOption } from './types.js';
2
2
  interface Props {
3
3
  /** Field identifier */
4
4
  id: string;
@@ -26,8 +26,8 @@
26
26
 
27
27
  let {
28
28
  id,
29
- value = "",
30
- placeholder = "",
29
+ value = '',
30
+ placeholder = '',
31
31
  required = false,
32
32
  ariaDescribedBy,
33
33
  onChange
@@ -46,7 +46,7 @@
46
46
  {id}
47
47
  type="text"
48
48
  class="form-text-field"
49
- value={value ?? ""}
49
+ value={value ?? ''}
50
50
  {placeholder}
51
51
  aria-describedby={ariaDescribedBy}
52
52
  aria-required={required}
@@ -85,4 +85,3 @@
85
85
  0 1px 2px rgba(0, 0, 0, 0.04);
86
86
  }
87
87
  </style>
88
-
@@ -28,8 +28,8 @@
28
28
 
29
29
  let {
30
30
  id,
31
- value = "",
32
- placeholder = "",
31
+ value = '',
32
+ placeholder = '',
33
33
  rows = 4,
34
34
  required = false,
35
35
  ariaDescribedBy,
@@ -48,7 +48,7 @@
48
48
  <textarea
49
49
  {id}
50
50
  class="form-textarea"
51
- value={value ?? ""}
51
+ value={value ?? ''}
52
52
  {placeholder}
53
53
  {rows}
54
54
  aria-describedby={ariaDescribedBy}
@@ -91,4 +91,3 @@
91
91
  0 1px 2px rgba(0, 0, 0, 0.04);
92
92
  }
93
93
  </style>
94
-
@@ -27,8 +27,8 @@
27
27
  let {
28
28
  id,
29
29
  value = false,
30
- onLabel = "Enabled",
31
- offLabel = "Disabled",
30
+ onLabel = 'Enabled',
31
+ offLabel = 'Disabled',
32
32
  ariaDescribedBy,
33
33
  onChange
34
34
  }: Props = $props();
@@ -120,4 +120,3 @@
120
120
  color: var(--color-ref-blue-600, #2563eb);
121
121
  }
122
122
  </style>
123
-
@@ -29,17 +29,17 @@
29
29
  * />
30
30
  * ```
31
31
  */
32
- export * from "./types.js";
33
- export { default as FormField } from "./FormField.svelte";
34
- export { default as FormFieldWrapper } from "./FormFieldWrapper.svelte";
35
- export { default as FormTextField } from "./FormTextField.svelte";
36
- export { default as FormTextarea } from "./FormTextarea.svelte";
37
- export { default as FormNumberField } from "./FormNumberField.svelte";
38
- export { default as FormRangeField } from "./FormRangeField.svelte";
39
- export { default as FormToggle } from "./FormToggle.svelte";
40
- export { default as FormSelect } from "./FormSelect.svelte";
41
- export { default as FormCheckboxGroup } from "./FormCheckboxGroup.svelte";
42
- export { default as FormArray } from "./FormArray.svelte";
43
- export { default as FormCodeEditor } from "./FormCodeEditor.svelte";
44
- export { default as FormMarkdownEditor } from "./FormMarkdownEditor.svelte";
45
- export { default as FormTemplateEditor } from "./FormTemplateEditor.svelte";
32
+ export * from './types.js';
33
+ export { default as FormField } from './FormField.svelte';
34
+ export { default as FormFieldWrapper } from './FormFieldWrapper.svelte';
35
+ export { default as FormTextField } from './FormTextField.svelte';
36
+ export { default as FormTextarea } from './FormTextarea.svelte';
37
+ export { default as FormNumberField } from './FormNumberField.svelte';
38
+ export { default as FormRangeField } from './FormRangeField.svelte';
39
+ export { default as FormToggle } from './FormToggle.svelte';
40
+ export { default as FormSelect } from './FormSelect.svelte';
41
+ export { default as FormCheckboxGroup } from './FormCheckboxGroup.svelte';
42
+ export { default as FormArray } from './FormArray.svelte';
43
+ export { default as FormCodeEditor } from './FormCodeEditor.svelte';
44
+ export { default as FormMarkdownEditor } from './FormMarkdownEditor.svelte';
45
+ export { default as FormTemplateEditor } from './FormTemplateEditor.svelte';
@@ -30,20 +30,20 @@
30
30
  * ```
31
31
  */
32
32
  // Types
33
- export * from "./types.js";
33
+ export * from './types.js';
34
34
  // Main factory component
35
- export { default as FormField } from "./FormField.svelte";
35
+ export { default as FormField } from './FormField.svelte';
36
36
  // Wrapper component
37
- export { default as FormFieldWrapper } from "./FormFieldWrapper.svelte";
37
+ export { default as FormFieldWrapper } from './FormFieldWrapper.svelte';
38
38
  // Individual field components
39
- export { default as FormTextField } from "./FormTextField.svelte";
40
- export { default as FormTextarea } from "./FormTextarea.svelte";
41
- export { default as FormNumberField } from "./FormNumberField.svelte";
42
- export { default as FormRangeField } from "./FormRangeField.svelte";
43
- export { default as FormToggle } from "./FormToggle.svelte";
44
- export { default as FormSelect } from "./FormSelect.svelte";
45
- export { default as FormCheckboxGroup } from "./FormCheckboxGroup.svelte";
46
- export { default as FormArray } from "./FormArray.svelte";
47
- export { default as FormCodeEditor } from "./FormCodeEditor.svelte";
48
- export { default as FormMarkdownEditor } from "./FormMarkdownEditor.svelte";
49
- export { default as FormTemplateEditor } from "./FormTemplateEditor.svelte";
39
+ export { default as FormTextField } from './FormTextField.svelte';
40
+ export { default as FormTextarea } from './FormTextarea.svelte';
41
+ export { default as FormNumberField } from './FormNumberField.svelte';
42
+ export { default as FormRangeField } from './FormRangeField.svelte';
43
+ export { default as FormToggle } from './FormToggle.svelte';
44
+ export { default as FormSelect } from './FormSelect.svelte';
45
+ export { default as FormCheckboxGroup } from './FormCheckboxGroup.svelte';
46
+ export { default as FormArray } from './FormArray.svelte';
47
+ export { default as FormCodeEditor } from './FormCodeEditor.svelte';
48
+ export { default as FormMarkdownEditor } from './FormMarkdownEditor.svelte';
49
+ export { default as FormTemplateEditor } from './FormTemplateEditor.svelte';
@@ -9,7 +9,7 @@
9
9
  * Supported field types for form rendering
10
10
  * Can be extended to support complex types like 'array' and 'object'
11
11
  */
12
- export type FieldType = "string" | "number" | "integer" | "boolean" | "select" | "array" | "object";
12
+ export type FieldType = 'string' | 'number' | 'integer' | 'boolean' | 'select' | 'array' | 'object';
13
13
  /**
14
14
  * Field format for specialized rendering
15
15
  * - multiline: Renders as textarea
@@ -20,7 +20,7 @@ export type FieldType = "string" | "number" | "integer" | "boolean" | "select" |
20
20
  * - markdown: Renders as SimpleMDE Markdown editor
21
21
  * - template: Renders as CodeMirror editor with Twig/Liquid syntax highlighting
22
22
  */
23
- export type FieldFormat = "multiline" | "hidden" | "range" | "json" | "code" | "markdown" | "template" | string;
23
+ export type FieldFormat = 'multiline' | 'hidden' | 'range' | 'json' | 'code' | 'markdown' | 'template' | string;
24
24
  /**
25
25
  * Option type for select and checkbox group fields
26
26
  */
@@ -9,7 +9,7 @@
9
9
  * Type guard to check if options are FieldOption objects
10
10
  */
11
11
  export function isFieldOptionArray(options) {
12
- return options.length > 0 && typeof options[0] === "object" && "value" in options[0];
12
+ return options.length > 0 && typeof options[0] === 'object' && 'value' in options[0];
13
13
  }
14
14
  /**
15
15
  * Normalize options to FieldOption format