@d34dman/flowdrop 0.0.21 → 0.0.23
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/App.svelte +69 -260
- package/dist/components/ConfigForm.svelte +357 -267
- package/dist/components/ConfigForm.svelte.d.ts +12 -3
- package/dist/components/ConfigPanel.svelte +160 -0
- package/dist/components/ConfigPanel.svelte.d.ts +32 -0
- package/dist/components/ReadOnlyDetails.svelte +168 -0
- package/dist/components/ReadOnlyDetails.svelte.d.ts +25 -0
- package/dist/components/WorkflowEditor.svelte +1 -1
- package/dist/components/form/FormArray.svelte +1049 -0
- package/dist/components/form/FormArray.svelte.d.ts +22 -0
- package/dist/components/form/FormCheckboxGroup.svelte +152 -0
- package/dist/components/form/FormCheckboxGroup.svelte.d.ts +15 -0
- package/dist/components/form/FormField.svelte +279 -0
- package/dist/components/form/FormField.svelte.d.ts +18 -0
- package/dist/components/form/FormFieldWrapper.svelte +133 -0
- package/dist/components/form/FormFieldWrapper.svelte.d.ts +18 -0
- package/dist/components/form/FormNumberField.svelte +109 -0
- package/dist/components/form/FormNumberField.svelte.d.ts +23 -0
- package/dist/components/form/FormSelect.svelte +126 -0
- package/dist/components/form/FormSelect.svelte.d.ts +18 -0
- package/dist/components/form/FormTextField.svelte +88 -0
- package/dist/components/form/FormTextField.svelte.d.ts +17 -0
- package/dist/components/form/FormTextarea.svelte +94 -0
- package/dist/components/form/FormTextarea.svelte.d.ts +19 -0
- package/dist/components/form/FormToggle.svelte +123 -0
- package/dist/components/form/FormToggle.svelte.d.ts +17 -0
- package/dist/components/form/index.d.ts +41 -0
- package/dist/components/form/index.js +45 -0
- package/dist/components/form/types.d.ts +208 -0
- package/dist/components/form/types.js +29 -0
- package/dist/components/nodes/GatewayNode.svelte +84 -12
- package/dist/components/nodes/NotesNode.svelte +89 -307
- package/dist/components/nodes/NotesNode.svelte.d.ts +3 -22
- package/dist/components/nodes/SimpleNode.svelte +41 -5
- package/dist/components/nodes/SimpleNode.svelte.d.ts +2 -1
- package/dist/components/nodes/SquareNode.svelte +41 -5
- package/dist/components/nodes/SquareNode.svelte.d.ts +2 -1
- package/dist/components/nodes/WorkflowNode.svelte +88 -5
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3 -4
- package/dist/stores/workflowStore.d.ts +15 -0
- package/dist/stores/workflowStore.js +28 -0
- package/dist/types/index.d.ts +77 -0
- package/dist/types/index.js +16 -0
- package/package.json +3 -3
- package/dist/components/ConfigSidebar.svelte +0 -916
- package/dist/components/ConfigSidebar.svelte.d.ts +0 -51
- package/dist/config/demo.d.ts +0 -58
- package/dist/config/demo.js +0 -142
- package/dist/data/samples.d.ts +0 -51
- package/dist/data/samples.js +0 -3245
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
FormNumberField Component
|
|
3
|
+
Number input field for numeric values
|
|
4
|
+
|
|
5
|
+
Features:
|
|
6
|
+
- Tabular numeric font for alignment
|
|
7
|
+
- Min/max/step support
|
|
8
|
+
- Proper ARIA attributes for accessibility
|
|
9
|
+
-->
|
|
10
|
+
|
|
11
|
+
<script lang="ts">
|
|
12
|
+
interface Props {
|
|
13
|
+
/** Field identifier */
|
|
14
|
+
id: string;
|
|
15
|
+
/** Current value */
|
|
16
|
+
value: number | string;
|
|
17
|
+
/** Placeholder text */
|
|
18
|
+
placeholder?: string;
|
|
19
|
+
/** Minimum allowed value */
|
|
20
|
+
min?: number;
|
|
21
|
+
/** Maximum allowed value */
|
|
22
|
+
max?: number;
|
|
23
|
+
/** Step increment */
|
|
24
|
+
step?: number;
|
|
25
|
+
/** Whether the field is required */
|
|
26
|
+
required?: boolean;
|
|
27
|
+
/** ARIA description ID */
|
|
28
|
+
ariaDescribedBy?: string;
|
|
29
|
+
/** Callback when value changes */
|
|
30
|
+
onChange: (value: number | string) => void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
let {
|
|
34
|
+
id,
|
|
35
|
+
value = "",
|
|
36
|
+
placeholder = "",
|
|
37
|
+
min,
|
|
38
|
+
max,
|
|
39
|
+
step,
|
|
40
|
+
required = false,
|
|
41
|
+
ariaDescribedBy,
|
|
42
|
+
onChange
|
|
43
|
+
}: Props = $props();
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Handle input changes
|
|
47
|
+
* Returns the value as a number if valid, otherwise as string
|
|
48
|
+
*/
|
|
49
|
+
function handleInput(event: Event): void {
|
|
50
|
+
const target = event.currentTarget as HTMLInputElement;
|
|
51
|
+
const inputValue = target.value;
|
|
52
|
+
|
|
53
|
+
if (inputValue === "") {
|
|
54
|
+
onChange("");
|
|
55
|
+
} else {
|
|
56
|
+
const numValue = Number(inputValue);
|
|
57
|
+
onChange(isNaN(numValue) ? inputValue : numValue);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<input
|
|
63
|
+
{id}
|
|
64
|
+
type="number"
|
|
65
|
+
class="form-number-field"
|
|
66
|
+
value={value ?? ""}
|
|
67
|
+
{placeholder}
|
|
68
|
+
{min}
|
|
69
|
+
{max}
|
|
70
|
+
{step}
|
|
71
|
+
aria-describedby={ariaDescribedBy}
|
|
72
|
+
aria-required={required}
|
|
73
|
+
oninput={handleInput}
|
|
74
|
+
/>
|
|
75
|
+
|
|
76
|
+
<style>
|
|
77
|
+
.form-number-field {
|
|
78
|
+
width: 100%;
|
|
79
|
+
padding: 0.625rem 0.875rem;
|
|
80
|
+
border: 1px solid var(--color-ref-gray-200, #e5e7eb);
|
|
81
|
+
border-radius: 0.5rem;
|
|
82
|
+
font-size: 0.875rem;
|
|
83
|
+
font-family: inherit;
|
|
84
|
+
font-variant-numeric: tabular-nums;
|
|
85
|
+
color: var(--color-ref-gray-900, #111827);
|
|
86
|
+
background-color: var(--color-ref-gray-50, #f9fafb);
|
|
87
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
88
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.form-number-field::placeholder {
|
|
92
|
+
color: var(--color-ref-gray-400, #9ca3af);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.form-number-field:hover {
|
|
96
|
+
border-color: var(--color-ref-gray-300, #d1d5db);
|
|
97
|
+
background-color: #ffffff;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.form-number-field:focus {
|
|
101
|
+
outline: none;
|
|
102
|
+
border-color: var(--color-ref-blue-500, #3b82f6);
|
|
103
|
+
background-color: #ffffff;
|
|
104
|
+
box-shadow:
|
|
105
|
+
0 0 0 3px rgba(59, 130, 246, 0.12),
|
|
106
|
+
0 1px 2px rgba(0, 0, 0, 0.04);
|
|
107
|
+
}
|
|
108
|
+
</style>
|
|
109
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
/** Field identifier */
|
|
3
|
+
id: string;
|
|
4
|
+
/** Current value */
|
|
5
|
+
value: number | string;
|
|
6
|
+
/** Placeholder text */
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
/** Minimum allowed value */
|
|
9
|
+
min?: number;
|
|
10
|
+
/** Maximum allowed value */
|
|
11
|
+
max?: number;
|
|
12
|
+
/** Step increment */
|
|
13
|
+
step?: number;
|
|
14
|
+
/** Whether the field is required */
|
|
15
|
+
required?: boolean;
|
|
16
|
+
/** ARIA description ID */
|
|
17
|
+
ariaDescribedBy?: string;
|
|
18
|
+
/** Callback when value changes */
|
|
19
|
+
onChange: (value: number | string) => void;
|
|
20
|
+
}
|
|
21
|
+
declare const FormNumberField: import("svelte").Component<Props, {}, "">;
|
|
22
|
+
type FormNumberField = ReturnType<typeof FormNumberField>;
|
|
23
|
+
export default FormNumberField;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
FormSelect Component
|
|
3
|
+
Dropdown select for single value selection
|
|
4
|
+
|
|
5
|
+
Features:
|
|
6
|
+
- Custom styled dropdown with chevron icon
|
|
7
|
+
- Supports both string[] and FieldOption[] for options
|
|
8
|
+
- Proper ARIA attributes for accessibility
|
|
9
|
+
-->
|
|
10
|
+
|
|
11
|
+
<script lang="ts">
|
|
12
|
+
import Icon from "@iconify/svelte";
|
|
13
|
+
import { normalizeOptions, type FieldOption } from "./types.js";
|
|
14
|
+
|
|
15
|
+
interface Props {
|
|
16
|
+
/** Field identifier */
|
|
17
|
+
id: string;
|
|
18
|
+
/** Current value */
|
|
19
|
+
value: string;
|
|
20
|
+
/** Available options - can be string[] or FieldOption[] */
|
|
21
|
+
options: FieldOption[] | string[];
|
|
22
|
+
/** Whether the field is required */
|
|
23
|
+
required?: boolean;
|
|
24
|
+
/** ARIA description ID */
|
|
25
|
+
ariaDescribedBy?: string;
|
|
26
|
+
/** Callback when value changes */
|
|
27
|
+
onChange: (value: string) => void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let {
|
|
31
|
+
id,
|
|
32
|
+
value = "",
|
|
33
|
+
options = [],
|
|
34
|
+
required = false,
|
|
35
|
+
ariaDescribedBy,
|
|
36
|
+
onChange
|
|
37
|
+
}: Props = $props();
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Normalize options to consistent FieldOption format
|
|
41
|
+
*/
|
|
42
|
+
const normalizedOptions = $derived(normalizeOptions(options));
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Handle select changes
|
|
46
|
+
*/
|
|
47
|
+
function handleChange(event: Event): void {
|
|
48
|
+
const target = event.currentTarget as HTMLSelectElement;
|
|
49
|
+
onChange(target.value);
|
|
50
|
+
}
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<div class="form-select-wrapper">
|
|
54
|
+
<select
|
|
55
|
+
{id}
|
|
56
|
+
class="form-select"
|
|
57
|
+
value={value ?? ""}
|
|
58
|
+
aria-describedby={ariaDescribedBy}
|
|
59
|
+
aria-required={required}
|
|
60
|
+
onchange={handleChange}
|
|
61
|
+
>
|
|
62
|
+
{#each normalizedOptions as option (option.value)}
|
|
63
|
+
<option value={option.value}>{option.label}</option>
|
|
64
|
+
{/each}
|
|
65
|
+
</select>
|
|
66
|
+
<span class="form-select__icon" aria-hidden="true">
|
|
67
|
+
<Icon icon="heroicons:chevron-down" />
|
|
68
|
+
</span>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
<style>
|
|
72
|
+
.form-select-wrapper {
|
|
73
|
+
position: relative;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.form-select {
|
|
77
|
+
width: 100%;
|
|
78
|
+
padding: 0.625rem 2.5rem 0.625rem 0.875rem;
|
|
79
|
+
border: 1px solid var(--color-ref-gray-200, #e5e7eb);
|
|
80
|
+
border-radius: 0.5rem;
|
|
81
|
+
font-size: 0.875rem;
|
|
82
|
+
font-family: inherit;
|
|
83
|
+
color: var(--color-ref-gray-900, #111827);
|
|
84
|
+
background-color: var(--color-ref-gray-50, #f9fafb);
|
|
85
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
86
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
87
|
+
cursor: pointer;
|
|
88
|
+
appearance: none;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.form-select:hover {
|
|
92
|
+
border-color: var(--color-ref-gray-300, #d1d5db);
|
|
93
|
+
background-color: #ffffff;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.form-select:focus {
|
|
97
|
+
outline: none;
|
|
98
|
+
border-color: var(--color-ref-blue-500, #3b82f6);
|
|
99
|
+
background-color: #ffffff;
|
|
100
|
+
box-shadow:
|
|
101
|
+
0 0 0 3px rgba(59, 130, 246, 0.12),
|
|
102
|
+
0 1px 2px rgba(0, 0, 0, 0.04);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.form-select__icon {
|
|
106
|
+
position: absolute;
|
|
107
|
+
right: 0.75rem;
|
|
108
|
+
top: 50%;
|
|
109
|
+
transform: translateY(-50%);
|
|
110
|
+
pointer-events: none;
|
|
111
|
+
color: var(--color-ref-gray-400, #9ca3af);
|
|
112
|
+
display: flex;
|
|
113
|
+
align-items: center;
|
|
114
|
+
transition: color 0.2s;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.form-select__icon :global(svg) {
|
|
118
|
+
width: 1rem;
|
|
119
|
+
height: 1rem;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.form-select:focus + .form-select__icon {
|
|
123
|
+
color: var(--color-ref-blue-500, #3b82f6);
|
|
124
|
+
}
|
|
125
|
+
</style>
|
|
126
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type FieldOption } from "./types.js";
|
|
2
|
+
interface Props {
|
|
3
|
+
/** Field identifier */
|
|
4
|
+
id: string;
|
|
5
|
+
/** Current value */
|
|
6
|
+
value: string;
|
|
7
|
+
/** Available options - can be string[] or FieldOption[] */
|
|
8
|
+
options: FieldOption[] | string[];
|
|
9
|
+
/** Whether the field is required */
|
|
10
|
+
required?: boolean;
|
|
11
|
+
/** ARIA description ID */
|
|
12
|
+
ariaDescribedBy?: string;
|
|
13
|
+
/** Callback when value changes */
|
|
14
|
+
onChange: (value: string) => void;
|
|
15
|
+
}
|
|
16
|
+
declare const FormSelect: import("svelte").Component<Props, {}, "">;
|
|
17
|
+
type FormSelect = ReturnType<typeof FormSelect>;
|
|
18
|
+
export default FormSelect;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
FormTextField Component
|
|
3
|
+
Text input field for string values
|
|
4
|
+
|
|
5
|
+
Features:
|
|
6
|
+
- Standard text input with focus and hover states
|
|
7
|
+
- Proper ARIA attributes for accessibility
|
|
8
|
+
- Placeholder support
|
|
9
|
+
-->
|
|
10
|
+
|
|
11
|
+
<script lang="ts">
|
|
12
|
+
interface Props {
|
|
13
|
+
/** Field identifier */
|
|
14
|
+
id: string;
|
|
15
|
+
/** Current value */
|
|
16
|
+
value: string;
|
|
17
|
+
/** Placeholder text */
|
|
18
|
+
placeholder?: string;
|
|
19
|
+
/** Whether the field is required */
|
|
20
|
+
required?: boolean;
|
|
21
|
+
/** ARIA description ID */
|
|
22
|
+
ariaDescribedBy?: string;
|
|
23
|
+
/** Callback when value changes */
|
|
24
|
+
onChange: (value: string) => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let {
|
|
28
|
+
id,
|
|
29
|
+
value = "",
|
|
30
|
+
placeholder = "",
|
|
31
|
+
required = false,
|
|
32
|
+
ariaDescribedBy,
|
|
33
|
+
onChange
|
|
34
|
+
}: Props = $props();
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Handle input changes
|
|
38
|
+
*/
|
|
39
|
+
function handleInput(event: Event): void {
|
|
40
|
+
const target = event.currentTarget as HTMLInputElement;
|
|
41
|
+
onChange(target.value);
|
|
42
|
+
}
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<input
|
|
46
|
+
{id}
|
|
47
|
+
type="text"
|
|
48
|
+
class="form-text-field"
|
|
49
|
+
value={value ?? ""}
|
|
50
|
+
{placeholder}
|
|
51
|
+
aria-describedby={ariaDescribedBy}
|
|
52
|
+
aria-required={required}
|
|
53
|
+
oninput={handleInput}
|
|
54
|
+
/>
|
|
55
|
+
|
|
56
|
+
<style>
|
|
57
|
+
.form-text-field {
|
|
58
|
+
width: 100%;
|
|
59
|
+
padding: 0.625rem 0.875rem;
|
|
60
|
+
border: 1px solid var(--color-ref-gray-200, #e5e7eb);
|
|
61
|
+
border-radius: 0.5rem;
|
|
62
|
+
font-size: 0.875rem;
|
|
63
|
+
font-family: inherit;
|
|
64
|
+
color: var(--color-ref-gray-900, #111827);
|
|
65
|
+
background-color: var(--color-ref-gray-50, #f9fafb);
|
|
66
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
67
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.form-text-field::placeholder {
|
|
71
|
+
color: var(--color-ref-gray-400, #9ca3af);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.form-text-field:hover {
|
|
75
|
+
border-color: var(--color-ref-gray-300, #d1d5db);
|
|
76
|
+
background-color: #ffffff;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.form-text-field:focus {
|
|
80
|
+
outline: none;
|
|
81
|
+
border-color: var(--color-ref-blue-500, #3b82f6);
|
|
82
|
+
background-color: #ffffff;
|
|
83
|
+
box-shadow:
|
|
84
|
+
0 0 0 3px rgba(59, 130, 246, 0.12),
|
|
85
|
+
0 1px 2px rgba(0, 0, 0, 0.04);
|
|
86
|
+
}
|
|
87
|
+
</style>
|
|
88
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
/** Field identifier */
|
|
3
|
+
id: string;
|
|
4
|
+
/** Current value */
|
|
5
|
+
value: string;
|
|
6
|
+
/** Placeholder text */
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
/** Whether the field is required */
|
|
9
|
+
required?: boolean;
|
|
10
|
+
/** ARIA description ID */
|
|
11
|
+
ariaDescribedBy?: string;
|
|
12
|
+
/** Callback when value changes */
|
|
13
|
+
onChange: (value: string) => void;
|
|
14
|
+
}
|
|
15
|
+
declare const FormTextField: import("svelte").Component<Props, {}, "">;
|
|
16
|
+
type FormTextField = ReturnType<typeof FormTextField>;
|
|
17
|
+
export default FormTextField;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
FormTextarea Component
|
|
3
|
+
Multiline text input field for longer string values
|
|
4
|
+
|
|
5
|
+
Features:
|
|
6
|
+
- Resizable textarea with minimum height
|
|
7
|
+
- Focus and hover states
|
|
8
|
+
- Proper ARIA attributes for accessibility
|
|
9
|
+
-->
|
|
10
|
+
|
|
11
|
+
<script lang="ts">
|
|
12
|
+
interface Props {
|
|
13
|
+
/** Field identifier */
|
|
14
|
+
id: string;
|
|
15
|
+
/** Current value */
|
|
16
|
+
value: string;
|
|
17
|
+
/** Placeholder text */
|
|
18
|
+
placeholder?: string;
|
|
19
|
+
/** Number of visible rows */
|
|
20
|
+
rows?: number;
|
|
21
|
+
/** Whether the field is required */
|
|
22
|
+
required?: boolean;
|
|
23
|
+
/** ARIA description ID */
|
|
24
|
+
ariaDescribedBy?: string;
|
|
25
|
+
/** Callback when value changes */
|
|
26
|
+
onChange: (value: string) => void;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let {
|
|
30
|
+
id,
|
|
31
|
+
value = "",
|
|
32
|
+
placeholder = "",
|
|
33
|
+
rows = 4,
|
|
34
|
+
required = false,
|
|
35
|
+
ariaDescribedBy,
|
|
36
|
+
onChange
|
|
37
|
+
}: Props = $props();
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Handle textarea changes
|
|
41
|
+
*/
|
|
42
|
+
function handleInput(event: Event): void {
|
|
43
|
+
const target = event.currentTarget as HTMLTextAreaElement;
|
|
44
|
+
onChange(target.value);
|
|
45
|
+
}
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<textarea
|
|
49
|
+
{id}
|
|
50
|
+
class="form-textarea"
|
|
51
|
+
value={value ?? ""}
|
|
52
|
+
{placeholder}
|
|
53
|
+
{rows}
|
|
54
|
+
aria-describedby={ariaDescribedBy}
|
|
55
|
+
aria-required={required}
|
|
56
|
+
oninput={handleInput}
|
|
57
|
+
></textarea>
|
|
58
|
+
|
|
59
|
+
<style>
|
|
60
|
+
.form-textarea {
|
|
61
|
+
width: 100%;
|
|
62
|
+
padding: 0.625rem 0.875rem;
|
|
63
|
+
border: 1px solid var(--color-ref-gray-200, #e5e7eb);
|
|
64
|
+
border-radius: 0.5rem;
|
|
65
|
+
font-size: 0.875rem;
|
|
66
|
+
font-family: inherit;
|
|
67
|
+
color: var(--color-ref-gray-900, #111827);
|
|
68
|
+
background-color: var(--color-ref-gray-50, #f9fafb);
|
|
69
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
70
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
71
|
+
resize: vertical;
|
|
72
|
+
min-height: 5rem;
|
|
73
|
+
line-height: 1.5;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.form-textarea::placeholder {
|
|
77
|
+
color: var(--color-ref-gray-400, #9ca3af);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.form-textarea:hover {
|
|
81
|
+
border-color: var(--color-ref-gray-300, #d1d5db);
|
|
82
|
+
background-color: #ffffff;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.form-textarea:focus {
|
|
86
|
+
outline: none;
|
|
87
|
+
border-color: var(--color-ref-blue-500, #3b82f6);
|
|
88
|
+
background-color: #ffffff;
|
|
89
|
+
box-shadow:
|
|
90
|
+
0 0 0 3px rgba(59, 130, 246, 0.12),
|
|
91
|
+
0 1px 2px rgba(0, 0, 0, 0.04);
|
|
92
|
+
}
|
|
93
|
+
</style>
|
|
94
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
/** Field identifier */
|
|
3
|
+
id: string;
|
|
4
|
+
/** Current value */
|
|
5
|
+
value: string;
|
|
6
|
+
/** Placeholder text */
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
/** Number of visible rows */
|
|
9
|
+
rows?: number;
|
|
10
|
+
/** Whether the field is required */
|
|
11
|
+
required?: boolean;
|
|
12
|
+
/** ARIA description ID */
|
|
13
|
+
ariaDescribedBy?: string;
|
|
14
|
+
/** Callback when value changes */
|
|
15
|
+
onChange: (value: string) => void;
|
|
16
|
+
}
|
|
17
|
+
declare const FormTextarea: import("svelte").Component<Props, {}, "">;
|
|
18
|
+
type FormTextarea = ReturnType<typeof FormTextarea>;
|
|
19
|
+
export default FormTextarea;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
FormToggle Component
|
|
3
|
+
Toggle switch for boolean values
|
|
4
|
+
|
|
5
|
+
Features:
|
|
6
|
+
- Smooth toggle animation
|
|
7
|
+
- On/Off labels with state-based coloring
|
|
8
|
+
- Focus-visible states for keyboard navigation
|
|
9
|
+
-->
|
|
10
|
+
|
|
11
|
+
<script lang="ts">
|
|
12
|
+
interface Props {
|
|
13
|
+
/** Field identifier */
|
|
14
|
+
id: string;
|
|
15
|
+
/** Current value */
|
|
16
|
+
value: boolean;
|
|
17
|
+
/** Label shown when toggle is on */
|
|
18
|
+
onLabel?: string;
|
|
19
|
+
/** Label shown when toggle is off */
|
|
20
|
+
offLabel?: string;
|
|
21
|
+
/** ARIA description ID */
|
|
22
|
+
ariaDescribedBy?: string;
|
|
23
|
+
/** Callback when value changes */
|
|
24
|
+
onChange: (value: boolean) => void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let {
|
|
28
|
+
id,
|
|
29
|
+
value = false,
|
|
30
|
+
onLabel = "Enabled",
|
|
31
|
+
offLabel = "Disabled",
|
|
32
|
+
ariaDescribedBy,
|
|
33
|
+
onChange
|
|
34
|
+
}: Props = $props();
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Handle toggle changes
|
|
38
|
+
*/
|
|
39
|
+
function handleChange(event: Event): void {
|
|
40
|
+
const target = event.currentTarget as HTMLInputElement;
|
|
41
|
+
onChange(target.checked);
|
|
42
|
+
}
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<label class="form-toggle">
|
|
46
|
+
<input
|
|
47
|
+
{id}
|
|
48
|
+
type="checkbox"
|
|
49
|
+
class="form-toggle__input"
|
|
50
|
+
checked={value}
|
|
51
|
+
aria-describedby={ariaDescribedBy}
|
|
52
|
+
onchange={handleChange}
|
|
53
|
+
/>
|
|
54
|
+
<span class="form-toggle__track">
|
|
55
|
+
<span class="form-toggle__thumb"></span>
|
|
56
|
+
</span>
|
|
57
|
+
<span class="form-toggle__label">
|
|
58
|
+
{value ? onLabel : offLabel}
|
|
59
|
+
</span>
|
|
60
|
+
</label>
|
|
61
|
+
|
|
62
|
+
<style>
|
|
63
|
+
.form-toggle {
|
|
64
|
+
display: flex;
|
|
65
|
+
align-items: center;
|
|
66
|
+
gap: 0.75rem;
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
padding: 0.5rem 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.form-toggle__input {
|
|
72
|
+
position: absolute;
|
|
73
|
+
opacity: 0;
|
|
74
|
+
width: 0;
|
|
75
|
+
height: 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.form-toggle__track {
|
|
79
|
+
position: relative;
|
|
80
|
+
width: 2.75rem;
|
|
81
|
+
height: 1.5rem;
|
|
82
|
+
background-color: var(--color-ref-gray-300, #d1d5db);
|
|
83
|
+
border-radius: 0.75rem;
|
|
84
|
+
transition: background-color 0.2s;
|
|
85
|
+
flex-shrink: 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.form-toggle__thumb {
|
|
89
|
+
position: absolute;
|
|
90
|
+
top: 0.125rem;
|
|
91
|
+
left: 0.125rem;
|
|
92
|
+
width: 1.25rem;
|
|
93
|
+
height: 1.25rem;
|
|
94
|
+
background-color: #ffffff;
|
|
95
|
+
border-radius: 50%;
|
|
96
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
|
97
|
+
transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.form-toggle__input:checked + .form-toggle__track {
|
|
101
|
+
background-color: var(--color-ref-blue-500, #3b82f6);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.form-toggle__input:checked + .form-toggle__track .form-toggle__thumb {
|
|
105
|
+
transform: translateX(1.25rem);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.form-toggle__input:focus-visible + .form-toggle__track {
|
|
109
|
+
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.form-toggle__label {
|
|
113
|
+
font-size: 0.875rem;
|
|
114
|
+
color: var(--color-ref-gray-600, #4b5563);
|
|
115
|
+
font-weight: 500;
|
|
116
|
+
min-width: 4.5rem;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.form-toggle__input:checked ~ .form-toggle__label {
|
|
120
|
+
color: var(--color-ref-blue-600, #2563eb);
|
|
121
|
+
}
|
|
122
|
+
</style>
|
|
123
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface Props {
|
|
2
|
+
/** Field identifier */
|
|
3
|
+
id: string;
|
|
4
|
+
/** Current value */
|
|
5
|
+
value: boolean;
|
|
6
|
+
/** Label shown when toggle is on */
|
|
7
|
+
onLabel?: string;
|
|
8
|
+
/** Label shown when toggle is off */
|
|
9
|
+
offLabel?: string;
|
|
10
|
+
/** ARIA description ID */
|
|
11
|
+
ariaDescribedBy?: string;
|
|
12
|
+
/** Callback when value changes */
|
|
13
|
+
onChange: (value: boolean) => void;
|
|
14
|
+
}
|
|
15
|
+
declare const FormToggle: import("svelte").Component<Props, {}, "">;
|
|
16
|
+
type FormToggle = ReturnType<typeof FormToggle>;
|
|
17
|
+
export default FormToggle;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Form Components Module
|
|
3
|
+
*
|
|
4
|
+
* Modular form components for dynamic form rendering based on JSON Schema.
|
|
5
|
+
* Designed for extensibility to support complex types like arrays and objects.
|
|
6
|
+
*
|
|
7
|
+
* @module form
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```svelte
|
|
11
|
+
* <script>
|
|
12
|
+
* import { FormField } from "./";
|
|
13
|
+
* import type { FieldSchema } from "./";
|
|
14
|
+
*
|
|
15
|
+
* const schema: FieldSchema = {
|
|
16
|
+
* type: "string",
|
|
17
|
+
* title: "Name",
|
|
18
|
+
* description: "Enter your name"
|
|
19
|
+
* };
|
|
20
|
+
*
|
|
21
|
+
* let value = $state("");
|
|
22
|
+
* </script>
|
|
23
|
+
*
|
|
24
|
+
* <FormField
|
|
25
|
+
* fieldKey="name"
|
|
26
|
+
* {schema}
|
|
27
|
+
* {value}
|
|
28
|
+
* onChange={(v) => value = v}
|
|
29
|
+
* />
|
|
30
|
+
* ```
|
|
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 FormToggle } from "./FormToggle.svelte";
|
|
39
|
+
export { default as FormSelect } from "./FormSelect.svelte";
|
|
40
|
+
export { default as FormCheckboxGroup } from "./FormCheckboxGroup.svelte";
|
|
41
|
+
export { default as FormArray } from "./FormArray.svelte";
|