sv5ui 1.5.1 → 1.7.0
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/Calendar/Calendar.svelte +48 -6
- package/dist/Calendar/calendar.types.d.ts +19 -0
- package/dist/Calendar/calendar.variants.js +2 -1
- package/dist/Carousel/Carousel.svelte +279 -0
- package/dist/Carousel/Carousel.svelte.d.ts +26 -0
- package/dist/Carousel/carousel.types.d.ts +242 -0
- package/dist/Carousel/carousel.types.js +1 -0
- package/dist/Carousel/carousel.variants.d.ts +408 -0
- package/dist/Carousel/carousel.variants.js +88 -0
- package/dist/Carousel/index.d.ts +2 -0
- package/dist/Carousel/index.js +1 -0
- package/dist/Checkbox/Checkbox.svelte +8 -2
- package/dist/CheckboxGroup/CheckboxGroup.svelte +15 -2
- package/dist/FileUpload/FileUpload.svelte +81 -10
- package/dist/FileUpload/file-upload.types.d.ts +39 -0
- package/dist/FileUpload/index.d.ts +1 -1
- package/dist/Form/Form.svelte +203 -0
- package/dist/Form/Form.svelte.d.ts +26 -0
- package/dist/Form/form.context.svelte.d.ts +64 -0
- package/dist/Form/form.context.svelte.js +478 -0
- package/dist/Form/form.types.d.ts +164 -0
- package/dist/Form/form.types.js +12 -0
- package/dist/Form/form.variants.d.ts +39 -0
- package/dist/Form/form.variants.js +17 -0
- package/dist/Form/index.d.ts +4 -0
- package/dist/Form/index.js +6 -0
- package/dist/Form/validate-schema.d.ts +13 -0
- package/dist/Form/validate-schema.js +113 -0
- package/dist/FormField/FormField.svelte +71 -8
- package/dist/FormField/form-field.types.d.ts +15 -0
- package/dist/Input/Input.svelte +31 -5
- package/dist/Input/Input.svelte.d.ts +25 -4
- package/dist/Input/input.types.d.ts +24 -3
- package/dist/Modal/Modal.svelte +14 -3
- package/dist/Modal/modal.types.d.ts +15 -4
- package/dist/Modal/modal.variants.d.ts +110 -20
- package/dist/Modal/modal.variants.js +27 -9
- package/dist/PinInput/PinInput.svelte +27 -6
- package/dist/PinInput/pin-input.types.d.ts +11 -0
- package/dist/RadioGroup/RadioGroup.svelte +17 -3
- package/dist/Select/Select.svelte +100 -19
- package/dist/Select/select.types.d.ts +44 -2
- package/dist/SelectMenu/SelectMenu.svelte +215 -23
- package/dist/SelectMenu/select-menu.types.d.ts +62 -1
- package/dist/SelectMenu/select-menu.variants.d.ts +26 -0
- package/dist/SelectMenu/select-menu.variants.js +34 -6
- package/dist/Slideover/Slideover.svelte +13 -2
- package/dist/Slideover/slideover.types.d.ts +14 -3
- package/dist/Slideover/slideover.variants.d.ts +85 -5
- package/dist/Slideover/slideover.variants.js +42 -12
- package/dist/Slider/Slider.svelte +4 -1
- package/dist/Switch/Switch.svelte +8 -2
- package/dist/Textarea/Textarea.svelte +27 -1
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/useFormField.svelte.d.ts +64 -0
- package/dist/hooks/useFormField.svelte.js +70 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/package.json +31 -3
|
@@ -42,10 +42,21 @@ export interface SlideoverProps extends RootProps, ContentProps {
|
|
|
42
42
|
*/
|
|
43
43
|
overlay?: SlideoverVariantProps['overlay'];
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
45
|
+
* Controls the entrance/exit animation.
|
|
46
|
+
* - `'none'` / `false`: no animation
|
|
47
|
+
* - `'fade'`: overlay + content fade
|
|
48
|
+
* - `'slide'` / `true`: overlay fade + content slide-in from the chosen side (default)
|
|
49
|
+
* - `'scale'`: overlay fade + content scale-in
|
|
50
|
+
* @default 'slide'
|
|
51
|
+
*/
|
|
52
|
+
transition?: SlideoverVariantProps['transition'] | boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Controls the panel dimension along its axis. For `side="left"` /
|
|
55
|
+
* `side="right"` this sets `max-width`; for `side="top"` / `side="bottom"`
|
|
56
|
+
* this sets `max-height`.
|
|
57
|
+
* @default 'md'
|
|
47
58
|
*/
|
|
48
|
-
|
|
59
|
+
size?: SlideoverVariantProps['size'];
|
|
49
60
|
/**
|
|
50
61
|
* Display the slideover with inset margins and rounded corners.
|
|
51
62
|
* @default false
|
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { type VariantProps } from 'tailwind-variants';
|
|
2
2
|
export declare const slideoverVariants: import("tailwind-variants").TVReturnType<{
|
|
3
3
|
transition: {
|
|
4
|
-
|
|
4
|
+
none: {};
|
|
5
|
+
fade: {
|
|
6
|
+
overlay: string;
|
|
7
|
+
content: string;
|
|
8
|
+
};
|
|
9
|
+
slide: {
|
|
10
|
+
overlay: string;
|
|
11
|
+
};
|
|
12
|
+
scale: {
|
|
5
13
|
overlay: string;
|
|
14
|
+
content: string;
|
|
6
15
|
};
|
|
7
16
|
};
|
|
8
17
|
side: {
|
|
@@ -19,6 +28,13 @@ export declare const slideoverVariants: import("tailwind-variants").TVReturnType
|
|
|
19
28
|
content: string;
|
|
20
29
|
};
|
|
21
30
|
};
|
|
31
|
+
size: {
|
|
32
|
+
sm: {};
|
|
33
|
+
md: {};
|
|
34
|
+
lg: {};
|
|
35
|
+
xl: {};
|
|
36
|
+
full: {};
|
|
37
|
+
};
|
|
22
38
|
inset: {
|
|
23
39
|
true: {};
|
|
24
40
|
false: {
|
|
@@ -43,9 +59,18 @@ export declare const slideoverVariants: import("tailwind-variants").TVReturnType
|
|
|
43
59
|
close: string;
|
|
44
60
|
}, undefined, {
|
|
45
61
|
transition: {
|
|
46
|
-
|
|
62
|
+
none: {};
|
|
63
|
+
fade: {
|
|
64
|
+
overlay: string;
|
|
65
|
+
content: string;
|
|
66
|
+
};
|
|
67
|
+
slide: {
|
|
47
68
|
overlay: string;
|
|
48
69
|
};
|
|
70
|
+
scale: {
|
|
71
|
+
overlay: string;
|
|
72
|
+
content: string;
|
|
73
|
+
};
|
|
49
74
|
};
|
|
50
75
|
side: {
|
|
51
76
|
top: {
|
|
@@ -61,6 +86,13 @@ export declare const slideoverVariants: import("tailwind-variants").TVReturnType
|
|
|
61
86
|
content: string;
|
|
62
87
|
};
|
|
63
88
|
};
|
|
89
|
+
size: {
|
|
90
|
+
sm: {};
|
|
91
|
+
md: {};
|
|
92
|
+
lg: {};
|
|
93
|
+
xl: {};
|
|
94
|
+
full: {};
|
|
95
|
+
};
|
|
64
96
|
inset: {
|
|
65
97
|
true: {};
|
|
66
98
|
false: {
|
|
@@ -85,9 +117,18 @@ export declare const slideoverVariants: import("tailwind-variants").TVReturnType
|
|
|
85
117
|
close: string;
|
|
86
118
|
}, import("tailwind-variants").TVReturnType<{
|
|
87
119
|
transition: {
|
|
88
|
-
|
|
120
|
+
none: {};
|
|
121
|
+
fade: {
|
|
122
|
+
overlay: string;
|
|
123
|
+
content: string;
|
|
124
|
+
};
|
|
125
|
+
slide: {
|
|
89
126
|
overlay: string;
|
|
90
127
|
};
|
|
128
|
+
scale: {
|
|
129
|
+
overlay: string;
|
|
130
|
+
content: string;
|
|
131
|
+
};
|
|
91
132
|
};
|
|
92
133
|
side: {
|
|
93
134
|
top: {
|
|
@@ -103,6 +144,13 @@ export declare const slideoverVariants: import("tailwind-variants").TVReturnType
|
|
|
103
144
|
content: string;
|
|
104
145
|
};
|
|
105
146
|
};
|
|
147
|
+
size: {
|
|
148
|
+
sm: {};
|
|
149
|
+
md: {};
|
|
150
|
+
lg: {};
|
|
151
|
+
xl: {};
|
|
152
|
+
full: {};
|
|
153
|
+
};
|
|
106
154
|
inset: {
|
|
107
155
|
true: {};
|
|
108
156
|
false: {
|
|
@@ -131,8 +179,17 @@ export type SlideoverSlots = keyof ReturnType<typeof slideoverVariants>;
|
|
|
131
179
|
export declare const slideoverDefaults: {
|
|
132
180
|
defaultVariants: import("tailwind-variants").TVDefaultVariants<{
|
|
133
181
|
transition: {
|
|
134
|
-
|
|
182
|
+
none: {};
|
|
183
|
+
fade: {
|
|
184
|
+
overlay: string;
|
|
185
|
+
content: string;
|
|
186
|
+
};
|
|
187
|
+
slide: {
|
|
188
|
+
overlay: string;
|
|
189
|
+
};
|
|
190
|
+
scale: {
|
|
135
191
|
overlay: string;
|
|
192
|
+
content: string;
|
|
136
193
|
};
|
|
137
194
|
};
|
|
138
195
|
side: {
|
|
@@ -149,6 +206,13 @@ export declare const slideoverDefaults: {
|
|
|
149
206
|
content: string;
|
|
150
207
|
};
|
|
151
208
|
};
|
|
209
|
+
size: {
|
|
210
|
+
sm: {};
|
|
211
|
+
md: {};
|
|
212
|
+
lg: {};
|
|
213
|
+
xl: {};
|
|
214
|
+
full: {};
|
|
215
|
+
};
|
|
152
216
|
inset: {
|
|
153
217
|
true: {};
|
|
154
218
|
false: {
|
|
@@ -173,9 +237,18 @@ export declare const slideoverDefaults: {
|
|
|
173
237
|
close: string;
|
|
174
238
|
}, {
|
|
175
239
|
transition: {
|
|
176
|
-
|
|
240
|
+
none: {};
|
|
241
|
+
fade: {
|
|
242
|
+
overlay: string;
|
|
243
|
+
content: string;
|
|
244
|
+
};
|
|
245
|
+
slide: {
|
|
177
246
|
overlay: string;
|
|
178
247
|
};
|
|
248
|
+
scale: {
|
|
249
|
+
overlay: string;
|
|
250
|
+
content: string;
|
|
251
|
+
};
|
|
179
252
|
};
|
|
180
253
|
side: {
|
|
181
254
|
top: {
|
|
@@ -191,6 +264,13 @@ export declare const slideoverDefaults: {
|
|
|
191
264
|
content: string;
|
|
192
265
|
};
|
|
193
266
|
};
|
|
267
|
+
size: {
|
|
268
|
+
sm: {};
|
|
269
|
+
md: {};
|
|
270
|
+
lg: {};
|
|
271
|
+
xl: {};
|
|
272
|
+
full: {};
|
|
273
|
+
};
|
|
194
274
|
inset: {
|
|
195
275
|
true: {};
|
|
196
276
|
false: {
|
|
@@ -14,24 +14,40 @@ export const slideoverVariants = tv({
|
|
|
14
14
|
},
|
|
15
15
|
variants: {
|
|
16
16
|
transition: {
|
|
17
|
-
|
|
17
|
+
none: {},
|
|
18
|
+
fade: {
|
|
19
|
+
overlay: 'data-[state=open]:animate-[fade-in_200ms_ease-out] data-[state=closed]:animate-[fade-out_150ms_ease-in]',
|
|
20
|
+
content: 'data-[state=open]:animate-[fade-in_200ms_ease-out] data-[state=closed]:animate-[fade-out_150ms_ease-in]'
|
|
21
|
+
},
|
|
22
|
+
slide: {
|
|
18
23
|
overlay: 'data-[state=open]:animate-[fade-in_200ms_ease-out] data-[state=closed]:animate-[fade-out_150ms_ease-in]'
|
|
24
|
+
},
|
|
25
|
+
scale: {
|
|
26
|
+
overlay: 'data-[state=open]:animate-[fade-in_200ms_ease-out] data-[state=closed]:animate-[fade-out_150ms_ease-in]',
|
|
27
|
+
content: 'data-[state=open]:animate-[scale-in_200ms_cubic-bezier(0.32,0.72,0,1)] data-[state=closed]:animate-[scale-out_150ms_cubic-bezier(0.32,0.72,0,1)]'
|
|
19
28
|
}
|
|
20
29
|
},
|
|
21
30
|
side: {
|
|
22
31
|
top: {
|
|
23
|
-
content: 'fixed top-0 inset-x-0
|
|
32
|
+
content: 'fixed top-0 inset-x-0'
|
|
24
33
|
},
|
|
25
34
|
right: {
|
|
26
|
-
content: 'fixed right-0 inset-y-0 w-full
|
|
35
|
+
content: 'fixed right-0 inset-y-0 w-full'
|
|
27
36
|
},
|
|
28
37
|
bottom: {
|
|
29
|
-
content: 'fixed bottom-0 inset-x-0
|
|
38
|
+
content: 'fixed bottom-0 inset-x-0'
|
|
30
39
|
},
|
|
31
40
|
left: {
|
|
32
|
-
content: 'fixed left-0 inset-y-0 w-full
|
|
41
|
+
content: 'fixed left-0 inset-y-0 w-full'
|
|
33
42
|
}
|
|
34
43
|
},
|
|
44
|
+
size: {
|
|
45
|
+
sm: {},
|
|
46
|
+
md: {},
|
|
47
|
+
lg: {},
|
|
48
|
+
xl: {},
|
|
49
|
+
full: {}
|
|
50
|
+
},
|
|
35
51
|
inset: {
|
|
36
52
|
true: {},
|
|
37
53
|
false: {
|
|
@@ -45,39 +61,52 @@ export const slideoverVariants = tv({
|
|
|
45
61
|
}
|
|
46
62
|
},
|
|
47
63
|
compoundVariants: [
|
|
64
|
+
// Side-specific slide animations
|
|
48
65
|
{
|
|
49
|
-
transition:
|
|
66
|
+
transition: 'slide',
|
|
50
67
|
side: 'top',
|
|
51
68
|
class: {
|
|
52
69
|
content: 'data-[state=open]:animate-[slide-in-full-top_200ms_ease-out,fade-in_200ms_ease-out] data-[state=closed]:animate-[slide-out-full-top_150ms_ease-in,fade-out_150ms_ease-in]'
|
|
53
70
|
}
|
|
54
71
|
},
|
|
55
72
|
{
|
|
56
|
-
transition:
|
|
73
|
+
transition: 'slide',
|
|
57
74
|
side: 'right',
|
|
58
75
|
class: {
|
|
59
76
|
content: 'data-[state=open]:animate-[slide-in-full-right_200ms_ease-out,fade-in_200ms_ease-out] data-[state=closed]:animate-[slide-out-full-right_150ms_ease-in,fade-out_150ms_ease-in]'
|
|
60
77
|
}
|
|
61
78
|
},
|
|
62
79
|
{
|
|
63
|
-
transition:
|
|
80
|
+
transition: 'slide',
|
|
64
81
|
side: 'bottom',
|
|
65
82
|
class: {
|
|
66
83
|
content: 'data-[state=open]:animate-[slide-in-full-bottom_200ms_ease-out,fade-in_200ms_ease-out] data-[state=closed]:animate-[slide-out-full-bottom_150ms_ease-in,fade-out_150ms_ease-in]'
|
|
67
84
|
}
|
|
68
85
|
},
|
|
69
86
|
{
|
|
70
|
-
transition:
|
|
87
|
+
transition: 'slide',
|
|
71
88
|
side: 'left',
|
|
72
89
|
class: {
|
|
73
90
|
content: 'data-[state=open]:animate-[slide-in-full-left_200ms_ease-out,fade-in_200ms_ease-out] data-[state=closed]:animate-[slide-out-full-left_150ms_ease-in,fade-out_150ms_ease-in]'
|
|
74
91
|
}
|
|
75
92
|
},
|
|
93
|
+
// Sizes — left/right control width, top/bottom control height
|
|
94
|
+
{ side: ['left', 'right'], size: 'sm', class: { content: 'max-w-sm' } },
|
|
95
|
+
{ side: ['left', 'right'], size: 'md', class: { content: 'max-w-md' } },
|
|
96
|
+
{ side: ['left', 'right'], size: 'lg', class: { content: 'max-w-lg' } },
|
|
97
|
+
{ side: ['left', 'right'], size: 'xl', class: { content: 'max-w-xl' } },
|
|
98
|
+
{ side: ['left', 'right'], size: 'full', class: { content: 'max-w-full' } },
|
|
99
|
+
{ side: ['top', 'bottom'], size: 'sm', class: { content: 'max-h-[40dvh]' } },
|
|
100
|
+
{ side: ['top', 'bottom'], size: 'md', class: { content: 'max-h-[60dvh]' } },
|
|
101
|
+
{ side: ['top', 'bottom'], size: 'lg', class: { content: 'max-h-[75dvh]' } },
|
|
102
|
+
{ side: ['top', 'bottom'], size: 'xl', class: { content: 'max-h-[90dvh]' } },
|
|
103
|
+
{ side: ['top', 'bottom'], size: 'full', class: { content: 'max-h-full' } },
|
|
104
|
+
// Inset positioning + rounded corners + shadow ring per side
|
|
76
105
|
{
|
|
77
106
|
inset: true,
|
|
78
107
|
side: 'top',
|
|
79
108
|
class: {
|
|
80
|
-
content: 'top-4 inset-x-4
|
|
109
|
+
content: 'top-4 inset-x-4 rounded-xl shadow-lg ring ring-outline-variant'
|
|
81
110
|
}
|
|
82
111
|
},
|
|
83
112
|
{
|
|
@@ -91,7 +120,7 @@ export const slideoverVariants = tv({
|
|
|
91
120
|
inset: true,
|
|
92
121
|
side: 'bottom',
|
|
93
122
|
class: {
|
|
94
|
-
content: 'bottom-4 inset-x-4
|
|
123
|
+
content: 'bottom-4 inset-x-4 rounded-xl shadow-lg ring ring-outline-variant'
|
|
95
124
|
}
|
|
96
125
|
},
|
|
97
126
|
{
|
|
@@ -103,8 +132,9 @@ export const slideoverVariants = tv({
|
|
|
103
132
|
}
|
|
104
133
|
],
|
|
105
134
|
defaultVariants: {
|
|
106
|
-
transition:
|
|
135
|
+
transition: 'slide',
|
|
107
136
|
side: 'right',
|
|
137
|
+
size: 'md',
|
|
108
138
|
inset: false,
|
|
109
139
|
overlay: true
|
|
110
140
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { Slider, useId } from 'bits-ui'
|
|
9
9
|
import { sliderVariants, sliderDefaults } from './slider.variants.js'
|
|
10
10
|
import { getComponentConfig } from '../config.js'
|
|
11
|
-
import { useFormField } from '../hooks/useFormField.svelte.js'
|
|
11
|
+
import { useFormField, useFormFieldEmit } from '../hooks/useFormField.svelte.js'
|
|
12
12
|
|
|
13
13
|
const config = getComponentConfig('slider', sliderDefaults)
|
|
14
14
|
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
}: Props = $props()
|
|
38
38
|
|
|
39
39
|
const formFieldContext = useFormField()
|
|
40
|
+
const emit = useFormFieldEmit()
|
|
40
41
|
|
|
41
42
|
const autoId = useId()
|
|
42
43
|
const hasError = $derived(
|
|
@@ -59,10 +60,12 @@
|
|
|
59
60
|
|
|
60
61
|
function handleValueChange(v: number[]) {
|
|
61
62
|
value = isMultiple ? v : (v[0] ?? min)
|
|
63
|
+
emit.onInput()
|
|
62
64
|
onValueChange?.(value)
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
function handleValueCommit(v: number[]) {
|
|
68
|
+
emit.onChange()
|
|
66
69
|
onValueCommit?.(isMultiple ? v : (v[0] ?? min))
|
|
67
70
|
}
|
|
68
71
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { switchVariants, switchDefaults } from './switch.variants.js'
|
|
10
10
|
import { getComponentConfig, iconsDefaults } from '../config.js'
|
|
11
11
|
import Icon from '../Icon/Icon.svelte'
|
|
12
|
-
import { useFormField } from '../hooks/useFormField.svelte.js'
|
|
12
|
+
import { useFormField, useFormFieldEmit } from '../hooks/useFormField.svelte.js'
|
|
13
13
|
|
|
14
14
|
const config = getComponentConfig('switch', switchDefaults)
|
|
15
15
|
const icons = getComponentConfig('icons', iconsDefaults)
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
}: Props = $props()
|
|
40
40
|
|
|
41
41
|
const formFieldContext = useFormField()
|
|
42
|
+
const emit = useFormFieldEmit()
|
|
42
43
|
|
|
43
44
|
const hasError = $derived(
|
|
44
45
|
formFieldContext?.error !== undefined && formFieldContext?.error !== false
|
|
@@ -108,7 +109,12 @@
|
|
|
108
109
|
<div class={classes.container}>
|
|
109
110
|
<Switch.Root
|
|
110
111
|
bind:checked
|
|
111
|
-
{
|
|
112
|
+
onCheckedChange={(val) => {
|
|
113
|
+
emit.onChange()
|
|
114
|
+
onCheckedChange?.(val)
|
|
115
|
+
}}
|
|
116
|
+
onblur={() => emit.onBlur()}
|
|
117
|
+
onfocus={() => emit.onFocus()}
|
|
112
118
|
id={resolvedId}
|
|
113
119
|
name={resolvedName}
|
|
114
120
|
{value}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
type FieldGroupVariantProps
|
|
14
14
|
} from '../FieldGroup/field-group.variants.js'
|
|
15
15
|
import Icon from '../Icon/Icon.svelte'
|
|
16
|
-
import { useFormField } from '../hooks/useFormField.svelte.js'
|
|
16
|
+
import { useFormField, useFormFieldEmit } from '../hooks/useFormField.svelte.js'
|
|
17
17
|
|
|
18
18
|
const config = getComponentConfig('textarea', textareaDefaults)
|
|
19
19
|
const icons = getComponentConfig('icons', iconsDefaults)
|
|
@@ -41,10 +41,32 @@
|
|
|
41
41
|
rows = 3,
|
|
42
42
|
maxrows = 0,
|
|
43
43
|
class: className,
|
|
44
|
+
onblur,
|
|
45
|
+
oninput,
|
|
46
|
+
onchange,
|
|
47
|
+
onfocus,
|
|
44
48
|
...restProps
|
|
45
49
|
}: Props = $props()
|
|
46
50
|
|
|
47
51
|
const formFieldContext = useFormField()
|
|
52
|
+
const emit = useFormFieldEmit()
|
|
53
|
+
|
|
54
|
+
function handleBlur(event: FocusEvent & { currentTarget: HTMLTextAreaElement }) {
|
|
55
|
+
emit.onBlur()
|
|
56
|
+
onblur?.(event)
|
|
57
|
+
}
|
|
58
|
+
function handleInput(event: Event & { currentTarget: HTMLTextAreaElement }) {
|
|
59
|
+
emit.onInput()
|
|
60
|
+
oninput?.(event)
|
|
61
|
+
}
|
|
62
|
+
function handleChange(event: Event & { currentTarget: HTMLTextAreaElement }) {
|
|
63
|
+
emit.onChange()
|
|
64
|
+
onchange?.(event)
|
|
65
|
+
}
|
|
66
|
+
function handleFocus(event: FocusEvent & { currentTarget: HTMLTextAreaElement }) {
|
|
67
|
+
emit.onFocus()
|
|
68
|
+
onfocus?.(event)
|
|
69
|
+
}
|
|
48
70
|
|
|
49
71
|
const fieldGroupContext = getContext<
|
|
50
72
|
| {
|
|
@@ -175,6 +197,10 @@
|
|
|
175
197
|
aria-describedby={ariaDescribedBy}
|
|
176
198
|
aria-invalid={resolvedHighlight ? true : undefined}
|
|
177
199
|
class={classes.base}
|
|
200
|
+
onblur={handleBlur}
|
|
201
|
+
oninput={handleInput}
|
|
202
|
+
onchange={handleChange}
|
|
203
|
+
onfocus={handleFocus}
|
|
178
204
|
></textarea>
|
|
179
205
|
|
|
180
206
|
{#if trailingSlot}
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { useMediaQuery } from './useMediaQuery.svelte.js';
|
|
|
2
2
|
export type { UseMediaQueryOptions } from './useMediaQuery.svelte.js';
|
|
3
3
|
export { useClipboard } from './useClipboard.svelte.js';
|
|
4
4
|
export type { UseClipboardOptions } from './useClipboard.svelte.js';
|
|
5
|
-
export { useFormField } from './useFormField.svelte.js';
|
|
5
|
+
export { useFormField, useFormFieldEmit, wireFormEvents, FORM_FIELD_CONTEXT_KEY } from './useFormField.svelte.js';
|
|
6
6
|
export type { FormFieldContext } from './useFormField.svelte.js';
|
|
7
7
|
export { useClickOutside } from './useClickOutside.svelte.js';
|
|
8
8
|
export type { UseClickOutsideOptions } from './useClickOutside.svelte.js';
|
package/dist/hooks/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { useMediaQuery } from './useMediaQuery.svelte.js';
|
|
2
2
|
export { useClipboard } from './useClipboard.svelte.js';
|
|
3
|
-
export { useFormField } from './useFormField.svelte.js';
|
|
3
|
+
export { useFormField, useFormFieldEmit, wireFormEvents, FORM_FIELD_CONTEXT_KEY } from './useFormField.svelte.js';
|
|
4
4
|
export { useClickOutside } from './useClickOutside.svelte.js';
|
|
5
5
|
export { useInfiniteScroll } from './useInfiniteScroll.svelte.js';
|
|
6
6
|
export { useEscapeKeydown } from './useEscapeKeydown.svelte.js';
|
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
import type { FormFieldProps } from '../FormField/form-field.types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Symbol key for the FormField context. Using a Symbol instead of a string
|
|
4
|
+
* prevents collisions with unrelated `getContext('formField')` calls from
|
|
5
|
+
* user code or other libraries.
|
|
6
|
+
*/
|
|
7
|
+
export declare const FORM_FIELD_CONTEXT_KEY: unique symbol;
|
|
2
8
|
export interface FormFieldContext {
|
|
3
9
|
name?: string;
|
|
4
10
|
size: NonNullable<FormFieldProps['size']>;
|
|
5
11
|
error?: string | boolean;
|
|
6
12
|
ariaId: string;
|
|
13
|
+
/** Whether input events should validate this field before first blur. */
|
|
14
|
+
eagerValidation?: boolean;
|
|
15
|
+
/** Per-field override for the input debounce delay. */
|
|
16
|
+
validateOnInputDelay?: number;
|
|
17
|
+
/** Regex pattern used to match form errors for this field (in addition to exact name). */
|
|
18
|
+
errorPattern?: RegExp;
|
|
7
19
|
}
|
|
8
20
|
/**
|
|
9
21
|
* Access the nearest FormField context. Returns `undefined` when used outside a FormField.
|
|
@@ -19,3 +31,55 @@ export interface FormFieldContext {
|
|
|
19
31
|
* ```
|
|
20
32
|
*/
|
|
21
33
|
export declare function useFormField(): FormFieldContext | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Event emitter helpers for inputs nested inside a `<FormField>` within a `<Form>`.
|
|
36
|
+
* Each returned function is a safe no-op when used outside a Form, so inputs can
|
|
37
|
+
* unconditionally wire them to their native events.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```svelte
|
|
41
|
+
* <script>
|
|
42
|
+
* import { useFormFieldEmit } from 'sv5ui'
|
|
43
|
+
* const emit = useFormFieldEmit()
|
|
44
|
+
* </script>
|
|
45
|
+
*
|
|
46
|
+
* <input onblur={emit.onBlur} oninput={emit.onInput} onchange={emit.onChange} onfocus={emit.onFocus} />
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function useFormFieldEmit(): {
|
|
50
|
+
onBlur(): void;
|
|
51
|
+
onFocus(): void;
|
|
52
|
+
onChange(): void;
|
|
53
|
+
onInput(): void;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* Wires native DOM input events to the parent Form's event emitters while
|
|
57
|
+
* preserving any user-supplied handlers. Reduces boilerplate in wrapper
|
|
58
|
+
* components (Input, Textarea, etc.) from ~20 lines of handler definitions
|
|
59
|
+
* to 4 lines:
|
|
60
|
+
*
|
|
61
|
+
* ```svelte
|
|
62
|
+
* <script>
|
|
63
|
+
* const events = wireFormEvents({ onblur, oninput, onchange, onfocus })
|
|
64
|
+
* </script>
|
|
65
|
+
*
|
|
66
|
+
* <input {...events} />
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* Each handler fires the Form emitter first, then calls the user handler
|
|
70
|
+
* (if any) with the original event.
|
|
71
|
+
*/
|
|
72
|
+
type InputEventHandler<E extends Event = Event> = (event: E) => void;
|
|
73
|
+
type FocusEventHandler = InputEventHandler<FocusEvent>;
|
|
74
|
+
export declare function wireFormEvents(userHandlers: {
|
|
75
|
+
onblur?: FocusEventHandler | null;
|
|
76
|
+
oninput?: InputEventHandler | null;
|
|
77
|
+
onchange?: InputEventHandler | null;
|
|
78
|
+
onfocus?: FocusEventHandler | null;
|
|
79
|
+
}): {
|
|
80
|
+
onblur(event: FocusEvent): void;
|
|
81
|
+
oninput(event: Event): void;
|
|
82
|
+
onchange(event: Event): void;
|
|
83
|
+
onfocus(event: FocusEvent): void;
|
|
84
|
+
};
|
|
85
|
+
export {};
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { getContext } from 'svelte';
|
|
2
|
+
import { getFormContext } from '../Form/form.context.svelte.js';
|
|
3
|
+
/**
|
|
4
|
+
* Symbol key for the FormField context. Using a Symbol instead of a string
|
|
5
|
+
* prevents collisions with unrelated `getContext('formField')` calls from
|
|
6
|
+
* user code or other libraries.
|
|
7
|
+
*/
|
|
8
|
+
export const FORM_FIELD_CONTEXT_KEY = Symbol('sv5ui:form-field');
|
|
2
9
|
/**
|
|
3
10
|
* Access the nearest FormField context. Returns `undefined` when used outside a FormField.
|
|
4
11
|
*
|
|
@@ -13,5 +20,67 @@ import { getContext } from 'svelte';
|
|
|
13
20
|
* ```
|
|
14
21
|
*/
|
|
15
22
|
export function useFormField() {
|
|
16
|
-
return getContext(
|
|
23
|
+
return getContext(FORM_FIELD_CONTEXT_KEY);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Event emitter helpers for inputs nested inside a `<FormField>` within a `<Form>`.
|
|
27
|
+
* Each returned function is a safe no-op when used outside a Form, so inputs can
|
|
28
|
+
* unconditionally wire them to their native events.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```svelte
|
|
32
|
+
* <script>
|
|
33
|
+
* import { useFormFieldEmit } from 'sv5ui'
|
|
34
|
+
* const emit = useFormFieldEmit()
|
|
35
|
+
* </script>
|
|
36
|
+
*
|
|
37
|
+
* <input onblur={emit.onBlur} oninput={emit.onInput} onchange={emit.onChange} onfocus={emit.onFocus} />
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export function useFormFieldEmit() {
|
|
41
|
+
const fieldCtx = getContext(FORM_FIELD_CONTEXT_KEY);
|
|
42
|
+
const formCtx = getFormContext();
|
|
43
|
+
return {
|
|
44
|
+
onBlur() {
|
|
45
|
+
const n = fieldCtx?.name;
|
|
46
|
+
if (n)
|
|
47
|
+
formCtx?.onBlur(n);
|
|
48
|
+
},
|
|
49
|
+
onFocus() {
|
|
50
|
+
const n = fieldCtx?.name;
|
|
51
|
+
if (n)
|
|
52
|
+
formCtx?.onFocus(n);
|
|
53
|
+
},
|
|
54
|
+
onChange() {
|
|
55
|
+
const n = fieldCtx?.name;
|
|
56
|
+
if (n)
|
|
57
|
+
formCtx?.onChange(n);
|
|
58
|
+
},
|
|
59
|
+
onInput() {
|
|
60
|
+
const n = fieldCtx?.name;
|
|
61
|
+
if (n)
|
|
62
|
+
formCtx?.onInput(n, fieldCtx?.eagerValidation);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export function wireFormEvents(userHandlers) {
|
|
67
|
+
const emit = useFormFieldEmit();
|
|
68
|
+
return {
|
|
69
|
+
onblur(event) {
|
|
70
|
+
emit.onBlur();
|
|
71
|
+
userHandlers.onblur?.(event);
|
|
72
|
+
},
|
|
73
|
+
oninput(event) {
|
|
74
|
+
emit.onInput();
|
|
75
|
+
userHandlers.oninput?.(event);
|
|
76
|
+
},
|
|
77
|
+
onchange(event) {
|
|
78
|
+
emit.onChange();
|
|
79
|
+
userHandlers.onchange?.(event);
|
|
80
|
+
},
|
|
81
|
+
onfocus(event) {
|
|
82
|
+
emit.onFocus();
|
|
83
|
+
userHandlers.onfocus?.(event);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
17
86
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export * from './Tabs/index.js';
|
|
|
31
31
|
export * from './Pagination/index.js';
|
|
32
32
|
export * from './FieldGroup/index.js';
|
|
33
33
|
export * from './FormField/index.js';
|
|
34
|
+
export * from './Form/index.js';
|
|
34
35
|
export * from './Input/index.js';
|
|
35
36
|
export * from './Textarea/index.js';
|
|
36
37
|
export * from './Select/index.js';
|
|
@@ -45,6 +46,7 @@ export * from './PinInput/index.js';
|
|
|
45
46
|
export * from './ThemeModeButton/index.js';
|
|
46
47
|
export * from './Table/index.js';
|
|
47
48
|
export * from './Toast/index.js';
|
|
49
|
+
export * from './Carousel/index.js';
|
|
48
50
|
export * from './hooks/index.js';
|
|
49
51
|
export { defineConfig } from './config.js';
|
|
50
52
|
export type { UIConfig } from './config.js';
|
package/dist/index.js
CHANGED
|
@@ -32,6 +32,7 @@ export * from './Tabs/index.js';
|
|
|
32
32
|
export * from './Pagination/index.js';
|
|
33
33
|
export * from './FieldGroup/index.js';
|
|
34
34
|
export * from './FormField/index.js';
|
|
35
|
+
export * from './Form/index.js';
|
|
35
36
|
export * from './Input/index.js';
|
|
36
37
|
export * from './Textarea/index.js';
|
|
37
38
|
export * from './Select/index.js';
|
|
@@ -46,6 +47,7 @@ export * from './PinInput/index.js';
|
|
|
46
47
|
export * from './ThemeModeButton/index.js';
|
|
47
48
|
export * from './Table/index.js';
|
|
48
49
|
export * from './Toast/index.js';
|
|
50
|
+
export * from './Carousel/index.js';
|
|
49
51
|
// Composables
|
|
50
52
|
export * from './hooks/index.js';
|
|
51
53
|
// Configuration
|