📝(react) react-hook-form forms Sports examples
Our forms needs to be usable with react-hook-form
This commit is contained in:
@@ -1,20 +1,149 @@
|
|||||||
|
import { yupResolver } from "@hookform/resolvers/yup";
|
||||||
import { Meta } from "@storybook/react";
|
import { Meta } from "@storybook/react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { useForm, Controller, ControllerRenderProps } from "react-hook-form";
|
||||||
|
import * as Yup from "yup";
|
||||||
import { Input } from ":/components/Forms/Input";
|
import { Input } from ":/components/Forms/Input";
|
||||||
import { Checkbox } from ":/components/Forms/Checkbox";
|
|
||||||
import { Button } from ":/components/Button";
|
import { Button } from ":/components/Button";
|
||||||
import { Select } from ":/components/Forms/Select";
|
import { Select } from ":/components/Forms/Select";
|
||||||
import { CunninghamProvider } from ":/components/Provider";
|
import { CunninghamProvider } from ":/components/Provider";
|
||||||
import { FileUploader } from ":/components/Forms/FileUploader";
|
import { Radio, RadioGroup } from ":/components/Forms/Radio";
|
||||||
import { Switch } from ":/components/Forms/Switch";
|
import {
|
||||||
import { Radio } from ":/components/Forms/Radio";
|
getFieldState,
|
||||||
|
getFieldErrorMessage,
|
||||||
|
onSubmit,
|
||||||
|
} from ":/tests/reactHookFormUtils";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: "Components/Forms/Examples",
|
title: "Components/Forms/Reac-Hook-Form",
|
||||||
} as Meta;
|
} as Meta;
|
||||||
|
|
||||||
|
enum GenderEnum {
|
||||||
|
MALE = "male",
|
||||||
|
FEMALE = "female",
|
||||||
|
OTHER = "other",
|
||||||
|
}
|
||||||
|
enum CompetitionEnum {
|
||||||
|
ATHLETICS = "Athletics",
|
||||||
|
SWIMMING = "Swimming",
|
||||||
|
MARATHON = "Marathon",
|
||||||
|
}
|
||||||
|
enum RewardEnum {
|
||||||
|
BRONZE = "bronze",
|
||||||
|
SILVER = "silver",
|
||||||
|
GOLD = "gold",
|
||||||
|
FLOCON = "flocon",
|
||||||
|
OURSON = "ourson",
|
||||||
|
CHAMOIS = "chamois",
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SportsStoryFormValues {
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
gender: GenderEnum;
|
||||||
|
competition: CompetitionEnum;
|
||||||
|
rewards: RewardEnum[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const sportsSchema = Yup.object().shape({
|
||||||
|
firstName: Yup.string().required(),
|
||||||
|
lastName: Yup.string().required(),
|
||||||
|
gender: Yup.string<GenderEnum>().required(),
|
||||||
|
competition: Yup.string()
|
||||||
|
.defined()
|
||||||
|
.required()
|
||||||
|
.oneOf(Object.values(CompetitionEnum)),
|
||||||
|
rewards: Yup.array().of(Yup.string<RewardEnum>().defined()).defined(),
|
||||||
|
});
|
||||||
|
|
||||||
export const Sports = () => {
|
export const Sports = () => {
|
||||||
|
const { register, handleSubmit, formState, control } =
|
||||||
|
useForm<SportsStoryFormValues>({
|
||||||
|
defaultValues: {
|
||||||
|
firstName: "",
|
||||||
|
lastName: "",
|
||||||
|
rewards: [],
|
||||||
|
},
|
||||||
|
mode: "onChange",
|
||||||
|
reValidateMode: "onChange",
|
||||||
|
resolver: yupResolver(sportsSchema),
|
||||||
|
});
|
||||||
|
|
||||||
|
const renderCompetitionSelect = ({
|
||||||
|
field,
|
||||||
|
}: {
|
||||||
|
field: ControllerRenderProps<SportsStoryFormValues, "competition">;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
label="Competition"
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
label: "Athletics",
|
||||||
|
value: CompetitionEnum.ATHLETICS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Swimming",
|
||||||
|
value: CompetitionEnum.SWIMMING,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Marathon",
|
||||||
|
value: CompetitionEnum.MARATHON,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
state={getFieldState("competition", formState)}
|
||||||
|
text={getFieldErrorMessage("competition", formState)}
|
||||||
|
onBlur={field.onBlur}
|
||||||
|
onChange={field.onChange}
|
||||||
|
value={field.value}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderRewardsMultiSelect = ({
|
||||||
|
field,
|
||||||
|
}: {
|
||||||
|
field: ControllerRenderProps<SportsStoryFormValues, "rewards">;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
label="Rewards"
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
label: "Bronze",
|
||||||
|
value: RewardEnum.BRONZE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Silver",
|
||||||
|
value: RewardEnum.SILVER,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Gold",
|
||||||
|
value: RewardEnum.GOLD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Flocon",
|
||||||
|
value: RewardEnum.FLOCON,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Ourson",
|
||||||
|
value: RewardEnum.OURSON,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Chamois",
|
||||||
|
value: RewardEnum.CHAMOIS,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
state={getFieldState("rewards", formState)}
|
||||||
|
text={getFieldErrorMessage("rewards", formState)}
|
||||||
|
onBlur={field.onBlur}
|
||||||
|
onChange={field.onChange}
|
||||||
|
value={field.value}
|
||||||
|
multi={true}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CunninghamProvider>
|
<CunninghamProvider>
|
||||||
<form
|
<form
|
||||||
@@ -24,6 +153,7 @@ export const Sports = () => {
|
|||||||
gap: "1rem",
|
gap: "1rem",
|
||||||
width: "400px",
|
width: "400px",
|
||||||
}}
|
}}
|
||||||
|
onSubmit={handleSubmit(onSubmit)}
|
||||||
>
|
>
|
||||||
<h1
|
<h1
|
||||||
className="fs-h3 fw-bold clr-greyscale-900"
|
className="fs-h3 fw-bold clr-greyscale-900"
|
||||||
@@ -32,54 +162,51 @@ export const Sports = () => {
|
|||||||
Register
|
Register
|
||||||
</h1>
|
</h1>
|
||||||
<div style={{ display: "flex", gap: "1rem" }}>
|
<div style={{ display: "flex", gap: "1rem" }}>
|
||||||
<Input label="First name" />
|
<Input
|
||||||
<Input label="Last name" />
|
label="First name"
|
||||||
|
state={getFieldState("firstName", formState)}
|
||||||
|
text={getFieldErrorMessage("firstName", formState)}
|
||||||
|
{...register("firstName")}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
label="Last name"
|
||||||
|
state={getFieldState("lastName", formState)}
|
||||||
|
text={getFieldErrorMessage("lastName", formState)}
|
||||||
|
{...register("lastName")}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ display: "flex", gap: "0.5rem" }}>
|
<RadioGroup
|
||||||
<Radio name="gender" label="Male" fullWidth={true} />
|
state={getFieldState("gender", formState)}
|
||||||
<Radio name="gender" label="Female" />
|
text={getFieldErrorMessage("gender", formState)}
|
||||||
<Radio name="gender" label="Other" />
|
style={{ display: "flex", flexDirection: "row", gap: "0.5rem" }}
|
||||||
</div>
|
>
|
||||||
<Select
|
<Radio
|
||||||
label="Competition"
|
label="Male"
|
||||||
options={[
|
fullWidth={true}
|
||||||
{
|
state={getFieldState("gender", formState)}
|
||||||
label: "Athletics",
|
{...register("gender")}
|
||||||
},
|
/>
|
||||||
{
|
<Radio
|
||||||
label: "Swimming",
|
label="Female"
|
||||||
},
|
state={getFieldState("gender", formState)}
|
||||||
{
|
{...register("gender")}
|
||||||
label: "Marathon",
|
/>
|
||||||
},
|
<Radio
|
||||||
]}
|
label="Other"
|
||||||
fullWidth={true}
|
state={getFieldState("gender", formState)}
|
||||||
|
{...register("gender")}
|
||||||
|
/>
|
||||||
|
</RadioGroup>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="competition"
|
||||||
|
render={renderCompetitionSelect}
|
||||||
/>
|
/>
|
||||||
<Select
|
<Controller
|
||||||
label="Previous rewards"
|
control={control}
|
||||||
multi={true}
|
name="rewards"
|
||||||
options={[
|
render={renderRewardsMultiSelect}
|
||||||
{
|
|
||||||
label: "Bronze",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Silver",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Gold",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Flocon",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Ourson",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "Chamois",
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
fullWidth={true}
|
|
||||||
/>
|
/>
|
||||||
<Button fullWidth={true}>Apply</Button>
|
<Button fullWidth={true}>Apply</Button>
|
||||||
<Button fullWidth={true} color="secondary">
|
<Button fullWidth={true} color="secondary">
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ export const RadioGroup = ({
|
|||||||
state,
|
state,
|
||||||
text,
|
text,
|
||||||
rightText,
|
rightText,
|
||||||
}: PropsWithChildren & FieldProps) => {
|
style,
|
||||||
|
}: PropsWithChildren & FieldProps & { style: React.CSSProperties }) => {
|
||||||
return (
|
return (
|
||||||
<Field
|
<Field
|
||||||
className="c__radio__group c__checkbox__group"
|
className="c__radio__group c__checkbox__group"
|
||||||
@@ -44,7 +45,9 @@ export const RadioGroup = ({
|
|||||||
rightText={rightText}
|
rightText={rightText}
|
||||||
compact={true}
|
compact={true}
|
||||||
>
|
>
|
||||||
<div className="c__checkbox__group__list">{children}</div>
|
<div className="c__checkbox__group__list" style={style}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
</Field>
|
</Field>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user