Skip to content

Commit 3d0aacd

Browse files
committed
feat(form): add more slot props to support custom fields
1 parent f58a8ac commit 3d0aacd

File tree

5 files changed

+112
-60
lines changed

5 files changed

+112
-60
lines changed

README.md

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ Declarative forms for [Svelte](https://svelte.dev/).
1414

1515
- optional schema-based validation through [Yup](https://github.com/jquense/yup)
1616
- access to nested properties using paths
17+
- supports custom components
18+
- provides `Input`, `Select`, `Choice` components to reduce boilerplate
1719

1820
## Install
1921

@@ -29,7 +31,7 @@ $ yarn add sveltejs-forms
2931

3032
## How to use
3133

32-
### Example
34+
### With provided `Input`, `Select`, `Choice` helper components
3335

3436
```html
3537
<script>
@@ -132,3 +134,84 @@ $ yarn add sveltejs-forms
132134
The form is valid: {isValid}
133135
</Form>
134136
```
137+
138+
### With custom component:
139+
140+
```html
141+
<script>
142+
import { Form } from 'sveltejs-forms';
143+
import Select from 'svelte-select';
144+
import * as yup from 'yup';
145+
146+
let svelteSelect;
147+
148+
function handleSubmit({ detail: { values, setSubmitting, resetForm } }) {
149+
setTimeout(() => {
150+
console.log(values);
151+
setSubmitting(false);
152+
svelteSelect.handleClear();
153+
resetForm();
154+
}, 2000);
155+
}
156+
157+
const schema = yup.object().shape({
158+
food: yup
159+
.array()
160+
.of(yup.string().required())
161+
.min(2),
162+
});
163+
164+
let items = [
165+
{ value: 'chocolate', label: 'Chocolate' },
166+
{ value: 'pizza', label: 'Pizza' },
167+
{ value: 'cake', label: 'Cake' },
168+
{ value: 'chips', label: 'Chips' },
169+
{ value: 'ice-cream', label: 'Ice Cream' },
170+
];
171+
</script>
172+
173+
<Form
174+
{schema}
175+
on:submit={handleSubmit}
176+
let:setValue
177+
let:validate
178+
let:values
179+
let:errors
180+
let:touched>
181+
182+
<Select
183+
{items}
184+
isMulti={true}
185+
bind:this={svelteSelect}
186+
inputAttributes="{{ name: 'food' }}"
187+
hasError="{touched['food'] && errors['food']}"
188+
on:select="{({ detail }) => {
189+
setValue('food', detail && detail.map(item => item.value));
190+
validate();
191+
}}"
192+
on:clear="{() => {
193+
setValue('food', []);
194+
validate();
195+
}}"
196+
selectedValue="{items.filter(item => values['food'].includes(item.value))}" />
197+
198+
<button type="submit">Sign in</button>
199+
</Form>
200+
```
201+
202+
## Slot props
203+
204+
| Name | Type |
205+
|------|------|
206+
| isSubmitting | `boolean`
207+
| isValid | `boolean`
208+
| setValue(path, value) | `function`
209+
| touchField(path) | `function`
210+
| validate() | `function`
211+
| values | `object`
212+
| errors | `object`
213+
| touched | `object`
214+
215+
## Contributions
216+
217+
**All contributions (no matter if small) are always welcome.**

src/components/Choice.svelte

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,9 @@
99
export let options;
1010
export let multiple = false;
1111
12-
const {
13-
touchField,
14-
validate,
15-
values,
16-
errors,
17-
touched,
18-
validateOnBlur,
19-
validateOnChange,
20-
} = getContext(FORM);
12+
const { touchField, values, errors, touched, validateOnChange } = getContext(
13+
FORM
14+
);
2115
2216
const choice = writableDerived(
2317
values,
@@ -26,18 +20,11 @@
2620
);
2721
2822
function onChange() {
29-
touchField(name);
30-
31-
if (validateOnChange) {
32-
validate();
33-
}
23+
touchField(name, validateOnChange);
3424
}
3525
3626
function onBlur() {
37-
if (validateOnBlur) {
38-
touchField(name);
39-
validate();
40-
}
27+
touchField(name);
4128
}
4229
</script>
4330

src/components/Form.svelte

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,20 @@
8989
}
9090
}
9191
92-
function touchField(path) {
93-
$touched = set($touched, path, true);
92+
function touchField(path, shouldValidate = false) {
93+
if (validateOnBlur || shouldValidate) {
94+
$touched = set($touched, path, true);
95+
validate();
96+
}
9497
}
9598
9699
function setValue(path, value) {
97100
$values = set($values, path, value);
101+
$touched = set($touched, path, true);
102+
103+
if (validateOnChange) {
104+
validate();
105+
}
98106
}
99107
100108
function handleResetClick() {
@@ -121,5 +129,13 @@
121129
on:reset={handleResetClick}
122130
class="sveltejs-forms"
123131
bind:this={form}>
124-
<slot isSubmitting={$isSubmitting} {isValid} />
132+
<slot
133+
isSubmitting={$isSubmitting}
134+
{isValid}
135+
{setValue}
136+
{touchField}
137+
{validate}
138+
values={$values}
139+
errors={$errors}
140+
touched={$touched} />
125141
</form>

src/components/Input.svelte

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,31 +8,14 @@
88
export let placeholder = '';
99
export let multiline = false;
1010
11-
const {
12-
touchField,
13-
setValue,
14-
validate,
15-
values,
16-
errors,
17-
touched,
18-
validateOnBlur,
19-
validateOnChange,
20-
} = getContext(FORM);
11+
const { touchField, setValue, values, errors, touched } = getContext(FORM);
2112
2213
function onChange(event) {
2314
setValue(name, event.target.value);
24-
touchField(name);
25-
26-
if (validateOnChange) {
27-
validate();
28-
}
2915
}
3016
3117
function onBlur() {
32-
if (validateOnBlur) {
33-
touchField(name);
34-
validate();
35-
}
18+
touchField(name);
3619
}
3720
</script>
3821

src/components/Select.svelte

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,14 @@
66
export let name;
77
export let options;
88
9-
const {
10-
touchField,
11-
setValue,
12-
validate,
13-
values,
14-
errors,
15-
touched,
16-
validateOnBlur,
17-
validateOnChange,
18-
} = getContext(FORM);
9+
const { touchField, setValue, values, errors, touched } = getContext(FORM);
1910
2011
function onChange(event) {
2112
setValue(name, event.target.value);
22-
touchField(name);
23-
24-
if (validateOnChange) {
25-
validate();
26-
}
2713
}
2814
2915
function onBlur() {
30-
if (validateOnBlur) {
31-
touchField(name);
32-
validate();
33-
}
16+
touchField(name);
3417
}
3518
</script>
3619

0 commit comments

Comments
 (0)