@d34dman/flowdrop 0.0.23 → 0.0.25
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/dist/components/ConfigForm.svelte +1 -1
- package/dist/components/form/FormCodeEditor.svelte +415 -0
- package/dist/components/form/FormCodeEditor.svelte.d.ts +23 -0
- package/dist/components/form/FormField.svelte +137 -68
- package/dist/components/form/FormField.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/FormRangeField.svelte +252 -0
- package/dist/components/form/FormRangeField.svelte.d.ts +21 -0
- package/dist/components/form/FormTemplateEditor.svelte +463 -0
- package/dist/components/form/FormTemplateEditor.svelte.d.ts +25 -0
- package/dist/components/form/index.d.ts +4 -0
- package/dist/components/form/index.js +4 -0
- package/dist/components/form/types.d.ts +70 -1
- package/dist/components/nodes/GatewayNode.svelte +1 -13
- package/dist/index.d.ts +1 -1
- package/dist/types/index.d.ts +99 -1
- package/package.json +9 -3
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
FormTemplateEditor Component
|
|
3
|
+
CodeMirror-based template editor for Twig/Liquid-style templates
|
|
4
|
+
|
|
5
|
+
Features:
|
|
6
|
+
- Custom syntax highlighting for {{ variable }} placeholders
|
|
7
|
+
- Dark/light theme support
|
|
8
|
+
- Consistent styling with other form components
|
|
9
|
+
- Line wrapping for better template readability
|
|
10
|
+
- Optional variable hints display
|
|
11
|
+
- Proper ARIA attributes for accessibility
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
Use with schema format: "template" to render this editor
|
|
15
|
+
-->
|
|
16
|
+
|
|
17
|
+
<script lang="ts">
|
|
18
|
+
import { onMount, onDestroy } from 'svelte';
|
|
19
|
+
import { EditorView, basicSetup } from 'codemirror';
|
|
20
|
+
import { EditorState } from '@codemirror/state';
|
|
21
|
+
import {
|
|
22
|
+
Decoration,
|
|
23
|
+
type DecorationSet,
|
|
24
|
+
ViewPlugin,
|
|
25
|
+
type ViewUpdate,
|
|
26
|
+
MatchDecorator
|
|
27
|
+
} from '@codemirror/view';
|
|
28
|
+
import { oneDark } from '@codemirror/theme-one-dark';
|
|
29
|
+
|
|
30
|
+
interface Props {
|
|
31
|
+
/** Field identifier */
|
|
32
|
+
id: string;
|
|
33
|
+
/** Current template value */
|
|
34
|
+
value: string;
|
|
35
|
+
/** Placeholder text shown when empty */
|
|
36
|
+
placeholder?: string;
|
|
37
|
+
/** Whether the field is required */
|
|
38
|
+
required?: boolean;
|
|
39
|
+
/** Whether to use dark theme */
|
|
40
|
+
darkTheme?: boolean;
|
|
41
|
+
/** Editor height in pixels or CSS value */
|
|
42
|
+
height?: string;
|
|
43
|
+
/** Available variable names for hints (optional) */
|
|
44
|
+
variableHints?: string[];
|
|
45
|
+
/** Placeholder variable example for the hint */
|
|
46
|
+
placeholderExample?: string;
|
|
47
|
+
/** ARIA description ID */
|
|
48
|
+
ariaDescribedBy?: string;
|
|
49
|
+
/** Callback when value changes */
|
|
50
|
+
onChange: (value: string) => void;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let {
|
|
54
|
+
id,
|
|
55
|
+
value = '',
|
|
56
|
+
placeholder = 'Enter your template here...\nUse {{ variable }} for dynamic values.',
|
|
57
|
+
required = false,
|
|
58
|
+
darkTheme = false,
|
|
59
|
+
height = '250px',
|
|
60
|
+
variableHints = [],
|
|
61
|
+
placeholderExample = 'Hello {{ name }}, your order #{{ order_id }} is ready!',
|
|
62
|
+
ariaDescribedBy,
|
|
63
|
+
onChange
|
|
64
|
+
}: Props = $props();
|
|
65
|
+
|
|
66
|
+
/** Reference to the container element */
|
|
67
|
+
let containerRef: HTMLDivElement | undefined = $state(undefined);
|
|
68
|
+
|
|
69
|
+
/** CodeMirror editor instance */
|
|
70
|
+
let editorView: EditorView | undefined = $state(undefined);
|
|
71
|
+
|
|
72
|
+
/** Flag to prevent update loops */
|
|
73
|
+
let isInternalUpdate = false;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Create a MatchDecorator for {{ variable }} patterns
|
|
77
|
+
* This highlights the entire {{ variable }} expression
|
|
78
|
+
*/
|
|
79
|
+
const variableMatcher = new MatchDecorator({
|
|
80
|
+
// Match {{ variable_name }} patterns (with optional whitespace)
|
|
81
|
+
regexp: /\{\{\s*[\w.]+\s*\}\}/g,
|
|
82
|
+
decoration: Decoration.mark({ class: 'cm-template-variable' })
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* ViewPlugin that applies the variable highlighting decorations
|
|
87
|
+
*/
|
|
88
|
+
const variableHighlighter = ViewPlugin.fromClass(
|
|
89
|
+
class {
|
|
90
|
+
decorations: DecorationSet;
|
|
91
|
+
constructor(view: EditorView) {
|
|
92
|
+
this.decorations = variableMatcher.createDeco(view);
|
|
93
|
+
}
|
|
94
|
+
update(update: ViewUpdate) {
|
|
95
|
+
this.decorations = variableMatcher.updateDeco(update, this.decorations);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
decorations: (v) => v.decorations
|
|
100
|
+
}
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Handle editor content changes
|
|
105
|
+
*/
|
|
106
|
+
function handleUpdate(update: { docChanged: boolean; state: EditorState }): void {
|
|
107
|
+
if (!update.docChanged || isInternalUpdate) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const content = update.state.doc.toString();
|
|
112
|
+
onChange(content);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Create editor extensions array for template editing
|
|
117
|
+
*/
|
|
118
|
+
function createExtensions() {
|
|
119
|
+
const extensions = [
|
|
120
|
+
basicSetup,
|
|
121
|
+
variableHighlighter,
|
|
122
|
+
EditorView.updateListener.of(handleUpdate),
|
|
123
|
+
EditorView.theme({
|
|
124
|
+
'&': {
|
|
125
|
+
height: height,
|
|
126
|
+
fontSize: '0.875rem',
|
|
127
|
+
fontFamily: "'JetBrains Mono', 'Fira Code', 'Monaco', 'Menlo', monospace"
|
|
128
|
+
},
|
|
129
|
+
'.cm-scroller': {
|
|
130
|
+
overflow: 'auto'
|
|
131
|
+
},
|
|
132
|
+
'.cm-content': {
|
|
133
|
+
minHeight: '100px',
|
|
134
|
+
padding: '0.5rem 0'
|
|
135
|
+
},
|
|
136
|
+
'&.cm-focused': {
|
|
137
|
+
outline: 'none'
|
|
138
|
+
},
|
|
139
|
+
'.cm-line': {
|
|
140
|
+
padding: '0 0.5rem'
|
|
141
|
+
},
|
|
142
|
+
// Style for the highlighted {{ variable }} pattern
|
|
143
|
+
'.cm-template-variable': {
|
|
144
|
+
color: '#a855f7',
|
|
145
|
+
backgroundColor: 'rgba(168, 85, 247, 0.1)',
|
|
146
|
+
borderRadius: '3px',
|
|
147
|
+
padding: '1px 2px',
|
|
148
|
+
fontWeight: '500'
|
|
149
|
+
}
|
|
150
|
+
}),
|
|
151
|
+
EditorView.lineWrapping,
|
|
152
|
+
EditorState.tabSize.of(2)
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
if (darkTheme) {
|
|
156
|
+
extensions.push(oneDark);
|
|
157
|
+
// Add dark theme override for variable highlighting
|
|
158
|
+
extensions.push(
|
|
159
|
+
EditorView.theme({
|
|
160
|
+
'.cm-template-variable': {
|
|
161
|
+
color: '#c084fc',
|
|
162
|
+
backgroundColor: 'rgba(192, 132, 252, 0.15)'
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return extensions;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Insert a variable placeholder at current cursor position
|
|
173
|
+
*/
|
|
174
|
+
function insertVariable(varName: string): void {
|
|
175
|
+
if (!editorView) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const insertText = `{{ ${varName} }}`;
|
|
180
|
+
const { from, to } = editorView.state.selection.main;
|
|
181
|
+
|
|
182
|
+
editorView.dispatch({
|
|
183
|
+
changes: { from, to, insert: insertText },
|
|
184
|
+
selection: { anchor: from + insertText.length }
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
editorView.focus();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Initialize CodeMirror editor on mount
|
|
192
|
+
*/
|
|
193
|
+
onMount(() => {
|
|
194
|
+
if (!containerRef) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
editorView = new EditorView({
|
|
199
|
+
state: EditorState.create({
|
|
200
|
+
doc: value,
|
|
201
|
+
extensions: createExtensions()
|
|
202
|
+
}),
|
|
203
|
+
parent: containerRef
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Clean up editor on destroy
|
|
209
|
+
*/
|
|
210
|
+
onDestroy(() => {
|
|
211
|
+
if (editorView) {
|
|
212
|
+
editorView.destroy();
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Update editor content when value prop changes externally
|
|
218
|
+
*/
|
|
219
|
+
$effect(() => {
|
|
220
|
+
if (!editorView) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const currentContent = editorView.state.doc.toString();
|
|
225
|
+
|
|
226
|
+
// Only update if content actually changed and wasn't from internal edit
|
|
227
|
+
if (value !== currentContent && !isInternalUpdate) {
|
|
228
|
+
isInternalUpdate = true;
|
|
229
|
+
editorView.dispatch({
|
|
230
|
+
changes: {
|
|
231
|
+
from: 0,
|
|
232
|
+
to: editorView.state.doc.length,
|
|
233
|
+
insert: value
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
isInternalUpdate = false;
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
</script>
|
|
240
|
+
|
|
241
|
+
<div class="form-template-editor">
|
|
242
|
+
<!-- Hidden input for form submission compatibility -->
|
|
243
|
+
<input
|
|
244
|
+
type="hidden"
|
|
245
|
+
{id}
|
|
246
|
+
name={id}
|
|
247
|
+
{value}
|
|
248
|
+
aria-describedby={ariaDescribedBy}
|
|
249
|
+
aria-required={required}
|
|
250
|
+
/>
|
|
251
|
+
|
|
252
|
+
<!-- CodeMirror container -->
|
|
253
|
+
<div
|
|
254
|
+
bind:this={containerRef}
|
|
255
|
+
class="form-template-editor__container"
|
|
256
|
+
class:form-template-editor__container--dark={darkTheme}
|
|
257
|
+
role="textbox"
|
|
258
|
+
aria-multiline="true"
|
|
259
|
+
aria-label="Template editor"
|
|
260
|
+
></div>
|
|
261
|
+
|
|
262
|
+
<!-- Variable hints section (shown when variables are available) -->
|
|
263
|
+
{#if variableHints.length > 0}
|
|
264
|
+
<div class="form-template-editor__hints">
|
|
265
|
+
<span class="form-template-editor__hints-label">Available variables:</span>
|
|
266
|
+
<div class="form-template-editor__hints-list">
|
|
267
|
+
{#each variableHints as varName (varName)}
|
|
268
|
+
<button
|
|
269
|
+
type="button"
|
|
270
|
+
class="form-template-editor__hint-btn"
|
|
271
|
+
onclick={() => insertVariable(varName)}
|
|
272
|
+
title={`Insert {{ ${varName} }}`}
|
|
273
|
+
>
|
|
274
|
+
<code>{'{{ '}{varName}{' }}'}</code>
|
|
275
|
+
</button>
|
|
276
|
+
{/each}
|
|
277
|
+
</div>
|
|
278
|
+
</div>
|
|
279
|
+
{/if}
|
|
280
|
+
|
|
281
|
+
<!-- Placeholder hint when empty -->
|
|
282
|
+
{#if !value && placeholderExample}
|
|
283
|
+
<div class="form-template-editor__placeholder">
|
|
284
|
+
<span class="form-template-editor__placeholder-label">Example template:</span>
|
|
285
|
+
<code class="form-template-editor__placeholder-example">{placeholderExample}</code>
|
|
286
|
+
</div>
|
|
287
|
+
{/if}
|
|
288
|
+
|
|
289
|
+
<!-- Syntax help -->
|
|
290
|
+
<div class="form-template-editor__help">
|
|
291
|
+
<svg
|
|
292
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
293
|
+
viewBox="0 0 20 20"
|
|
294
|
+
fill="currentColor"
|
|
295
|
+
class="form-template-editor__help-icon"
|
|
296
|
+
>
|
|
297
|
+
<path
|
|
298
|
+
fill-rule="evenodd"
|
|
299
|
+
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"
|
|
300
|
+
clip-rule="evenodd"
|
|
301
|
+
/>
|
|
302
|
+
</svg>
|
|
303
|
+
<span
|
|
304
|
+
>Use <code>{'{{ variable }}'}</code> syntax to insert dynamic values from the data input</span
|
|
305
|
+
>
|
|
306
|
+
</div>
|
|
307
|
+
</div>
|
|
308
|
+
|
|
309
|
+
<style>
|
|
310
|
+
.form-template-editor {
|
|
311
|
+
position: relative;
|
|
312
|
+
width: 100%;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.form-template-editor__container {
|
|
316
|
+
border: 1px solid var(--color-ref-gray-200, #e5e7eb);
|
|
317
|
+
border-radius: 0.5rem;
|
|
318
|
+
overflow: hidden;
|
|
319
|
+
background-color: var(--color-ref-gray-50, #f9fafb);
|
|
320
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
321
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.form-template-editor__container:hover {
|
|
325
|
+
border-color: var(--color-ref-gray-300, #d1d5db);
|
|
326
|
+
background-color: #ffffff;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.form-template-editor__container:focus-within {
|
|
330
|
+
border-color: var(--color-ref-purple-500, #a855f7);
|
|
331
|
+
background-color: #ffffff;
|
|
332
|
+
box-shadow:
|
|
333
|
+
0 0 0 3px rgba(168, 85, 247, 0.12),
|
|
334
|
+
0 1px 2px rgba(0, 0, 0, 0.04);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/* Dark theme overrides */
|
|
338
|
+
.form-template-editor__container--dark {
|
|
339
|
+
background-color: #282c34;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.form-template-editor__container--dark:hover,
|
|
343
|
+
.form-template-editor__container--dark:focus-within {
|
|
344
|
+
background-color: #282c34;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/* CodeMirror styling overrides */
|
|
348
|
+
.form-template-editor__container :global(.cm-editor) {
|
|
349
|
+
border-radius: 0.5rem;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.form-template-editor__container :global(.cm-gutters) {
|
|
353
|
+
background-color: var(--color-ref-gray-100, #f3f4f6);
|
|
354
|
+
border-right: 1px solid var(--color-ref-gray-200, #e5e7eb);
|
|
355
|
+
border-radius: 0.5rem 0 0 0.5rem;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
.form-template-editor__container--dark :global(.cm-gutters) {
|
|
359
|
+
background-color: #21252b;
|
|
360
|
+
border-right-color: #3e4451;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/* Variable hints section */
|
|
364
|
+
.form-template-editor__hints {
|
|
365
|
+
margin-top: 0.625rem;
|
|
366
|
+
padding: 0.625rem;
|
|
367
|
+
background-color: var(--color-ref-purple-50, #faf5ff);
|
|
368
|
+
border: 1px solid var(--color-ref-purple-200, #e9d5ff);
|
|
369
|
+
border-radius: 0.375rem;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.form-template-editor__hints-label {
|
|
373
|
+
display: block;
|
|
374
|
+
font-size: 0.6875rem;
|
|
375
|
+
font-weight: 500;
|
|
376
|
+
color: var(--color-ref-purple-700, #7e22ce);
|
|
377
|
+
text-transform: uppercase;
|
|
378
|
+
letter-spacing: 0.05em;
|
|
379
|
+
margin-bottom: 0.375rem;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
.form-template-editor__hints-list {
|
|
383
|
+
display: flex;
|
|
384
|
+
flex-wrap: wrap;
|
|
385
|
+
gap: 0.375rem;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.form-template-editor__hint-btn {
|
|
389
|
+
padding: 0.25rem 0.5rem;
|
|
390
|
+
background-color: var(--color-ref-purple-100, #f3e8ff);
|
|
391
|
+
border: 1px solid var(--color-ref-purple-300, #d8b4fe);
|
|
392
|
+
border-radius: 0.25rem;
|
|
393
|
+
cursor: pointer;
|
|
394
|
+
transition: all 0.15s ease;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.form-template-editor__hint-btn:hover {
|
|
398
|
+
background-color: var(--color-ref-purple-200, #e9d5ff);
|
|
399
|
+
border-color: var(--color-ref-purple-400, #c084fc);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.form-template-editor__hint-btn:active {
|
|
403
|
+
transform: scale(0.98);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.form-template-editor__hint-btn code {
|
|
407
|
+
font-family: 'JetBrains Mono', 'Fira Code', 'Monaco', 'Menlo', monospace;
|
|
408
|
+
font-size: 0.6875rem;
|
|
409
|
+
color: var(--color-ref-purple-800, #6b21a8);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/* Placeholder hint */
|
|
413
|
+
.form-template-editor__placeholder {
|
|
414
|
+
margin-top: 0.5rem;
|
|
415
|
+
padding: 0.5rem 0.75rem;
|
|
416
|
+
background-color: var(--color-ref-gray-50, #f9fafb);
|
|
417
|
+
border: 1px dashed var(--color-ref-gray-300, #d1d5db);
|
|
418
|
+
border-radius: 0.375rem;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.form-template-editor__placeholder-label {
|
|
422
|
+
display: block;
|
|
423
|
+
font-size: 0.6875rem;
|
|
424
|
+
font-weight: 500;
|
|
425
|
+
color: var(--color-ref-gray-500, #6b7280);
|
|
426
|
+
text-transform: uppercase;
|
|
427
|
+
letter-spacing: 0.05em;
|
|
428
|
+
margin-bottom: 0.25rem;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.form-template-editor__placeholder-example {
|
|
432
|
+
display: block;
|
|
433
|
+
font-family: 'JetBrains Mono', 'Fira Code', 'Monaco', 'Menlo', monospace;
|
|
434
|
+
font-size: 0.75rem;
|
|
435
|
+
color: var(--color-ref-gray-700, #374151);
|
|
436
|
+
word-break: break-all;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/* Help text */
|
|
440
|
+
.form-template-editor__help {
|
|
441
|
+
display: flex;
|
|
442
|
+
align-items: flex-start;
|
|
443
|
+
gap: 0.375rem;
|
|
444
|
+
margin-top: 0.5rem;
|
|
445
|
+
font-size: 0.6875rem;
|
|
446
|
+
color: var(--color-ref-gray-500, #6b7280);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.form-template-editor__help-icon {
|
|
450
|
+
width: 0.875rem;
|
|
451
|
+
height: 0.875rem;
|
|
452
|
+
flex-shrink: 0;
|
|
453
|
+
margin-top: 0.0625rem;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
.form-template-editor__help code {
|
|
457
|
+
padding: 0.0625rem 0.25rem;
|
|
458
|
+
background-color: var(--color-ref-gray-100, #f3f4f6);
|
|
459
|
+
border-radius: 0.1875rem;
|
|
460
|
+
font-family: 'JetBrains Mono', 'Fira Code', 'Monaco', 'Menlo', monospace;
|
|
461
|
+
font-size: 0.625rem;
|
|
462
|
+
}
|
|
463
|
+
</style>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
/** Field identifier */
|
|
3
|
+
id: string;
|
|
4
|
+
/** Current template value */
|
|
5
|
+
value: string;
|
|
6
|
+
/** Placeholder text shown when empty */
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
/** Whether the field is required */
|
|
9
|
+
required?: boolean;
|
|
10
|
+
/** Whether to use dark theme */
|
|
11
|
+
darkTheme?: boolean;
|
|
12
|
+
/** Editor height in pixels or CSS value */
|
|
13
|
+
height?: string;
|
|
14
|
+
/** Available variable names for hints (optional) */
|
|
15
|
+
variableHints?: string[];
|
|
16
|
+
/** Placeholder variable example for the hint */
|
|
17
|
+
placeholderExample?: string;
|
|
18
|
+
/** ARIA description ID */
|
|
19
|
+
ariaDescribedBy?: string;
|
|
20
|
+
/** Callback when value changes */
|
|
21
|
+
onChange: (value: string) => void;
|
|
22
|
+
}
|
|
23
|
+
declare const FormTemplateEditor: import("svelte").Component<Props, {}, "">;
|
|
24
|
+
type FormTemplateEditor = ReturnType<typeof FormTemplateEditor>;
|
|
25
|
+
export default FormTemplateEditor;
|
|
@@ -35,7 +35,11 @@ export { default as FormFieldWrapper } from "./FormFieldWrapper.svelte";
|
|
|
35
35
|
export { default as FormTextField } from "./FormTextField.svelte";
|
|
36
36
|
export { default as FormTextarea } from "./FormTextarea.svelte";
|
|
37
37
|
export { default as FormNumberField } from "./FormNumberField.svelte";
|
|
38
|
+
export { default as FormRangeField } from "./FormRangeField.svelte";
|
|
38
39
|
export { default as FormToggle } from "./FormToggle.svelte";
|
|
39
40
|
export { default as FormSelect } from "./FormSelect.svelte";
|
|
40
41
|
export { default as FormCheckboxGroup } from "./FormCheckboxGroup.svelte";
|
|
41
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";
|
|
@@ -39,7 +39,11 @@ export { default as FormFieldWrapper } from "./FormFieldWrapper.svelte";
|
|
|
39
39
|
export { default as FormTextField } from "./FormTextField.svelte";
|
|
40
40
|
export { default as FormTextarea } from "./FormTextarea.svelte";
|
|
41
41
|
export { default as FormNumberField } from "./FormNumberField.svelte";
|
|
42
|
+
export { default as FormRangeField } from "./FormRangeField.svelte";
|
|
42
43
|
export { default as FormToggle } from "./FormToggle.svelte";
|
|
43
44
|
export { default as FormSelect } from "./FormSelect.svelte";
|
|
44
45
|
export { default as FormCheckboxGroup } from "./FormCheckboxGroup.svelte";
|
|
45
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";
|
|
@@ -14,8 +14,13 @@ export type FieldType = "string" | "number" | "integer" | "boolean" | "select" |
|
|
|
14
14
|
* Field format for specialized rendering
|
|
15
15
|
* - multiline: Renders as textarea
|
|
16
16
|
* - hidden: Field is hidden from UI but included in form submission
|
|
17
|
+
* - range: Renders as range slider for numeric values
|
|
18
|
+
* - json: Renders as CodeMirror JSON editor
|
|
19
|
+
* - code: Alias for json, renders as CodeMirror editor
|
|
20
|
+
* - markdown: Renders as SimpleMDE Markdown editor
|
|
21
|
+
* - template: Renders as CodeMirror editor with Twig/Liquid syntax highlighting
|
|
17
22
|
*/
|
|
18
|
-
export type FieldFormat = "multiline" | "hidden" | string;
|
|
23
|
+
export type FieldFormat = "multiline" | "hidden" | "range" | "json" | "code" | "markdown" | "template" | string;
|
|
19
24
|
/**
|
|
20
25
|
* Option type for select and checkbox group fields
|
|
21
26
|
*/
|
|
@@ -84,6 +89,19 @@ export interface ToggleFieldProps extends BaseFieldProps {
|
|
|
84
89
|
offLabel?: string;
|
|
85
90
|
onChange: (value: boolean) => void;
|
|
86
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Properties for range slider fields
|
|
94
|
+
*/
|
|
95
|
+
export interface RangeFieldProps extends BaseFieldProps {
|
|
96
|
+
value: number | string;
|
|
97
|
+
/** Minimum allowed value */
|
|
98
|
+
min?: number;
|
|
99
|
+
/** Maximum allowed value */
|
|
100
|
+
max?: number;
|
|
101
|
+
/** Step increment for the slider */
|
|
102
|
+
step?: number;
|
|
103
|
+
onChange: (value: number) => void;
|
|
104
|
+
}
|
|
87
105
|
/**
|
|
88
106
|
* Properties for select dropdown fields
|
|
89
107
|
*/
|
|
@@ -117,6 +135,55 @@ export interface ArrayFieldProps extends BaseFieldProps {
|
|
|
117
135
|
addLabel?: string;
|
|
118
136
|
onChange: (value: unknown[]) => void;
|
|
119
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Properties for code editor fields (CodeMirror-based)
|
|
140
|
+
*/
|
|
141
|
+
export interface CodeEditorFieldProps extends BaseFieldProps {
|
|
142
|
+
/** Current value - can be string (raw JSON) or object */
|
|
143
|
+
value: unknown;
|
|
144
|
+
/** Whether to use dark theme */
|
|
145
|
+
darkTheme?: boolean;
|
|
146
|
+
/** Editor height in pixels or CSS value */
|
|
147
|
+
height?: string;
|
|
148
|
+
/** Whether to auto-format JSON on blur */
|
|
149
|
+
autoFormat?: boolean;
|
|
150
|
+
/** Callback when value changes */
|
|
151
|
+
onChange: (value: unknown) => void;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Properties for markdown editor fields (SimpleMDE-based)
|
|
155
|
+
*/
|
|
156
|
+
export interface MarkdownEditorFieldProps extends BaseFieldProps {
|
|
157
|
+
/** Current value (markdown string) */
|
|
158
|
+
value: string;
|
|
159
|
+
/** Editor height in pixels or CSS value */
|
|
160
|
+
height?: string;
|
|
161
|
+
/** Whether to show the toolbar */
|
|
162
|
+
showToolbar?: boolean;
|
|
163
|
+
/** Whether to show the status bar */
|
|
164
|
+
showStatusBar?: boolean;
|
|
165
|
+
/** Whether to enable spell checking */
|
|
166
|
+
spellChecker?: boolean;
|
|
167
|
+
/** Callback when value changes */
|
|
168
|
+
onChange: (value: string) => void;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Properties for template editor fields (CodeMirror with Twig/Liquid syntax)
|
|
172
|
+
*/
|
|
173
|
+
export interface TemplateEditorFieldProps extends BaseFieldProps {
|
|
174
|
+
/** Current template value */
|
|
175
|
+
value: string;
|
|
176
|
+
/** Whether to use dark theme */
|
|
177
|
+
darkTheme?: boolean;
|
|
178
|
+
/** Editor height in pixels or CSS value */
|
|
179
|
+
height?: string;
|
|
180
|
+
/** Available variable names for hints (optional) */
|
|
181
|
+
variableHints?: string[];
|
|
182
|
+
/** Placeholder variable example for the hint */
|
|
183
|
+
placeholderExample?: string;
|
|
184
|
+
/** Callback when value changes */
|
|
185
|
+
onChange: (value: string) => void;
|
|
186
|
+
}
|
|
120
187
|
/**
|
|
121
188
|
* Field schema definition derived from JSON Schema property
|
|
122
189
|
* Used to determine which field component to render
|
|
@@ -144,6 +211,8 @@ export interface FieldSchema {
|
|
|
144
211
|
minimum?: number;
|
|
145
212
|
/** Maximum value for numbers */
|
|
146
213
|
maximum?: number;
|
|
214
|
+
/** Step increment for number/range inputs */
|
|
215
|
+
step?: number;
|
|
147
216
|
/** Minimum length for strings */
|
|
148
217
|
minLength?: number;
|
|
149
218
|
/** Maximum length for strings */
|
|
@@ -10,24 +10,12 @@
|
|
|
10
10
|
|
|
11
11
|
<script lang="ts">
|
|
12
12
|
import { Position, Handle } from '@xyflow/svelte';
|
|
13
|
-
import type { WorkflowNode, NodePort } from '../../types/index.js';
|
|
13
|
+
import type { WorkflowNode, NodePort, Branch } from '../../types/index.js';
|
|
14
14
|
import Icon from '@iconify/svelte';
|
|
15
15
|
import { getNodeIcon } from '../../utils/icons.js';
|
|
16
16
|
import { getDataTypeColorToken, getCategoryColorToken } from '../../utils/colors.js';
|
|
17
17
|
import { connectedHandles } from '../../stores/workflowStore.js';
|
|
18
18
|
|
|
19
|
-
/**
|
|
20
|
-
* Branch interface for gateway nodes
|
|
21
|
-
* - name: Internal identifier used for handle IDs and connections
|
|
22
|
-
* - label: Display label shown in the UI (optional, defaults to name)
|
|
23
|
-
* - value: Optional value associated with the branch (e.g., for Switch matching)
|
|
24
|
-
*/
|
|
25
|
-
interface Branch {
|
|
26
|
-
name: string;
|
|
27
|
-
label?: string;
|
|
28
|
-
value?: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
19
|
interface Props {
|
|
32
20
|
data: WorkflowNode['data'] & {
|
|
33
21
|
nodeId?: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import './styles/base.css';
|
|
6
6
|
import './registry/builtinNodes.js';
|
|
7
|
-
export type { NodeCategory, NodeDataType, NodePort, NodeMetadata, NodeExtensions, NodeUIExtensions, ConfigValues, WorkflowNode, WorkflowEdge, Workflow, ApiResponse, NodesResponse, WorkflowResponse, WorkflowsResponse, ExecutionStatus, ExecutionResult, FlowDropConfig, WorkflowEvents, BuiltinNodeType } from './types/index.js';
|
|
7
|
+
export type { NodeCategory, NodeDataType, NodePort, DynamicPort, Branch, NodeMetadata, NodeExtensions, NodeUIExtensions, ConfigValues, WorkflowNode, WorkflowEdge, Workflow, ApiResponse, NodesResponse, WorkflowResponse, WorkflowsResponse, ExecutionStatus, ExecutionResult, FlowDropConfig, WorkflowEvents, BuiltinNodeType } from './types/index.js';
|
|
8
8
|
export type { WorkflowEditorConfig, EditorFeatures, UIConfig, APIConfig, ExecutionConfig, StorageConfig } from './types/config.js';
|
|
9
9
|
export type { AuthProvider, StaticAuthConfig, CallbackAuthConfig } from './types/auth.js';
|
|
10
10
|
export { StaticAuthProvider, CallbackAuthProvider, NoAuthProvider } from './types/auth.js';
|