@d34dman/flowdrop 0.0.27 → 0.0.29
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/SchemaForm.svelte +492 -0
- package/dist/components/SchemaForm.svelte.d.ts +65 -0
- package/dist/components/form/FormFieldLight.svelte +422 -0
- package/dist/components/form/FormFieldLight.svelte.d.ts +18 -0
- package/dist/components/form/types.d.ts +96 -0
- package/dist/core/index.d.ts +39 -0
- package/dist/core/index.js +50 -0
- package/dist/display/index.d.ts +29 -0
- package/dist/display/index.js +36 -0
- package/dist/editor/index.d.ts +78 -0
- package/dist/editor/index.js +117 -0
- package/dist/form/code.d.ts +100 -0
- package/dist/form/code.js +153 -0
- package/dist/form/fieldRegistry.d.ts +163 -0
- package/dist/form/fieldRegistry.js +175 -0
- package/dist/form/full.d.ts +53 -0
- package/dist/form/full.js +75 -0
- package/dist/form/index.d.ts +57 -0
- package/dist/form/index.js +68 -0
- package/dist/form/markdown.d.ts +68 -0
- package/dist/form/markdown.js +93 -0
- package/dist/index.d.ts +31 -64
- package/dist/index.js +49 -79
- package/package.json +47 -4
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
SchemaForm Component
|
|
3
|
+
|
|
4
|
+
A standalone form generator that creates dynamic forms from JSON Schema definitions.
|
|
5
|
+
Designed for external use without coupling to FlowDrop workflow nodes.
|
|
6
|
+
|
|
7
|
+
Features:
|
|
8
|
+
- Dynamic form generation from JSON Schema
|
|
9
|
+
- Two-way binding with value updates via onChange callback
|
|
10
|
+
- Optional save/cancel action buttons
|
|
11
|
+
- Support for all standard JSON Schema field types
|
|
12
|
+
- Accessible form controls with ARIA attributes
|
|
13
|
+
|
|
14
|
+
@example
|
|
15
|
+
```svelte
|
|
16
|
+
<script lang="ts">
|
|
17
|
+
import { SchemaForm } from "flowdrop";
|
|
18
|
+
import type { ConfigSchema } from "flowdrop";
|
|
19
|
+
|
|
20
|
+
const schema: ConfigSchema = {
|
|
21
|
+
type: "object",
|
|
22
|
+
properties: {
|
|
23
|
+
name: { type: "string", title: "Name", description: "Enter your name" },
|
|
24
|
+
age: { type: "number", title: "Age", minimum: 0, maximum: 120 },
|
|
25
|
+
active: { type: "boolean", title: "Active", default: true }
|
|
26
|
+
},
|
|
27
|
+
required: ["name"]
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
let values = $state({ name: "", age: 25, active: true });
|
|
31
|
+
|
|
32
|
+
function handleChange(newValues: Record<string, unknown>) {
|
|
33
|
+
values = newValues;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function handleSave(finalValues: Record<string, unknown>) {
|
|
37
|
+
console.log("Saved:", finalValues);
|
|
38
|
+
}
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<SchemaForm
|
|
42
|
+
{schema}
|
|
43
|
+
{values}
|
|
44
|
+
onChange={handleChange}
|
|
45
|
+
showActions={true}
|
|
46
|
+
onSave={handleSave}
|
|
47
|
+
onCancel={() => console.log("Cancelled")}
|
|
48
|
+
/>
|
|
49
|
+
```
|
|
50
|
+
-->
|
|
51
|
+
|
|
52
|
+
<script lang="ts">
|
|
53
|
+
import Icon from "@iconify/svelte";
|
|
54
|
+
import type { ConfigSchema } from "../types/index.js";
|
|
55
|
+
import { FormField } from "./form/index.js";
|
|
56
|
+
import type { FieldSchema } from "./form/index.js";
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Props interface for SchemaForm component
|
|
60
|
+
*/
|
|
61
|
+
interface Props {
|
|
62
|
+
/**
|
|
63
|
+
* JSON Schema definition for the form.
|
|
64
|
+
* Should follow JSON Schema draft-07 format with type: "object".
|
|
65
|
+
*/
|
|
66
|
+
schema: ConfigSchema;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Current form values as key-value pairs.
|
|
70
|
+
* Keys should correspond to properties defined in the schema.
|
|
71
|
+
*/
|
|
72
|
+
values?: Record<string, unknown>;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Callback fired whenever any field value changes.
|
|
76
|
+
* Receives the complete updated values object.
|
|
77
|
+
* @param values - Updated form values
|
|
78
|
+
*/
|
|
79
|
+
onChange?: (values: Record<string, unknown>) => void;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Whether to display Save and Cancel action buttons.
|
|
83
|
+
* @default false
|
|
84
|
+
*/
|
|
85
|
+
showActions?: boolean;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Label for the save button.
|
|
89
|
+
* @default "Save"
|
|
90
|
+
*/
|
|
91
|
+
saveLabel?: string;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Label for the cancel button.
|
|
95
|
+
* @default "Cancel"
|
|
96
|
+
*/
|
|
97
|
+
cancelLabel?: string;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Callback fired when the Save button is clicked.
|
|
101
|
+
* Receives the final form values.
|
|
102
|
+
* @param values - Final form values
|
|
103
|
+
*/
|
|
104
|
+
onSave?: (values: Record<string, unknown>) => void;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Callback fired when the Cancel button is clicked.
|
|
108
|
+
*/
|
|
109
|
+
onCancel?: () => void;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Whether the form is in a loading state.
|
|
113
|
+
* Disables all inputs when true.
|
|
114
|
+
* @default false
|
|
115
|
+
*/
|
|
116
|
+
loading?: boolean;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Whether the form is disabled.
|
|
120
|
+
* @default false
|
|
121
|
+
*/
|
|
122
|
+
disabled?: boolean;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Custom CSS class for the form container.
|
|
126
|
+
*/
|
|
127
|
+
class?: string;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
let {
|
|
131
|
+
schema,
|
|
132
|
+
values = {},
|
|
133
|
+
onChange,
|
|
134
|
+
showActions = false,
|
|
135
|
+
saveLabel = "Save",
|
|
136
|
+
cancelLabel = "Cancel",
|
|
137
|
+
onSave,
|
|
138
|
+
onCancel,
|
|
139
|
+
loading = false,
|
|
140
|
+
disabled = false,
|
|
141
|
+
class: className = ""
|
|
142
|
+
}: Props = $props();
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Internal reactive state for form values
|
|
146
|
+
*/
|
|
147
|
+
let formValues = $state<Record<string, unknown>>({});
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Initialize form values when schema or values change
|
|
151
|
+
* Merges default values from schema with provided values
|
|
152
|
+
*/
|
|
153
|
+
$effect(() => {
|
|
154
|
+
if (schema?.properties) {
|
|
155
|
+
const mergedValues: Record<string, unknown> = {};
|
|
156
|
+
Object.entries(schema.properties).forEach(([key, field]) => {
|
|
157
|
+
const fieldConfig = field as Record<string, unknown>;
|
|
158
|
+
// Use provided value if available, otherwise use schema default
|
|
159
|
+
mergedValues[key] = values[key] !== undefined ? values[key] : fieldConfig.default;
|
|
160
|
+
});
|
|
161
|
+
formValues = mergedValues;
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Check if a field is required based on schema
|
|
167
|
+
* @param key - Field key to check
|
|
168
|
+
* @returns Whether the field is required
|
|
169
|
+
*/
|
|
170
|
+
function isFieldRequired(key: string): boolean {
|
|
171
|
+
if (!schema?.required) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
return schema.required.includes(key);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Handle field value changes from FormField components
|
|
179
|
+
* Updates internal state and fires onChange callback
|
|
180
|
+
* @param key - Field key that changed
|
|
181
|
+
* @param value - New field value
|
|
182
|
+
*/
|
|
183
|
+
function handleFieldChange(key: string, value: unknown): void {
|
|
184
|
+
formValues[key] = value;
|
|
185
|
+
|
|
186
|
+
// Notify parent of the change
|
|
187
|
+
if (onChange) {
|
|
188
|
+
onChange({ ...formValues });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Handle form submission
|
|
194
|
+
* Collects all form values and fires onSave callback
|
|
195
|
+
*/
|
|
196
|
+
function handleSave(): void {
|
|
197
|
+
if (loading || disabled) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Collect all form values including hidden fields
|
|
202
|
+
const form = document.querySelector(".schema-form");
|
|
203
|
+
const updatedValues: Record<string, unknown> = { ...formValues };
|
|
204
|
+
|
|
205
|
+
if (form) {
|
|
206
|
+
const inputs = form.querySelectorAll("input, select, textarea");
|
|
207
|
+
inputs.forEach((input: Element) => {
|
|
208
|
+
const inputEl = input as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
|
|
209
|
+
if (inputEl.id) {
|
|
210
|
+
if (inputEl instanceof HTMLInputElement && inputEl.type === "checkbox") {
|
|
211
|
+
updatedValues[inputEl.id] = inputEl.checked;
|
|
212
|
+
} else if (
|
|
213
|
+
inputEl instanceof HTMLInputElement &&
|
|
214
|
+
(inputEl.type === "number" || inputEl.type === "range")
|
|
215
|
+
) {
|
|
216
|
+
updatedValues[inputEl.id] = inputEl.value ? Number(inputEl.value) : inputEl.value;
|
|
217
|
+
} else if (inputEl instanceof HTMLInputElement && inputEl.type === "hidden") {
|
|
218
|
+
// Parse hidden field values that might be JSON
|
|
219
|
+
try {
|
|
220
|
+
const parsed = JSON.parse(inputEl.value);
|
|
221
|
+
updatedValues[inputEl.id] = parsed;
|
|
222
|
+
} catch {
|
|
223
|
+
// If not JSON, use raw value
|
|
224
|
+
updatedValues[inputEl.id] = inputEl.value;
|
|
225
|
+
}
|
|
226
|
+
} else {
|
|
227
|
+
updatedValues[inputEl.id] = inputEl.value;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Preserve hidden field values from original values if not collected from form
|
|
234
|
+
if (values && schema?.properties) {
|
|
235
|
+
Object.entries(schema.properties).forEach(
|
|
236
|
+
([key, property]: [string, Record<string, unknown>]) => {
|
|
237
|
+
if (property.format === "hidden" && !(key in updatedValues) && key in values) {
|
|
238
|
+
updatedValues[key] = values[key];
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (onSave) {
|
|
245
|
+
onSave(updatedValues);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Handle cancel action
|
|
251
|
+
*/
|
|
252
|
+
function handleCancel(): void {
|
|
253
|
+
if (onCancel) {
|
|
254
|
+
onCancel();
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Convert ConfigProperty to FieldSchema for FormField component
|
|
260
|
+
* @param property - Schema property definition
|
|
261
|
+
* @returns FieldSchema compatible with FormField
|
|
262
|
+
*/
|
|
263
|
+
function toFieldSchema(property: Record<string, unknown>): FieldSchema {
|
|
264
|
+
return property as FieldSchema;
|
|
265
|
+
}
|
|
266
|
+
</script>
|
|
267
|
+
|
|
268
|
+
{#if schema?.properties}
|
|
269
|
+
<form
|
|
270
|
+
class="schema-form {className}"
|
|
271
|
+
class:schema-form--loading={loading}
|
|
272
|
+
class:schema-form--disabled={disabled}
|
|
273
|
+
onsubmit={(e) => {
|
|
274
|
+
e.preventDefault();
|
|
275
|
+
handleSave();
|
|
276
|
+
}}
|
|
277
|
+
>
|
|
278
|
+
<div class="schema-form__fields">
|
|
279
|
+
{#each Object.entries(schema.properties) as [key, field], index (key)}
|
|
280
|
+
{@const fieldSchema = toFieldSchema(field as Record<string, unknown>)}
|
|
281
|
+
{@const required = isFieldRequired(key)}
|
|
282
|
+
|
|
283
|
+
<FormField
|
|
284
|
+
fieldKey={key}
|
|
285
|
+
schema={fieldSchema}
|
|
286
|
+
value={formValues[key]}
|
|
287
|
+
{required}
|
|
288
|
+
animationIndex={index}
|
|
289
|
+
onChange={(val) => handleFieldChange(key, val)}
|
|
290
|
+
/>
|
|
291
|
+
{/each}
|
|
292
|
+
</div>
|
|
293
|
+
|
|
294
|
+
{#if showActions}
|
|
295
|
+
<div class="schema-form__footer">
|
|
296
|
+
<button
|
|
297
|
+
type="button"
|
|
298
|
+
class="schema-form__button schema-form__button--secondary"
|
|
299
|
+
onclick={handleCancel}
|
|
300
|
+
disabled={loading}
|
|
301
|
+
>
|
|
302
|
+
<Icon icon="heroicons:x-mark" class="schema-form__button-icon" />
|
|
303
|
+
<span>{cancelLabel}</span>
|
|
304
|
+
</button>
|
|
305
|
+
<button
|
|
306
|
+
type="submit"
|
|
307
|
+
class="schema-form__button schema-form__button--primary"
|
|
308
|
+
disabled={loading || disabled}
|
|
309
|
+
>
|
|
310
|
+
{#if loading}
|
|
311
|
+
<span class="schema-form__button-spinner"></span>
|
|
312
|
+
{:else}
|
|
313
|
+
<Icon icon="heroicons:check" class="schema-form__button-icon" />
|
|
314
|
+
{/if}
|
|
315
|
+
<span>{saveLabel}</span>
|
|
316
|
+
</button>
|
|
317
|
+
</div>
|
|
318
|
+
{/if}
|
|
319
|
+
</form>
|
|
320
|
+
{:else}
|
|
321
|
+
<div class="schema-form__empty">
|
|
322
|
+
<div class="schema-form__empty-icon">
|
|
323
|
+
<Icon icon="heroicons:document-text" />
|
|
324
|
+
</div>
|
|
325
|
+
<p class="schema-form__empty-text">No schema properties defined.</p>
|
|
326
|
+
</div>
|
|
327
|
+
{/if}
|
|
328
|
+
|
|
329
|
+
<style>
|
|
330
|
+
/* ============================================
|
|
331
|
+
SCHEMA FORM - Container Styles
|
|
332
|
+
============================================ */
|
|
333
|
+
|
|
334
|
+
.schema-form {
|
|
335
|
+
display: flex;
|
|
336
|
+
flex-direction: column;
|
|
337
|
+
gap: 1.5rem;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.schema-form--loading,
|
|
341
|
+
.schema-form--disabled {
|
|
342
|
+
opacity: 0.7;
|
|
343
|
+
pointer-events: none;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.schema-form__fields {
|
|
347
|
+
display: flex;
|
|
348
|
+
flex-direction: column;
|
|
349
|
+
gap: 1.25rem;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/* ============================================
|
|
353
|
+
FOOTER ACTIONS
|
|
354
|
+
============================================ */
|
|
355
|
+
|
|
356
|
+
.schema-form__footer {
|
|
357
|
+
display: flex;
|
|
358
|
+
gap: 0.75rem;
|
|
359
|
+
justify-content: flex-end;
|
|
360
|
+
padding-top: 1rem;
|
|
361
|
+
border-top: 1px solid var(--color-ref-gray-100, #f3f4f6);
|
|
362
|
+
margin-top: 0.5rem;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
.schema-form__button {
|
|
366
|
+
display: inline-flex;
|
|
367
|
+
align-items: center;
|
|
368
|
+
justify-content: center;
|
|
369
|
+
gap: 0.5rem;
|
|
370
|
+
padding: 0.625rem 1rem;
|
|
371
|
+
border-radius: 0.5rem;
|
|
372
|
+
font-size: 0.875rem;
|
|
373
|
+
font-weight: 600;
|
|
374
|
+
font-family: inherit;
|
|
375
|
+
cursor: pointer;
|
|
376
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
377
|
+
border: 1px solid transparent;
|
|
378
|
+
min-height: 2.5rem;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
.schema-form__button:disabled {
|
|
382
|
+
opacity: 0.5;
|
|
383
|
+
cursor: not-allowed;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.schema-form__button :global(svg) {
|
|
387
|
+
width: 1rem;
|
|
388
|
+
height: 1rem;
|
|
389
|
+
flex-shrink: 0;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.schema-form__button--secondary {
|
|
393
|
+
background-color: #ffffff;
|
|
394
|
+
border-color: var(--color-ref-gray-200, #e5e7eb);
|
|
395
|
+
color: var(--color-ref-gray-700, #374151);
|
|
396
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.schema-form__button--secondary:hover:not(:disabled) {
|
|
400
|
+
background-color: var(--color-ref-gray-50, #f9fafb);
|
|
401
|
+
border-color: var(--color-ref-gray-300, #d1d5db);
|
|
402
|
+
color: var(--color-ref-gray-900, #111827);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.schema-form__button--secondary:focus-visible {
|
|
406
|
+
outline: none;
|
|
407
|
+
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.schema-form__button--primary {
|
|
411
|
+
background: linear-gradient(
|
|
412
|
+
135deg,
|
|
413
|
+
var(--color-ref-blue-500, #3b82f6) 0%,
|
|
414
|
+
var(--color-ref-blue-600, #2563eb) 100%
|
|
415
|
+
);
|
|
416
|
+
color: #ffffff;
|
|
417
|
+
box-shadow:
|
|
418
|
+
0 1px 3px rgba(59, 130, 246, 0.3),
|
|
419
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.schema-form__button--primary:hover:not(:disabled) {
|
|
423
|
+
background: linear-gradient(
|
|
424
|
+
135deg,
|
|
425
|
+
var(--color-ref-blue-600, #2563eb) 0%,
|
|
426
|
+
var(--color-ref-blue-700, #1d4ed8) 100%
|
|
427
|
+
);
|
|
428
|
+
box-shadow:
|
|
429
|
+
0 4px 12px rgba(59, 130, 246, 0.35),
|
|
430
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.1);
|
|
431
|
+
transform: translateY(-1px);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
.schema-form__button--primary:active:not(:disabled) {
|
|
435
|
+
transform: translateY(0);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.schema-form__button--primary:focus-visible {
|
|
439
|
+
outline: none;
|
|
440
|
+
box-shadow:
|
|
441
|
+
0 0 0 3px rgba(59, 130, 246, 0.4),
|
|
442
|
+
0 4px 12px rgba(59, 130, 246, 0.35);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
.schema-form__button-spinner {
|
|
446
|
+
width: 1rem;
|
|
447
|
+
height: 1rem;
|
|
448
|
+
border: 2px solid rgba(255, 255, 255, 0.3);
|
|
449
|
+
border-top-color: white;
|
|
450
|
+
border-radius: 50%;
|
|
451
|
+
animation: schema-form-spin 0.6s linear infinite;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
@keyframes schema-form-spin {
|
|
455
|
+
to {
|
|
456
|
+
transform: rotate(360deg);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/* ============================================
|
|
461
|
+
EMPTY STATE
|
|
462
|
+
============================================ */
|
|
463
|
+
|
|
464
|
+
.schema-form__empty {
|
|
465
|
+
display: flex;
|
|
466
|
+
flex-direction: column;
|
|
467
|
+
align-items: center;
|
|
468
|
+
justify-content: center;
|
|
469
|
+
padding: 3rem 1.5rem;
|
|
470
|
+
text-align: center;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
.schema-form__empty-icon {
|
|
474
|
+
width: 3rem;
|
|
475
|
+
height: 3rem;
|
|
476
|
+
margin-bottom: 1rem;
|
|
477
|
+
color: var(--color-ref-gray-300, #d1d5db);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
.schema-form__empty-icon :global(svg) {
|
|
481
|
+
width: 100%;
|
|
482
|
+
height: 100%;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
.schema-form__empty-text {
|
|
486
|
+
margin: 0;
|
|
487
|
+
font-size: 0.875rem;
|
|
488
|
+
color: var(--color-ref-gray-500, #6b7280);
|
|
489
|
+
font-style: italic;
|
|
490
|
+
line-height: 1.5;
|
|
491
|
+
}
|
|
492
|
+
</style>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { ConfigSchema } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Props interface for SchemaForm component
|
|
4
|
+
*/
|
|
5
|
+
interface Props {
|
|
6
|
+
/**
|
|
7
|
+
* JSON Schema definition for the form.
|
|
8
|
+
* Should follow JSON Schema draft-07 format with type: "object".
|
|
9
|
+
*/
|
|
10
|
+
schema: ConfigSchema;
|
|
11
|
+
/**
|
|
12
|
+
* Current form values as key-value pairs.
|
|
13
|
+
* Keys should correspond to properties defined in the schema.
|
|
14
|
+
*/
|
|
15
|
+
values?: Record<string, unknown>;
|
|
16
|
+
/**
|
|
17
|
+
* Callback fired whenever any field value changes.
|
|
18
|
+
* Receives the complete updated values object.
|
|
19
|
+
* @param values - Updated form values
|
|
20
|
+
*/
|
|
21
|
+
onChange?: (values: Record<string, unknown>) => void;
|
|
22
|
+
/**
|
|
23
|
+
* Whether to display Save and Cancel action buttons.
|
|
24
|
+
* @default false
|
|
25
|
+
*/
|
|
26
|
+
showActions?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Label for the save button.
|
|
29
|
+
* @default "Save"
|
|
30
|
+
*/
|
|
31
|
+
saveLabel?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Label for the cancel button.
|
|
34
|
+
* @default "Cancel"
|
|
35
|
+
*/
|
|
36
|
+
cancelLabel?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Callback fired when the Save button is clicked.
|
|
39
|
+
* Receives the final form values.
|
|
40
|
+
* @param values - Final form values
|
|
41
|
+
*/
|
|
42
|
+
onSave?: (values: Record<string, unknown>) => void;
|
|
43
|
+
/**
|
|
44
|
+
* Callback fired when the Cancel button is clicked.
|
|
45
|
+
*/
|
|
46
|
+
onCancel?: () => void;
|
|
47
|
+
/**
|
|
48
|
+
* Whether the form is in a loading state.
|
|
49
|
+
* Disables all inputs when true.
|
|
50
|
+
* @default false
|
|
51
|
+
*/
|
|
52
|
+
loading?: boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Whether the form is disabled.
|
|
55
|
+
* @default false
|
|
56
|
+
*/
|
|
57
|
+
disabled?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Custom CSS class for the form container.
|
|
60
|
+
*/
|
|
61
|
+
class?: string;
|
|
62
|
+
}
|
|
63
|
+
declare const SchemaForm: import("svelte").Component<Props, {}, "">;
|
|
64
|
+
type SchemaForm = ReturnType<typeof SchemaForm>;
|
|
65
|
+
export default SchemaForm;
|