Skip to content

Commit

Permalink
feat(form): add more slot props to support custom fields
Browse files Browse the repository at this point in the history
  • Loading branch information
mdauner committed Oct 16, 2019
1 parent f58a8ac commit 3d0aacd
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 60 deletions.
85 changes: 84 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Declarative forms for [Svelte](https://svelte.dev/).

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

## Install

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

## How to use

### Example
### With provided `Input`, `Select`, `Choice` helper components

```html
<script>
Expand Down Expand Up @@ -132,3 +134,84 @@ $ yarn add sveltejs-forms
The form is valid: {isValid}
</Form>
```

### With custom component:

```html
<script>
import { Form } from 'sveltejs-forms';
import Select from 'svelte-select';
import * as yup from 'yup';
let svelteSelect;
function handleSubmit({ detail: { values, setSubmitting, resetForm } }) {
setTimeout(() => {
console.log(values);
setSubmitting(false);
svelteSelect.handleClear();
resetForm();
}, 2000);
}
const schema = yup.object().shape({
food: yup
.array()
.of(yup.string().required())
.min(2),
});
let items = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'pizza', label: 'Pizza' },
{ value: 'cake', label: 'Cake' },
{ value: 'chips', label: 'Chips' },
{ value: 'ice-cream', label: 'Ice Cream' },
];
</script>

<Form
{schema}
on:submit={handleSubmit}
let:setValue
let:validate
let:values
let:errors
let:touched>

<Select
{items}
isMulti={true}
bind:this={svelteSelect}
inputAttributes="{{ name: 'food' }}"
hasError="{touched['food'] && errors['food']}"
on:select="{({ detail }) => {
setValue('food', detail && detail.map(item => item.value));
validate();
}}"
on:clear="{() => {
setValue('food', []);
validate();
}}"
selectedValue="{items.filter(item => values['food'].includes(item.value))}" />

<button type="submit">Sign in</button>
</Form>
```

## Slot props

| Name | Type |
|------|------|
| isSubmitting | `boolean`
| isValid | `boolean`
| setValue(path, value) | `function`
| touchField(path) | `function`
| validate() | `function`
| values | `object`
| errors | `object`
| touched | `object`

## Contributions

**All contributions (no matter if small) are always welcome.**
23 changes: 5 additions & 18 deletions src/components/Choice.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,9 @@
export let options;
export let multiple = false;
const {
touchField,
validate,
values,
errors,
touched,
validateOnBlur,
validateOnChange,
} = getContext(FORM);
const { touchField, values, errors, touched, validateOnChange } = getContext(
FORM
);
const choice = writableDerived(
values,
Expand All @@ -26,18 +20,11 @@
);
function onChange() {
touchField(name);
if (validateOnChange) {
validate();
}
touchField(name, validateOnChange);
}
function onBlur() {
if (validateOnBlur) {
touchField(name);
validate();
}
touchField(name);
}
</script>

Expand Down
22 changes: 19 additions & 3 deletions src/components/Form.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,20 @@
}
}
function touchField(path) {
$touched = set($touched, path, true);
function touchField(path, shouldValidate = false) {
if (validateOnBlur || shouldValidate) {
$touched = set($touched, path, true);
validate();
}
}
function setValue(path, value) {
$values = set($values, path, value);
$touched = set($touched, path, true);
if (validateOnChange) {
validate();
}
}
function handleResetClick() {
Expand All @@ -121,5 +129,13 @@
on:reset={handleResetClick}
class="sveltejs-forms"
bind:this={form}>
<slot isSubmitting={$isSubmitting} {isValid} />
<slot
isSubmitting={$isSubmitting}
{isValid}
{setValue}
{touchField}
{validate}
values={$values}
errors={$errors}
touched={$touched} />
</form>
21 changes: 2 additions & 19 deletions src/components/Input.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,14 @@
export let placeholder = '';
export let multiline = false;
const {
touchField,
setValue,
validate,
values,
errors,
touched,
validateOnBlur,
validateOnChange,
} = getContext(FORM);
const { touchField, setValue, values, errors, touched } = getContext(FORM);
function onChange(event) {
setValue(name, event.target.value);
touchField(name);
if (validateOnChange) {
validate();
}
}
function onBlur() {
if (validateOnBlur) {
touchField(name);
validate();
}
touchField(name);
}
</script>

Expand Down
21 changes: 2 additions & 19 deletions src/components/Select.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,14 @@
export let name;
export let options;
const {
touchField,
setValue,
validate,
values,
errors,
touched,
validateOnBlur,
validateOnChange,
} = getContext(FORM);
const { touchField, setValue, values, errors, touched } = getContext(FORM);
function onChange(event) {
setValue(name, event.target.value);
touchField(name);
if (validateOnChange) {
validate();
}
}
function onBlur() {
if (validateOnBlur) {
touchField(name);
validate();
}
touchField(name);
}
</script>

Expand Down

0 comments on commit 3d0aacd

Please sign in to comment.