@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.
- package/README.md +52 -62
- package/dist/components/App.svelte +12 -2
- package/dist/components/ConfigForm.svelte +500 -9
- package/dist/components/ConfigForm.svelte.d.ts +2 -0
- package/dist/components/ConfigModal.svelte +4 -70
- package/dist/components/ConfigPanel.svelte +4 -9
- package/dist/components/EdgeRefresher.svelte +41 -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 +30 -0
- package/dist/components/WorkflowEditor.svelte.d.ts +3 -1
- package/dist/components/form/FormCheckboxGroup.svelte +2 -9
- package/dist/components/form/FormField.svelte +1 -12
- package/dist/components/form/FormFieldWrapper.svelte +2 -10
- package/dist/components/form/FormFieldWrapper.svelte.d.ts +1 -1
- package/dist/components/form/FormMarkdownEditor.svelte +0 -2
- 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/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 -14
- package/dist/components/form/index.js +14 -14
- package/dist/components/form/types.d.ts +2 -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/SimpleNode.svelte +92 -142
- package/dist/components/nodes/SquareNode.svelte +75 -58
- package/dist/components/nodes/WorkflowNode.svelte +1 -3
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/services/dynamicSchemaService.d.ts +108 -0
- package/dist/services/dynamicSchemaService.js +445 -0
- package/dist/styles/base.css +1 -1
- package/dist/types/index.d.ts +213 -0
- 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:
|
|
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;
|
|
@@ -128,9 +128,12 @@
|
|
|
128
128
|
</script>
|
|
129
129
|
|
|
130
130
|
<div class="universal-node">
|
|
131
|
-
<!-- Render the node component dynamically -->
|
|
132
|
-
|
|
133
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
@@ -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 ===
|
|
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
|
|
13
|
-
import { normalizeOptions, type FieldOption } from
|
|
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
|
-
|
|
@@ -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 =
|
|
31
|
-
offLabel =
|
|
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
|
|
33
|
-
export { default as FormField } from
|
|
34
|
-
export { default as FormFieldWrapper } from
|
|
35
|
-
export { default as FormTextField } from
|
|
36
|
-
export { default as FormTextarea } from
|
|
37
|
-
export { default as FormNumberField } from
|
|
38
|
-
export { default as FormRangeField } from
|
|
39
|
-
export { default as FormToggle } from
|
|
40
|
-
export { default as FormSelect } from
|
|
41
|
-
export { default as FormCheckboxGroup } from
|
|
42
|
-
export { default as FormArray } from
|
|
43
|
-
export { default as FormCodeEditor } from
|
|
44
|
-
export { default as FormMarkdownEditor } from
|
|
45
|
-
export { default as FormTemplateEditor } from
|
|
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
|
|
33
|
+
export * from './types.js';
|
|
34
34
|
// Main factory component
|
|
35
|
-
export { default as FormField } from
|
|
35
|
+
export { default as FormField } from './FormField.svelte';
|
|
36
36
|
// Wrapper component
|
|
37
|
-
export { default as FormFieldWrapper } from
|
|
37
|
+
export { default as FormFieldWrapper } from './FormFieldWrapper.svelte';
|
|
38
38
|
// Individual field components
|
|
39
|
-
export { default as FormTextField } from
|
|
40
|
-
export { default as FormTextarea } from
|
|
41
|
-
export { default as FormNumberField } from
|
|
42
|
-
export { default as FormRangeField } from
|
|
43
|
-
export { default as FormToggle } from
|
|
44
|
-
export { default as FormSelect } from
|
|
45
|
-
export { default as FormCheckboxGroup } from
|
|
46
|
-
export { default as FormArray } from
|
|
47
|
-
export { default as FormCodeEditor } from
|
|
48
|
-
export { default as FormMarkdownEditor } from
|
|
49
|
-
export { default as FormTemplateEditor } from
|
|
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 =
|
|
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 =
|
|
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] ===
|
|
12
|
+
return options.length > 0 && typeof options[0] === 'object' && 'value' in options[0];
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
15
|
* Normalize options to FieldOption format
|