Improved form field hooks and remove yup
This commit is contained in:
@@ -0,0 +1 @@
|
||||
$main-color: #8fc;
|
||||
+19
-3
@@ -1,3 +1,5 @@
|
||||
@import 'defaults';
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
@@ -5,20 +7,34 @@
|
||||
input, button {
|
||||
font-size: 24px;
|
||||
padding: 5px 10px;
|
||||
border: solid 1px #ddd;
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
border: solid 1px #ddd;
|
||||
&:focus {
|
||||
border: solid 1px #aaa;
|
||||
}
|
||||
|
||||
&:valid {
|
||||
background-color: scale-color($main-color, $lightness: 80%);
|
||||
}
|
||||
|
||||
&.dirty:invalid {
|
||||
background-color: scale-color(red, $lightness: 80%);
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: #dfc;
|
||||
border: 0;
|
||||
background-color: $main-color;
|
||||
color: #555;
|
||||
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.2);
|
||||
|
||||
&:active {
|
||||
background-color: #ceb;
|
||||
box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
|
||||
+25
-20
@@ -1,50 +1,55 @@
|
||||
import { component, html, useState } from 'haunted';
|
||||
import { spread } from '@open-wc/lit-helpers';
|
||||
import { useMutation } from '@apollo/react-hooks';
|
||||
import * as yup from 'yup';
|
||||
|
||||
import { useFormField } from './myhooks';
|
||||
import { AddBook, GetBooks } from './queries'
|
||||
import Css from './bookform.scss';
|
||||
|
||||
const schema = yup.object().shape({
|
||||
title: yup.string().required(),
|
||||
author: yup.string().required(),
|
||||
});
|
||||
|
||||
const BookForm = () => {
|
||||
const [titleProps, setTitle] = useFormField("title");
|
||||
const [authorProps, setAuthor] = useFormField("author");
|
||||
const [titleProps, titleMeta] = useFormField("title");
|
||||
const [authorProps, authorMeta] = useFormField("author");
|
||||
const [addBook, { loading }] = useMutation(AddBook);
|
||||
|
||||
return html`
|
||||
<style>${Css.toString()}</style>
|
||||
<input placeholder="book title" ...=${spread(titleProps)}>
|
||||
<input placeholder="author name" ...=${spread(authorProps)}>
|
||||
<button @click=${async () => {
|
||||
<form @submit=${async (e: Event) => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
const newBook = await schema.validate({
|
||||
const newBook = {
|
||||
author: authorProps[".value"],
|
||||
title: titleProps[".value"]
|
||||
});
|
||||
};
|
||||
|
||||
await addBook({
|
||||
variables: newBook,
|
||||
update: (cache, { data }) => {
|
||||
const { books }: any = cache.readQuery({ query: GetBooks });
|
||||
cache.writeQuery({ query: GetBooks, data: { books: [...books, data.addBook] }});
|
||||
cache.writeQuery({
|
||||
query: GetBooks,
|
||||
data: { books: [...books, data.addBook] }
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
setTitle("");
|
||||
setAuthor("");
|
||||
titleMeta.reset();
|
||||
authorMeta.reset();
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
if (e instanceof yup.ValidationError) {
|
||||
console.log("validation error");
|
||||
}
|
||||
}
|
||||
}} ?disabled=${loading}>Add book</button>
|
||||
}}>
|
||||
<input
|
||||
required
|
||||
class=${titleMeta.isDirty ? "dirty" : ""}
|
||||
placeholder="book title"
|
||||
...=${spread(titleProps)}>
|
||||
<input
|
||||
required
|
||||
class=${authorMeta.isDirty ? "dirty" : ""}
|
||||
placeholder="author name"
|
||||
...=${spread(authorProps)}>
|
||||
<button ?disabled=${loading}>+ Add book</button>
|
||||
</form>
|
||||
`;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
@import 'defaults';
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
font-size: 24px;
|
||||
@@ -5,7 +7,7 @@
|
||||
}
|
||||
|
||||
p {
|
||||
border-bottom: solid 1px #cdf;
|
||||
border-bottom: solid 1px $main-color;
|
||||
|
||||
.author {
|
||||
font-size: 20px;
|
||||
@@ -14,7 +16,7 @@ p {
|
||||
}
|
||||
|
||||
a {
|
||||
color: #cdf;
|
||||
color: $main-color;
|
||||
font-size: 14px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
+3
-1
@@ -1,3 +1,5 @@
|
||||
@import 'defaults';
|
||||
|
||||
:host {
|
||||
font-family: Ubuntu, sans-serif;
|
||||
display: block;
|
||||
@@ -13,5 +15,5 @@
|
||||
|
||||
h1 {
|
||||
margin-top: 0;
|
||||
background-color: #dfc;
|
||||
background-color: $main-color;
|
||||
}
|
||||
|
||||
+28
-10
@@ -1,29 +1,47 @@
|
||||
import { useState, useCallback } from 'haunted';
|
||||
|
||||
type FormFieldProps = {
|
||||
name: string;
|
||||
type: "text";
|
||||
'.value': string;
|
||||
'@input': (e: any) => void;
|
||||
};
|
||||
|
||||
type FormFieldMeta = {
|
||||
setValue: ReturnType<typeof useState>[1];
|
||||
isDirty: boolean;
|
||||
reset: () => void;
|
||||
};
|
||||
|
||||
type FormField = [
|
||||
{
|
||||
name: string;
|
||||
type: "text";
|
||||
'.value': string;
|
||||
'@change': (e: any) => void;
|
||||
},
|
||||
ReturnType<typeof useState>[1]
|
||||
FormFieldProps,
|
||||
FormFieldMeta
|
||||
];
|
||||
|
||||
export const useFormField = (name: string, defaultValue = ""): FormField => {
|
||||
const [value, setValue] = useState(defaultValue);
|
||||
const [dirty, setDirty] = useState(false);
|
||||
const changeHandler = useCallback((e: any) => {
|
||||
setValue(e.target.value);
|
||||
}, [setValue]);
|
||||
setDirty(true);
|
||||
}, [setValue, setDirty]);
|
||||
const reset = useCallback(() => {
|
||||
setValue(defaultValue);
|
||||
setDirty(false);
|
||||
}, [setValue, setDirty, defaultValue]);
|
||||
|
||||
return [
|
||||
{
|
||||
name,
|
||||
type: "text",
|
||||
'.value': value,
|
||||
'@change': changeHandler
|
||||
'@input': changeHandler
|
||||
},
|
||||
setValue
|
||||
{
|
||||
setValue,
|
||||
isDirty: dirty,
|
||||
reset,
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user