@d34dman/flowdrop 0.0.24 → 0.0.26
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.
- package/README.md +52 -62
- package/dist/components/App.svelte +15 -2
- package/dist/components/ConfigForm.svelte +4 -1
- package/dist/components/ConfigModal.svelte +4 -70
- package/dist/components/ConfigPanel.svelte +4 -9
- package/dist/components/EdgeRefresher.svelte +42 -0
- package/dist/components/EdgeRefresher.svelte.d.ts +9 -0
- package/dist/components/ReadOnlyDetails.svelte +3 -1
- package/dist/components/UniversalNode.svelte +6 -3
- package/dist/components/WorkflowEditor.svelte +33 -0
- package/dist/components/WorkflowEditor.svelte.d.ts +3 -1
- package/dist/components/form/FormCheckboxGroup.svelte +2 -9
- package/dist/components/form/FormCodeEditor.svelte +416 -0
- package/dist/components/form/FormCodeEditor.svelte.d.ts +23 -0
- package/dist/components/form/FormField.svelte +125 -85
- package/dist/components/form/FormField.svelte.d.ts +1 -1
- package/dist/components/form/FormFieldWrapper.svelte +2 -10
- package/dist/components/form/FormFieldWrapper.svelte.d.ts +1 -1
- package/dist/components/form/FormMarkdownEditor.svelte +553 -0
- package/dist/components/form/FormMarkdownEditor.svelte.d.ts +29 -0
- package/dist/components/form/FormNumberField.svelte +5 -6
- package/dist/components/form/FormRangeField.svelte +3 -13
- package/dist/components/form/FormSelect.svelte +4 -5
- package/dist/components/form/FormSelect.svelte.d.ts +1 -1
- package/dist/components/form/FormTemplateEditor.svelte +463 -0
- package/dist/components/form/FormTemplateEditor.svelte.d.ts +25 -0
- package/dist/components/form/FormTextField.svelte +3 -4
- package/dist/components/form/FormTextarea.svelte +3 -4
- package/dist/components/form/FormToggle.svelte +2 -3
- package/dist/components/form/index.d.ts +14 -11
- package/dist/components/form/index.js +14 -11
- package/dist/components/form/types.d.ts +55 -2
- package/dist/components/form/types.js +1 -1
- package/dist/components/nodes/NotesNode.svelte +39 -45
- package/dist/components/nodes/NotesNode.svelte.d.ts +1 -1
- package/dist/components/nodes/WorkflowNode.svelte +1 -3
- package/dist/styles/base.css +1 -1
- package/package.json +162 -148
|
@@ -5,33 +5,40 @@
|
|
|
5
5
|
Features:
|
|
6
6
|
- Automatically selects the correct field component based on schema
|
|
7
7
|
- Wraps fields with FormFieldWrapper for consistent layout
|
|
8
|
-
- Supports all current field types (string, number, boolean, select, checkbox group, range)
|
|
8
|
+
- Supports all current field types (string, number, boolean, select, checkbox group, range, json, markdown, template)
|
|
9
9
|
- Extensible architecture for future complex types (array, object)
|
|
10
10
|
|
|
11
11
|
Type Resolution Order:
|
|
12
12
|
1. format: 'hidden' -> skip rendering (return nothing)
|
|
13
|
-
2.
|
|
14
|
-
3.
|
|
15
|
-
4. format: '
|
|
16
|
-
5.
|
|
17
|
-
6.
|
|
18
|
-
7.
|
|
19
|
-
8.
|
|
20
|
-
9. type: '
|
|
21
|
-
10.
|
|
13
|
+
2. format: 'json' or 'code' -> FormCodeEditor (CodeMirror JSON editor)
|
|
14
|
+
3. format: 'markdown' -> FormMarkdownEditor (SimpleMDE Markdown editor)
|
|
15
|
+
4. format: 'template' -> FormTemplateEditor (CodeMirror with Twig/Liquid syntax)
|
|
16
|
+
5. enum with multiple: true -> FormCheckboxGroup
|
|
17
|
+
6. enum -> FormSelect
|
|
18
|
+
7. format: 'multiline' -> FormTextarea
|
|
19
|
+
8. format: 'range' (number/integer) -> FormRangeField
|
|
20
|
+
9. type: 'string' -> FormTextField
|
|
21
|
+
10. type: 'number' or 'integer' -> FormNumberField
|
|
22
|
+
11. type: 'boolean' -> FormToggle
|
|
23
|
+
12. type: 'select' or has options -> FormSelect
|
|
24
|
+
13. type: 'object' (without format) -> FormCodeEditor (for JSON objects)
|
|
25
|
+
14. fallback -> FormTextField
|
|
22
26
|
-->
|
|
23
27
|
|
|
24
28
|
<script lang="ts">
|
|
25
|
-
import FormFieldWrapper from
|
|
26
|
-
import FormTextField from
|
|
27
|
-
import FormTextarea from
|
|
28
|
-
import FormNumberField from
|
|
29
|
-
import FormRangeField from
|
|
30
|
-
import FormToggle from
|
|
31
|
-
import FormSelect from
|
|
32
|
-
import FormCheckboxGroup from
|
|
33
|
-
import FormArray from
|
|
34
|
-
import
|
|
29
|
+
import FormFieldWrapper from './FormFieldWrapper.svelte';
|
|
30
|
+
import FormTextField from './FormTextField.svelte';
|
|
31
|
+
import FormTextarea from './FormTextarea.svelte';
|
|
32
|
+
import FormNumberField from './FormNumberField.svelte';
|
|
33
|
+
import FormRangeField from './FormRangeField.svelte';
|
|
34
|
+
import FormToggle from './FormToggle.svelte';
|
|
35
|
+
import FormSelect from './FormSelect.svelte';
|
|
36
|
+
import FormCheckboxGroup from './FormCheckboxGroup.svelte';
|
|
37
|
+
import FormArray from './FormArray.svelte';
|
|
38
|
+
import FormCodeEditor from './FormCodeEditor.svelte';
|
|
39
|
+
import FormMarkdownEditor from './FormMarkdownEditor.svelte';
|
|
40
|
+
import FormTemplateEditor from './FormTemplateEditor.svelte';
|
|
41
|
+
import type { FieldSchema, FieldOption } from './types.js';
|
|
35
42
|
|
|
36
43
|
interface Props {
|
|
37
44
|
/** Unique key/id for the field */
|
|
@@ -48,19 +55,14 @@
|
|
|
48
55
|
onChange: (value: unknown) => void;
|
|
49
56
|
}
|
|
50
57
|
|
|
51
|
-
let {
|
|
52
|
-
fieldKey,
|
|
53
|
-
schema,
|
|
54
|
-
value,
|
|
55
|
-
required = false,
|
|
56
|
-
animationIndex = 0,
|
|
57
|
-
onChange
|
|
58
|
-
}: Props = $props();
|
|
58
|
+
let { fieldKey, schema, value, required = false, animationIndex = 0, onChange }: Props = $props();
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
61
|
* Computed description ID for ARIA association
|
|
62
62
|
*/
|
|
63
|
-
const descriptionId = $derived(
|
|
63
|
+
const descriptionId = $derived(
|
|
64
|
+
schema.description && schema.title ? `${fieldKey}-description` : undefined
|
|
65
|
+
);
|
|
64
66
|
|
|
65
67
|
/**
|
|
66
68
|
* Animation delay based on index
|
|
@@ -77,62 +79,77 @@
|
|
|
77
79
|
*/
|
|
78
80
|
const fieldType = $derived.by(() => {
|
|
79
81
|
// Hidden fields should not be rendered
|
|
80
|
-
if (schema.format ===
|
|
81
|
-
return
|
|
82
|
+
if (schema.format === 'hidden') {
|
|
83
|
+
return 'hidden';
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// JSON/code editor for format: "json" or "code"
|
|
87
|
+
if (schema.format === 'json' || schema.format === 'code') {
|
|
88
|
+
return 'code-editor';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Markdown editor for format: "markdown"
|
|
92
|
+
if (schema.format === 'markdown') {
|
|
93
|
+
return 'markdown-editor';
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Template editor for format: "template" (Twig/Liquid syntax)
|
|
97
|
+
if (schema.format === 'template') {
|
|
98
|
+
return 'template-editor';
|
|
82
99
|
}
|
|
83
100
|
|
|
84
101
|
// Enum with multiple selection -> checkbox group
|
|
85
102
|
if (schema.enum && schema.multiple) {
|
|
86
|
-
return
|
|
103
|
+
return 'checkbox-group';
|
|
87
104
|
}
|
|
88
105
|
|
|
89
106
|
// Enum with single selection -> select
|
|
90
107
|
if (schema.enum) {
|
|
91
|
-
return
|
|
108
|
+
return 'select-enum';
|
|
92
109
|
}
|
|
93
110
|
|
|
94
111
|
// Multiline string -> textarea
|
|
95
|
-
if (schema.type ===
|
|
96
|
-
return
|
|
112
|
+
if (schema.type === 'string' && schema.format === 'multiline') {
|
|
113
|
+
return 'textarea';
|
|
97
114
|
}
|
|
98
115
|
|
|
99
116
|
// Range slider for number/integer with format: "range"
|
|
100
|
-
if ((schema.type ===
|
|
101
|
-
return
|
|
117
|
+
if ((schema.type === 'number' || schema.type === 'integer') && schema.format === 'range') {
|
|
118
|
+
return 'range';
|
|
102
119
|
}
|
|
103
120
|
|
|
104
121
|
// String -> text field
|
|
105
|
-
if (schema.type ===
|
|
106
|
-
return
|
|
122
|
+
if (schema.type === 'string') {
|
|
123
|
+
return 'text';
|
|
107
124
|
}
|
|
108
125
|
|
|
109
126
|
// Number or integer -> number field
|
|
110
|
-
if (schema.type ===
|
|
111
|
-
return
|
|
127
|
+
if (schema.type === 'number' || schema.type === 'integer') {
|
|
128
|
+
return 'number';
|
|
112
129
|
}
|
|
113
130
|
|
|
114
131
|
// Boolean -> toggle
|
|
115
|
-
if (schema.type ===
|
|
116
|
-
return
|
|
132
|
+
if (schema.type === 'boolean') {
|
|
133
|
+
return 'toggle';
|
|
117
134
|
}
|
|
118
135
|
|
|
119
136
|
// Select type or has options -> select
|
|
120
|
-
if (schema.type ===
|
|
121
|
-
return
|
|
137
|
+
if (schema.type === 'select' || schema.options) {
|
|
138
|
+
return 'select-options';
|
|
122
139
|
}
|
|
123
140
|
|
|
124
141
|
// Future: Array type support
|
|
125
|
-
if (schema.type ===
|
|
126
|
-
return
|
|
142
|
+
if (schema.type === 'array') {
|
|
143
|
+
return 'array';
|
|
127
144
|
}
|
|
128
145
|
|
|
129
|
-
//
|
|
130
|
-
if (schema.type ===
|
|
131
|
-
return
|
|
146
|
+
// Object type without specific format -> CodeMirror JSON editor
|
|
147
|
+
if (schema.type === 'object') {
|
|
148
|
+
return 'code-editor';
|
|
132
149
|
}
|
|
133
150
|
|
|
134
151
|
// Fallback to text
|
|
135
|
-
return
|
|
152
|
+
return 'text';
|
|
136
153
|
});
|
|
137
154
|
|
|
138
155
|
/**
|
|
@@ -154,7 +171,7 @@
|
|
|
154
171
|
/**
|
|
155
172
|
* Get current value as the appropriate type
|
|
156
173
|
*/
|
|
157
|
-
const stringValue = $derived(String(value ??
|
|
174
|
+
const stringValue = $derived(String(value ?? ''));
|
|
158
175
|
const numberValue = $derived(value as number | string);
|
|
159
176
|
const booleanValue = $derived(Boolean(value ?? schema.default ?? false));
|
|
160
177
|
const arrayValue = $derived.by((): string[] => {
|
|
@@ -171,7 +188,7 @@
|
|
|
171
188
|
});
|
|
172
189
|
</script>
|
|
173
190
|
|
|
174
|
-
{#if fieldType !==
|
|
191
|
+
{#if fieldType !== 'hidden'}
|
|
175
192
|
<FormFieldWrapper
|
|
176
193
|
id={fieldKey}
|
|
177
194
|
label={fieldLabel}
|
|
@@ -179,7 +196,7 @@
|
|
|
179
196
|
description={schema.title ? schema.description : undefined}
|
|
180
197
|
{animationDelay}
|
|
181
198
|
>
|
|
182
|
-
{#if fieldType ===
|
|
199
|
+
{#if fieldType === 'checkbox-group'}
|
|
183
200
|
<FormCheckboxGroup
|
|
184
201
|
id={fieldKey}
|
|
185
202
|
value={arrayValue}
|
|
@@ -187,7 +204,7 @@
|
|
|
187
204
|
ariaDescribedBy={descriptionId}
|
|
188
205
|
onChange={(val) => onChange(val)}
|
|
189
206
|
/>
|
|
190
|
-
{:else if fieldType ===
|
|
207
|
+
{:else if fieldType === 'select-enum'}
|
|
191
208
|
<FormSelect
|
|
192
209
|
id={fieldKey}
|
|
193
210
|
value={stringValue}
|
|
@@ -196,36 +213,36 @@
|
|
|
196
213
|
ariaDescribedBy={descriptionId}
|
|
197
214
|
onChange={(val) => onChange(val)}
|
|
198
215
|
/>
|
|
199
|
-
{:else if fieldType ===
|
|
216
|
+
{:else if fieldType === 'textarea'}
|
|
200
217
|
<FormTextarea
|
|
201
218
|
id={fieldKey}
|
|
202
219
|
value={stringValue}
|
|
203
|
-
placeholder={schema.placeholder ??
|
|
220
|
+
placeholder={schema.placeholder ?? ''}
|
|
204
221
|
{required}
|
|
205
222
|
ariaDescribedBy={descriptionId}
|
|
206
223
|
onChange={(val) => onChange(val)}
|
|
207
224
|
/>
|
|
208
|
-
{:else if fieldType ===
|
|
225
|
+
{:else if fieldType === 'text'}
|
|
209
226
|
<FormTextField
|
|
210
227
|
id={fieldKey}
|
|
211
228
|
value={stringValue}
|
|
212
|
-
placeholder={schema.placeholder ??
|
|
229
|
+
placeholder={schema.placeholder ?? ''}
|
|
213
230
|
{required}
|
|
214
231
|
ariaDescribedBy={descriptionId}
|
|
215
232
|
onChange={(val) => onChange(val)}
|
|
216
233
|
/>
|
|
217
|
-
{:else if fieldType ===
|
|
234
|
+
{:else if fieldType === 'number'}
|
|
218
235
|
<FormNumberField
|
|
219
236
|
id={fieldKey}
|
|
220
237
|
value={numberValue}
|
|
221
|
-
placeholder={schema.placeholder ??
|
|
238
|
+
placeholder={schema.placeholder ?? ''}
|
|
222
239
|
min={schema.minimum}
|
|
223
240
|
max={schema.maximum}
|
|
224
241
|
{required}
|
|
225
242
|
ariaDescribedBy={descriptionId}
|
|
226
243
|
onChange={(val) => onChange(val)}
|
|
227
244
|
/>
|
|
228
|
-
{:else if fieldType ===
|
|
245
|
+
{:else if fieldType === 'range'}
|
|
229
246
|
<FormRangeField
|
|
230
247
|
id={fieldKey}
|
|
231
248
|
value={numberValue}
|
|
@@ -236,14 +253,14 @@
|
|
|
236
253
|
ariaDescribedBy={descriptionId}
|
|
237
254
|
onChange={(val) => onChange(val)}
|
|
238
255
|
/>
|
|
239
|
-
{:else if fieldType ===
|
|
256
|
+
{:else if fieldType === 'toggle'}
|
|
240
257
|
<FormToggle
|
|
241
258
|
id={fieldKey}
|
|
242
259
|
value={booleanValue}
|
|
243
260
|
ariaDescribedBy={descriptionId}
|
|
244
261
|
onChange={(val) => onChange(val)}
|
|
245
262
|
/>
|
|
246
|
-
{:else if fieldType ===
|
|
263
|
+
{:else if fieldType === 'select-options'}
|
|
247
264
|
<FormSelect
|
|
248
265
|
id={fieldKey}
|
|
249
266
|
value={stringValue}
|
|
@@ -252,27 +269,62 @@
|
|
|
252
269
|
ariaDescribedBy={descriptionId}
|
|
253
270
|
onChange={(val) => onChange(val)}
|
|
254
271
|
/>
|
|
255
|
-
{:else if fieldType ===
|
|
272
|
+
{:else if fieldType === 'array' && schema.items}
|
|
256
273
|
<FormArray
|
|
257
274
|
id={fieldKey}
|
|
258
275
|
value={arrayItems}
|
|
259
276
|
itemSchema={schema.items}
|
|
260
277
|
minItems={schema.minItems}
|
|
261
278
|
maxItems={schema.maxItems}
|
|
262
|
-
addLabel={`Add ${schema.items.title ??
|
|
279
|
+
addLabel={`Add ${schema.items.title ?? 'Item'}`}
|
|
280
|
+
onChange={(val) => onChange(val)}
|
|
281
|
+
/>
|
|
282
|
+
{:else if fieldType === 'code-editor'}
|
|
283
|
+
<FormCodeEditor
|
|
284
|
+
id={fieldKey}
|
|
285
|
+
{value}
|
|
286
|
+
placeholder={schema.placeholder ?? '{}'}
|
|
287
|
+
{required}
|
|
288
|
+
height={(schema.height as string | undefined) ?? '200px'}
|
|
289
|
+
darkTheme={(schema.darkTheme as boolean | undefined) ?? false}
|
|
290
|
+
autoFormat={(schema.autoFormat as boolean | undefined) ?? true}
|
|
291
|
+
ariaDescribedBy={descriptionId}
|
|
292
|
+
onChange={(val) => onChange(val)}
|
|
293
|
+
/>
|
|
294
|
+
{:else if fieldType === 'markdown-editor'}
|
|
295
|
+
<FormMarkdownEditor
|
|
296
|
+
id={fieldKey}
|
|
297
|
+
value={stringValue}
|
|
298
|
+
placeholder={schema.placeholder ?? 'Write your markdown here...'}
|
|
299
|
+
{required}
|
|
300
|
+
height={(schema.height as string | undefined) ?? '300px'}
|
|
301
|
+
showToolbar={(schema.showToolbar as boolean | undefined) ?? true}
|
|
302
|
+
showStatusBar={(schema.showStatusBar as boolean | undefined) ?? true}
|
|
303
|
+
spellChecker={(schema.spellChecker as boolean | undefined) ?? false}
|
|
304
|
+
ariaDescribedBy={descriptionId}
|
|
305
|
+
onChange={(val) => onChange(val)}
|
|
306
|
+
/>
|
|
307
|
+
{:else if fieldType === 'template-editor'}
|
|
308
|
+
<FormTemplateEditor
|
|
309
|
+
id={fieldKey}
|
|
310
|
+
value={stringValue}
|
|
311
|
+
placeholder={schema.placeholder ??
|
|
312
|
+
'Enter your template here...\nUse {{ variable }} for dynamic values.'}
|
|
313
|
+
{required}
|
|
314
|
+
height={(schema.height as string | undefined) ?? '250px'}
|
|
315
|
+
darkTheme={(schema.darkTheme as boolean | undefined) ?? false}
|
|
316
|
+
variableHints={(schema.variableHints as string[] | undefined) ?? []}
|
|
317
|
+
placeholderExample={(schema.placeholderExample as string | undefined) ??
|
|
318
|
+
'Hello {{ name }}, your order #{{ order_id }} is ready!'}
|
|
319
|
+
ariaDescribedBy={descriptionId}
|
|
263
320
|
onChange={(val) => onChange(val)}
|
|
264
321
|
/>
|
|
265
|
-
{:else if fieldType === "object"}
|
|
266
|
-
<!-- Future: Object field component -->
|
|
267
|
-
<div class="form-field__unsupported">
|
|
268
|
-
<p>Object fields are not yet supported. Coming soon!</p>
|
|
269
|
-
</div>
|
|
270
322
|
{:else}
|
|
271
323
|
<!-- Fallback to text input -->
|
|
272
324
|
<FormTextField
|
|
273
325
|
id={fieldKey}
|
|
274
326
|
value={stringValue}
|
|
275
|
-
placeholder={schema.placeholder ??
|
|
327
|
+
placeholder={schema.placeholder ?? ''}
|
|
276
328
|
ariaDescribedBy={descriptionId}
|
|
277
329
|
onChange={(val) => onChange(val)}
|
|
278
330
|
/>
|
|
@@ -281,17 +333,5 @@
|
|
|
281
333
|
{/if}
|
|
282
334
|
|
|
283
335
|
<style>
|
|
284
|
-
|
|
285
|
-
padding: 0.75rem;
|
|
286
|
-
background-color: var(--color-ref-amber-50, #fffbeb);
|
|
287
|
-
border: 1px solid var(--color-ref-amber-200, #fde68a);
|
|
288
|
-
border-radius: 0.5rem;
|
|
289
|
-
color: var(--color-ref-amber-800, #92400e);
|
|
290
|
-
font-size: 0.8125rem;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
.form-field__unsupported p {
|
|
294
|
-
margin: 0;
|
|
295
|
-
}
|
|
336
|
+
/* Styles moved to individual form components */
|
|
296
337
|
</style>
|
|
297
|
-
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
-->
|
|
11
11
|
|
|
12
12
|
<script lang="ts">
|
|
13
|
-
import type { Snippet } from
|
|
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
|
-
|